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//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  113    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  114    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  115    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, ProjectPath,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    git_store::{GitStoreEvent, RepositoryEvent},
  137    project_settings::DiagnosticSeverity,
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    hover_links::{find_url, find_url_from_range},
  220};
  221use crate::{
  222    editor_settings::MultiCursorModifier,
  223    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  224};
  225
  226pub const FILE_HEADER_HEIGHT: u32 = 2;
  227pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  228pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241
  242pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  243pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  244pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  245
  246pub type RenderDiffHunkControlsFn = Arc<
  247    dyn Fn(
  248        u32,
  249        &DiffHunkStatus,
  250        Range<Anchor>,
  251        bool,
  252        Pixels,
  253        &Entity<Editor>,
  254        &mut Window,
  255        &mut App,
  256    ) -> AnyElement,
  257>;
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    DebuggerValue(usize),
  279    // LSP
  280    Hint(usize),
  281    Color(usize),
  282}
  283
  284impl InlayId {
  285    fn id(&self) -> usize {
  286        match self {
  287            Self::InlineCompletion(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289            Self::Hint(id) => *id,
  290            Self::Color(id) => *id,
  291        }
  292    }
  293}
  294
  295pub enum ActiveDebugLine {}
  296pub enum DebugStackFrameLine {}
  297enum DocumentHighlightRead {}
  298enum DocumentHighlightWrite {}
  299enum InputComposition {}
  300pub enum PendingInput {}
  301enum SelectedTextHighlight {}
  302
  303pub enum ConflictsOuter {}
  304pub enum ConflictsOurs {}
  305pub enum ConflictsTheirs {}
  306pub enum ConflictsOursMarker {}
  307pub enum ConflictsTheirsMarker {}
  308
  309#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  310pub enum Navigated {
  311    Yes,
  312    No,
  313}
  314
  315impl Navigated {
  316    pub fn from_bool(yes: bool) -> Navigated {
  317        if yes { Navigated::Yes } else { Navigated::No }
  318    }
  319}
  320
  321#[derive(Debug, Clone, PartialEq, Eq)]
  322enum DisplayDiffHunk {
  323    Folded {
  324        display_row: DisplayRow,
  325    },
  326    Unfolded {
  327        is_created_file: bool,
  328        diff_base_byte_range: Range<usize>,
  329        display_row_range: Range<DisplayRow>,
  330        multi_buffer_range: Range<Anchor>,
  331        status: DiffHunkStatus,
  332    },
  333}
  334
  335pub enum HideMouseCursorOrigin {
  336    TypingAction,
  337    MovementAction,
  338}
  339
  340pub fn init_settings(cx: &mut App) {
  341    EditorSettings::register(cx);
  342}
  343
  344pub fn init(cx: &mut App) {
  345    init_settings(cx);
  346
  347    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  348
  349    workspace::register_project_item::<Editor>(cx);
  350    workspace::FollowableViewRegistry::register::<Editor>(cx);
  351    workspace::register_serializable_item::<Editor>(cx);
  352
  353    cx.observe_new(
  354        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  355            workspace.register_action(Editor::new_file);
  356            workspace.register_action(Editor::new_file_vertical);
  357            workspace.register_action(Editor::new_file_horizontal);
  358            workspace.register_action(Editor::cancel_language_server_work);
  359        },
  360    )
  361    .detach();
  362
  363    cx.on_action(move |_: &workspace::NewFile, cx| {
  364        let app_state = workspace::AppState::global(cx);
  365        if let Some(app_state) = app_state.upgrade() {
  366            workspace::open_new(
  367                Default::default(),
  368                app_state,
  369                cx,
  370                |workspace, window, cx| {
  371                    Editor::new_file(workspace, &Default::default(), window, cx)
  372                },
  373            )
  374            .detach();
  375        }
  376    });
  377    cx.on_action(move |_: &workspace::NewWindow, cx| {
  378        let app_state = workspace::AppState::global(cx);
  379        if let Some(app_state) = app_state.upgrade() {
  380            workspace::open_new(
  381                Default::default(),
  382                app_state,
  383                cx,
  384                |workspace, window, cx| {
  385                    cx.activate(true);
  386                    Editor::new_file(workspace, &Default::default(), window, cx)
  387                },
  388            )
  389            .detach();
  390        }
  391    });
  392}
  393
  394pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  395    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  396}
  397
  398pub trait DiagnosticRenderer {
  399    fn render_group(
  400        &self,
  401        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  402        buffer_id: BufferId,
  403        snapshot: EditorSnapshot,
  404        editor: WeakEntity<Editor>,
  405        cx: &mut App,
  406    ) -> Vec<BlockProperties<Anchor>>;
  407
  408    fn render_hover(
  409        &self,
  410        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  411        range: Range<Point>,
  412        buffer_id: BufferId,
  413        cx: &mut App,
  414    ) -> Option<Entity<markdown::Markdown>>;
  415
  416    fn open_link(
  417        &self,
  418        editor: &mut Editor,
  419        link: SharedString,
  420        window: &mut Window,
  421        cx: &mut Context<Editor>,
  422    );
  423}
  424
  425pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  426
  427impl GlobalDiagnosticRenderer {
  428    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  429        cx.try_global::<Self>().map(|g| g.0.clone())
  430    }
  431}
  432
  433impl gpui::Global for GlobalDiagnosticRenderer {}
  434pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  435    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  436}
  437
  438pub struct SearchWithinRange;
  439
  440trait InvalidationRegion {
  441    fn ranges(&self) -> &[Range<Anchor>];
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum SelectPhase {
  446    Begin {
  447        position: DisplayPoint,
  448        add: bool,
  449        click_count: usize,
  450    },
  451    BeginColumnar {
  452        position: DisplayPoint,
  453        reset: bool,
  454        mode: ColumnarMode,
  455        goal_column: u32,
  456    },
  457    Extend {
  458        position: DisplayPoint,
  459        click_count: usize,
  460    },
  461    Update {
  462        position: DisplayPoint,
  463        goal_column: u32,
  464        scroll_delta: gpui::Point<f32>,
  465    },
  466    End,
  467}
  468
  469#[derive(Clone, Debug, PartialEq)]
  470pub enum ColumnarMode {
  471    FromMouse,
  472    FromSelection,
  473}
  474
  475#[derive(Clone, Debug)]
  476pub enum SelectMode {
  477    Character,
  478    Word(Range<Anchor>),
  479    Line(Range<Anchor>),
  480    All,
  481}
  482
  483#[derive(Clone, PartialEq, Eq, Debug)]
  484pub enum EditorMode {
  485    SingleLine {
  486        auto_width: bool,
  487    },
  488    AutoHeight {
  489        min_lines: usize,
  490        max_lines: Option<usize>,
  491    },
  492    Full {
  493        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  494        scale_ui_elements_with_buffer_font_size: bool,
  495        /// When set to `true`, the editor will render a background for the active line.
  496        show_active_line_background: bool,
  497        /// When set to `true`, the editor's height will be determined by its content.
  498        sized_by_content: bool,
  499    },
  500    Minimap {
  501        parent: WeakEntity<Editor>,
  502    },
  503}
  504
  505impl EditorMode {
  506    pub fn full() -> Self {
  507        Self::Full {
  508            scale_ui_elements_with_buffer_font_size: true,
  509            show_active_line_background: true,
  510            sized_by_content: false,
  511        }
  512    }
  513
  514    #[inline]
  515    pub fn is_full(&self) -> bool {
  516        matches!(self, Self::Full { .. })
  517    }
  518
  519    #[inline]
  520    pub fn is_single_line(&self) -> bool {
  521        matches!(self, Self::SingleLine { .. })
  522    }
  523
  524    #[inline]
  525    fn is_minimap(&self) -> bool {
  526        matches!(self, Self::Minimap { .. })
  527    }
  528}
  529
  530#[derive(Copy, Clone, Debug)]
  531pub enum SoftWrap {
  532    /// Prefer not to wrap at all.
  533    ///
  534    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  535    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  536    GitDiff,
  537    /// Prefer a single line generally, unless an overly long line is encountered.
  538    None,
  539    /// Soft wrap lines that exceed the editor width.
  540    EditorWidth,
  541    /// Soft wrap lines at the preferred line length.
  542    Column(u32),
  543    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  544    Bounded(u32),
  545}
  546
  547#[derive(Clone)]
  548pub struct EditorStyle {
  549    pub background: Hsla,
  550    pub local_player: PlayerColor,
  551    pub text: TextStyle,
  552    pub scrollbar_width: Pixels,
  553    pub syntax: Arc<SyntaxTheme>,
  554    pub status: StatusColors,
  555    pub inlay_hints_style: HighlightStyle,
  556    pub inline_completion_styles: InlineCompletionStyles,
  557    pub unnecessary_code_fade: f32,
  558    pub show_underlines: bool,
  559}
  560
  561impl Default for EditorStyle {
  562    fn default() -> Self {
  563        Self {
  564            background: Hsla::default(),
  565            local_player: PlayerColor::default(),
  566            text: TextStyle::default(),
  567            scrollbar_width: Pixels::default(),
  568            syntax: Default::default(),
  569            // HACK: Status colors don't have a real default.
  570            // We should look into removing the status colors from the editor
  571            // style and retrieve them directly from the theme.
  572            status: StatusColors::dark(),
  573            inlay_hints_style: HighlightStyle::default(),
  574            inline_completion_styles: InlineCompletionStyles {
  575                insertion: HighlightStyle::default(),
  576                whitespace: HighlightStyle::default(),
  577            },
  578            unnecessary_code_fade: Default::default(),
  579            show_underlines: true,
  580        }
  581    }
  582}
  583
  584pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  585    let show_background = language_settings::language_settings(None, None, cx)
  586        .inlay_hints
  587        .show_background;
  588
  589    HighlightStyle {
  590        color: Some(cx.theme().status().hint),
  591        background_color: show_background.then(|| cx.theme().status().hint_background),
  592        ..HighlightStyle::default()
  593    }
  594}
  595
  596pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  597    InlineCompletionStyles {
  598        insertion: HighlightStyle {
  599            color: Some(cx.theme().status().predictive),
  600            ..HighlightStyle::default()
  601        },
  602        whitespace: HighlightStyle {
  603            background_color: Some(cx.theme().status().created_background),
  604            ..HighlightStyle::default()
  605        },
  606    }
  607}
  608
  609type CompletionId = usize;
  610
  611pub(crate) enum EditDisplayMode {
  612    TabAccept,
  613    DiffPopover,
  614    Inline,
  615}
  616
  617enum InlineCompletion {
  618    Edit {
  619        edits: Vec<(Range<Anchor>, String)>,
  620        edit_preview: Option<EditPreview>,
  621        display_mode: EditDisplayMode,
  622        snapshot: BufferSnapshot,
  623    },
  624    Move {
  625        target: Anchor,
  626        snapshot: BufferSnapshot,
  627    },
  628}
  629
  630struct InlineCompletionState {
  631    inlay_ids: Vec<InlayId>,
  632    completion: InlineCompletion,
  633    completion_id: Option<SharedString>,
  634    invalidation_range: Range<Anchor>,
  635}
  636
  637enum EditPredictionSettings {
  638    Disabled,
  639    Enabled {
  640        show_in_menu: bool,
  641        preview_requires_modifier: bool,
  642    },
  643}
  644
  645enum InlineCompletionHighlight {}
  646
  647#[derive(Debug, Clone)]
  648struct InlineDiagnostic {
  649    message: SharedString,
  650    group_id: usize,
  651    is_primary: bool,
  652    start: Point,
  653    severity: lsp::DiagnosticSeverity,
  654}
  655
  656pub enum MenuInlineCompletionsPolicy {
  657    Never,
  658    ByProvider,
  659}
  660
  661pub enum EditPredictionPreview {
  662    /// Modifier is not pressed
  663    Inactive { released_too_fast: bool },
  664    /// Modifier pressed
  665    Active {
  666        since: Instant,
  667        previous_scroll_position: Option<ScrollAnchor>,
  668    },
  669}
  670
  671impl EditPredictionPreview {
  672    pub fn released_too_fast(&self) -> bool {
  673        match self {
  674            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  675            EditPredictionPreview::Active { .. } => false,
  676        }
  677    }
  678
  679    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  680        if let EditPredictionPreview::Active {
  681            previous_scroll_position,
  682            ..
  683        } = self
  684        {
  685            *previous_scroll_position = scroll_position;
  686        }
  687    }
  688}
  689
  690pub struct ContextMenuOptions {
  691    pub min_entries_visible: usize,
  692    pub max_entries_visible: usize,
  693    pub placement: Option<ContextMenuPlacement>,
  694}
  695
  696#[derive(Debug, Clone, PartialEq, Eq)]
  697pub enum ContextMenuPlacement {
  698    Above,
  699    Below,
  700}
  701
  702#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  703struct EditorActionId(usize);
  704
  705impl EditorActionId {
  706    pub fn post_inc(&mut self) -> Self {
  707        let answer = self.0;
  708
  709        *self = Self(answer + 1);
  710
  711        Self(answer)
  712    }
  713}
  714
  715// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  716// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  717
  718type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  719type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  720
  721#[derive(Default)]
  722struct ScrollbarMarkerState {
  723    scrollbar_size: Size<Pixels>,
  724    dirty: bool,
  725    markers: Arc<[PaintQuad]>,
  726    pending_refresh: Option<Task<Result<()>>>,
  727}
  728
  729impl ScrollbarMarkerState {
  730    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  731        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  732    }
  733}
  734
  735#[derive(Clone, Copy, PartialEq, Eq)]
  736pub enum MinimapVisibility {
  737    Disabled,
  738    Enabled {
  739        /// The configuration currently present in the users settings.
  740        setting_configuration: bool,
  741        /// Whether to override the currently set visibility from the users setting.
  742        toggle_override: bool,
  743    },
  744}
  745
  746impl MinimapVisibility {
  747    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  748        if mode.is_full() {
  749            Self::Enabled {
  750                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  751                toggle_override: false,
  752            }
  753        } else {
  754            Self::Disabled
  755        }
  756    }
  757
  758    fn hidden(&self) -> Self {
  759        match *self {
  760            Self::Enabled {
  761                setting_configuration,
  762                ..
  763            } => Self::Enabled {
  764                setting_configuration,
  765                toggle_override: setting_configuration,
  766            },
  767            Self::Disabled => Self::Disabled,
  768        }
  769    }
  770
  771    fn disabled(&self) -> bool {
  772        match *self {
  773            Self::Disabled => true,
  774            _ => false,
  775        }
  776    }
  777
  778    fn settings_visibility(&self) -> bool {
  779        match *self {
  780            Self::Enabled {
  781                setting_configuration,
  782                ..
  783            } => setting_configuration,
  784            _ => false,
  785        }
  786    }
  787
  788    fn visible(&self) -> bool {
  789        match *self {
  790            Self::Enabled {
  791                setting_configuration,
  792                toggle_override,
  793            } => setting_configuration ^ toggle_override,
  794            _ => false,
  795        }
  796    }
  797
  798    fn toggle_visibility(&self) -> Self {
  799        match *self {
  800            Self::Enabled {
  801                toggle_override,
  802                setting_configuration,
  803            } => Self::Enabled {
  804                setting_configuration,
  805                toggle_override: !toggle_override,
  806            },
  807            Self::Disabled => Self::Disabled,
  808        }
  809    }
  810}
  811
  812#[derive(Clone, Debug)]
  813struct RunnableTasks {
  814    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  815    offset: multi_buffer::Anchor,
  816    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  817    column: u32,
  818    // Values of all named captures, including those starting with '_'
  819    extra_variables: HashMap<String, String>,
  820    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  821    context_range: Range<BufferOffset>,
  822}
  823
  824impl RunnableTasks {
  825    fn resolve<'a>(
  826        &'a self,
  827        cx: &'a task::TaskContext,
  828    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  829        self.templates.iter().filter_map(|(kind, template)| {
  830            template
  831                .resolve_task(&kind.to_id_base(), cx)
  832                .map(|task| (kind.clone(), task))
  833        })
  834    }
  835}
  836
  837#[derive(Clone)]
  838pub struct ResolvedTasks {
  839    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  840    position: Anchor,
  841}
  842
  843#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  844struct BufferOffset(usize);
  845
  846// Addons allow storing per-editor state in other crates (e.g. Vim)
  847pub trait Addon: 'static {
  848    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  849
  850    fn render_buffer_header_controls(
  851        &self,
  852        _: &ExcerptInfo,
  853        _: &Window,
  854        _: &App,
  855    ) -> Option<AnyElement> {
  856        None
  857    }
  858
  859    fn to_any(&self) -> &dyn std::any::Any;
  860
  861    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  862        None
  863    }
  864}
  865
  866/// A set of caret positions, registered when the editor was edited.
  867pub struct ChangeList {
  868    changes: Vec<Vec<Anchor>>,
  869    /// Currently "selected" change.
  870    position: Option<usize>,
  871}
  872
  873impl ChangeList {
  874    pub fn new() -> Self {
  875        Self {
  876            changes: Vec::new(),
  877            position: None,
  878        }
  879    }
  880
  881    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  882    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  883    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  884        if self.changes.is_empty() {
  885            return None;
  886        }
  887
  888        let prev = self.position.unwrap_or(self.changes.len());
  889        let next = if direction == Direction::Prev {
  890            prev.saturating_sub(count)
  891        } else {
  892            (prev + count).min(self.changes.len() - 1)
  893        };
  894        self.position = Some(next);
  895        self.changes.get(next).map(|anchors| anchors.as_slice())
  896    }
  897
  898    /// Adds a new change to the list, resetting the change list position.
  899    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  900        self.position.take();
  901        if pop_state {
  902            self.changes.pop();
  903        }
  904        self.changes.push(new_positions.clone());
  905    }
  906
  907    pub fn last(&self) -> Option<&[Anchor]> {
  908        self.changes.last().map(|anchors| anchors.as_slice())
  909    }
  910}
  911
  912#[derive(Clone)]
  913struct InlineBlamePopoverState {
  914    scroll_handle: ScrollHandle,
  915    commit_message: Option<ParsedCommitMessage>,
  916    markdown: Entity<Markdown>,
  917}
  918
  919struct InlineBlamePopover {
  920    position: gpui::Point<Pixels>,
  921    hide_task: Option<Task<()>>,
  922    popover_bounds: Option<Bounds<Pixels>>,
  923    popover_state: InlineBlamePopoverState,
  924}
  925
  926enum SelectionDragState {
  927    /// State when no drag related activity is detected.
  928    None,
  929    /// State when the mouse is down on a selection that is about to be dragged.
  930    ReadyToDrag {
  931        selection: Selection<Anchor>,
  932        click_position: gpui::Point<Pixels>,
  933        mouse_down_time: Instant,
  934    },
  935    /// State when the mouse is dragging the selection in the editor.
  936    Dragging {
  937        selection: Selection<Anchor>,
  938        drop_cursor: Selection<Anchor>,
  939        hide_drop_cursor: bool,
  940    },
  941}
  942
  943enum ColumnarSelectionState {
  944    FromMouse {
  945        selection_tail: Anchor,
  946        display_point: Option<DisplayPoint>,
  947    },
  948    FromSelection {
  949        selection_tail: Anchor,
  950    },
  951}
  952
  953/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  954/// a breakpoint on them.
  955#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  956struct PhantomBreakpointIndicator {
  957    display_row: DisplayRow,
  958    /// There's a small debounce between hovering over the line and showing the indicator.
  959    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  960    is_active: bool,
  961    collides_with_existing_breakpoint: bool,
  962}
  963
  964/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  965///
  966/// See the [module level documentation](self) for more information.
  967pub struct Editor {
  968    focus_handle: FocusHandle,
  969    last_focused_descendant: Option<WeakFocusHandle>,
  970    /// The text buffer being edited
  971    buffer: Entity<MultiBuffer>,
  972    /// Map of how text in the buffer should be displayed.
  973    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  974    pub display_map: Entity<DisplayMap>,
  975    pub selections: SelectionsCollection,
  976    pub scroll_manager: ScrollManager,
  977    /// When inline assist editors are linked, they all render cursors because
  978    /// typing enters text into each of them, even the ones that aren't focused.
  979    pub(crate) show_cursor_when_unfocused: bool,
  980    columnar_selection_state: Option<ColumnarSelectionState>,
  981    add_selections_state: Option<AddSelectionsState>,
  982    select_next_state: Option<SelectNextState>,
  983    select_prev_state: Option<SelectNextState>,
  984    selection_history: SelectionHistory,
  985    defer_selection_effects: bool,
  986    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  987    autoclose_regions: Vec<AutocloseRegion>,
  988    snippet_stack: InvalidationStack<SnippetState>,
  989    select_syntax_node_history: SelectSyntaxNodeHistory,
  990    ime_transaction: Option<TransactionId>,
  991    pub diagnostics_max_severity: DiagnosticSeverity,
  992    active_diagnostics: ActiveDiagnostic,
  993    show_inline_diagnostics: bool,
  994    inline_diagnostics_update: Task<()>,
  995    inline_diagnostics_enabled: bool,
  996    diagnostics_enabled: bool,
  997    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  998    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  999    hard_wrap: Option<usize>,
 1000
 1001    // TODO: make this a access method
 1002    pub project: Option<Entity<Project>>,
 1003    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1004    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1005    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1006    blink_manager: Entity<BlinkManager>,
 1007    show_cursor_names: bool,
 1008    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1009    pub show_local_selections: bool,
 1010    mode: EditorMode,
 1011    show_breadcrumbs: bool,
 1012    show_gutter: bool,
 1013    show_scrollbars: ScrollbarAxes,
 1014    minimap_visibility: MinimapVisibility,
 1015    offset_content: bool,
 1016    disable_expand_excerpt_buttons: bool,
 1017    show_line_numbers: Option<bool>,
 1018    use_relative_line_numbers: Option<bool>,
 1019    show_git_diff_gutter: Option<bool>,
 1020    show_code_actions: Option<bool>,
 1021    show_runnables: Option<bool>,
 1022    show_breakpoints: Option<bool>,
 1023    show_wrap_guides: Option<bool>,
 1024    show_indent_guides: Option<bool>,
 1025    placeholder_text: Option<Arc<str>>,
 1026    highlight_order: usize,
 1027    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1028    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1029    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1030    scrollbar_marker_state: ScrollbarMarkerState,
 1031    active_indent_guides_state: ActiveIndentGuidesState,
 1032    nav_history: Option<ItemNavHistory>,
 1033    context_menu: RefCell<Option<CodeContextMenu>>,
 1034    context_menu_options: Option<ContextMenuOptions>,
 1035    mouse_context_menu: Option<MouseContextMenu>,
 1036    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1037    inline_blame_popover: Option<InlineBlamePopover>,
 1038    inline_blame_popover_show_task: Option<Task<()>>,
 1039    signature_help_state: SignatureHelpState,
 1040    auto_signature_help: Option<bool>,
 1041    find_all_references_task_sources: Vec<Anchor>,
 1042    next_completion_id: CompletionId,
 1043    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1044    code_actions_task: Option<Task<Result<()>>>,
 1045    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1046    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1047    document_highlights_task: Option<Task<()>>,
 1048    linked_editing_range_task: Option<Task<Option<()>>>,
 1049    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1050    pending_rename: Option<RenameState>,
 1051    searchable: bool,
 1052    cursor_shape: CursorShape,
 1053    current_line_highlight: Option<CurrentLineHighlight>,
 1054    collapse_matches: bool,
 1055    autoindent_mode: Option<AutoindentMode>,
 1056    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1057    input_enabled: bool,
 1058    use_modal_editing: bool,
 1059    read_only: bool,
 1060    leader_id: Option<CollaboratorId>,
 1061    remote_id: Option<ViewId>,
 1062    pub hover_state: HoverState,
 1063    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1064    gutter_hovered: bool,
 1065    hovered_link_state: Option<HoveredLinkState>,
 1066    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1067    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1068    active_inline_completion: Option<InlineCompletionState>,
 1069    /// Used to prevent flickering as the user types while the menu is open
 1070    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1071    edit_prediction_settings: EditPredictionSettings,
 1072    inline_completions_hidden_for_vim_mode: bool,
 1073    show_inline_completions_override: Option<bool>,
 1074    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1075    edit_prediction_preview: EditPredictionPreview,
 1076    edit_prediction_indent_conflict: bool,
 1077    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1078    inlay_hint_cache: InlayHintCache,
 1079    next_inlay_id: usize,
 1080    _subscriptions: Vec<Subscription>,
 1081    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1082    gutter_dimensions: GutterDimensions,
 1083    style: Option<EditorStyle>,
 1084    text_style_refinement: Option<TextStyleRefinement>,
 1085    next_editor_action_id: EditorActionId,
 1086    editor_actions: Rc<
 1087        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1088    >,
 1089    use_autoclose: bool,
 1090    use_auto_surround: bool,
 1091    auto_replace_emoji_shortcode: bool,
 1092    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1093    show_git_blame_gutter: bool,
 1094    show_git_blame_inline: bool,
 1095    show_git_blame_inline_delay_task: Option<Task<()>>,
 1096    git_blame_inline_enabled: bool,
 1097    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1098    serialize_dirty_buffers: bool,
 1099    show_selection_menu: Option<bool>,
 1100    blame: Option<Entity<GitBlame>>,
 1101    blame_subscription: Option<Subscription>,
 1102    custom_context_menu: Option<
 1103        Box<
 1104            dyn 'static
 1105                + Fn(
 1106                    &mut Self,
 1107                    DisplayPoint,
 1108                    &mut Window,
 1109                    &mut Context<Self>,
 1110                ) -> Option<Entity<ui::ContextMenu>>,
 1111        >,
 1112    >,
 1113    last_bounds: Option<Bounds<Pixels>>,
 1114    last_position_map: Option<Rc<PositionMap>>,
 1115    expect_bounds_change: Option<Bounds<Pixels>>,
 1116    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1117    tasks_update_task: Option<Task<()>>,
 1118    breakpoint_store: Option<Entity<BreakpointStore>>,
 1119    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1120    hovered_diff_hunk_row: Option<DisplayRow>,
 1121    pull_diagnostics_task: Task<()>,
 1122    in_project_search: bool,
 1123    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1124    breadcrumb_header: Option<String>,
 1125    focused_block: Option<FocusedBlock>,
 1126    next_scroll_position: NextScrollCursorCenterTopBottom,
 1127    addons: HashMap<TypeId, Box<dyn Addon>>,
 1128    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1129    load_diff_task: Option<Shared<Task<()>>>,
 1130    /// Whether we are temporarily displaying a diff other than git's
 1131    temporary_diff_override: bool,
 1132    selection_mark_mode: bool,
 1133    toggle_fold_multiple_buffers: Task<()>,
 1134    _scroll_cursor_center_top_bottom_task: Task<()>,
 1135    serialize_selections: Task<()>,
 1136    serialize_folds: Task<()>,
 1137    mouse_cursor_hidden: bool,
 1138    minimap: Option<Entity<Self>>,
 1139    hide_mouse_mode: HideMouseMode,
 1140    pub change_list: ChangeList,
 1141    inline_value_cache: InlineValueCache,
 1142    selection_drag_state: SelectionDragState,
 1143    drag_and_drop_selection_enabled: bool,
 1144    next_color_inlay_id: usize,
 1145    colors: Option<LspColorData>,
 1146}
 1147
 1148#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1149enum NextScrollCursorCenterTopBottom {
 1150    #[default]
 1151    Center,
 1152    Top,
 1153    Bottom,
 1154}
 1155
 1156impl NextScrollCursorCenterTopBottom {
 1157    fn next(&self) -> Self {
 1158        match self {
 1159            Self::Center => Self::Top,
 1160            Self::Top => Self::Bottom,
 1161            Self::Bottom => Self::Center,
 1162        }
 1163    }
 1164}
 1165
 1166#[derive(Clone)]
 1167pub struct EditorSnapshot {
 1168    pub mode: EditorMode,
 1169    show_gutter: bool,
 1170    show_line_numbers: Option<bool>,
 1171    show_git_diff_gutter: Option<bool>,
 1172    show_code_actions: Option<bool>,
 1173    show_runnables: Option<bool>,
 1174    show_breakpoints: Option<bool>,
 1175    git_blame_gutter_max_author_length: Option<usize>,
 1176    pub display_snapshot: DisplaySnapshot,
 1177    pub placeholder_text: Option<Arc<str>>,
 1178    is_focused: bool,
 1179    scroll_anchor: ScrollAnchor,
 1180    ongoing_scroll: OngoingScroll,
 1181    current_line_highlight: CurrentLineHighlight,
 1182    gutter_hovered: bool,
 1183}
 1184
 1185#[derive(Default, Debug, Clone, Copy)]
 1186pub struct GutterDimensions {
 1187    pub left_padding: Pixels,
 1188    pub right_padding: Pixels,
 1189    pub width: Pixels,
 1190    pub margin: Pixels,
 1191    pub git_blame_entries_width: Option<Pixels>,
 1192}
 1193
 1194impl GutterDimensions {
 1195    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1196        Self {
 1197            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1198            ..Default::default()
 1199        }
 1200    }
 1201
 1202    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1203        -cx.text_system().descent(font_id, font_size)
 1204    }
 1205    /// The full width of the space taken up by the gutter.
 1206    pub fn full_width(&self) -> Pixels {
 1207        self.margin + self.width
 1208    }
 1209
 1210    /// The width of the space reserved for the fold indicators,
 1211    /// use alongside 'justify_end' and `gutter_width` to
 1212    /// right align content with the line numbers
 1213    pub fn fold_area_width(&self) -> Pixels {
 1214        self.margin + self.right_padding
 1215    }
 1216}
 1217
 1218struct CharacterDimensions {
 1219    em_width: Pixels,
 1220    em_advance: Pixels,
 1221    line_height: Pixels,
 1222}
 1223
 1224#[derive(Debug)]
 1225pub struct RemoteSelection {
 1226    pub replica_id: ReplicaId,
 1227    pub selection: Selection<Anchor>,
 1228    pub cursor_shape: CursorShape,
 1229    pub collaborator_id: CollaboratorId,
 1230    pub line_mode: bool,
 1231    pub user_name: Option<SharedString>,
 1232    pub color: PlayerColor,
 1233}
 1234
 1235#[derive(Clone, Debug)]
 1236struct SelectionHistoryEntry {
 1237    selections: Arc<[Selection<Anchor>]>,
 1238    select_next_state: Option<SelectNextState>,
 1239    select_prev_state: Option<SelectNextState>,
 1240    add_selections_state: Option<AddSelectionsState>,
 1241}
 1242
 1243#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1244enum SelectionHistoryMode {
 1245    Normal,
 1246    Undoing,
 1247    Redoing,
 1248    Skipping,
 1249}
 1250
 1251#[derive(Clone, PartialEq, Eq, Hash)]
 1252struct HoveredCursor {
 1253    replica_id: u16,
 1254    selection_id: usize,
 1255}
 1256
 1257impl Default for SelectionHistoryMode {
 1258    fn default() -> Self {
 1259        Self::Normal
 1260    }
 1261}
 1262
 1263#[derive(Debug)]
 1264pub struct SelectionEffects {
 1265    nav_history: Option<bool>,
 1266    completions: bool,
 1267    scroll: Option<Autoscroll>,
 1268}
 1269
 1270impl Default for SelectionEffects {
 1271    fn default() -> Self {
 1272        Self {
 1273            nav_history: None,
 1274            completions: true,
 1275            scroll: Some(Autoscroll::fit()),
 1276        }
 1277    }
 1278}
 1279impl SelectionEffects {
 1280    pub fn scroll(scroll: Autoscroll) -> Self {
 1281        Self {
 1282            scroll: Some(scroll),
 1283            ..Default::default()
 1284        }
 1285    }
 1286
 1287    pub fn no_scroll() -> Self {
 1288        Self {
 1289            scroll: None,
 1290            ..Default::default()
 1291        }
 1292    }
 1293
 1294    pub fn completions(self, completions: bool) -> Self {
 1295        Self {
 1296            completions,
 1297            ..self
 1298        }
 1299    }
 1300
 1301    pub fn nav_history(self, nav_history: bool) -> Self {
 1302        Self {
 1303            nav_history: Some(nav_history),
 1304            ..self
 1305        }
 1306    }
 1307}
 1308
 1309struct DeferredSelectionEffectsState {
 1310    changed: bool,
 1311    effects: SelectionEffects,
 1312    old_cursor_position: Anchor,
 1313    history_entry: SelectionHistoryEntry,
 1314}
 1315
 1316#[derive(Default)]
 1317struct SelectionHistory {
 1318    #[allow(clippy::type_complexity)]
 1319    selections_by_transaction:
 1320        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1321    mode: SelectionHistoryMode,
 1322    undo_stack: VecDeque<SelectionHistoryEntry>,
 1323    redo_stack: VecDeque<SelectionHistoryEntry>,
 1324}
 1325
 1326impl SelectionHistory {
 1327    #[track_caller]
 1328    fn insert_transaction(
 1329        &mut self,
 1330        transaction_id: TransactionId,
 1331        selections: Arc<[Selection<Anchor>]>,
 1332    ) {
 1333        if selections.is_empty() {
 1334            log::error!(
 1335                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1336                std::panic::Location::caller()
 1337            );
 1338            return;
 1339        }
 1340        self.selections_by_transaction
 1341            .insert(transaction_id, (selections, None));
 1342    }
 1343
 1344    #[allow(clippy::type_complexity)]
 1345    fn transaction(
 1346        &self,
 1347        transaction_id: TransactionId,
 1348    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1349        self.selections_by_transaction.get(&transaction_id)
 1350    }
 1351
 1352    #[allow(clippy::type_complexity)]
 1353    fn transaction_mut(
 1354        &mut self,
 1355        transaction_id: TransactionId,
 1356    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1357        self.selections_by_transaction.get_mut(&transaction_id)
 1358    }
 1359
 1360    fn push(&mut self, entry: SelectionHistoryEntry) {
 1361        if !entry.selections.is_empty() {
 1362            match self.mode {
 1363                SelectionHistoryMode::Normal => {
 1364                    self.push_undo(entry);
 1365                    self.redo_stack.clear();
 1366                }
 1367                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1368                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1369                SelectionHistoryMode::Skipping => {}
 1370            }
 1371        }
 1372    }
 1373
 1374    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1375        if self
 1376            .undo_stack
 1377            .back()
 1378            .map_or(true, |e| e.selections != entry.selections)
 1379        {
 1380            self.undo_stack.push_back(entry);
 1381            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1382                self.undo_stack.pop_front();
 1383            }
 1384        }
 1385    }
 1386
 1387    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1388        if self
 1389            .redo_stack
 1390            .back()
 1391            .map_or(true, |e| e.selections != entry.selections)
 1392        {
 1393            self.redo_stack.push_back(entry);
 1394            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1395                self.redo_stack.pop_front();
 1396            }
 1397        }
 1398    }
 1399}
 1400
 1401#[derive(Clone, Copy)]
 1402pub struct RowHighlightOptions {
 1403    pub autoscroll: bool,
 1404    pub include_gutter: bool,
 1405}
 1406
 1407impl Default for RowHighlightOptions {
 1408    fn default() -> Self {
 1409        Self {
 1410            autoscroll: Default::default(),
 1411            include_gutter: true,
 1412        }
 1413    }
 1414}
 1415
 1416struct RowHighlight {
 1417    index: usize,
 1418    range: Range<Anchor>,
 1419    color: Hsla,
 1420    options: RowHighlightOptions,
 1421    type_id: TypeId,
 1422}
 1423
 1424#[derive(Clone, Debug)]
 1425struct AddSelectionsState {
 1426    groups: Vec<AddSelectionsGroup>,
 1427}
 1428
 1429#[derive(Clone, Debug)]
 1430struct AddSelectionsGroup {
 1431    above: bool,
 1432    stack: Vec<usize>,
 1433}
 1434
 1435#[derive(Clone)]
 1436struct SelectNextState {
 1437    query: AhoCorasick,
 1438    wordwise: bool,
 1439    done: bool,
 1440}
 1441
 1442impl std::fmt::Debug for SelectNextState {
 1443    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1444        f.debug_struct(std::any::type_name::<Self>())
 1445            .field("wordwise", &self.wordwise)
 1446            .field("done", &self.done)
 1447            .finish()
 1448    }
 1449}
 1450
 1451#[derive(Debug)]
 1452struct AutocloseRegion {
 1453    selection_id: usize,
 1454    range: Range<Anchor>,
 1455    pair: BracketPair,
 1456}
 1457
 1458#[derive(Debug)]
 1459struct SnippetState {
 1460    ranges: Vec<Vec<Range<Anchor>>>,
 1461    active_index: usize,
 1462    choices: Vec<Option<Vec<String>>>,
 1463}
 1464
 1465#[doc(hidden)]
 1466pub struct RenameState {
 1467    pub range: Range<Anchor>,
 1468    pub old_name: Arc<str>,
 1469    pub editor: Entity<Editor>,
 1470    block_id: CustomBlockId,
 1471}
 1472
 1473struct InvalidationStack<T>(Vec<T>);
 1474
 1475struct RegisteredInlineCompletionProvider {
 1476    provider: Arc<dyn InlineCompletionProviderHandle>,
 1477    _subscription: Subscription,
 1478}
 1479
 1480#[derive(Debug, PartialEq, Eq)]
 1481pub struct ActiveDiagnosticGroup {
 1482    pub active_range: Range<Anchor>,
 1483    pub active_message: String,
 1484    pub group_id: usize,
 1485    pub blocks: HashSet<CustomBlockId>,
 1486}
 1487
 1488#[derive(Debug, PartialEq, Eq)]
 1489
 1490pub(crate) enum ActiveDiagnostic {
 1491    None,
 1492    All,
 1493    Group(ActiveDiagnosticGroup),
 1494}
 1495
 1496#[derive(Serialize, Deserialize, Clone, Debug)]
 1497pub struct ClipboardSelection {
 1498    /// The number of bytes in this selection.
 1499    pub len: usize,
 1500    /// Whether this was a full-line selection.
 1501    pub is_entire_line: bool,
 1502    /// The indentation of the first line when this content was originally copied.
 1503    pub first_line_indent: u32,
 1504}
 1505
 1506// selections, scroll behavior, was newest selection reversed
 1507type SelectSyntaxNodeHistoryState = (
 1508    Box<[Selection<usize>]>,
 1509    SelectSyntaxNodeScrollBehavior,
 1510    bool,
 1511);
 1512
 1513#[derive(Default)]
 1514struct SelectSyntaxNodeHistory {
 1515    stack: Vec<SelectSyntaxNodeHistoryState>,
 1516    // disable temporarily to allow changing selections without losing the stack
 1517    pub disable_clearing: bool,
 1518}
 1519
 1520impl SelectSyntaxNodeHistory {
 1521    pub fn try_clear(&mut self) {
 1522        if !self.disable_clearing {
 1523            self.stack.clear();
 1524        }
 1525    }
 1526
 1527    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1528        self.stack.push(selection);
 1529    }
 1530
 1531    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1532        self.stack.pop()
 1533    }
 1534}
 1535
 1536enum SelectSyntaxNodeScrollBehavior {
 1537    CursorTop,
 1538    FitSelection,
 1539    CursorBottom,
 1540}
 1541
 1542#[derive(Debug)]
 1543pub(crate) struct NavigationData {
 1544    cursor_anchor: Anchor,
 1545    cursor_position: Point,
 1546    scroll_anchor: ScrollAnchor,
 1547    scroll_top_row: u32,
 1548}
 1549
 1550#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1551pub enum GotoDefinitionKind {
 1552    Symbol,
 1553    Declaration,
 1554    Type,
 1555    Implementation,
 1556}
 1557
 1558#[derive(Debug, Clone)]
 1559enum InlayHintRefreshReason {
 1560    ModifiersChanged(bool),
 1561    Toggle(bool),
 1562    SettingsChange(InlayHintSettings),
 1563    NewLinesShown,
 1564    BufferEdited(HashSet<Arc<Language>>),
 1565    RefreshRequested,
 1566    ExcerptsRemoved(Vec<ExcerptId>),
 1567}
 1568
 1569impl InlayHintRefreshReason {
 1570    fn description(&self) -> &'static str {
 1571        match self {
 1572            Self::ModifiersChanged(_) => "modifiers changed",
 1573            Self::Toggle(_) => "toggle",
 1574            Self::SettingsChange(_) => "settings change",
 1575            Self::NewLinesShown => "new lines shown",
 1576            Self::BufferEdited(_) => "buffer edited",
 1577            Self::RefreshRequested => "refresh requested",
 1578            Self::ExcerptsRemoved(_) => "excerpts removed",
 1579        }
 1580    }
 1581}
 1582
 1583pub enum FormatTarget {
 1584    Buffers(HashSet<Entity<Buffer>>),
 1585    Ranges(Vec<Range<MultiBufferPoint>>),
 1586}
 1587
 1588pub(crate) struct FocusedBlock {
 1589    id: BlockId,
 1590    focus_handle: WeakFocusHandle,
 1591}
 1592
 1593#[derive(Clone)]
 1594enum JumpData {
 1595    MultiBufferRow {
 1596        row: MultiBufferRow,
 1597        line_offset_from_top: u32,
 1598    },
 1599    MultiBufferPoint {
 1600        excerpt_id: ExcerptId,
 1601        position: Point,
 1602        anchor: text::Anchor,
 1603        line_offset_from_top: u32,
 1604    },
 1605}
 1606
 1607pub enum MultibufferSelectionMode {
 1608    First,
 1609    All,
 1610}
 1611
 1612#[derive(Clone, Copy, Debug, Default)]
 1613pub struct RewrapOptions {
 1614    pub override_language_settings: bool,
 1615    pub preserve_existing_whitespace: bool,
 1616}
 1617
 1618impl Editor {
 1619    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1620        let buffer = cx.new(|cx| Buffer::local("", cx));
 1621        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1622        Self::new(
 1623            EditorMode::SingleLine { auto_width: false },
 1624            buffer,
 1625            None,
 1626            window,
 1627            cx,
 1628        )
 1629    }
 1630
 1631    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1632        let buffer = cx.new(|cx| Buffer::local("", cx));
 1633        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1634        Self::new(EditorMode::full(), buffer, None, window, cx)
 1635    }
 1636
 1637    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1638        let buffer = cx.new(|cx| Buffer::local("", cx));
 1639        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1640        Self::new(
 1641            EditorMode::SingleLine { auto_width: true },
 1642            buffer,
 1643            None,
 1644            window,
 1645            cx,
 1646        )
 1647    }
 1648
 1649    pub fn auto_height(
 1650        min_lines: usize,
 1651        max_lines: usize,
 1652        window: &mut Window,
 1653        cx: &mut Context<Self>,
 1654    ) -> Self {
 1655        let buffer = cx.new(|cx| Buffer::local("", cx));
 1656        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1657        Self::new(
 1658            EditorMode::AutoHeight {
 1659                min_lines,
 1660                max_lines: Some(max_lines),
 1661            },
 1662            buffer,
 1663            None,
 1664            window,
 1665            cx,
 1666        )
 1667    }
 1668
 1669    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1670    /// The editor grows as tall as needed to fit its content.
 1671    pub fn auto_height_unbounded(
 1672        min_lines: usize,
 1673        window: &mut Window,
 1674        cx: &mut Context<Self>,
 1675    ) -> Self {
 1676        let buffer = cx.new(|cx| Buffer::local("", cx));
 1677        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1678        Self::new(
 1679            EditorMode::AutoHeight {
 1680                min_lines,
 1681                max_lines: None,
 1682            },
 1683            buffer,
 1684            None,
 1685            window,
 1686            cx,
 1687        )
 1688    }
 1689
 1690    pub fn for_buffer(
 1691        buffer: Entity<Buffer>,
 1692        project: Option<Entity<Project>>,
 1693        window: &mut Window,
 1694        cx: &mut Context<Self>,
 1695    ) -> Self {
 1696        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1697        Self::new(EditorMode::full(), buffer, project, window, cx)
 1698    }
 1699
 1700    pub fn for_multibuffer(
 1701        buffer: Entity<MultiBuffer>,
 1702        project: Option<Entity<Project>>,
 1703        window: &mut Window,
 1704        cx: &mut Context<Self>,
 1705    ) -> Self {
 1706        Self::new(EditorMode::full(), buffer, project, window, cx)
 1707    }
 1708
 1709    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1710        let mut clone = Self::new(
 1711            self.mode.clone(),
 1712            self.buffer.clone(),
 1713            self.project.clone(),
 1714            window,
 1715            cx,
 1716        );
 1717        self.display_map.update(cx, |display_map, cx| {
 1718            let snapshot = display_map.snapshot(cx);
 1719            clone.display_map.update(cx, |display_map, cx| {
 1720                display_map.set_state(&snapshot, cx);
 1721            });
 1722        });
 1723        clone.folds_did_change(cx);
 1724        clone.selections.clone_state(&self.selections);
 1725        clone.scroll_manager.clone_state(&self.scroll_manager);
 1726        clone.searchable = self.searchable;
 1727        clone.read_only = self.read_only;
 1728        clone
 1729    }
 1730
 1731    pub fn new(
 1732        mode: EditorMode,
 1733        buffer: Entity<MultiBuffer>,
 1734        project: Option<Entity<Project>>,
 1735        window: &mut Window,
 1736        cx: &mut Context<Self>,
 1737    ) -> Self {
 1738        Editor::new_internal(mode, buffer, project, None, window, cx)
 1739    }
 1740
 1741    fn new_internal(
 1742        mode: EditorMode,
 1743        buffer: Entity<MultiBuffer>,
 1744        project: Option<Entity<Project>>,
 1745        display_map: Option<Entity<DisplayMap>>,
 1746        window: &mut Window,
 1747        cx: &mut Context<Self>,
 1748    ) -> Self {
 1749        debug_assert!(
 1750            display_map.is_none() || mode.is_minimap(),
 1751            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1752        );
 1753
 1754        let full_mode = mode.is_full();
 1755        let diagnostics_max_severity = if full_mode {
 1756            EditorSettings::get_global(cx)
 1757                .diagnostics_max_severity
 1758                .unwrap_or(DiagnosticSeverity::Hint)
 1759        } else {
 1760            DiagnosticSeverity::Off
 1761        };
 1762        let style = window.text_style();
 1763        let font_size = style.font_size.to_pixels(window.rem_size());
 1764        let editor = cx.entity().downgrade();
 1765        let fold_placeholder = FoldPlaceholder {
 1766            constrain_width: true,
 1767            render: Arc::new(move |fold_id, fold_range, cx| {
 1768                let editor = editor.clone();
 1769                div()
 1770                    .id(fold_id)
 1771                    .bg(cx.theme().colors().ghost_element_background)
 1772                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1773                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1774                    .rounded_xs()
 1775                    .size_full()
 1776                    .cursor_pointer()
 1777                    .child("")
 1778                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1779                    .on_click(move |_, _window, cx| {
 1780                        editor
 1781                            .update(cx, |editor, cx| {
 1782                                editor.unfold_ranges(
 1783                                    &[fold_range.start..fold_range.end],
 1784                                    true,
 1785                                    false,
 1786                                    cx,
 1787                                );
 1788                                cx.stop_propagation();
 1789                            })
 1790                            .ok();
 1791                    })
 1792                    .into_any()
 1793            }),
 1794            merge_adjacent: true,
 1795            ..FoldPlaceholder::default()
 1796        };
 1797        let display_map = display_map.unwrap_or_else(|| {
 1798            cx.new(|cx| {
 1799                DisplayMap::new(
 1800                    buffer.clone(),
 1801                    style.font(),
 1802                    font_size,
 1803                    None,
 1804                    FILE_HEADER_HEIGHT,
 1805                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1806                    fold_placeholder,
 1807                    diagnostics_max_severity,
 1808                    cx,
 1809                )
 1810            })
 1811        });
 1812
 1813        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1814
 1815        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1816
 1817        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1818            .then(|| language_settings::SoftWrap::None);
 1819
 1820        let mut project_subscriptions = Vec::new();
 1821        if mode.is_full() {
 1822            if let Some(project) = project.as_ref() {
 1823                project_subscriptions.push(cx.subscribe_in(
 1824                    project,
 1825                    window,
 1826                    |editor, _, event, window, cx| match event {
 1827                        project::Event::RefreshCodeLens => {
 1828                            // we always query lens with actions, without storing them, always refreshing them
 1829                        }
 1830                        project::Event::RefreshInlayHints => {
 1831                            editor
 1832                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1833                        }
 1834                        project::Event::LanguageServerAdded(server_id, ..)
 1835                        | project::Event::LanguageServerRemoved(server_id) => {
 1836                            if editor.tasks_update_task.is_none() {
 1837                                editor.tasks_update_task =
 1838                                    Some(editor.refresh_runnables(window, cx));
 1839                            }
 1840                            editor.update_lsp_data(Some(*server_id), None, window, cx);
 1841                        }
 1842                        project::Event::SnippetEdit(id, snippet_edits) => {
 1843                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1844                                let focus_handle = editor.focus_handle(cx);
 1845                                if focus_handle.is_focused(window) {
 1846                                    let snapshot = buffer.read(cx).snapshot();
 1847                                    for (range, snippet) in snippet_edits {
 1848                                        let editor_range =
 1849                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1850                                        editor
 1851                                            .insert_snippet(
 1852                                                &[editor_range],
 1853                                                snippet.clone(),
 1854                                                window,
 1855                                                cx,
 1856                                            )
 1857                                            .ok();
 1858                                    }
 1859                                }
 1860                            }
 1861                        }
 1862                        _ => {}
 1863                    },
 1864                ));
 1865                if let Some(task_inventory) = project
 1866                    .read(cx)
 1867                    .task_store()
 1868                    .read(cx)
 1869                    .task_inventory()
 1870                    .cloned()
 1871                {
 1872                    project_subscriptions.push(cx.observe_in(
 1873                        &task_inventory,
 1874                        window,
 1875                        |editor, _, window, cx| {
 1876                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1877                        },
 1878                    ));
 1879                };
 1880
 1881                project_subscriptions.push(cx.subscribe_in(
 1882                    &project.read(cx).breakpoint_store(),
 1883                    window,
 1884                    |editor, _, event, window, cx| match event {
 1885                        BreakpointStoreEvent::ClearDebugLines => {
 1886                            editor.clear_row_highlights::<ActiveDebugLine>();
 1887                            editor.refresh_inline_values(cx);
 1888                        }
 1889                        BreakpointStoreEvent::SetDebugLine => {
 1890                            if editor.go_to_active_debug_line(window, cx) {
 1891                                cx.stop_propagation();
 1892                            }
 1893
 1894                            editor.refresh_inline_values(cx);
 1895                        }
 1896                        _ => {}
 1897                    },
 1898                ));
 1899                let git_store = project.read(cx).git_store().clone();
 1900                let project = project.clone();
 1901                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1902                    match event {
 1903                        GitStoreEvent::RepositoryUpdated(
 1904                            _,
 1905                            RepositoryEvent::Updated {
 1906                                new_instance: true, ..
 1907                            },
 1908                            _,
 1909                        ) => {
 1910                            this.load_diff_task = Some(
 1911                                update_uncommitted_diff_for_buffer(
 1912                                    cx.entity(),
 1913                                    &project,
 1914                                    this.buffer.read(cx).all_buffers(),
 1915                                    this.buffer.clone(),
 1916                                    cx,
 1917                                )
 1918                                .shared(),
 1919                            );
 1920                        }
 1921                        _ => {}
 1922                    }
 1923                }));
 1924            }
 1925        }
 1926
 1927        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1928
 1929        let inlay_hint_settings =
 1930            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1931        let focus_handle = cx.focus_handle();
 1932        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1933            .detach();
 1934        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1935            .detach();
 1936        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1937            .detach();
 1938        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1939            .detach();
 1940        cx.observe_pending_input(window, Self::observe_pending_input)
 1941            .detach();
 1942
 1943        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1944            Some(false)
 1945        } else {
 1946            None
 1947        };
 1948
 1949        let breakpoint_store = match (&mode, project.as_ref()) {
 1950            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1951            _ => None,
 1952        };
 1953
 1954        let mut code_action_providers = Vec::new();
 1955        let mut load_uncommitted_diff = None;
 1956        if let Some(project) = project.clone() {
 1957            load_uncommitted_diff = Some(
 1958                update_uncommitted_diff_for_buffer(
 1959                    cx.entity(),
 1960                    &project,
 1961                    buffer.read(cx).all_buffers(),
 1962                    buffer.clone(),
 1963                    cx,
 1964                )
 1965                .shared(),
 1966            );
 1967            code_action_providers.push(Rc::new(project) as Rc<_>);
 1968        }
 1969
 1970        let mut editor = Self {
 1971            focus_handle,
 1972            show_cursor_when_unfocused: false,
 1973            last_focused_descendant: None,
 1974            buffer: buffer.clone(),
 1975            display_map: display_map.clone(),
 1976            selections,
 1977            scroll_manager: ScrollManager::new(cx),
 1978            columnar_selection_state: None,
 1979            add_selections_state: None,
 1980            select_next_state: None,
 1981            select_prev_state: None,
 1982            selection_history: SelectionHistory::default(),
 1983            defer_selection_effects: false,
 1984            deferred_selection_effects_state: None,
 1985            autoclose_regions: Vec::new(),
 1986            snippet_stack: InvalidationStack::default(),
 1987            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1988            ime_transaction: None,
 1989            active_diagnostics: ActiveDiagnostic::None,
 1990            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1991            inline_diagnostics_update: Task::ready(()),
 1992            inline_diagnostics: Vec::new(),
 1993            soft_wrap_mode_override,
 1994            diagnostics_max_severity,
 1995            hard_wrap: None,
 1996            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1997            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1998            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1999            project,
 2000            blink_manager: blink_manager.clone(),
 2001            show_local_selections: true,
 2002            show_scrollbars: ScrollbarAxes {
 2003                horizontal: full_mode,
 2004                vertical: full_mode,
 2005            },
 2006            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2007            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2008            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2009            show_gutter: mode.is_full(),
 2010            show_line_numbers: None,
 2011            use_relative_line_numbers: None,
 2012            disable_expand_excerpt_buttons: false,
 2013            show_git_diff_gutter: None,
 2014            show_code_actions: None,
 2015            show_runnables: None,
 2016            show_breakpoints: None,
 2017            show_wrap_guides: None,
 2018            show_indent_guides,
 2019            placeholder_text: None,
 2020            highlight_order: 0,
 2021            highlighted_rows: HashMap::default(),
 2022            background_highlights: TreeMap::default(),
 2023            gutter_highlights: TreeMap::default(),
 2024            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2025            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2026            nav_history: None,
 2027            context_menu: RefCell::new(None),
 2028            context_menu_options: None,
 2029            mouse_context_menu: None,
 2030            completion_tasks: Vec::new(),
 2031            inline_blame_popover: None,
 2032            inline_blame_popover_show_task: None,
 2033            signature_help_state: SignatureHelpState::default(),
 2034            auto_signature_help: None,
 2035            find_all_references_task_sources: Vec::new(),
 2036            next_completion_id: 0,
 2037            next_inlay_id: 0,
 2038            code_action_providers,
 2039            available_code_actions: None,
 2040            code_actions_task: None,
 2041            quick_selection_highlight_task: None,
 2042            debounced_selection_highlight_task: None,
 2043            document_highlights_task: None,
 2044            linked_editing_range_task: None,
 2045            pending_rename: None,
 2046            searchable: true,
 2047            cursor_shape: EditorSettings::get_global(cx)
 2048                .cursor_shape
 2049                .unwrap_or_default(),
 2050            current_line_highlight: None,
 2051            autoindent_mode: Some(AutoindentMode::EachLine),
 2052            collapse_matches: false,
 2053            workspace: None,
 2054            input_enabled: true,
 2055            use_modal_editing: mode.is_full(),
 2056            read_only: mode.is_minimap(),
 2057            use_autoclose: true,
 2058            use_auto_surround: true,
 2059            auto_replace_emoji_shortcode: false,
 2060            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2061            leader_id: None,
 2062            remote_id: None,
 2063            hover_state: HoverState::default(),
 2064            pending_mouse_down: None,
 2065            hovered_link_state: None,
 2066            edit_prediction_provider: None,
 2067            active_inline_completion: None,
 2068            stale_inline_completion_in_menu: None,
 2069            edit_prediction_preview: EditPredictionPreview::Inactive {
 2070                released_too_fast: false,
 2071            },
 2072            inline_diagnostics_enabled: mode.is_full(),
 2073            diagnostics_enabled: mode.is_full(),
 2074            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2075            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2076
 2077            gutter_hovered: false,
 2078            pixel_position_of_newest_cursor: None,
 2079            last_bounds: None,
 2080            last_position_map: None,
 2081            expect_bounds_change: None,
 2082            gutter_dimensions: GutterDimensions::default(),
 2083            style: None,
 2084            show_cursor_names: false,
 2085            hovered_cursors: HashMap::default(),
 2086            next_editor_action_id: EditorActionId::default(),
 2087            editor_actions: Rc::default(),
 2088            inline_completions_hidden_for_vim_mode: false,
 2089            show_inline_completions_override: None,
 2090            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2091            edit_prediction_settings: EditPredictionSettings::Disabled,
 2092            edit_prediction_indent_conflict: false,
 2093            edit_prediction_requires_modifier_in_indent_conflict: true,
 2094            custom_context_menu: None,
 2095            show_git_blame_gutter: false,
 2096            show_git_blame_inline: false,
 2097            show_selection_menu: None,
 2098            show_git_blame_inline_delay_task: None,
 2099            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2100            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2101            serialize_dirty_buffers: !mode.is_minimap()
 2102                && ProjectSettings::get_global(cx)
 2103                    .session
 2104                    .restore_unsaved_buffers,
 2105            blame: None,
 2106            blame_subscription: None,
 2107            tasks: BTreeMap::default(),
 2108
 2109            breakpoint_store,
 2110            gutter_breakpoint_indicator: (None, None),
 2111            hovered_diff_hunk_row: None,
 2112            _subscriptions: vec![
 2113                cx.observe(&buffer, Self::on_buffer_changed),
 2114                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2115                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2116                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2117                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2118                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2119                cx.observe_window_activation(window, |editor, window, cx| {
 2120                    let active = window.is_window_active();
 2121                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2122                        if active {
 2123                            blink_manager.enable(cx);
 2124                        } else {
 2125                            blink_manager.disable(cx);
 2126                        }
 2127                    });
 2128                    if active {
 2129                        editor.show_mouse_cursor(cx);
 2130                    }
 2131                }),
 2132            ],
 2133            tasks_update_task: None,
 2134            pull_diagnostics_task: Task::ready(()),
 2135            colors: None,
 2136            next_color_inlay_id: 0,
 2137            linked_edit_ranges: Default::default(),
 2138            in_project_search: false,
 2139            previous_search_ranges: None,
 2140            breadcrumb_header: None,
 2141            focused_block: None,
 2142            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2143            addons: HashMap::default(),
 2144            registered_buffers: HashMap::default(),
 2145            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2146            selection_mark_mode: false,
 2147            toggle_fold_multiple_buffers: Task::ready(()),
 2148            serialize_selections: Task::ready(()),
 2149            serialize_folds: Task::ready(()),
 2150            text_style_refinement: None,
 2151            load_diff_task: load_uncommitted_diff,
 2152            temporary_diff_override: false,
 2153            mouse_cursor_hidden: false,
 2154            minimap: None,
 2155            hide_mouse_mode: EditorSettings::get_global(cx)
 2156                .hide_mouse
 2157                .unwrap_or_default(),
 2158            change_list: ChangeList::new(),
 2159            mode,
 2160            selection_drag_state: SelectionDragState::None,
 2161            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2162        };
 2163        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2164            editor
 2165                ._subscriptions
 2166                .push(cx.observe(breakpoints, |_, _, cx| {
 2167                    cx.notify();
 2168                }));
 2169        }
 2170        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2171        editor._subscriptions.extend(project_subscriptions);
 2172
 2173        editor._subscriptions.push(cx.subscribe_in(
 2174            &cx.entity(),
 2175            window,
 2176            |editor, _, e: &EditorEvent, window, cx| match e {
 2177                EditorEvent::ScrollPositionChanged { local, .. } => {
 2178                    if *local {
 2179                        let new_anchor = editor.scroll_manager.anchor();
 2180                        let snapshot = editor.snapshot(window, cx);
 2181                        editor.update_restoration_data(cx, move |data| {
 2182                            data.scroll_position = (
 2183                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2184                                new_anchor.offset,
 2185                            );
 2186                        });
 2187                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2188                        editor.inline_blame_popover.take();
 2189                    }
 2190                }
 2191                EditorEvent::Edited { .. } => {
 2192                    if !vim_enabled(cx) {
 2193                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2194                        let pop_state = editor
 2195                            .change_list
 2196                            .last()
 2197                            .map(|previous| {
 2198                                previous.len() == selections.len()
 2199                                    && previous.iter().enumerate().all(|(ix, p)| {
 2200                                        p.to_display_point(&map).row()
 2201                                            == selections[ix].head().row()
 2202                                    })
 2203                            })
 2204                            .unwrap_or(false);
 2205                        let new_positions = selections
 2206                            .into_iter()
 2207                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2208                            .collect();
 2209                        editor
 2210                            .change_list
 2211                            .push_to_change_list(pop_state, new_positions);
 2212                    }
 2213                }
 2214                _ => (),
 2215            },
 2216        ));
 2217
 2218        if let Some(dap_store) = editor
 2219            .project
 2220            .as_ref()
 2221            .map(|project| project.read(cx).dap_store())
 2222        {
 2223            let weak_editor = cx.weak_entity();
 2224
 2225            editor
 2226                ._subscriptions
 2227                .push(
 2228                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2229                        let session_entity = cx.entity();
 2230                        weak_editor
 2231                            .update(cx, |editor, cx| {
 2232                                editor._subscriptions.push(
 2233                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2234                                );
 2235                            })
 2236                            .ok();
 2237                    }),
 2238                );
 2239
 2240            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2241                editor
 2242                    ._subscriptions
 2243                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2244            }
 2245        }
 2246
 2247        // skip adding the initial selection to selection history
 2248        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2249        editor.end_selection(window, cx);
 2250        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2251
 2252        editor.scroll_manager.show_scrollbars(window, cx);
 2253        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2254
 2255        if full_mode {
 2256            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2257            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2258
 2259            if editor.git_blame_inline_enabled {
 2260                editor.start_git_blame_inline(false, window, cx);
 2261            }
 2262
 2263            editor.go_to_active_debug_line(window, cx);
 2264
 2265            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2266                if let Some(project) = editor.project.as_ref() {
 2267                    let handle = project.update(cx, |project, cx| {
 2268                        project.register_buffer_with_language_servers(&buffer, cx)
 2269                    });
 2270                    editor
 2271                        .registered_buffers
 2272                        .insert(buffer.read(cx).remote_id(), handle);
 2273                }
 2274            }
 2275
 2276            editor.minimap =
 2277                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2278            editor.colors = Some(LspColorData::new(cx));
 2279            editor.update_lsp_data(None, None, window, cx);
 2280        }
 2281
 2282        editor.report_editor_event("Editor Opened", None, cx);
 2283        editor
 2284    }
 2285
 2286    pub fn deploy_mouse_context_menu(
 2287        &mut self,
 2288        position: gpui::Point<Pixels>,
 2289        context_menu: Entity<ContextMenu>,
 2290        window: &mut Window,
 2291        cx: &mut Context<Self>,
 2292    ) {
 2293        self.mouse_context_menu = Some(MouseContextMenu::new(
 2294            self,
 2295            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2296            context_menu,
 2297            window,
 2298            cx,
 2299        ));
 2300    }
 2301
 2302    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2303        self.mouse_context_menu
 2304            .as_ref()
 2305            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2306    }
 2307
 2308    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2309        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2310    }
 2311
 2312    fn key_context_internal(
 2313        &self,
 2314        has_active_edit_prediction: bool,
 2315        window: &Window,
 2316        cx: &App,
 2317    ) -> KeyContext {
 2318        let mut key_context = KeyContext::new_with_defaults();
 2319        key_context.add("Editor");
 2320        let mode = match self.mode {
 2321            EditorMode::SingleLine { .. } => "single_line",
 2322            EditorMode::AutoHeight { .. } => "auto_height",
 2323            EditorMode::Minimap { .. } => "minimap",
 2324            EditorMode::Full { .. } => "full",
 2325        };
 2326
 2327        if EditorSettings::jupyter_enabled(cx) {
 2328            key_context.add("jupyter");
 2329        }
 2330
 2331        key_context.set("mode", mode);
 2332        if self.pending_rename.is_some() {
 2333            key_context.add("renaming");
 2334        }
 2335
 2336        match self.context_menu.borrow().as_ref() {
 2337            Some(CodeContextMenu::Completions(_)) => {
 2338                key_context.add("menu");
 2339                key_context.add("showing_completions");
 2340            }
 2341            Some(CodeContextMenu::CodeActions(_)) => {
 2342                key_context.add("menu");
 2343                key_context.add("showing_code_actions")
 2344            }
 2345            None => {}
 2346        }
 2347
 2348        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2349        if !self.focus_handle(cx).contains_focused(window, cx)
 2350            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2351        {
 2352            for addon in self.addons.values() {
 2353                addon.extend_key_context(&mut key_context, cx)
 2354            }
 2355        }
 2356
 2357        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2358            if let Some(extension) = singleton_buffer
 2359                .read(cx)
 2360                .file()
 2361                .and_then(|file| file.path().extension()?.to_str())
 2362            {
 2363                key_context.set("extension", extension.to_string());
 2364            }
 2365        } else {
 2366            key_context.add("multibuffer");
 2367        }
 2368
 2369        if has_active_edit_prediction {
 2370            if self.edit_prediction_in_conflict() {
 2371                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2372            } else {
 2373                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2374                key_context.add("copilot_suggestion");
 2375            }
 2376        }
 2377
 2378        if self.selection_mark_mode {
 2379            key_context.add("selection_mode");
 2380        }
 2381
 2382        key_context
 2383    }
 2384
 2385    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2386        if self.mouse_cursor_hidden {
 2387            self.mouse_cursor_hidden = false;
 2388            cx.notify();
 2389        }
 2390    }
 2391
 2392    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2393        let hide_mouse_cursor = match origin {
 2394            HideMouseCursorOrigin::TypingAction => {
 2395                matches!(
 2396                    self.hide_mouse_mode,
 2397                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2398                )
 2399            }
 2400            HideMouseCursorOrigin::MovementAction => {
 2401                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2402            }
 2403        };
 2404        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2405            self.mouse_cursor_hidden = hide_mouse_cursor;
 2406            cx.notify();
 2407        }
 2408    }
 2409
 2410    pub fn edit_prediction_in_conflict(&self) -> bool {
 2411        if !self.show_edit_predictions_in_menu() {
 2412            return false;
 2413        }
 2414
 2415        let showing_completions = self
 2416            .context_menu
 2417            .borrow()
 2418            .as_ref()
 2419            .map_or(false, |context| {
 2420                matches!(context, CodeContextMenu::Completions(_))
 2421            });
 2422
 2423        showing_completions
 2424            || self.edit_prediction_requires_modifier()
 2425            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2426            // bindings to insert tab characters.
 2427            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2428    }
 2429
 2430    pub fn accept_edit_prediction_keybind(
 2431        &self,
 2432        accept_partial: bool,
 2433        window: &Window,
 2434        cx: &App,
 2435    ) -> AcceptEditPredictionBinding {
 2436        let key_context = self.key_context_internal(true, window, cx);
 2437        let in_conflict = self.edit_prediction_in_conflict();
 2438
 2439        let bindings = if accept_partial {
 2440            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2441        } else {
 2442            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2443        };
 2444
 2445        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2446        // just the first one.
 2447        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2448            !in_conflict
 2449                || binding
 2450                    .keystrokes()
 2451                    .first()
 2452                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2453        }))
 2454    }
 2455
 2456    pub fn new_file(
 2457        workspace: &mut Workspace,
 2458        _: &workspace::NewFile,
 2459        window: &mut Window,
 2460        cx: &mut Context<Workspace>,
 2461    ) {
 2462        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2463            "Failed to create buffer",
 2464            window,
 2465            cx,
 2466            |e, _, _| match e.error_code() {
 2467                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2468                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2469                e.error_tag("required").unwrap_or("the latest version")
 2470            )),
 2471                _ => None,
 2472            },
 2473        );
 2474    }
 2475
 2476    pub fn new_in_workspace(
 2477        workspace: &mut Workspace,
 2478        window: &mut Window,
 2479        cx: &mut Context<Workspace>,
 2480    ) -> Task<Result<Entity<Editor>>> {
 2481        let project = workspace.project().clone();
 2482        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2483
 2484        cx.spawn_in(window, async move |workspace, cx| {
 2485            let buffer = create.await?;
 2486            workspace.update_in(cx, |workspace, window, cx| {
 2487                let editor =
 2488                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2489                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2490                editor
 2491            })
 2492        })
 2493    }
 2494
 2495    fn new_file_vertical(
 2496        workspace: &mut Workspace,
 2497        _: &workspace::NewFileSplitVertical,
 2498        window: &mut Window,
 2499        cx: &mut Context<Workspace>,
 2500    ) {
 2501        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2502    }
 2503
 2504    fn new_file_horizontal(
 2505        workspace: &mut Workspace,
 2506        _: &workspace::NewFileSplitHorizontal,
 2507        window: &mut Window,
 2508        cx: &mut Context<Workspace>,
 2509    ) {
 2510        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2511    }
 2512
 2513    fn new_file_in_direction(
 2514        workspace: &mut Workspace,
 2515        direction: SplitDirection,
 2516        window: &mut Window,
 2517        cx: &mut Context<Workspace>,
 2518    ) {
 2519        let project = workspace.project().clone();
 2520        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2521
 2522        cx.spawn_in(window, async move |workspace, cx| {
 2523            let buffer = create.await?;
 2524            workspace.update_in(cx, move |workspace, window, cx| {
 2525                workspace.split_item(
 2526                    direction,
 2527                    Box::new(
 2528                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2529                    ),
 2530                    window,
 2531                    cx,
 2532                )
 2533            })?;
 2534            anyhow::Ok(())
 2535        })
 2536        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2537            match e.error_code() {
 2538                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2539                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2540                e.error_tag("required").unwrap_or("the latest version")
 2541            )),
 2542                _ => None,
 2543            }
 2544        });
 2545    }
 2546
 2547    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2548        self.leader_id
 2549    }
 2550
 2551    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2552        &self.buffer
 2553    }
 2554
 2555    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2556        self.workspace.as_ref()?.0.upgrade()
 2557    }
 2558
 2559    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2560        self.buffer().read(cx).title(cx)
 2561    }
 2562
 2563    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2564        let git_blame_gutter_max_author_length = self
 2565            .render_git_blame_gutter(cx)
 2566            .then(|| {
 2567                if let Some(blame) = self.blame.as_ref() {
 2568                    let max_author_length =
 2569                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2570                    Some(max_author_length)
 2571                } else {
 2572                    None
 2573                }
 2574            })
 2575            .flatten();
 2576
 2577        EditorSnapshot {
 2578            mode: self.mode.clone(),
 2579            show_gutter: self.show_gutter,
 2580            show_line_numbers: self.show_line_numbers,
 2581            show_git_diff_gutter: self.show_git_diff_gutter,
 2582            show_code_actions: self.show_code_actions,
 2583            show_runnables: self.show_runnables,
 2584            show_breakpoints: self.show_breakpoints,
 2585            git_blame_gutter_max_author_length,
 2586            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2587            scroll_anchor: self.scroll_manager.anchor(),
 2588            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2589            placeholder_text: self.placeholder_text.clone(),
 2590            is_focused: self.focus_handle.is_focused(window),
 2591            current_line_highlight: self
 2592                .current_line_highlight
 2593                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2594            gutter_hovered: self.gutter_hovered,
 2595        }
 2596    }
 2597
 2598    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2599        self.buffer.read(cx).language_at(point, cx)
 2600    }
 2601
 2602    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2603        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2604    }
 2605
 2606    pub fn active_excerpt(
 2607        &self,
 2608        cx: &App,
 2609    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2610        self.buffer
 2611            .read(cx)
 2612            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2613    }
 2614
 2615    pub fn mode(&self) -> &EditorMode {
 2616        &self.mode
 2617    }
 2618
 2619    pub fn set_mode(&mut self, mode: EditorMode) {
 2620        self.mode = mode;
 2621    }
 2622
 2623    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2624        self.collaboration_hub.as_deref()
 2625    }
 2626
 2627    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2628        self.collaboration_hub = Some(hub);
 2629    }
 2630
 2631    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2632        self.in_project_search = in_project_search;
 2633    }
 2634
 2635    pub fn set_custom_context_menu(
 2636        &mut self,
 2637        f: impl 'static
 2638        + Fn(
 2639            &mut Self,
 2640            DisplayPoint,
 2641            &mut Window,
 2642            &mut Context<Self>,
 2643        ) -> Option<Entity<ui::ContextMenu>>,
 2644    ) {
 2645        self.custom_context_menu = Some(Box::new(f))
 2646    }
 2647
 2648    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2649        self.completion_provider = provider;
 2650    }
 2651
 2652    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2653        self.semantics_provider.clone()
 2654    }
 2655
 2656    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2657        self.semantics_provider = provider;
 2658    }
 2659
 2660    pub fn set_edit_prediction_provider<T>(
 2661        &mut self,
 2662        provider: Option<Entity<T>>,
 2663        window: &mut Window,
 2664        cx: &mut Context<Self>,
 2665    ) where
 2666        T: EditPredictionProvider,
 2667    {
 2668        self.edit_prediction_provider =
 2669            provider.map(|provider| RegisteredInlineCompletionProvider {
 2670                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2671                    if this.focus_handle.is_focused(window) {
 2672                        this.update_visible_inline_completion(window, cx);
 2673                    }
 2674                }),
 2675                provider: Arc::new(provider),
 2676            });
 2677        self.update_edit_prediction_settings(cx);
 2678        self.refresh_inline_completion(false, false, window, cx);
 2679    }
 2680
 2681    pub fn placeholder_text(&self) -> Option<&str> {
 2682        self.placeholder_text.as_deref()
 2683    }
 2684
 2685    pub fn set_placeholder_text(
 2686        &mut self,
 2687        placeholder_text: impl Into<Arc<str>>,
 2688        cx: &mut Context<Self>,
 2689    ) {
 2690        let placeholder_text = Some(placeholder_text.into());
 2691        if self.placeholder_text != placeholder_text {
 2692            self.placeholder_text = placeholder_text;
 2693            cx.notify();
 2694        }
 2695    }
 2696
 2697    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2698        self.cursor_shape = cursor_shape;
 2699
 2700        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2701        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2702
 2703        cx.notify();
 2704    }
 2705
 2706    pub fn set_current_line_highlight(
 2707        &mut self,
 2708        current_line_highlight: Option<CurrentLineHighlight>,
 2709    ) {
 2710        self.current_line_highlight = current_line_highlight;
 2711    }
 2712
 2713    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2714        self.collapse_matches = collapse_matches;
 2715    }
 2716
 2717    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2718        let buffers = self.buffer.read(cx).all_buffers();
 2719        let Some(project) = self.project.as_ref() else {
 2720            return;
 2721        };
 2722        project.update(cx, |project, cx| {
 2723            for buffer in buffers {
 2724                self.registered_buffers
 2725                    .entry(buffer.read(cx).remote_id())
 2726                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2727            }
 2728        })
 2729    }
 2730
 2731    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2732        if self.collapse_matches {
 2733            return range.start..range.start;
 2734        }
 2735        range.clone()
 2736    }
 2737
 2738    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2739        if self.display_map.read(cx).clip_at_line_ends != clip {
 2740            self.display_map
 2741                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2742        }
 2743    }
 2744
 2745    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2746        self.input_enabled = input_enabled;
 2747    }
 2748
 2749    pub fn set_inline_completions_hidden_for_vim_mode(
 2750        &mut self,
 2751        hidden: bool,
 2752        window: &mut Window,
 2753        cx: &mut Context<Self>,
 2754    ) {
 2755        if hidden != self.inline_completions_hidden_for_vim_mode {
 2756            self.inline_completions_hidden_for_vim_mode = hidden;
 2757            if hidden {
 2758                self.update_visible_inline_completion(window, cx);
 2759            } else {
 2760                self.refresh_inline_completion(true, false, window, cx);
 2761            }
 2762        }
 2763    }
 2764
 2765    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2766        self.menu_inline_completions_policy = value;
 2767    }
 2768
 2769    pub fn set_autoindent(&mut self, autoindent: bool) {
 2770        if autoindent {
 2771            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2772        } else {
 2773            self.autoindent_mode = None;
 2774        }
 2775    }
 2776
 2777    pub fn read_only(&self, cx: &App) -> bool {
 2778        self.read_only || self.buffer.read(cx).read_only()
 2779    }
 2780
 2781    pub fn set_read_only(&mut self, read_only: bool) {
 2782        self.read_only = read_only;
 2783    }
 2784
 2785    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2786        self.use_autoclose = autoclose;
 2787    }
 2788
 2789    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2790        self.use_auto_surround = auto_surround;
 2791    }
 2792
 2793    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2794        self.auto_replace_emoji_shortcode = auto_replace;
 2795    }
 2796
 2797    pub fn toggle_edit_predictions(
 2798        &mut self,
 2799        _: &ToggleEditPrediction,
 2800        window: &mut Window,
 2801        cx: &mut Context<Self>,
 2802    ) {
 2803        if self.show_inline_completions_override.is_some() {
 2804            self.set_show_edit_predictions(None, window, cx);
 2805        } else {
 2806            let show_edit_predictions = !self.edit_predictions_enabled();
 2807            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2808        }
 2809    }
 2810
 2811    pub fn set_show_edit_predictions(
 2812        &mut self,
 2813        show_edit_predictions: Option<bool>,
 2814        window: &mut Window,
 2815        cx: &mut Context<Self>,
 2816    ) {
 2817        self.show_inline_completions_override = show_edit_predictions;
 2818        self.update_edit_prediction_settings(cx);
 2819
 2820        if let Some(false) = show_edit_predictions {
 2821            self.discard_inline_completion(false, cx);
 2822        } else {
 2823            self.refresh_inline_completion(false, true, window, cx);
 2824        }
 2825    }
 2826
 2827    fn inline_completions_disabled_in_scope(
 2828        &self,
 2829        buffer: &Entity<Buffer>,
 2830        buffer_position: language::Anchor,
 2831        cx: &App,
 2832    ) -> bool {
 2833        let snapshot = buffer.read(cx).snapshot();
 2834        let settings = snapshot.settings_at(buffer_position, cx);
 2835
 2836        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2837            return false;
 2838        };
 2839
 2840        scope.override_name().map_or(false, |scope_name| {
 2841            settings
 2842                .edit_predictions_disabled_in
 2843                .iter()
 2844                .any(|s| s == scope_name)
 2845        })
 2846    }
 2847
 2848    pub fn set_use_modal_editing(&mut self, to: bool) {
 2849        self.use_modal_editing = to;
 2850    }
 2851
 2852    pub fn use_modal_editing(&self) -> bool {
 2853        self.use_modal_editing
 2854    }
 2855
 2856    fn selections_did_change(
 2857        &mut self,
 2858        local: bool,
 2859        old_cursor_position: &Anchor,
 2860        effects: SelectionEffects,
 2861        window: &mut Window,
 2862        cx: &mut Context<Self>,
 2863    ) {
 2864        window.invalidate_character_coordinates();
 2865
 2866        // Copy selections to primary selection buffer
 2867        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2868        if local {
 2869            let selections = self.selections.all::<usize>(cx);
 2870            let buffer_handle = self.buffer.read(cx).read(cx);
 2871
 2872            let mut text = String::new();
 2873            for (index, selection) in selections.iter().enumerate() {
 2874                let text_for_selection = buffer_handle
 2875                    .text_for_range(selection.start..selection.end)
 2876                    .collect::<String>();
 2877
 2878                text.push_str(&text_for_selection);
 2879                if index != selections.len() - 1 {
 2880                    text.push('\n');
 2881                }
 2882            }
 2883
 2884            if !text.is_empty() {
 2885                cx.write_to_primary(ClipboardItem::new_string(text));
 2886            }
 2887        }
 2888
 2889        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2890            self.buffer.update(cx, |buffer, cx| {
 2891                buffer.set_active_selections(
 2892                    &self.selections.disjoint_anchors(),
 2893                    self.selections.line_mode,
 2894                    self.cursor_shape,
 2895                    cx,
 2896                )
 2897            });
 2898        }
 2899        let display_map = self
 2900            .display_map
 2901            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2902        let buffer = &display_map.buffer_snapshot;
 2903        if self.selections.count() == 1 {
 2904            self.add_selections_state = None;
 2905        }
 2906        self.select_next_state = None;
 2907        self.select_prev_state = None;
 2908        self.select_syntax_node_history.try_clear();
 2909        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2910        self.snippet_stack
 2911            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2912        self.take_rename(false, window, cx);
 2913
 2914        let newest_selection = self.selections.newest_anchor();
 2915        let new_cursor_position = newest_selection.head();
 2916        let selection_start = newest_selection.start;
 2917
 2918        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2919            self.push_to_nav_history(
 2920                *old_cursor_position,
 2921                Some(new_cursor_position.to_point(buffer)),
 2922                false,
 2923                effects.nav_history == Some(true),
 2924                cx,
 2925            );
 2926        }
 2927
 2928        if local {
 2929            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2930                if !self.registered_buffers.contains_key(&buffer_id) {
 2931                    if let Some(project) = self.project.as_ref() {
 2932                        project.update(cx, |project, cx| {
 2933                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2934                                return;
 2935                            };
 2936                            self.registered_buffers.insert(
 2937                                buffer_id,
 2938                                project.register_buffer_with_language_servers(&buffer, cx),
 2939                            );
 2940                        })
 2941                    }
 2942                }
 2943            }
 2944
 2945            let mut context_menu = self.context_menu.borrow_mut();
 2946            let completion_menu = match context_menu.as_ref() {
 2947                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2948                Some(CodeContextMenu::CodeActions(_)) => {
 2949                    *context_menu = None;
 2950                    None
 2951                }
 2952                None => None,
 2953            };
 2954            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2955            drop(context_menu);
 2956
 2957            if effects.completions {
 2958                if let Some(completion_position) = completion_position {
 2959                    let start_offset = selection_start.to_offset(buffer);
 2960                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2961                    let continue_showing = if position_matches {
 2962                        if self.snippet_stack.is_empty() {
 2963                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2964                        } else {
 2965                            // Snippet choices can be shown even when the cursor is in whitespace.
 2966                            // Dismissing the menu with actions like backspace is handled by
 2967                            // invalidation regions.
 2968                            true
 2969                        }
 2970                    } else {
 2971                        false
 2972                    };
 2973
 2974                    if continue_showing {
 2975                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2976                    } else {
 2977                        self.hide_context_menu(window, cx);
 2978                    }
 2979                }
 2980            }
 2981
 2982            hide_hover(self, cx);
 2983
 2984            if old_cursor_position.to_display_point(&display_map).row()
 2985                != new_cursor_position.to_display_point(&display_map).row()
 2986            {
 2987                self.available_code_actions.take();
 2988            }
 2989            self.refresh_code_actions(window, cx);
 2990            self.refresh_document_highlights(cx);
 2991            self.refresh_selected_text_highlights(false, window, cx);
 2992            refresh_matching_bracket_highlights(self, window, cx);
 2993            self.update_visible_inline_completion(window, cx);
 2994            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2995            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2996            self.inline_blame_popover.take();
 2997            if self.git_blame_inline_enabled {
 2998                self.start_inline_blame_timer(window, cx);
 2999            }
 3000        }
 3001
 3002        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3003        cx.emit(EditorEvent::SelectionsChanged { local });
 3004
 3005        let selections = &self.selections.disjoint;
 3006        if selections.len() == 1 {
 3007            cx.emit(SearchEvent::ActiveMatchChanged)
 3008        }
 3009        if local {
 3010            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3011                let inmemory_selections = selections
 3012                    .iter()
 3013                    .map(|s| {
 3014                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3015                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3016                    })
 3017                    .collect();
 3018                self.update_restoration_data(cx, |data| {
 3019                    data.selections = inmemory_selections;
 3020                });
 3021
 3022                if WorkspaceSettings::get(None, cx).restore_on_startup
 3023                    != RestoreOnStartupBehavior::None
 3024                {
 3025                    if let Some(workspace_id) =
 3026                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3027                    {
 3028                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3029                        let selections = selections.clone();
 3030                        let background_executor = cx.background_executor().clone();
 3031                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3032                        self.serialize_selections = cx.background_spawn(async move {
 3033                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3034                            let db_selections = selections
 3035                                .iter()
 3036                                .map(|selection| {
 3037                                    (
 3038                                        selection.start.to_offset(&snapshot),
 3039                                        selection.end.to_offset(&snapshot),
 3040                                    )
 3041                                })
 3042                                .collect();
 3043
 3044                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3045                                .await
 3046                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3047                                .log_err();
 3048                        });
 3049                    }
 3050                }
 3051            }
 3052        }
 3053
 3054        cx.notify();
 3055    }
 3056
 3057    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3058        use text::ToOffset as _;
 3059        use text::ToPoint as _;
 3060
 3061        if self.mode.is_minimap()
 3062            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3063        {
 3064            return;
 3065        }
 3066
 3067        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3068            return;
 3069        };
 3070
 3071        let snapshot = singleton.read(cx).snapshot();
 3072        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3073            let display_snapshot = display_map.snapshot(cx);
 3074
 3075            display_snapshot
 3076                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3077                .map(|fold| {
 3078                    fold.range.start.text_anchor.to_point(&snapshot)
 3079                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3080                })
 3081                .collect()
 3082        });
 3083        self.update_restoration_data(cx, |data| {
 3084            data.folds = inmemory_folds;
 3085        });
 3086
 3087        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3088            return;
 3089        };
 3090        let background_executor = cx.background_executor().clone();
 3091        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3092        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3093            display_map
 3094                .snapshot(cx)
 3095                .folds_in_range(0..snapshot.len())
 3096                .map(|fold| {
 3097                    (
 3098                        fold.range.start.text_anchor.to_offset(&snapshot),
 3099                        fold.range.end.text_anchor.to_offset(&snapshot),
 3100                    )
 3101                })
 3102                .collect()
 3103        });
 3104        self.serialize_folds = cx.background_spawn(async move {
 3105            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3106            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3107                .await
 3108                .with_context(|| {
 3109                    format!(
 3110                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3111                    )
 3112                })
 3113                .log_err();
 3114        });
 3115    }
 3116
 3117    pub fn sync_selections(
 3118        &mut self,
 3119        other: Entity<Editor>,
 3120        cx: &mut Context<Self>,
 3121    ) -> gpui::Subscription {
 3122        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3123        self.selections.change_with(cx, |selections| {
 3124            selections.select_anchors(other_selections);
 3125        });
 3126
 3127        let other_subscription =
 3128            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3129                EditorEvent::SelectionsChanged { local: true } => {
 3130                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3131                    if other_selections.is_empty() {
 3132                        return;
 3133                    }
 3134                    this.selections.change_with(cx, |selections| {
 3135                        selections.select_anchors(other_selections);
 3136                    });
 3137                }
 3138                _ => {}
 3139            });
 3140
 3141        let this_subscription =
 3142            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3143                EditorEvent::SelectionsChanged { local: true } => {
 3144                    let these_selections = this.selections.disjoint.to_vec();
 3145                    if these_selections.is_empty() {
 3146                        return;
 3147                    }
 3148                    other.update(cx, |other_editor, cx| {
 3149                        other_editor.selections.change_with(cx, |selections| {
 3150                            selections.select_anchors(these_selections);
 3151                        })
 3152                    });
 3153                }
 3154                _ => {}
 3155            });
 3156
 3157        Subscription::join(other_subscription, this_subscription)
 3158    }
 3159
 3160    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3161    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3162    /// effects of selection change occur at the end of the transaction.
 3163    pub fn change_selections<R>(
 3164        &mut self,
 3165        effects: impl Into<SelectionEffects>,
 3166        window: &mut Window,
 3167        cx: &mut Context<Self>,
 3168        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3169    ) -> R {
 3170        let effects = effects.into();
 3171        if let Some(state) = &mut self.deferred_selection_effects_state {
 3172            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3173            state.effects.completions = effects.completions;
 3174            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3175            let (changed, result) = self.selections.change_with(cx, change);
 3176            state.changed |= changed;
 3177            return result;
 3178        }
 3179        let mut state = DeferredSelectionEffectsState {
 3180            changed: false,
 3181            effects,
 3182            old_cursor_position: self.selections.newest_anchor().head(),
 3183            history_entry: SelectionHistoryEntry {
 3184                selections: self.selections.disjoint_anchors(),
 3185                select_next_state: self.select_next_state.clone(),
 3186                select_prev_state: self.select_prev_state.clone(),
 3187                add_selections_state: self.add_selections_state.clone(),
 3188            },
 3189        };
 3190        let (changed, result) = self.selections.change_with(cx, change);
 3191        state.changed = state.changed || changed;
 3192        if self.defer_selection_effects {
 3193            self.deferred_selection_effects_state = Some(state);
 3194        } else {
 3195            self.apply_selection_effects(state, window, cx);
 3196        }
 3197        result
 3198    }
 3199
 3200    /// Defers the effects of selection change, so that the effects of multiple calls to
 3201    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3202    /// to selection history and the state of popovers based on selection position aren't
 3203    /// erroneously updated.
 3204    pub fn with_selection_effects_deferred<R>(
 3205        &mut self,
 3206        window: &mut Window,
 3207        cx: &mut Context<Self>,
 3208        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3209    ) -> R {
 3210        let already_deferred = self.defer_selection_effects;
 3211        self.defer_selection_effects = true;
 3212        let result = update(self, window, cx);
 3213        if !already_deferred {
 3214            self.defer_selection_effects = false;
 3215            if let Some(state) = self.deferred_selection_effects_state.take() {
 3216                self.apply_selection_effects(state, window, cx);
 3217            }
 3218        }
 3219        result
 3220    }
 3221
 3222    fn apply_selection_effects(
 3223        &mut self,
 3224        state: DeferredSelectionEffectsState,
 3225        window: &mut Window,
 3226        cx: &mut Context<Self>,
 3227    ) {
 3228        if state.changed {
 3229            self.selection_history.push(state.history_entry);
 3230
 3231            if let Some(autoscroll) = state.effects.scroll {
 3232                self.request_autoscroll(autoscroll, cx);
 3233            }
 3234
 3235            let old_cursor_position = &state.old_cursor_position;
 3236
 3237            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3238
 3239            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3240                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3241            }
 3242        }
 3243    }
 3244
 3245    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3246    where
 3247        I: IntoIterator<Item = (Range<S>, T)>,
 3248        S: ToOffset,
 3249        T: Into<Arc<str>>,
 3250    {
 3251        if self.read_only(cx) {
 3252            return;
 3253        }
 3254
 3255        self.buffer
 3256            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3257    }
 3258
 3259    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3260    where
 3261        I: IntoIterator<Item = (Range<S>, T)>,
 3262        S: ToOffset,
 3263        T: Into<Arc<str>>,
 3264    {
 3265        if self.read_only(cx) {
 3266            return;
 3267        }
 3268
 3269        self.buffer.update(cx, |buffer, cx| {
 3270            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3271        });
 3272    }
 3273
 3274    pub fn edit_with_block_indent<I, S, T>(
 3275        &mut self,
 3276        edits: I,
 3277        original_indent_columns: Vec<Option<u32>>,
 3278        cx: &mut Context<Self>,
 3279    ) where
 3280        I: IntoIterator<Item = (Range<S>, T)>,
 3281        S: ToOffset,
 3282        T: Into<Arc<str>>,
 3283    {
 3284        if self.read_only(cx) {
 3285            return;
 3286        }
 3287
 3288        self.buffer.update(cx, |buffer, cx| {
 3289            buffer.edit(
 3290                edits,
 3291                Some(AutoindentMode::Block {
 3292                    original_indent_columns,
 3293                }),
 3294                cx,
 3295            )
 3296        });
 3297    }
 3298
 3299    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3300        self.hide_context_menu(window, cx);
 3301
 3302        match phase {
 3303            SelectPhase::Begin {
 3304                position,
 3305                add,
 3306                click_count,
 3307            } => self.begin_selection(position, add, click_count, window, cx),
 3308            SelectPhase::BeginColumnar {
 3309                position,
 3310                goal_column,
 3311                reset,
 3312                mode,
 3313            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3314            SelectPhase::Extend {
 3315                position,
 3316                click_count,
 3317            } => self.extend_selection(position, click_count, window, cx),
 3318            SelectPhase::Update {
 3319                position,
 3320                goal_column,
 3321                scroll_delta,
 3322            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3323            SelectPhase::End => self.end_selection(window, cx),
 3324        }
 3325    }
 3326
 3327    fn extend_selection(
 3328        &mut self,
 3329        position: DisplayPoint,
 3330        click_count: usize,
 3331        window: &mut Window,
 3332        cx: &mut Context<Self>,
 3333    ) {
 3334        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3335        let tail = self.selections.newest::<usize>(cx).tail();
 3336        self.begin_selection(position, false, click_count, window, cx);
 3337
 3338        let position = position.to_offset(&display_map, Bias::Left);
 3339        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3340
 3341        let mut pending_selection = self
 3342            .selections
 3343            .pending_anchor()
 3344            .expect("extend_selection not called with pending selection");
 3345        if position >= tail {
 3346            pending_selection.start = tail_anchor;
 3347        } else {
 3348            pending_selection.end = tail_anchor;
 3349            pending_selection.reversed = true;
 3350        }
 3351
 3352        let mut pending_mode = self.selections.pending_mode().unwrap();
 3353        match &mut pending_mode {
 3354            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3355            _ => {}
 3356        }
 3357
 3358        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3359            SelectionEffects::scroll(Autoscroll::fit())
 3360        } else {
 3361            SelectionEffects::no_scroll()
 3362        };
 3363
 3364        self.change_selections(effects, window, cx, |s| {
 3365            s.set_pending(pending_selection, pending_mode)
 3366        });
 3367    }
 3368
 3369    fn begin_selection(
 3370        &mut self,
 3371        position: DisplayPoint,
 3372        add: bool,
 3373        click_count: usize,
 3374        window: &mut Window,
 3375        cx: &mut Context<Self>,
 3376    ) {
 3377        if !self.focus_handle.is_focused(window) {
 3378            self.last_focused_descendant = None;
 3379            window.focus(&self.focus_handle);
 3380        }
 3381
 3382        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3383        let buffer = &display_map.buffer_snapshot;
 3384        let position = display_map.clip_point(position, Bias::Left);
 3385
 3386        let start;
 3387        let end;
 3388        let mode;
 3389        let mut auto_scroll;
 3390        match click_count {
 3391            1 => {
 3392                start = buffer.anchor_before(position.to_point(&display_map));
 3393                end = start;
 3394                mode = SelectMode::Character;
 3395                auto_scroll = true;
 3396            }
 3397            2 => {
 3398                let position = display_map
 3399                    .clip_point(position, Bias::Left)
 3400                    .to_offset(&display_map, Bias::Left);
 3401                let (range, _) = buffer.surrounding_word(position, false);
 3402                start = buffer.anchor_before(range.start);
 3403                end = buffer.anchor_before(range.end);
 3404                mode = SelectMode::Word(start..end);
 3405                auto_scroll = true;
 3406            }
 3407            3 => {
 3408                let position = display_map
 3409                    .clip_point(position, Bias::Left)
 3410                    .to_point(&display_map);
 3411                let line_start = display_map.prev_line_boundary(position).0;
 3412                let next_line_start = buffer.clip_point(
 3413                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3414                    Bias::Left,
 3415                );
 3416                start = buffer.anchor_before(line_start);
 3417                end = buffer.anchor_before(next_line_start);
 3418                mode = SelectMode::Line(start..end);
 3419                auto_scroll = true;
 3420            }
 3421            _ => {
 3422                start = buffer.anchor_before(0);
 3423                end = buffer.anchor_before(buffer.len());
 3424                mode = SelectMode::All;
 3425                auto_scroll = false;
 3426            }
 3427        }
 3428        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3429
 3430        let point_to_delete: Option<usize> = {
 3431            let selected_points: Vec<Selection<Point>> =
 3432                self.selections.disjoint_in_range(start..end, cx);
 3433
 3434            if !add || click_count > 1 {
 3435                None
 3436            } else if !selected_points.is_empty() {
 3437                Some(selected_points[0].id)
 3438            } else {
 3439                let clicked_point_already_selected =
 3440                    self.selections.disjoint.iter().find(|selection| {
 3441                        selection.start.to_point(buffer) == start.to_point(buffer)
 3442                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3443                    });
 3444
 3445                clicked_point_already_selected.map(|selection| selection.id)
 3446            }
 3447        };
 3448
 3449        let selections_count = self.selections.count();
 3450
 3451        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3452            if let Some(point_to_delete) = point_to_delete {
 3453                s.delete(point_to_delete);
 3454
 3455                if selections_count == 1 {
 3456                    s.set_pending_anchor_range(start..end, mode);
 3457                }
 3458            } else {
 3459                if !add {
 3460                    s.clear_disjoint();
 3461                }
 3462
 3463                s.set_pending_anchor_range(start..end, mode);
 3464            }
 3465        });
 3466    }
 3467
 3468    fn begin_columnar_selection(
 3469        &mut self,
 3470        position: DisplayPoint,
 3471        goal_column: u32,
 3472        reset: bool,
 3473        mode: ColumnarMode,
 3474        window: &mut Window,
 3475        cx: &mut Context<Self>,
 3476    ) {
 3477        if !self.focus_handle.is_focused(window) {
 3478            self.last_focused_descendant = None;
 3479            window.focus(&self.focus_handle);
 3480        }
 3481
 3482        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3483
 3484        if reset {
 3485            let pointer_position = display_map
 3486                .buffer_snapshot
 3487                .anchor_before(position.to_point(&display_map));
 3488
 3489            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3490                s.clear_disjoint();
 3491                s.set_pending_anchor_range(
 3492                    pointer_position..pointer_position,
 3493                    SelectMode::Character,
 3494                );
 3495            });
 3496        };
 3497
 3498        let tail = self.selections.newest::<Point>(cx).tail();
 3499        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3500        self.columnar_selection_state = match mode {
 3501            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3502                selection_tail: selection_anchor,
 3503                display_point: if reset {
 3504                    if position.column() != goal_column {
 3505                        Some(DisplayPoint::new(position.row(), goal_column))
 3506                    } else {
 3507                        None
 3508                    }
 3509                } else {
 3510                    None
 3511                },
 3512            }),
 3513            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3514                selection_tail: selection_anchor,
 3515            }),
 3516        };
 3517
 3518        if !reset {
 3519            self.select_columns(position, goal_column, &display_map, window, cx);
 3520        }
 3521    }
 3522
 3523    fn update_selection(
 3524        &mut self,
 3525        position: DisplayPoint,
 3526        goal_column: u32,
 3527        scroll_delta: gpui::Point<f32>,
 3528        window: &mut Window,
 3529        cx: &mut Context<Self>,
 3530    ) {
 3531        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3532
 3533        if self.columnar_selection_state.is_some() {
 3534            self.select_columns(position, goal_column, &display_map, window, cx);
 3535        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3536            let buffer = &display_map.buffer_snapshot;
 3537            let head;
 3538            let tail;
 3539            let mode = self.selections.pending_mode().unwrap();
 3540            match &mode {
 3541                SelectMode::Character => {
 3542                    head = position.to_point(&display_map);
 3543                    tail = pending.tail().to_point(buffer);
 3544                }
 3545                SelectMode::Word(original_range) => {
 3546                    let offset = display_map
 3547                        .clip_point(position, Bias::Left)
 3548                        .to_offset(&display_map, Bias::Left);
 3549                    let original_range = original_range.to_offset(buffer);
 3550
 3551                    let head_offset = if buffer.is_inside_word(offset, false)
 3552                        || original_range.contains(&offset)
 3553                    {
 3554                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3555                        if word_range.start < original_range.start {
 3556                            word_range.start
 3557                        } else {
 3558                            word_range.end
 3559                        }
 3560                    } else {
 3561                        offset
 3562                    };
 3563
 3564                    head = head_offset.to_point(buffer);
 3565                    if head_offset <= original_range.start {
 3566                        tail = original_range.end.to_point(buffer);
 3567                    } else {
 3568                        tail = original_range.start.to_point(buffer);
 3569                    }
 3570                }
 3571                SelectMode::Line(original_range) => {
 3572                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3573
 3574                    let position = display_map
 3575                        .clip_point(position, Bias::Left)
 3576                        .to_point(&display_map);
 3577                    let line_start = display_map.prev_line_boundary(position).0;
 3578                    let next_line_start = buffer.clip_point(
 3579                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3580                        Bias::Left,
 3581                    );
 3582
 3583                    if line_start < original_range.start {
 3584                        head = line_start
 3585                    } else {
 3586                        head = next_line_start
 3587                    }
 3588
 3589                    if head <= original_range.start {
 3590                        tail = original_range.end;
 3591                    } else {
 3592                        tail = original_range.start;
 3593                    }
 3594                }
 3595                SelectMode::All => {
 3596                    return;
 3597                }
 3598            };
 3599
 3600            if head < tail {
 3601                pending.start = buffer.anchor_before(head);
 3602                pending.end = buffer.anchor_before(tail);
 3603                pending.reversed = true;
 3604            } else {
 3605                pending.start = buffer.anchor_before(tail);
 3606                pending.end = buffer.anchor_before(head);
 3607                pending.reversed = false;
 3608            }
 3609
 3610            self.change_selections(None, window, cx, |s| {
 3611                s.set_pending(pending, mode);
 3612            });
 3613        } else {
 3614            log::error!("update_selection dispatched with no pending selection");
 3615            return;
 3616        }
 3617
 3618        self.apply_scroll_delta(scroll_delta, window, cx);
 3619        cx.notify();
 3620    }
 3621
 3622    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3623        self.columnar_selection_state.take();
 3624        if self.selections.pending_anchor().is_some() {
 3625            let selections = self.selections.all::<usize>(cx);
 3626            self.change_selections(None, window, cx, |s| {
 3627                s.select(selections);
 3628                s.clear_pending();
 3629            });
 3630        }
 3631    }
 3632
 3633    fn select_columns(
 3634        &mut self,
 3635        head: DisplayPoint,
 3636        goal_column: u32,
 3637        display_map: &DisplaySnapshot,
 3638        window: &mut Window,
 3639        cx: &mut Context<Self>,
 3640    ) {
 3641        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3642            return;
 3643        };
 3644
 3645        let tail = match columnar_state {
 3646            ColumnarSelectionState::FromMouse {
 3647                selection_tail,
 3648                display_point,
 3649            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3650            ColumnarSelectionState::FromSelection { selection_tail } => {
 3651                selection_tail.to_display_point(&display_map)
 3652            }
 3653        };
 3654
 3655        let start_row = cmp::min(tail.row(), head.row());
 3656        let end_row = cmp::max(tail.row(), head.row());
 3657        let start_column = cmp::min(tail.column(), goal_column);
 3658        let end_column = cmp::max(tail.column(), goal_column);
 3659        let reversed = start_column < tail.column();
 3660
 3661        let selection_ranges = (start_row.0..=end_row.0)
 3662            .map(DisplayRow)
 3663            .filter_map(|row| {
 3664                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3665                    || start_column <= display_map.line_len(row))
 3666                    && !display_map.is_block_line(row)
 3667                {
 3668                    let start = display_map
 3669                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3670                        .to_point(display_map);
 3671                    let end = display_map
 3672                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3673                        .to_point(display_map);
 3674                    if reversed {
 3675                        Some(end..start)
 3676                    } else {
 3677                        Some(start..end)
 3678                    }
 3679                } else {
 3680                    None
 3681                }
 3682            })
 3683            .collect::<Vec<_>>();
 3684
 3685        let ranges = match columnar_state {
 3686            ColumnarSelectionState::FromMouse { .. } => {
 3687                let mut non_empty_ranges = selection_ranges
 3688                    .iter()
 3689                    .filter(|selection_range| selection_range.start != selection_range.end)
 3690                    .peekable();
 3691                if non_empty_ranges.peek().is_some() {
 3692                    non_empty_ranges.cloned().collect()
 3693                } else {
 3694                    selection_ranges
 3695                }
 3696            }
 3697            _ => selection_ranges,
 3698        };
 3699
 3700        self.change_selections(None, window, cx, |s| {
 3701            s.select_ranges(ranges);
 3702        });
 3703        cx.notify();
 3704    }
 3705
 3706    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3707        self.selections
 3708            .all_adjusted(cx)
 3709            .iter()
 3710            .any(|selection| !selection.is_empty())
 3711    }
 3712
 3713    pub fn has_pending_nonempty_selection(&self) -> bool {
 3714        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3715            Some(Selection { start, end, .. }) => start != end,
 3716            None => false,
 3717        };
 3718
 3719        pending_nonempty_selection
 3720            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3721    }
 3722
 3723    pub fn has_pending_selection(&self) -> bool {
 3724        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3725    }
 3726
 3727    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3728        self.selection_mark_mode = false;
 3729        self.selection_drag_state = SelectionDragState::None;
 3730
 3731        if self.clear_expanded_diff_hunks(cx) {
 3732            cx.notify();
 3733            return;
 3734        }
 3735        if self.dismiss_menus_and_popups(true, window, cx) {
 3736            return;
 3737        }
 3738
 3739        if self.mode.is_full()
 3740            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3741        {
 3742            return;
 3743        }
 3744
 3745        cx.propagate();
 3746    }
 3747
 3748    pub fn dismiss_menus_and_popups(
 3749        &mut self,
 3750        is_user_requested: bool,
 3751        window: &mut Window,
 3752        cx: &mut Context<Self>,
 3753    ) -> bool {
 3754        if self.take_rename(false, window, cx).is_some() {
 3755            return true;
 3756        }
 3757
 3758        if hide_hover(self, cx) {
 3759            return true;
 3760        }
 3761
 3762        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3763            return true;
 3764        }
 3765
 3766        if self.hide_context_menu(window, cx).is_some() {
 3767            return true;
 3768        }
 3769
 3770        if self.mouse_context_menu.take().is_some() {
 3771            return true;
 3772        }
 3773
 3774        if is_user_requested && self.discard_inline_completion(true, cx) {
 3775            return true;
 3776        }
 3777
 3778        if self.snippet_stack.pop().is_some() {
 3779            return true;
 3780        }
 3781
 3782        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3783            self.dismiss_diagnostics(cx);
 3784            return true;
 3785        }
 3786
 3787        false
 3788    }
 3789
 3790    fn linked_editing_ranges_for(
 3791        &self,
 3792        selection: Range<text::Anchor>,
 3793        cx: &App,
 3794    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3795        if self.linked_edit_ranges.is_empty() {
 3796            return None;
 3797        }
 3798        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3799            selection.end.buffer_id.and_then(|end_buffer_id| {
 3800                if selection.start.buffer_id != Some(end_buffer_id) {
 3801                    return None;
 3802                }
 3803                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3804                let snapshot = buffer.read(cx).snapshot();
 3805                self.linked_edit_ranges
 3806                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3807                    .map(|ranges| (ranges, snapshot, buffer))
 3808            })?;
 3809        use text::ToOffset as TO;
 3810        // find offset from the start of current range to current cursor position
 3811        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3812
 3813        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3814        let start_difference = start_offset - start_byte_offset;
 3815        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3816        let end_difference = end_offset - start_byte_offset;
 3817        // Current range has associated linked ranges.
 3818        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3819        for range in linked_ranges.iter() {
 3820            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3821            let end_offset = start_offset + end_difference;
 3822            let start_offset = start_offset + start_difference;
 3823            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3824                continue;
 3825            }
 3826            if self.selections.disjoint_anchor_ranges().any(|s| {
 3827                if s.start.buffer_id != selection.start.buffer_id
 3828                    || s.end.buffer_id != selection.end.buffer_id
 3829                {
 3830                    return false;
 3831                }
 3832                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3833                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3834            }) {
 3835                continue;
 3836            }
 3837            let start = buffer_snapshot.anchor_after(start_offset);
 3838            let end = buffer_snapshot.anchor_after(end_offset);
 3839            linked_edits
 3840                .entry(buffer.clone())
 3841                .or_default()
 3842                .push(start..end);
 3843        }
 3844        Some(linked_edits)
 3845    }
 3846
 3847    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3848        let text: Arc<str> = text.into();
 3849
 3850        if self.read_only(cx) {
 3851            return;
 3852        }
 3853
 3854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3855
 3856        let selections = self.selections.all_adjusted(cx);
 3857        let mut bracket_inserted = false;
 3858        let mut edits = Vec::new();
 3859        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3860        let mut new_selections = Vec::with_capacity(selections.len());
 3861        let mut new_autoclose_regions = Vec::new();
 3862        let snapshot = self.buffer.read(cx).read(cx);
 3863        let mut clear_linked_edit_ranges = false;
 3864
 3865        for (selection, autoclose_region) in
 3866            self.selections_with_autoclose_regions(selections, &snapshot)
 3867        {
 3868            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3869                // Determine if the inserted text matches the opening or closing
 3870                // bracket of any of this language's bracket pairs.
 3871                let mut bracket_pair = None;
 3872                let mut is_bracket_pair_start = false;
 3873                let mut is_bracket_pair_end = false;
 3874                if !text.is_empty() {
 3875                    let mut bracket_pair_matching_end = None;
 3876                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3877                    //  and they are removing the character that triggered IME popup.
 3878                    for (pair, enabled) in scope.brackets() {
 3879                        if !pair.close && !pair.surround {
 3880                            continue;
 3881                        }
 3882
 3883                        if enabled && pair.start.ends_with(text.as_ref()) {
 3884                            let prefix_len = pair.start.len() - text.len();
 3885                            let preceding_text_matches_prefix = prefix_len == 0
 3886                                || (selection.start.column >= (prefix_len as u32)
 3887                                    && snapshot.contains_str_at(
 3888                                        Point::new(
 3889                                            selection.start.row,
 3890                                            selection.start.column - (prefix_len as u32),
 3891                                        ),
 3892                                        &pair.start[..prefix_len],
 3893                                    ));
 3894                            if preceding_text_matches_prefix {
 3895                                bracket_pair = Some(pair.clone());
 3896                                is_bracket_pair_start = true;
 3897                                break;
 3898                            }
 3899                        }
 3900                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3901                        {
 3902                            // take first bracket pair matching end, but don't break in case a later bracket
 3903                            // pair matches start
 3904                            bracket_pair_matching_end = Some(pair.clone());
 3905                        }
 3906                    }
 3907                    if let Some(end) = bracket_pair_matching_end
 3908                        && bracket_pair.is_none()
 3909                    {
 3910                        bracket_pair = Some(end);
 3911                        is_bracket_pair_end = true;
 3912                    }
 3913                }
 3914
 3915                if let Some(bracket_pair) = bracket_pair {
 3916                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3917                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3918                    let auto_surround =
 3919                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3920                    if selection.is_empty() {
 3921                        if is_bracket_pair_start {
 3922                            // If the inserted text is a suffix of an opening bracket and the
 3923                            // selection is preceded by the rest of the opening bracket, then
 3924                            // insert the closing bracket.
 3925                            let following_text_allows_autoclose = snapshot
 3926                                .chars_at(selection.start)
 3927                                .next()
 3928                                .map_or(true, |c| scope.should_autoclose_before(c));
 3929
 3930                            let preceding_text_allows_autoclose = selection.start.column == 0
 3931                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3932                                    true,
 3933                                    |c| {
 3934                                        bracket_pair.start != bracket_pair.end
 3935                                            || !snapshot
 3936                                                .char_classifier_at(selection.start)
 3937                                                .is_word(c)
 3938                                    },
 3939                                );
 3940
 3941                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3942                                && bracket_pair.start.len() == 1
 3943                            {
 3944                                let target = bracket_pair.start.chars().next().unwrap();
 3945                                let current_line_count = snapshot
 3946                                    .reversed_chars_at(selection.start)
 3947                                    .take_while(|&c| c != '\n')
 3948                                    .filter(|&c| c == target)
 3949                                    .count();
 3950                                current_line_count % 2 == 1
 3951                            } else {
 3952                                false
 3953                            };
 3954
 3955                            if autoclose
 3956                                && bracket_pair.close
 3957                                && following_text_allows_autoclose
 3958                                && preceding_text_allows_autoclose
 3959                                && !is_closing_quote
 3960                            {
 3961                                let anchor = snapshot.anchor_before(selection.end);
 3962                                new_selections.push((selection.map(|_| anchor), text.len()));
 3963                                new_autoclose_regions.push((
 3964                                    anchor,
 3965                                    text.len(),
 3966                                    selection.id,
 3967                                    bracket_pair.clone(),
 3968                                ));
 3969                                edits.push((
 3970                                    selection.range(),
 3971                                    format!("{}{}", text, bracket_pair.end).into(),
 3972                                ));
 3973                                bracket_inserted = true;
 3974                                continue;
 3975                            }
 3976                        }
 3977
 3978                        if let Some(region) = autoclose_region {
 3979                            // If the selection is followed by an auto-inserted closing bracket,
 3980                            // then don't insert that closing bracket again; just move the selection
 3981                            // past the closing bracket.
 3982                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3983                                && text.as_ref() == region.pair.end.as_str();
 3984                            if should_skip {
 3985                                let anchor = snapshot.anchor_after(selection.end);
 3986                                new_selections
 3987                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3988                                continue;
 3989                            }
 3990                        }
 3991
 3992                        let always_treat_brackets_as_autoclosed = snapshot
 3993                            .language_settings_at(selection.start, cx)
 3994                            .always_treat_brackets_as_autoclosed;
 3995                        if always_treat_brackets_as_autoclosed
 3996                            && is_bracket_pair_end
 3997                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3998                        {
 3999                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4000                            // and the inserted text is a closing bracket and the selection is followed
 4001                            // by the closing bracket then move the selection past the closing bracket.
 4002                            let anchor = snapshot.anchor_after(selection.end);
 4003                            new_selections.push((selection.map(|_| anchor), text.len()));
 4004                            continue;
 4005                        }
 4006                    }
 4007                    // If an opening bracket is 1 character long and is typed while
 4008                    // text is selected, then surround that text with the bracket pair.
 4009                    else if auto_surround
 4010                        && bracket_pair.surround
 4011                        && is_bracket_pair_start
 4012                        && bracket_pair.start.chars().count() == 1
 4013                    {
 4014                        edits.push((selection.start..selection.start, text.clone()));
 4015                        edits.push((
 4016                            selection.end..selection.end,
 4017                            bracket_pair.end.as_str().into(),
 4018                        ));
 4019                        bracket_inserted = true;
 4020                        new_selections.push((
 4021                            Selection {
 4022                                id: selection.id,
 4023                                start: snapshot.anchor_after(selection.start),
 4024                                end: snapshot.anchor_before(selection.end),
 4025                                reversed: selection.reversed,
 4026                                goal: selection.goal,
 4027                            },
 4028                            0,
 4029                        ));
 4030                        continue;
 4031                    }
 4032                }
 4033            }
 4034
 4035            if self.auto_replace_emoji_shortcode
 4036                && selection.is_empty()
 4037                && text.as_ref().ends_with(':')
 4038            {
 4039                if let Some(possible_emoji_short_code) =
 4040                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4041                {
 4042                    if !possible_emoji_short_code.is_empty() {
 4043                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4044                            let emoji_shortcode_start = Point::new(
 4045                                selection.start.row,
 4046                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4047                            );
 4048
 4049                            // Remove shortcode from buffer
 4050                            edits.push((
 4051                                emoji_shortcode_start..selection.start,
 4052                                "".to_string().into(),
 4053                            ));
 4054                            new_selections.push((
 4055                                Selection {
 4056                                    id: selection.id,
 4057                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4058                                    end: snapshot.anchor_before(selection.start),
 4059                                    reversed: selection.reversed,
 4060                                    goal: selection.goal,
 4061                                },
 4062                                0,
 4063                            ));
 4064
 4065                            // Insert emoji
 4066                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4067                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4068                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4069
 4070                            continue;
 4071                        }
 4072                    }
 4073                }
 4074            }
 4075
 4076            // If not handling any auto-close operation, then just replace the selected
 4077            // text with the given input and move the selection to the end of the
 4078            // newly inserted text.
 4079            let anchor = snapshot.anchor_after(selection.end);
 4080            if !self.linked_edit_ranges.is_empty() {
 4081                let start_anchor = snapshot.anchor_before(selection.start);
 4082
 4083                let is_word_char = text.chars().next().map_or(true, |char| {
 4084                    let classifier = snapshot
 4085                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4086                        .ignore_punctuation(true);
 4087                    classifier.is_word(char)
 4088                });
 4089
 4090                if is_word_char {
 4091                    if let Some(ranges) = self
 4092                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4093                    {
 4094                        for (buffer, edits) in ranges {
 4095                            linked_edits
 4096                                .entry(buffer.clone())
 4097                                .or_default()
 4098                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4099                        }
 4100                    }
 4101                } else {
 4102                    clear_linked_edit_ranges = true;
 4103                }
 4104            }
 4105
 4106            new_selections.push((selection.map(|_| anchor), 0));
 4107            edits.push((selection.start..selection.end, text.clone()));
 4108        }
 4109
 4110        drop(snapshot);
 4111
 4112        self.transact(window, cx, |this, window, cx| {
 4113            if clear_linked_edit_ranges {
 4114                this.linked_edit_ranges.clear();
 4115            }
 4116            let initial_buffer_versions =
 4117                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4118
 4119            this.buffer.update(cx, |buffer, cx| {
 4120                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4121            });
 4122            for (buffer, edits) in linked_edits {
 4123                buffer.update(cx, |buffer, cx| {
 4124                    let snapshot = buffer.snapshot();
 4125                    let edits = edits
 4126                        .into_iter()
 4127                        .map(|(range, text)| {
 4128                            use text::ToPoint as TP;
 4129                            let end_point = TP::to_point(&range.end, &snapshot);
 4130                            let start_point = TP::to_point(&range.start, &snapshot);
 4131                            (start_point..end_point, text)
 4132                        })
 4133                        .sorted_by_key(|(range, _)| range.start);
 4134                    buffer.edit(edits, None, cx);
 4135                })
 4136            }
 4137            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4138            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4139            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4140            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4141                .zip(new_selection_deltas)
 4142                .map(|(selection, delta)| Selection {
 4143                    id: selection.id,
 4144                    start: selection.start + delta,
 4145                    end: selection.end + delta,
 4146                    reversed: selection.reversed,
 4147                    goal: SelectionGoal::None,
 4148                })
 4149                .collect::<Vec<_>>();
 4150
 4151            let mut i = 0;
 4152            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4153                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4154                let start = map.buffer_snapshot.anchor_before(position);
 4155                let end = map.buffer_snapshot.anchor_after(position);
 4156                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4157                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4158                        Ordering::Less => i += 1,
 4159                        Ordering::Greater => break,
 4160                        Ordering::Equal => {
 4161                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4162                                Ordering::Less => i += 1,
 4163                                Ordering::Equal => break,
 4164                                Ordering::Greater => break,
 4165                            }
 4166                        }
 4167                    }
 4168                }
 4169                this.autoclose_regions.insert(
 4170                    i,
 4171                    AutocloseRegion {
 4172                        selection_id,
 4173                        range: start..end,
 4174                        pair,
 4175                    },
 4176                );
 4177            }
 4178
 4179            let had_active_inline_completion = this.has_active_inline_completion();
 4180            this.change_selections(
 4181                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4182                window,
 4183                cx,
 4184                |s| s.select(new_selections),
 4185            );
 4186
 4187            if !bracket_inserted {
 4188                if let Some(on_type_format_task) =
 4189                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4190                {
 4191                    on_type_format_task.detach_and_log_err(cx);
 4192                }
 4193            }
 4194
 4195            let editor_settings = EditorSettings::get_global(cx);
 4196            if bracket_inserted
 4197                && (editor_settings.auto_signature_help
 4198                    || editor_settings.show_signature_help_after_edits)
 4199            {
 4200                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4201            }
 4202
 4203            let trigger_in_words =
 4204                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4205            if this.hard_wrap.is_some() {
 4206                let latest: Range<Point> = this.selections.newest(cx).range();
 4207                if latest.is_empty()
 4208                    && this
 4209                        .buffer()
 4210                        .read(cx)
 4211                        .snapshot(cx)
 4212                        .line_len(MultiBufferRow(latest.start.row))
 4213                        == latest.start.column
 4214                {
 4215                    this.rewrap_impl(
 4216                        RewrapOptions {
 4217                            override_language_settings: true,
 4218                            preserve_existing_whitespace: true,
 4219                        },
 4220                        cx,
 4221                    )
 4222                }
 4223            }
 4224            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4225            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4226            this.refresh_inline_completion(true, false, window, cx);
 4227            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4228        });
 4229    }
 4230
 4231    fn find_possible_emoji_shortcode_at_position(
 4232        snapshot: &MultiBufferSnapshot,
 4233        position: Point,
 4234    ) -> Option<String> {
 4235        let mut chars = Vec::new();
 4236        let mut found_colon = false;
 4237        for char in snapshot.reversed_chars_at(position).take(100) {
 4238            // Found a possible emoji shortcode in the middle of the buffer
 4239            if found_colon {
 4240                if char.is_whitespace() {
 4241                    chars.reverse();
 4242                    return Some(chars.iter().collect());
 4243                }
 4244                // If the previous character is not a whitespace, we are in the middle of a word
 4245                // and we only want to complete the shortcode if the word is made up of other emojis
 4246                let mut containing_word = String::new();
 4247                for ch in snapshot
 4248                    .reversed_chars_at(position)
 4249                    .skip(chars.len() + 1)
 4250                    .take(100)
 4251                {
 4252                    if ch.is_whitespace() {
 4253                        break;
 4254                    }
 4255                    containing_word.push(ch);
 4256                }
 4257                let containing_word = containing_word.chars().rev().collect::<String>();
 4258                if util::word_consists_of_emojis(containing_word.as_str()) {
 4259                    chars.reverse();
 4260                    return Some(chars.iter().collect());
 4261                }
 4262            }
 4263
 4264            if char.is_whitespace() || !char.is_ascii() {
 4265                return None;
 4266            }
 4267            if char == ':' {
 4268                found_colon = true;
 4269            } else {
 4270                chars.push(char);
 4271            }
 4272        }
 4273        // Found a possible emoji shortcode at the beginning of the buffer
 4274        chars.reverse();
 4275        Some(chars.iter().collect())
 4276    }
 4277
 4278    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4279        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4280        self.transact(window, cx, |this, window, cx| {
 4281            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4282                let selections = this.selections.all::<usize>(cx);
 4283                let multi_buffer = this.buffer.read(cx);
 4284                let buffer = multi_buffer.snapshot(cx);
 4285                selections
 4286                    .iter()
 4287                    .map(|selection| {
 4288                        let start_point = selection.start.to_point(&buffer);
 4289                        let mut existing_indent =
 4290                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4291                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4292                        let start = selection.start;
 4293                        let end = selection.end;
 4294                        let selection_is_empty = start == end;
 4295                        let language_scope = buffer.language_scope_at(start);
 4296                        let (
 4297                            comment_delimiter,
 4298                            doc_delimiter,
 4299                            insert_extra_newline,
 4300                            indent_on_newline,
 4301                            indent_on_extra_newline,
 4302                        ) = if let Some(language) = &language_scope {
 4303                            let mut insert_extra_newline =
 4304                                insert_extra_newline_brackets(&buffer, start..end, language)
 4305                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4306
 4307                            // Comment extension on newline is allowed only for cursor selections
 4308                            let comment_delimiter = maybe!({
 4309                                if !selection_is_empty {
 4310                                    return None;
 4311                                }
 4312
 4313                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4314                                    return None;
 4315                                }
 4316
 4317                                let delimiters = language.line_comment_prefixes();
 4318                                let max_len_of_delimiter =
 4319                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4320                                let (snapshot, range) =
 4321                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4322
 4323                                let num_of_whitespaces = snapshot
 4324                                    .chars_for_range(range.clone())
 4325                                    .take_while(|c| c.is_whitespace())
 4326                                    .count();
 4327                                let comment_candidate = snapshot
 4328                                    .chars_for_range(range)
 4329                                    .skip(num_of_whitespaces)
 4330                                    .take(max_len_of_delimiter)
 4331                                    .collect::<String>();
 4332                                let (delimiter, trimmed_len) = delimiters
 4333                                    .iter()
 4334                                    .filter_map(|delimiter| {
 4335                                        let prefix = delimiter.trim_end();
 4336                                        if comment_candidate.starts_with(prefix) {
 4337                                            Some((delimiter, prefix.len()))
 4338                                        } else {
 4339                                            None
 4340                                        }
 4341                                    })
 4342                                    .max_by_key(|(_, len)| *len)?;
 4343
 4344                                let cursor_is_placed_after_comment_marker =
 4345                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4346                                if cursor_is_placed_after_comment_marker {
 4347                                    Some(delimiter.clone())
 4348                                } else {
 4349                                    None
 4350                                }
 4351                            });
 4352
 4353                            let mut indent_on_newline = IndentSize::spaces(0);
 4354                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4355
 4356                            let doc_delimiter = maybe!({
 4357                                if !selection_is_empty {
 4358                                    return None;
 4359                                }
 4360
 4361                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4362                                    return None;
 4363                                }
 4364
 4365                                let DocumentationConfig {
 4366                                    start: start_tag,
 4367                                    end: end_tag,
 4368                                    prefix: delimiter,
 4369                                    tab_size: len,
 4370                                } = language.documentation()?;
 4371
 4372                                let is_within_block_comment = buffer
 4373                                    .language_scope_at(start_point)
 4374                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4375                                if !is_within_block_comment {
 4376                                    return None;
 4377                                }
 4378
 4379                                let (snapshot, range) =
 4380                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4381
 4382                                let num_of_whitespaces = snapshot
 4383                                    .chars_for_range(range.clone())
 4384                                    .take_while(|c| c.is_whitespace())
 4385                                    .count();
 4386
 4387                                // 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.
 4388                                let column = start_point.column;
 4389                                let cursor_is_after_start_tag = {
 4390                                    let start_tag_len = start_tag.len();
 4391                                    let start_tag_line = snapshot
 4392                                        .chars_for_range(range.clone())
 4393                                        .skip(num_of_whitespaces)
 4394                                        .take(start_tag_len)
 4395                                        .collect::<String>();
 4396                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4397                                        num_of_whitespaces + start_tag_len <= column as usize
 4398                                    } else {
 4399                                        false
 4400                                    }
 4401                                };
 4402
 4403                                let cursor_is_after_delimiter = {
 4404                                    let delimiter_trim = delimiter.trim_end();
 4405                                    let delimiter_line = snapshot
 4406                                        .chars_for_range(range.clone())
 4407                                        .skip(num_of_whitespaces)
 4408                                        .take(delimiter_trim.len())
 4409                                        .collect::<String>();
 4410                                    if delimiter_line.starts_with(delimiter_trim) {
 4411                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4412                                    } else {
 4413                                        false
 4414                                    }
 4415                                };
 4416
 4417                                let cursor_is_before_end_tag_if_exists = {
 4418                                    let mut char_position = 0u32;
 4419                                    let mut end_tag_offset = None;
 4420
 4421                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4422                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4423                                            let chars_before_match =
 4424                                                chunk[..byte_pos].chars().count() as u32;
 4425                                            end_tag_offset =
 4426                                                Some(char_position + chars_before_match);
 4427                                            break 'outer;
 4428                                        }
 4429                                        char_position += chunk.chars().count() as u32;
 4430                                    }
 4431
 4432                                    if let Some(end_tag_offset) = end_tag_offset {
 4433                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4434                                        if cursor_is_after_start_tag {
 4435                                            if cursor_is_before_end_tag {
 4436                                                insert_extra_newline = true;
 4437                                            }
 4438                                            let cursor_is_at_start_of_end_tag =
 4439                                                column == end_tag_offset;
 4440                                            if cursor_is_at_start_of_end_tag {
 4441                                                indent_on_extra_newline.len = (*len).into();
 4442                                            }
 4443                                        }
 4444                                        cursor_is_before_end_tag
 4445                                    } else {
 4446                                        true
 4447                                    }
 4448                                };
 4449
 4450                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4451                                    && cursor_is_before_end_tag_if_exists
 4452                                {
 4453                                    if cursor_is_after_start_tag {
 4454                                        indent_on_newline.len = (*len).into();
 4455                                    }
 4456                                    Some(delimiter.clone())
 4457                                } else {
 4458                                    None
 4459                                }
 4460                            });
 4461
 4462                            (
 4463                                comment_delimiter,
 4464                                doc_delimiter,
 4465                                insert_extra_newline,
 4466                                indent_on_newline,
 4467                                indent_on_extra_newline,
 4468                            )
 4469                        } else {
 4470                            (
 4471                                None,
 4472                                None,
 4473                                false,
 4474                                IndentSize::default(),
 4475                                IndentSize::default(),
 4476                            )
 4477                        };
 4478
 4479                        let prevent_auto_indent = doc_delimiter.is_some();
 4480                        let delimiter = comment_delimiter.or(doc_delimiter);
 4481
 4482                        let capacity_for_delimiter =
 4483                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4484                        let mut new_text = String::with_capacity(
 4485                            1 + capacity_for_delimiter
 4486                                + existing_indent.len as usize
 4487                                + indent_on_newline.len as usize
 4488                                + indent_on_extra_newline.len as usize,
 4489                        );
 4490                        new_text.push('\n');
 4491                        new_text.extend(existing_indent.chars());
 4492                        new_text.extend(indent_on_newline.chars());
 4493
 4494                        if let Some(delimiter) = &delimiter {
 4495                            new_text.push_str(delimiter);
 4496                        }
 4497
 4498                        if insert_extra_newline {
 4499                            new_text.push('\n');
 4500                            new_text.extend(existing_indent.chars());
 4501                            new_text.extend(indent_on_extra_newline.chars());
 4502                        }
 4503
 4504                        let anchor = buffer.anchor_after(end);
 4505                        let new_selection = selection.map(|_| anchor);
 4506                        (
 4507                            ((start..end, new_text), prevent_auto_indent),
 4508                            (insert_extra_newline, new_selection),
 4509                        )
 4510                    })
 4511                    .unzip()
 4512            };
 4513
 4514            let mut auto_indent_edits = Vec::new();
 4515            let mut edits = Vec::new();
 4516            for (edit, prevent_auto_indent) in edits_with_flags {
 4517                if prevent_auto_indent {
 4518                    edits.push(edit);
 4519                } else {
 4520                    auto_indent_edits.push(edit);
 4521                }
 4522            }
 4523            if !edits.is_empty() {
 4524                this.edit(edits, cx);
 4525            }
 4526            if !auto_indent_edits.is_empty() {
 4527                this.edit_with_autoindent(auto_indent_edits, cx);
 4528            }
 4529
 4530            let buffer = this.buffer.read(cx).snapshot(cx);
 4531            let new_selections = selection_info
 4532                .into_iter()
 4533                .map(|(extra_newline_inserted, new_selection)| {
 4534                    let mut cursor = new_selection.end.to_point(&buffer);
 4535                    if extra_newline_inserted {
 4536                        cursor.row -= 1;
 4537                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4538                    }
 4539                    new_selection.map(|_| cursor)
 4540                })
 4541                .collect();
 4542
 4543            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4544                s.select(new_selections)
 4545            });
 4546            this.refresh_inline_completion(true, false, window, cx);
 4547        });
 4548    }
 4549
 4550    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4551        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4552
 4553        let buffer = self.buffer.read(cx);
 4554        let snapshot = buffer.snapshot(cx);
 4555
 4556        let mut edits = Vec::new();
 4557        let mut rows = Vec::new();
 4558
 4559        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4560            let cursor = selection.head();
 4561            let row = cursor.row;
 4562
 4563            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4564
 4565            let newline = "\n".to_string();
 4566            edits.push((start_of_line..start_of_line, newline));
 4567
 4568            rows.push(row + rows_inserted as u32);
 4569        }
 4570
 4571        self.transact(window, cx, |editor, window, cx| {
 4572            editor.edit(edits, cx);
 4573
 4574            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4575                let mut index = 0;
 4576                s.move_cursors_with(|map, _, _| {
 4577                    let row = rows[index];
 4578                    index += 1;
 4579
 4580                    let point = Point::new(row, 0);
 4581                    let boundary = map.next_line_boundary(point).1;
 4582                    let clipped = map.clip_point(boundary, Bias::Left);
 4583
 4584                    (clipped, SelectionGoal::None)
 4585                });
 4586            });
 4587
 4588            let mut indent_edits = Vec::new();
 4589            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4590            for row in rows {
 4591                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4592                for (row, indent) in indents {
 4593                    if indent.len == 0 {
 4594                        continue;
 4595                    }
 4596
 4597                    let text = match indent.kind {
 4598                        IndentKind::Space => " ".repeat(indent.len as usize),
 4599                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4600                    };
 4601                    let point = Point::new(row.0, 0);
 4602                    indent_edits.push((point..point, text));
 4603                }
 4604            }
 4605            editor.edit(indent_edits, cx);
 4606        });
 4607    }
 4608
 4609    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4610        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4611
 4612        let buffer = self.buffer.read(cx);
 4613        let snapshot = buffer.snapshot(cx);
 4614
 4615        let mut edits = Vec::new();
 4616        let mut rows = Vec::new();
 4617        let mut rows_inserted = 0;
 4618
 4619        for selection in self.selections.all_adjusted(cx) {
 4620            let cursor = selection.head();
 4621            let row = cursor.row;
 4622
 4623            let point = Point::new(row + 1, 0);
 4624            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4625
 4626            let newline = "\n".to_string();
 4627            edits.push((start_of_line..start_of_line, newline));
 4628
 4629            rows_inserted += 1;
 4630            rows.push(row + rows_inserted);
 4631        }
 4632
 4633        self.transact(window, cx, |editor, window, cx| {
 4634            editor.edit(edits, cx);
 4635
 4636            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4637                let mut index = 0;
 4638                s.move_cursors_with(|map, _, _| {
 4639                    let row = rows[index];
 4640                    index += 1;
 4641
 4642                    let point = Point::new(row, 0);
 4643                    let boundary = map.next_line_boundary(point).1;
 4644                    let clipped = map.clip_point(boundary, Bias::Left);
 4645
 4646                    (clipped, SelectionGoal::None)
 4647                });
 4648            });
 4649
 4650            let mut indent_edits = Vec::new();
 4651            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4652            for row in rows {
 4653                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4654                for (row, indent) in indents {
 4655                    if indent.len == 0 {
 4656                        continue;
 4657                    }
 4658
 4659                    let text = match indent.kind {
 4660                        IndentKind::Space => " ".repeat(indent.len as usize),
 4661                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4662                    };
 4663                    let point = Point::new(row.0, 0);
 4664                    indent_edits.push((point..point, text));
 4665                }
 4666            }
 4667            editor.edit(indent_edits, cx);
 4668        });
 4669    }
 4670
 4671    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4672        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4673            original_indent_columns: Vec::new(),
 4674        });
 4675        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4676    }
 4677
 4678    fn insert_with_autoindent_mode(
 4679        &mut self,
 4680        text: &str,
 4681        autoindent_mode: Option<AutoindentMode>,
 4682        window: &mut Window,
 4683        cx: &mut Context<Self>,
 4684    ) {
 4685        if self.read_only(cx) {
 4686            return;
 4687        }
 4688
 4689        let text: Arc<str> = text.into();
 4690        self.transact(window, cx, |this, window, cx| {
 4691            let old_selections = this.selections.all_adjusted(cx);
 4692            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4693                let anchors = {
 4694                    let snapshot = buffer.read(cx);
 4695                    old_selections
 4696                        .iter()
 4697                        .map(|s| {
 4698                            let anchor = snapshot.anchor_after(s.head());
 4699                            s.map(|_| anchor)
 4700                        })
 4701                        .collect::<Vec<_>>()
 4702                };
 4703                buffer.edit(
 4704                    old_selections
 4705                        .iter()
 4706                        .map(|s| (s.start..s.end, text.clone())),
 4707                    autoindent_mode,
 4708                    cx,
 4709                );
 4710                anchors
 4711            });
 4712
 4713            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4714                s.select_anchors(selection_anchors);
 4715            });
 4716
 4717            cx.notify();
 4718        });
 4719    }
 4720
 4721    fn trigger_completion_on_input(
 4722        &mut self,
 4723        text: &str,
 4724        trigger_in_words: bool,
 4725        window: &mut Window,
 4726        cx: &mut Context<Self>,
 4727    ) {
 4728        let completions_source = self
 4729            .context_menu
 4730            .borrow()
 4731            .as_ref()
 4732            .and_then(|menu| match menu {
 4733                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4734                CodeContextMenu::CodeActions(_) => None,
 4735            });
 4736
 4737        match completions_source {
 4738            Some(CompletionsMenuSource::Words) => {
 4739                self.show_word_completions(&ShowWordCompletions, window, cx)
 4740            }
 4741            Some(CompletionsMenuSource::Normal)
 4742            | Some(CompletionsMenuSource::SnippetChoices)
 4743            | None
 4744                if self.is_completion_trigger(
 4745                    text,
 4746                    trigger_in_words,
 4747                    completions_source.is_some(),
 4748                    cx,
 4749                ) =>
 4750            {
 4751                self.show_completions(
 4752                    &ShowCompletions {
 4753                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4754                    },
 4755                    window,
 4756                    cx,
 4757                )
 4758            }
 4759            _ => {
 4760                self.hide_context_menu(window, cx);
 4761            }
 4762        }
 4763    }
 4764
 4765    fn is_completion_trigger(
 4766        &self,
 4767        text: &str,
 4768        trigger_in_words: bool,
 4769        menu_is_open: bool,
 4770        cx: &mut Context<Self>,
 4771    ) -> bool {
 4772        let position = self.selections.newest_anchor().head();
 4773        let multibuffer = self.buffer.read(cx);
 4774        let Some(buffer) = position
 4775            .buffer_id
 4776            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4777        else {
 4778            return false;
 4779        };
 4780
 4781        if let Some(completion_provider) = &self.completion_provider {
 4782            completion_provider.is_completion_trigger(
 4783                &buffer,
 4784                position.text_anchor,
 4785                text,
 4786                trigger_in_words,
 4787                menu_is_open,
 4788                cx,
 4789            )
 4790        } else {
 4791            false
 4792        }
 4793    }
 4794
 4795    /// If any empty selections is touching the start of its innermost containing autoclose
 4796    /// region, expand it to select the brackets.
 4797    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4798        let selections = self.selections.all::<usize>(cx);
 4799        let buffer = self.buffer.read(cx).read(cx);
 4800        let new_selections = self
 4801            .selections_with_autoclose_regions(selections, &buffer)
 4802            .map(|(mut selection, region)| {
 4803                if !selection.is_empty() {
 4804                    return selection;
 4805                }
 4806
 4807                if let Some(region) = region {
 4808                    let mut range = region.range.to_offset(&buffer);
 4809                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4810                        range.start -= region.pair.start.len();
 4811                        if buffer.contains_str_at(range.start, &region.pair.start)
 4812                            && buffer.contains_str_at(range.end, &region.pair.end)
 4813                        {
 4814                            range.end += region.pair.end.len();
 4815                            selection.start = range.start;
 4816                            selection.end = range.end;
 4817
 4818                            return selection;
 4819                        }
 4820                    }
 4821                }
 4822
 4823                let always_treat_brackets_as_autoclosed = buffer
 4824                    .language_settings_at(selection.start, cx)
 4825                    .always_treat_brackets_as_autoclosed;
 4826
 4827                if !always_treat_brackets_as_autoclosed {
 4828                    return selection;
 4829                }
 4830
 4831                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4832                    for (pair, enabled) in scope.brackets() {
 4833                        if !enabled || !pair.close {
 4834                            continue;
 4835                        }
 4836
 4837                        if buffer.contains_str_at(selection.start, &pair.end) {
 4838                            let pair_start_len = pair.start.len();
 4839                            if buffer.contains_str_at(
 4840                                selection.start.saturating_sub(pair_start_len),
 4841                                &pair.start,
 4842                            ) {
 4843                                selection.start -= pair_start_len;
 4844                                selection.end += pair.end.len();
 4845
 4846                                return selection;
 4847                            }
 4848                        }
 4849                    }
 4850                }
 4851
 4852                selection
 4853            })
 4854            .collect();
 4855
 4856        drop(buffer);
 4857        self.change_selections(None, window, cx, |selections| {
 4858            selections.select(new_selections)
 4859        });
 4860    }
 4861
 4862    /// Iterate the given selections, and for each one, find the smallest surrounding
 4863    /// autoclose region. This uses the ordering of the selections and the autoclose
 4864    /// regions to avoid repeated comparisons.
 4865    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4866        &'a self,
 4867        selections: impl IntoIterator<Item = Selection<D>>,
 4868        buffer: &'a MultiBufferSnapshot,
 4869    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4870        let mut i = 0;
 4871        let mut regions = self.autoclose_regions.as_slice();
 4872        selections.into_iter().map(move |selection| {
 4873            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4874
 4875            let mut enclosing = None;
 4876            while let Some(pair_state) = regions.get(i) {
 4877                if pair_state.range.end.to_offset(buffer) < range.start {
 4878                    regions = &regions[i + 1..];
 4879                    i = 0;
 4880                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4881                    break;
 4882                } else {
 4883                    if pair_state.selection_id == selection.id {
 4884                        enclosing = Some(pair_state);
 4885                    }
 4886                    i += 1;
 4887                }
 4888            }
 4889
 4890            (selection, enclosing)
 4891        })
 4892    }
 4893
 4894    /// Remove any autoclose regions that no longer contain their selection.
 4895    fn invalidate_autoclose_regions(
 4896        &mut self,
 4897        mut selections: &[Selection<Anchor>],
 4898        buffer: &MultiBufferSnapshot,
 4899    ) {
 4900        self.autoclose_regions.retain(|state| {
 4901            let mut i = 0;
 4902            while let Some(selection) = selections.get(i) {
 4903                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4904                    selections = &selections[1..];
 4905                    continue;
 4906                }
 4907                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4908                    break;
 4909                }
 4910                if selection.id == state.selection_id {
 4911                    return true;
 4912                } else {
 4913                    i += 1;
 4914                }
 4915            }
 4916            false
 4917        });
 4918    }
 4919
 4920    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4921        let offset = position.to_offset(buffer);
 4922        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4923        if offset > word_range.start && kind == Some(CharKind::Word) {
 4924            Some(
 4925                buffer
 4926                    .text_for_range(word_range.start..offset)
 4927                    .collect::<String>(),
 4928            )
 4929        } else {
 4930            None
 4931        }
 4932    }
 4933
 4934    pub fn toggle_inline_values(
 4935        &mut self,
 4936        _: &ToggleInlineValues,
 4937        _: &mut Window,
 4938        cx: &mut Context<Self>,
 4939    ) {
 4940        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4941
 4942        self.refresh_inline_values(cx);
 4943    }
 4944
 4945    pub fn toggle_inlay_hints(
 4946        &mut self,
 4947        _: &ToggleInlayHints,
 4948        _: &mut Window,
 4949        cx: &mut Context<Self>,
 4950    ) {
 4951        self.refresh_inlay_hints(
 4952            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4953            cx,
 4954        );
 4955    }
 4956
 4957    pub fn inlay_hints_enabled(&self) -> bool {
 4958        self.inlay_hint_cache.enabled
 4959    }
 4960
 4961    pub fn inline_values_enabled(&self) -> bool {
 4962        self.inline_value_cache.enabled
 4963    }
 4964
 4965    #[cfg(any(test, feature = "test-support"))]
 4966    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4967        self.display_map
 4968            .read(cx)
 4969            .current_inlays()
 4970            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4971            .cloned()
 4972            .collect()
 4973    }
 4974
 4975    #[cfg(any(test, feature = "test-support"))]
 4976    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 4977        self.display_map
 4978            .read(cx)
 4979            .current_inlays()
 4980            .cloned()
 4981            .collect()
 4982    }
 4983
 4984    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4985        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4986            return;
 4987        }
 4988
 4989        let reason_description = reason.description();
 4990        let ignore_debounce = matches!(
 4991            reason,
 4992            InlayHintRefreshReason::SettingsChange(_)
 4993                | InlayHintRefreshReason::Toggle(_)
 4994                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4995                | InlayHintRefreshReason::ModifiersChanged(_)
 4996        );
 4997        let (invalidate_cache, required_languages) = match reason {
 4998            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4999                match self.inlay_hint_cache.modifiers_override(enabled) {
 5000                    Some(enabled) => {
 5001                        if enabled {
 5002                            (InvalidationStrategy::RefreshRequested, None)
 5003                        } else {
 5004                            self.splice_inlays(
 5005                                &self
 5006                                    .visible_inlay_hints(cx)
 5007                                    .iter()
 5008                                    .map(|inlay| inlay.id)
 5009                                    .collect::<Vec<InlayId>>(),
 5010                                Vec::new(),
 5011                                cx,
 5012                            );
 5013                            return;
 5014                        }
 5015                    }
 5016                    None => return,
 5017                }
 5018            }
 5019            InlayHintRefreshReason::Toggle(enabled) => {
 5020                if self.inlay_hint_cache.toggle(enabled) {
 5021                    if enabled {
 5022                        (InvalidationStrategy::RefreshRequested, None)
 5023                    } else {
 5024                        self.splice_inlays(
 5025                            &self
 5026                                .visible_inlay_hints(cx)
 5027                                .iter()
 5028                                .map(|inlay| inlay.id)
 5029                                .collect::<Vec<InlayId>>(),
 5030                            Vec::new(),
 5031                            cx,
 5032                        );
 5033                        return;
 5034                    }
 5035                } else {
 5036                    return;
 5037                }
 5038            }
 5039            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5040                match self.inlay_hint_cache.update_settings(
 5041                    &self.buffer,
 5042                    new_settings,
 5043                    self.visible_inlay_hints(cx),
 5044                    cx,
 5045                ) {
 5046                    ControlFlow::Break(Some(InlaySplice {
 5047                        to_remove,
 5048                        to_insert,
 5049                    })) => {
 5050                        self.splice_inlays(&to_remove, to_insert, cx);
 5051                        return;
 5052                    }
 5053                    ControlFlow::Break(None) => return,
 5054                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5055                }
 5056            }
 5057            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5058                if let Some(InlaySplice {
 5059                    to_remove,
 5060                    to_insert,
 5061                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5062                {
 5063                    self.splice_inlays(&to_remove, to_insert, cx);
 5064                }
 5065                self.display_map.update(cx, |display_map, _| {
 5066                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5067                });
 5068                return;
 5069            }
 5070            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5071            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5072                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5073            }
 5074            InlayHintRefreshReason::RefreshRequested => {
 5075                (InvalidationStrategy::RefreshRequested, None)
 5076            }
 5077        };
 5078
 5079        if let Some(InlaySplice {
 5080            to_remove,
 5081            to_insert,
 5082        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5083            reason_description,
 5084            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 5085            invalidate_cache,
 5086            ignore_debounce,
 5087            cx,
 5088        ) {
 5089            self.splice_inlays(&to_remove, to_insert, cx);
 5090        }
 5091    }
 5092
 5093    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5094        self.display_map
 5095            .read(cx)
 5096            .current_inlays()
 5097            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5098            .cloned()
 5099            .collect()
 5100    }
 5101
 5102    pub fn excerpts_for_inlay_hints_query(
 5103        &self,
 5104        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5105        cx: &mut Context<Editor>,
 5106    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5107        let Some(project) = self.project.as_ref() else {
 5108            return HashMap::default();
 5109        };
 5110        let project = project.read(cx);
 5111        let multi_buffer = self.buffer().read(cx);
 5112        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5113        let multi_buffer_visible_start = self
 5114            .scroll_manager
 5115            .anchor()
 5116            .anchor
 5117            .to_point(&multi_buffer_snapshot);
 5118        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5119            multi_buffer_visible_start
 5120                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5121            Bias::Left,
 5122        );
 5123        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5124        multi_buffer_snapshot
 5125            .range_to_buffer_ranges(multi_buffer_visible_range)
 5126            .into_iter()
 5127            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5128            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5129                let buffer_file = project::File::from_dyn(buffer.file())?;
 5130                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5131                let worktree_entry = buffer_worktree
 5132                    .read(cx)
 5133                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5134                if worktree_entry.is_ignored {
 5135                    return None;
 5136                }
 5137
 5138                let language = buffer.language()?;
 5139                if let Some(restrict_to_languages) = restrict_to_languages {
 5140                    if !restrict_to_languages.contains(language) {
 5141                        return None;
 5142                    }
 5143                }
 5144                Some((
 5145                    excerpt_id,
 5146                    (
 5147                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5148                        buffer.version().clone(),
 5149                        excerpt_visible_range,
 5150                    ),
 5151                ))
 5152            })
 5153            .collect()
 5154    }
 5155
 5156    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5157        TextLayoutDetails {
 5158            text_system: window.text_system().clone(),
 5159            editor_style: self.style.clone().unwrap(),
 5160            rem_size: window.rem_size(),
 5161            scroll_anchor: self.scroll_manager.anchor(),
 5162            visible_rows: self.visible_line_count(),
 5163            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5164        }
 5165    }
 5166
 5167    pub fn splice_inlays(
 5168        &self,
 5169        to_remove: &[InlayId],
 5170        to_insert: Vec<Inlay>,
 5171        cx: &mut Context<Self>,
 5172    ) {
 5173        self.display_map.update(cx, |display_map, cx| {
 5174            display_map.splice_inlays(to_remove, to_insert, cx)
 5175        });
 5176        cx.notify();
 5177    }
 5178
 5179    fn trigger_on_type_formatting(
 5180        &self,
 5181        input: String,
 5182        window: &mut Window,
 5183        cx: &mut Context<Self>,
 5184    ) -> Option<Task<Result<()>>> {
 5185        if input.len() != 1 {
 5186            return None;
 5187        }
 5188
 5189        let project = self.project.as_ref()?;
 5190        let position = self.selections.newest_anchor().head();
 5191        let (buffer, buffer_position) = self
 5192            .buffer
 5193            .read(cx)
 5194            .text_anchor_for_position(position, cx)?;
 5195
 5196        let settings = language_settings::language_settings(
 5197            buffer
 5198                .read(cx)
 5199                .language_at(buffer_position)
 5200                .map(|l| l.name()),
 5201            buffer.read(cx).file(),
 5202            cx,
 5203        );
 5204        if !settings.use_on_type_format {
 5205            return None;
 5206        }
 5207
 5208        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5209        // hence we do LSP request & edit on host side only — add formats to host's history.
 5210        let push_to_lsp_host_history = true;
 5211        // If this is not the host, append its history with new edits.
 5212        let push_to_client_history = project.read(cx).is_via_collab();
 5213
 5214        let on_type_formatting = project.update(cx, |project, cx| {
 5215            project.on_type_format(
 5216                buffer.clone(),
 5217                buffer_position,
 5218                input,
 5219                push_to_lsp_host_history,
 5220                cx,
 5221            )
 5222        });
 5223        Some(cx.spawn_in(window, async move |editor, cx| {
 5224            if let Some(transaction) = on_type_formatting.await? {
 5225                if push_to_client_history {
 5226                    buffer
 5227                        .update(cx, |buffer, _| {
 5228                            buffer.push_transaction(transaction, Instant::now());
 5229                            buffer.finalize_last_transaction();
 5230                        })
 5231                        .ok();
 5232                }
 5233                editor.update(cx, |editor, cx| {
 5234                    editor.refresh_document_highlights(cx);
 5235                })?;
 5236            }
 5237            Ok(())
 5238        }))
 5239    }
 5240
 5241    pub fn show_word_completions(
 5242        &mut self,
 5243        _: &ShowWordCompletions,
 5244        window: &mut Window,
 5245        cx: &mut Context<Self>,
 5246    ) {
 5247        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5248    }
 5249
 5250    pub fn show_completions(
 5251        &mut self,
 5252        options: &ShowCompletions,
 5253        window: &mut Window,
 5254        cx: &mut Context<Self>,
 5255    ) {
 5256        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5257    }
 5258
 5259    fn open_or_update_completions_menu(
 5260        &mut self,
 5261        requested_source: Option<CompletionsMenuSource>,
 5262        trigger: Option<&str>,
 5263        window: &mut Window,
 5264        cx: &mut Context<Self>,
 5265    ) {
 5266        if self.pending_rename.is_some() {
 5267            return;
 5268        }
 5269
 5270        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5271
 5272        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5273        // inserted and selected. To handle that case, the start of the selection is used so that
 5274        // the menu starts with all choices.
 5275        let position = self
 5276            .selections
 5277            .newest_anchor()
 5278            .start
 5279            .bias_right(&multibuffer_snapshot);
 5280        if position.diff_base_anchor.is_some() {
 5281            return;
 5282        }
 5283        let (buffer, buffer_position) =
 5284            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5285                output
 5286            } else {
 5287                return;
 5288            };
 5289        let buffer_snapshot = buffer.read(cx).snapshot();
 5290
 5291        let query: Option<Arc<String>> =
 5292            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5293
 5294        drop(multibuffer_snapshot);
 5295
 5296        let provider = match requested_source {
 5297            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5298            Some(CompletionsMenuSource::Words) => None,
 5299            Some(CompletionsMenuSource::SnippetChoices) => {
 5300                log::error!("bug: SnippetChoices requested_source is not handled");
 5301                None
 5302            }
 5303        };
 5304
 5305        let sort_completions = provider
 5306            .as_ref()
 5307            .map_or(false, |provider| provider.sort_completions());
 5308
 5309        let filter_completions = provider
 5310            .as_ref()
 5311            .map_or(true, |provider| provider.filter_completions());
 5312
 5313        let trigger_kind = match trigger {
 5314            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5315                CompletionTriggerKind::TRIGGER_CHARACTER
 5316            }
 5317            _ => CompletionTriggerKind::INVOKED,
 5318        };
 5319        let completion_context = CompletionContext {
 5320            trigger_character: trigger.and_then(|trigger| {
 5321                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5322                    Some(String::from(trigger))
 5323                } else {
 5324                    None
 5325                }
 5326            }),
 5327            trigger_kind,
 5328        };
 5329
 5330        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5331        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5332        // involve trigger chars, so this is skipped in that case.
 5333        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5334        {
 5335            let menu_is_open = matches!(
 5336                self.context_menu.borrow().as_ref(),
 5337                Some(CodeContextMenu::Completions(_))
 5338            );
 5339            if menu_is_open {
 5340                self.hide_context_menu(window, cx);
 5341            }
 5342        }
 5343
 5344        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5345            if filter_completions {
 5346                menu.filter(query.clone(), provider.clone(), window, cx);
 5347            }
 5348            // When `is_incomplete` is false, no need to re-query completions when the current query
 5349            // is a suffix of the initial query.
 5350            if !menu.is_incomplete {
 5351                // If the new query is a suffix of the old query (typing more characters) and
 5352                // the previous result was complete, the existing completions can be filtered.
 5353                //
 5354                // Note that this is always true for snippet completions.
 5355                let query_matches = match (&menu.initial_query, &query) {
 5356                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5357                    (None, _) => true,
 5358                    _ => false,
 5359                };
 5360                if query_matches {
 5361                    let position_matches = if menu.initial_position == position {
 5362                        true
 5363                    } else {
 5364                        let snapshot = self.buffer.read(cx).read(cx);
 5365                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5366                    };
 5367                    if position_matches {
 5368                        return;
 5369                    }
 5370                }
 5371            }
 5372        };
 5373
 5374        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5375            buffer_snapshot.surrounding_word(buffer_position)
 5376        {
 5377            let word_to_exclude = buffer_snapshot
 5378                .text_for_range(word_range.clone())
 5379                .collect::<String>();
 5380            (
 5381                buffer_snapshot.anchor_before(word_range.start)
 5382                    ..buffer_snapshot.anchor_after(buffer_position),
 5383                Some(word_to_exclude),
 5384            )
 5385        } else {
 5386            (buffer_position..buffer_position, None)
 5387        };
 5388
 5389        let language = buffer_snapshot
 5390            .language_at(buffer_position)
 5391            .map(|language| language.name());
 5392
 5393        let completion_settings =
 5394            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5395
 5396        let show_completion_documentation = buffer_snapshot
 5397            .settings_at(buffer_position, cx)
 5398            .show_completion_documentation;
 5399
 5400        // The document can be large, so stay in reasonable bounds when searching for words,
 5401        // otherwise completion pop-up might be slow to appear.
 5402        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5403        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5404        let min_word_search = buffer_snapshot.clip_point(
 5405            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5406            Bias::Left,
 5407        );
 5408        let max_word_search = buffer_snapshot.clip_point(
 5409            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5410            Bias::Right,
 5411        );
 5412        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5413            ..buffer_snapshot.point_to_offset(max_word_search);
 5414
 5415        let skip_digits = query
 5416            .as_ref()
 5417            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5418
 5419        let (mut words, provider_responses) = match &provider {
 5420            Some(provider) => {
 5421                let provider_responses = provider.completions(
 5422                    position.excerpt_id,
 5423                    &buffer,
 5424                    buffer_position,
 5425                    completion_context,
 5426                    window,
 5427                    cx,
 5428                );
 5429
 5430                let words = match completion_settings.words {
 5431                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5432                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5433                        .background_spawn(async move {
 5434                            buffer_snapshot.words_in_range(WordsQuery {
 5435                                fuzzy_contents: None,
 5436                                range: word_search_range,
 5437                                skip_digits,
 5438                            })
 5439                        }),
 5440                };
 5441
 5442                (words, provider_responses)
 5443            }
 5444            None => (
 5445                cx.background_spawn(async move {
 5446                    buffer_snapshot.words_in_range(WordsQuery {
 5447                        fuzzy_contents: None,
 5448                        range: word_search_range,
 5449                        skip_digits,
 5450                    })
 5451                }),
 5452                Task::ready(Ok(Vec::new())),
 5453            ),
 5454        };
 5455
 5456        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5457
 5458        let id = post_inc(&mut self.next_completion_id);
 5459        let task = cx.spawn_in(window, async move |editor, cx| {
 5460            let Ok(()) = editor.update(cx, |this, _| {
 5461                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5462            }) else {
 5463                return;
 5464            };
 5465
 5466            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5467            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5468            let mut completions = Vec::new();
 5469            let mut is_incomplete = false;
 5470            if let Some(provider_responses) = provider_responses.await.log_err() {
 5471                if !provider_responses.is_empty() {
 5472                    for response in provider_responses {
 5473                        completions.extend(response.completions);
 5474                        is_incomplete = is_incomplete || response.is_incomplete;
 5475                    }
 5476                    if completion_settings.words == WordsCompletionMode::Fallback {
 5477                        words = Task::ready(BTreeMap::default());
 5478                    }
 5479                }
 5480            }
 5481
 5482            let mut words = words.await;
 5483            if let Some(word_to_exclude) = &word_to_exclude {
 5484                words.remove(word_to_exclude);
 5485            }
 5486            for lsp_completion in &completions {
 5487                words.remove(&lsp_completion.new_text);
 5488            }
 5489            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5490                replace_range: word_replace_range.clone(),
 5491                new_text: word.clone(),
 5492                label: CodeLabel::plain(word, None),
 5493                icon_path: None,
 5494                documentation: None,
 5495                source: CompletionSource::BufferWord {
 5496                    word_range,
 5497                    resolved: false,
 5498                },
 5499                insert_text_mode: Some(InsertTextMode::AS_IS),
 5500                confirm: None,
 5501            }));
 5502
 5503            let menu = if completions.is_empty() {
 5504                None
 5505            } else {
 5506                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5507                    let languages = editor
 5508                        .workspace
 5509                        .as_ref()
 5510                        .and_then(|(workspace, _)| workspace.upgrade())
 5511                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5512                    let menu = CompletionsMenu::new(
 5513                        id,
 5514                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5515                        sort_completions,
 5516                        show_completion_documentation,
 5517                        position,
 5518                        query.clone(),
 5519                        is_incomplete,
 5520                        buffer.clone(),
 5521                        completions.into(),
 5522                        snippet_sort_order,
 5523                        languages,
 5524                        language,
 5525                        cx,
 5526                    );
 5527
 5528                    let query = if filter_completions { query } else { None };
 5529                    let matches_task = if let Some(query) = query {
 5530                        menu.do_async_filtering(query, cx)
 5531                    } else {
 5532                        Task::ready(menu.unfiltered_matches())
 5533                    };
 5534                    (menu, matches_task)
 5535                }) else {
 5536                    return;
 5537                };
 5538
 5539                let matches = matches_task.await;
 5540
 5541                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5542                    // Newer menu already set, so exit.
 5543                    match editor.context_menu.borrow().as_ref() {
 5544                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5545                            if prev_menu.id > id {
 5546                                return;
 5547                            }
 5548                        }
 5549                        _ => {}
 5550                    };
 5551
 5552                    // Only valid to take prev_menu because it the new menu is immediately set
 5553                    // below, or the menu is hidden.
 5554                    match editor.context_menu.borrow_mut().take() {
 5555                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5556                            let position_matches =
 5557                                if prev_menu.initial_position == menu.initial_position {
 5558                                    true
 5559                                } else {
 5560                                    let snapshot = editor.buffer.read(cx).read(cx);
 5561                                    prev_menu.initial_position.to_offset(&snapshot)
 5562                                        == menu.initial_position.to_offset(&snapshot)
 5563                                };
 5564                            if position_matches {
 5565                                // Preserve markdown cache before `set_filter_results` because it will
 5566                                // try to populate the documentation cache.
 5567                                menu.preserve_markdown_cache(prev_menu);
 5568                            }
 5569                        }
 5570                        _ => {}
 5571                    };
 5572
 5573                    menu.set_filter_results(matches, provider, window, cx);
 5574                }) else {
 5575                    return;
 5576                };
 5577
 5578                menu.visible().then_some(menu)
 5579            };
 5580
 5581            editor
 5582                .update_in(cx, |editor, window, cx| {
 5583                    if editor.focus_handle.is_focused(window) {
 5584                        if let Some(menu) = menu {
 5585                            *editor.context_menu.borrow_mut() =
 5586                                Some(CodeContextMenu::Completions(menu));
 5587
 5588                            crate::hover_popover::hide_hover(editor, cx);
 5589                            if editor.show_edit_predictions_in_menu() {
 5590                                editor.update_visible_inline_completion(window, cx);
 5591                            } else {
 5592                                editor.discard_inline_completion(false, cx);
 5593                            }
 5594
 5595                            cx.notify();
 5596                            return;
 5597                        }
 5598                    }
 5599
 5600                    if editor.completion_tasks.len() <= 1 {
 5601                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5602                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5603                        // If it was already hidden and we don't show inline completions in the menu, we should
 5604                        // also show the inline-completion when available.
 5605                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5606                            editor.update_visible_inline_completion(window, cx);
 5607                        }
 5608                    }
 5609                })
 5610                .ok();
 5611        });
 5612
 5613        self.completion_tasks.push((id, task));
 5614    }
 5615
 5616    #[cfg(feature = "test-support")]
 5617    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5618        let menu = self.context_menu.borrow();
 5619        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5620            let completions = menu.completions.borrow();
 5621            Some(completions.to_vec())
 5622        } else {
 5623            None
 5624        }
 5625    }
 5626
 5627    pub fn with_completions_menu_matching_id<R>(
 5628        &self,
 5629        id: CompletionId,
 5630        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5631    ) -> R {
 5632        let mut context_menu = self.context_menu.borrow_mut();
 5633        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5634            return f(None);
 5635        };
 5636        if completions_menu.id != id {
 5637            return f(None);
 5638        }
 5639        f(Some(completions_menu))
 5640    }
 5641
 5642    pub fn confirm_completion(
 5643        &mut self,
 5644        action: &ConfirmCompletion,
 5645        window: &mut Window,
 5646        cx: &mut Context<Self>,
 5647    ) -> Option<Task<Result<()>>> {
 5648        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5649        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5650    }
 5651
 5652    pub fn confirm_completion_insert(
 5653        &mut self,
 5654        _: &ConfirmCompletionInsert,
 5655        window: &mut Window,
 5656        cx: &mut Context<Self>,
 5657    ) -> Option<Task<Result<()>>> {
 5658        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5659        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5660    }
 5661
 5662    pub fn confirm_completion_replace(
 5663        &mut self,
 5664        _: &ConfirmCompletionReplace,
 5665        window: &mut Window,
 5666        cx: &mut Context<Self>,
 5667    ) -> Option<Task<Result<()>>> {
 5668        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5669        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5670    }
 5671
 5672    pub fn compose_completion(
 5673        &mut self,
 5674        action: &ComposeCompletion,
 5675        window: &mut Window,
 5676        cx: &mut Context<Self>,
 5677    ) -> Option<Task<Result<()>>> {
 5678        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5679        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5680    }
 5681
 5682    fn do_completion(
 5683        &mut self,
 5684        item_ix: Option<usize>,
 5685        intent: CompletionIntent,
 5686        window: &mut Window,
 5687        cx: &mut Context<Editor>,
 5688    ) -> Option<Task<Result<()>>> {
 5689        use language::ToOffset as _;
 5690
 5691        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5692        else {
 5693            return None;
 5694        };
 5695
 5696        let candidate_id = {
 5697            let entries = completions_menu.entries.borrow();
 5698            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5699            if self.show_edit_predictions_in_menu() {
 5700                self.discard_inline_completion(true, cx);
 5701            }
 5702            mat.candidate_id
 5703        };
 5704
 5705        let completion = completions_menu
 5706            .completions
 5707            .borrow()
 5708            .get(candidate_id)?
 5709            .clone();
 5710        cx.stop_propagation();
 5711
 5712        let buffer_handle = completions_menu.buffer.clone();
 5713
 5714        let CompletionEdit {
 5715            new_text,
 5716            snippet,
 5717            replace_range,
 5718        } = process_completion_for_edit(
 5719            &completion,
 5720            intent,
 5721            &buffer_handle,
 5722            &completions_menu.initial_position.text_anchor,
 5723            cx,
 5724        );
 5725
 5726        let buffer = buffer_handle.read(cx);
 5727        let snapshot = self.buffer.read(cx).snapshot(cx);
 5728        let newest_anchor = self.selections.newest_anchor();
 5729        let replace_range_multibuffer = {
 5730            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5731            let multibuffer_anchor = snapshot
 5732                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5733                .unwrap()
 5734                ..snapshot
 5735                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5736                    .unwrap();
 5737            multibuffer_anchor.start.to_offset(&snapshot)
 5738                ..multibuffer_anchor.end.to_offset(&snapshot)
 5739        };
 5740        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5741            return None;
 5742        }
 5743
 5744        let old_text = buffer
 5745            .text_for_range(replace_range.clone())
 5746            .collect::<String>();
 5747        let lookbehind = newest_anchor
 5748            .start
 5749            .text_anchor
 5750            .to_offset(buffer)
 5751            .saturating_sub(replace_range.start);
 5752        let lookahead = replace_range
 5753            .end
 5754            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5755        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5756        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5757
 5758        let selections = self.selections.all::<usize>(cx);
 5759        let mut ranges = Vec::new();
 5760        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5761
 5762        for selection in &selections {
 5763            let range = if selection.id == newest_anchor.id {
 5764                replace_range_multibuffer.clone()
 5765            } else {
 5766                let mut range = selection.range();
 5767
 5768                // if prefix is present, don't duplicate it
 5769                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5770                    range.start = range.start.saturating_sub(lookbehind);
 5771
 5772                    // if suffix is also present, mimic the newest cursor and replace it
 5773                    if selection.id != newest_anchor.id
 5774                        && snapshot.contains_str_at(range.end, suffix)
 5775                    {
 5776                        range.end += lookahead;
 5777                    }
 5778                }
 5779                range
 5780            };
 5781
 5782            ranges.push(range.clone());
 5783
 5784            if !self.linked_edit_ranges.is_empty() {
 5785                let start_anchor = snapshot.anchor_before(range.start);
 5786                let end_anchor = snapshot.anchor_after(range.end);
 5787                if let Some(ranges) = self
 5788                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5789                {
 5790                    for (buffer, edits) in ranges {
 5791                        linked_edits
 5792                            .entry(buffer.clone())
 5793                            .or_default()
 5794                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5795                    }
 5796                }
 5797            }
 5798        }
 5799
 5800        let common_prefix_len = old_text
 5801            .chars()
 5802            .zip(new_text.chars())
 5803            .take_while(|(a, b)| a == b)
 5804            .map(|(a, _)| a.len_utf8())
 5805            .sum::<usize>();
 5806
 5807        cx.emit(EditorEvent::InputHandled {
 5808            utf16_range_to_replace: None,
 5809            text: new_text[common_prefix_len..].into(),
 5810        });
 5811
 5812        self.transact(window, cx, |this, window, cx| {
 5813            if let Some(mut snippet) = snippet {
 5814                snippet.text = new_text.to_string();
 5815                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5816            } else {
 5817                this.buffer.update(cx, |buffer, cx| {
 5818                    let auto_indent = match completion.insert_text_mode {
 5819                        Some(InsertTextMode::AS_IS) => None,
 5820                        _ => this.autoindent_mode.clone(),
 5821                    };
 5822                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5823                    buffer.edit(edits, auto_indent, cx);
 5824                });
 5825            }
 5826            for (buffer, edits) in linked_edits {
 5827                buffer.update(cx, |buffer, cx| {
 5828                    let snapshot = buffer.snapshot();
 5829                    let edits = edits
 5830                        .into_iter()
 5831                        .map(|(range, text)| {
 5832                            use text::ToPoint as TP;
 5833                            let end_point = TP::to_point(&range.end, &snapshot);
 5834                            let start_point = TP::to_point(&range.start, &snapshot);
 5835                            (start_point..end_point, text)
 5836                        })
 5837                        .sorted_by_key(|(range, _)| range.start);
 5838                    buffer.edit(edits, None, cx);
 5839                })
 5840            }
 5841
 5842            this.refresh_inline_completion(true, false, window, cx);
 5843        });
 5844
 5845        let show_new_completions_on_confirm = completion
 5846            .confirm
 5847            .as_ref()
 5848            .map_or(false, |confirm| confirm(intent, window, cx));
 5849        if show_new_completions_on_confirm {
 5850            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5851        }
 5852
 5853        let provider = self.completion_provider.as_ref()?;
 5854        drop(completion);
 5855        let apply_edits = provider.apply_additional_edits_for_completion(
 5856            buffer_handle,
 5857            completions_menu.completions.clone(),
 5858            candidate_id,
 5859            true,
 5860            cx,
 5861        );
 5862
 5863        let editor_settings = EditorSettings::get_global(cx);
 5864        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5865            // After the code completion is finished, users often want to know what signatures are needed.
 5866            // so we should automatically call signature_help
 5867            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5868        }
 5869
 5870        Some(cx.foreground_executor().spawn(async move {
 5871            apply_edits.await?;
 5872            Ok(())
 5873        }))
 5874    }
 5875
 5876    pub fn toggle_code_actions(
 5877        &mut self,
 5878        action: &ToggleCodeActions,
 5879        window: &mut Window,
 5880        cx: &mut Context<Self>,
 5881    ) {
 5882        let quick_launch = action.quick_launch;
 5883        let mut context_menu = self.context_menu.borrow_mut();
 5884        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5885            if code_actions.deployed_from == action.deployed_from {
 5886                // Toggle if we're selecting the same one
 5887                *context_menu = None;
 5888                cx.notify();
 5889                return;
 5890            } else {
 5891                // Otherwise, clear it and start a new one
 5892                *context_menu = None;
 5893                cx.notify();
 5894            }
 5895        }
 5896        drop(context_menu);
 5897        let snapshot = self.snapshot(window, cx);
 5898        let deployed_from = action.deployed_from.clone();
 5899        let action = action.clone();
 5900        self.completion_tasks.clear();
 5901        self.discard_inline_completion(false, cx);
 5902
 5903        let multibuffer_point = match &action.deployed_from {
 5904            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5905                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5906            }
 5907            _ => self.selections.newest::<Point>(cx).head(),
 5908        };
 5909        let Some((buffer, buffer_row)) = snapshot
 5910            .buffer_snapshot
 5911            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5912            .and_then(|(buffer_snapshot, range)| {
 5913                self.buffer()
 5914                    .read(cx)
 5915                    .buffer(buffer_snapshot.remote_id())
 5916                    .map(|buffer| (buffer, range.start.row))
 5917            })
 5918        else {
 5919            return;
 5920        };
 5921        let buffer_id = buffer.read(cx).remote_id();
 5922        let tasks = self
 5923            .tasks
 5924            .get(&(buffer_id, buffer_row))
 5925            .map(|t| Arc::new(t.to_owned()));
 5926
 5927        if !self.focus_handle.is_focused(window) {
 5928            return;
 5929        }
 5930        let project = self.project.clone();
 5931
 5932        let code_actions_task = match deployed_from {
 5933            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5934            _ => self.code_actions(buffer_row, window, cx),
 5935        };
 5936
 5937        let runnable_task = match deployed_from {
 5938            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5939            _ => {
 5940                let mut task_context_task = Task::ready(None);
 5941                if let Some(tasks) = &tasks {
 5942                    if let Some(project) = project {
 5943                        task_context_task =
 5944                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5945                    }
 5946                }
 5947
 5948                cx.spawn_in(window, {
 5949                    let buffer = buffer.clone();
 5950                    async move |editor, cx| {
 5951                        let task_context = task_context_task.await;
 5952
 5953                        let resolved_tasks =
 5954                            tasks
 5955                                .zip(task_context.clone())
 5956                                .map(|(tasks, task_context)| ResolvedTasks {
 5957                                    templates: tasks.resolve(&task_context).collect(),
 5958                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5959                                        multibuffer_point.row,
 5960                                        tasks.column,
 5961                                    )),
 5962                                });
 5963                        let debug_scenarios = editor
 5964                            .update(cx, |editor, cx| {
 5965                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5966                            })?
 5967                            .await;
 5968                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5969                    }
 5970                })
 5971            }
 5972        };
 5973
 5974        cx.spawn_in(window, async move |editor, cx| {
 5975            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5976            let code_actions = code_actions_task.await;
 5977            let spawn_straight_away = quick_launch
 5978                && resolved_tasks
 5979                    .as_ref()
 5980                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5981                && code_actions
 5982                    .as_ref()
 5983                    .map_or(true, |actions| actions.is_empty())
 5984                && debug_scenarios.is_empty();
 5985
 5986            editor.update_in(cx, |editor, window, cx| {
 5987                crate::hover_popover::hide_hover(editor, cx);
 5988                let actions = CodeActionContents::new(
 5989                    resolved_tasks,
 5990                    code_actions,
 5991                    debug_scenarios,
 5992                    task_context.unwrap_or_default(),
 5993                );
 5994
 5995                // Don't show the menu if there are no actions available
 5996                if actions.is_empty() {
 5997                    cx.notify();
 5998                    return Task::ready(Ok(()));
 5999                }
 6000
 6001                *editor.context_menu.borrow_mut() =
 6002                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6003                        buffer,
 6004                        actions,
 6005                        selected_item: Default::default(),
 6006                        scroll_handle: UniformListScrollHandle::default(),
 6007                        deployed_from,
 6008                    }));
 6009                cx.notify();
 6010                if spawn_straight_away {
 6011                    if let Some(task) = editor.confirm_code_action(
 6012                        &ConfirmCodeAction { item_ix: Some(0) },
 6013                        window,
 6014                        cx,
 6015                    ) {
 6016                        return task;
 6017                    }
 6018                }
 6019
 6020                Task::ready(Ok(()))
 6021            })
 6022        })
 6023        .detach_and_log_err(cx);
 6024    }
 6025
 6026    fn debug_scenarios(
 6027        &mut self,
 6028        resolved_tasks: &Option<ResolvedTasks>,
 6029        buffer: &Entity<Buffer>,
 6030        cx: &mut App,
 6031    ) -> Task<Vec<task::DebugScenario>> {
 6032        maybe!({
 6033            let project = self.project.as_ref()?;
 6034            let dap_store = project.read(cx).dap_store();
 6035            let mut scenarios = vec![];
 6036            let resolved_tasks = resolved_tasks.as_ref()?;
 6037            let buffer = buffer.read(cx);
 6038            let language = buffer.language()?;
 6039            let file = buffer.file();
 6040            let debug_adapter = language_settings(language.name().into(), file, cx)
 6041                .debuggers
 6042                .first()
 6043                .map(SharedString::from)
 6044                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6045
 6046            dap_store.update(cx, |dap_store, cx| {
 6047                for (_, task) in &resolved_tasks.templates {
 6048                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6049                        task.original_task().clone(),
 6050                        debug_adapter.clone().into(),
 6051                        task.display_label().to_owned().into(),
 6052                        cx,
 6053                    );
 6054                    scenarios.push(maybe_scenario);
 6055                }
 6056            });
 6057            Some(cx.background_spawn(async move {
 6058                let scenarios = futures::future::join_all(scenarios)
 6059                    .await
 6060                    .into_iter()
 6061                    .flatten()
 6062                    .collect::<Vec<_>>();
 6063                scenarios
 6064            }))
 6065        })
 6066        .unwrap_or_else(|| Task::ready(vec![]))
 6067    }
 6068
 6069    fn code_actions(
 6070        &mut self,
 6071        buffer_row: u32,
 6072        window: &mut Window,
 6073        cx: &mut Context<Self>,
 6074    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6075        let mut task = self.code_actions_task.take();
 6076        cx.spawn_in(window, async move |editor, cx| {
 6077            while let Some(prev_task) = task {
 6078                prev_task.await.log_err();
 6079                task = editor
 6080                    .update(cx, |this, _| this.code_actions_task.take())
 6081                    .ok()?;
 6082            }
 6083
 6084            editor
 6085                .update(cx, |editor, cx| {
 6086                    editor
 6087                        .available_code_actions
 6088                        .clone()
 6089                        .and_then(|(location, code_actions)| {
 6090                            let snapshot = location.buffer.read(cx).snapshot();
 6091                            let point_range = location.range.to_point(&snapshot);
 6092                            let point_range = point_range.start.row..=point_range.end.row;
 6093                            if point_range.contains(&buffer_row) {
 6094                                Some(code_actions)
 6095                            } else {
 6096                                None
 6097                            }
 6098                        })
 6099                })
 6100                .ok()
 6101                .flatten()
 6102        })
 6103    }
 6104
 6105    pub fn confirm_code_action(
 6106        &mut self,
 6107        action: &ConfirmCodeAction,
 6108        window: &mut Window,
 6109        cx: &mut Context<Self>,
 6110    ) -> Option<Task<Result<()>>> {
 6111        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6112
 6113        let actions_menu =
 6114            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6115                menu
 6116            } else {
 6117                return None;
 6118            };
 6119
 6120        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6121        let action = actions_menu.actions.get(action_ix)?;
 6122        let title = action.label();
 6123        let buffer = actions_menu.buffer;
 6124        let workspace = self.workspace()?;
 6125
 6126        match action {
 6127            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6128                workspace.update(cx, |workspace, cx| {
 6129                    workspace.schedule_resolved_task(
 6130                        task_source_kind,
 6131                        resolved_task,
 6132                        false,
 6133                        window,
 6134                        cx,
 6135                    );
 6136
 6137                    Some(Task::ready(Ok(())))
 6138                })
 6139            }
 6140            CodeActionsItem::CodeAction {
 6141                excerpt_id,
 6142                action,
 6143                provider,
 6144            } => {
 6145                let apply_code_action =
 6146                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6147                let workspace = workspace.downgrade();
 6148                Some(cx.spawn_in(window, async move |editor, cx| {
 6149                    let project_transaction = apply_code_action.await?;
 6150                    Self::open_project_transaction(
 6151                        &editor,
 6152                        workspace,
 6153                        project_transaction,
 6154                        title,
 6155                        cx,
 6156                    )
 6157                    .await
 6158                }))
 6159            }
 6160            CodeActionsItem::DebugScenario(scenario) => {
 6161                let context = actions_menu.actions.context.clone();
 6162
 6163                workspace.update(cx, |workspace, cx| {
 6164                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6165                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6166                });
 6167                Some(Task::ready(Ok(())))
 6168            }
 6169        }
 6170    }
 6171
 6172    pub async fn open_project_transaction(
 6173        this: &WeakEntity<Editor>,
 6174        workspace: WeakEntity<Workspace>,
 6175        transaction: ProjectTransaction,
 6176        title: String,
 6177        cx: &mut AsyncWindowContext,
 6178    ) -> Result<()> {
 6179        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6180        cx.update(|_, cx| {
 6181            entries.sort_unstable_by_key(|(buffer, _)| {
 6182                buffer.read(cx).file().map(|f| f.path().clone())
 6183            });
 6184        })?;
 6185
 6186        // If the project transaction's edits are all contained within this editor, then
 6187        // avoid opening a new editor to display them.
 6188
 6189        if let Some((buffer, transaction)) = entries.first() {
 6190            if entries.len() == 1 {
 6191                let excerpt = this.update(cx, |editor, cx| {
 6192                    editor
 6193                        .buffer()
 6194                        .read(cx)
 6195                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6196                })?;
 6197                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6198                    if excerpted_buffer == *buffer {
 6199                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6200                            let excerpt_range = excerpt_range.to_offset(buffer);
 6201                            buffer
 6202                                .edited_ranges_for_transaction::<usize>(transaction)
 6203                                .all(|range| {
 6204                                    excerpt_range.start <= range.start
 6205                                        && excerpt_range.end >= range.end
 6206                                })
 6207                        })?;
 6208
 6209                        if all_edits_within_excerpt {
 6210                            return Ok(());
 6211                        }
 6212                    }
 6213                }
 6214            }
 6215        } else {
 6216            return Ok(());
 6217        }
 6218
 6219        let mut ranges_to_highlight = Vec::new();
 6220        let excerpt_buffer = cx.new(|cx| {
 6221            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6222            for (buffer_handle, transaction) in &entries {
 6223                let edited_ranges = buffer_handle
 6224                    .read(cx)
 6225                    .edited_ranges_for_transaction::<Point>(transaction)
 6226                    .collect::<Vec<_>>();
 6227                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6228                    PathKey::for_buffer(buffer_handle, cx),
 6229                    buffer_handle.clone(),
 6230                    edited_ranges,
 6231                    DEFAULT_MULTIBUFFER_CONTEXT,
 6232                    cx,
 6233                );
 6234
 6235                ranges_to_highlight.extend(ranges);
 6236            }
 6237            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6238            multibuffer
 6239        })?;
 6240
 6241        workspace.update_in(cx, |workspace, window, cx| {
 6242            let project = workspace.project().clone();
 6243            let editor =
 6244                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6245            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6246            editor.update(cx, |editor, cx| {
 6247                editor.highlight_background::<Self>(
 6248                    &ranges_to_highlight,
 6249                    |theme| theme.colors().editor_highlighted_line_background,
 6250                    cx,
 6251                );
 6252            });
 6253        })?;
 6254
 6255        Ok(())
 6256    }
 6257
 6258    pub fn clear_code_action_providers(&mut self) {
 6259        self.code_action_providers.clear();
 6260        self.available_code_actions.take();
 6261    }
 6262
 6263    pub fn add_code_action_provider(
 6264        &mut self,
 6265        provider: Rc<dyn CodeActionProvider>,
 6266        window: &mut Window,
 6267        cx: &mut Context<Self>,
 6268    ) {
 6269        if self
 6270            .code_action_providers
 6271            .iter()
 6272            .any(|existing_provider| existing_provider.id() == provider.id())
 6273        {
 6274            return;
 6275        }
 6276
 6277        self.code_action_providers.push(provider);
 6278        self.refresh_code_actions(window, cx);
 6279    }
 6280
 6281    pub fn remove_code_action_provider(
 6282        &mut self,
 6283        id: Arc<str>,
 6284        window: &mut Window,
 6285        cx: &mut Context<Self>,
 6286    ) {
 6287        self.code_action_providers
 6288            .retain(|provider| provider.id() != id);
 6289        self.refresh_code_actions(window, cx);
 6290    }
 6291
 6292    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6293        !self.code_action_providers.is_empty()
 6294            && EditorSettings::get_global(cx).toolbar.code_actions
 6295    }
 6296
 6297    pub fn has_available_code_actions(&self) -> bool {
 6298        self.available_code_actions
 6299            .as_ref()
 6300            .is_some_and(|(_, actions)| !actions.is_empty())
 6301    }
 6302
 6303    fn render_inline_code_actions(
 6304        &self,
 6305        icon_size: ui::IconSize,
 6306        display_row: DisplayRow,
 6307        is_active: bool,
 6308        cx: &mut Context<Self>,
 6309    ) -> AnyElement {
 6310        let show_tooltip = !self.context_menu_visible();
 6311        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6312            .icon_size(icon_size)
 6313            .shape(ui::IconButtonShape::Square)
 6314            .style(ButtonStyle::Transparent)
 6315            .icon_color(ui::Color::Hidden)
 6316            .toggle_state(is_active)
 6317            .when(show_tooltip, |this| {
 6318                this.tooltip({
 6319                    let focus_handle = self.focus_handle.clone();
 6320                    move |window, cx| {
 6321                        Tooltip::for_action_in(
 6322                            "Toggle Code Actions",
 6323                            &ToggleCodeActions {
 6324                                deployed_from: None,
 6325                                quick_launch: false,
 6326                            },
 6327                            &focus_handle,
 6328                            window,
 6329                            cx,
 6330                        )
 6331                    }
 6332                })
 6333            })
 6334            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6335                window.focus(&editor.focus_handle(cx));
 6336                editor.toggle_code_actions(
 6337                    &crate::actions::ToggleCodeActions {
 6338                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6339                            display_row,
 6340                        )),
 6341                        quick_launch: false,
 6342                    },
 6343                    window,
 6344                    cx,
 6345                );
 6346            }))
 6347            .into_any_element()
 6348    }
 6349
 6350    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6351        &self.context_menu
 6352    }
 6353
 6354    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6355        let newest_selection = self.selections.newest_anchor().clone();
 6356        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6357        let buffer = self.buffer.read(cx);
 6358        if newest_selection.head().diff_base_anchor.is_some() {
 6359            return None;
 6360        }
 6361        let (start_buffer, start) =
 6362            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6363        let (end_buffer, end) =
 6364            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6365        if start_buffer != end_buffer {
 6366            return None;
 6367        }
 6368
 6369        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6370            cx.background_executor()
 6371                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6372                .await;
 6373
 6374            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6375                let providers = this.code_action_providers.clone();
 6376                let tasks = this
 6377                    .code_action_providers
 6378                    .iter()
 6379                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6380                    .collect::<Vec<_>>();
 6381                (providers, tasks)
 6382            })?;
 6383
 6384            let mut actions = Vec::new();
 6385            for (provider, provider_actions) in
 6386                providers.into_iter().zip(future::join_all(tasks).await)
 6387            {
 6388                if let Some(provider_actions) = provider_actions.log_err() {
 6389                    actions.extend(provider_actions.into_iter().map(|action| {
 6390                        AvailableCodeAction {
 6391                            excerpt_id: newest_selection.start.excerpt_id,
 6392                            action,
 6393                            provider: provider.clone(),
 6394                        }
 6395                    }));
 6396                }
 6397            }
 6398
 6399            this.update(cx, |this, cx| {
 6400                this.available_code_actions = if actions.is_empty() {
 6401                    None
 6402                } else {
 6403                    Some((
 6404                        Location {
 6405                            buffer: start_buffer,
 6406                            range: start..end,
 6407                        },
 6408                        actions.into(),
 6409                    ))
 6410                };
 6411                cx.notify();
 6412            })
 6413        }));
 6414        None
 6415    }
 6416
 6417    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6418        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6419            self.show_git_blame_inline = false;
 6420
 6421            self.show_git_blame_inline_delay_task =
 6422                Some(cx.spawn_in(window, async move |this, cx| {
 6423                    cx.background_executor().timer(delay).await;
 6424
 6425                    this.update(cx, |this, cx| {
 6426                        this.show_git_blame_inline = true;
 6427                        cx.notify();
 6428                    })
 6429                    .log_err();
 6430                }));
 6431        }
 6432    }
 6433
 6434    fn show_blame_popover(
 6435        &mut self,
 6436        blame_entry: &BlameEntry,
 6437        position: gpui::Point<Pixels>,
 6438        cx: &mut Context<Self>,
 6439    ) {
 6440        if let Some(state) = &mut self.inline_blame_popover {
 6441            state.hide_task.take();
 6442        } else {
 6443            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6444            let blame_entry = blame_entry.clone();
 6445            let show_task = cx.spawn(async move |editor, cx| {
 6446                cx.background_executor()
 6447                    .timer(std::time::Duration::from_millis(delay))
 6448                    .await;
 6449                editor
 6450                    .update(cx, |editor, cx| {
 6451                        editor.inline_blame_popover_show_task.take();
 6452                        let Some(blame) = editor.blame.as_ref() else {
 6453                            return;
 6454                        };
 6455                        let blame = blame.read(cx);
 6456                        let details = blame.details_for_entry(&blame_entry);
 6457                        let markdown = cx.new(|cx| {
 6458                            Markdown::new(
 6459                                details
 6460                                    .as_ref()
 6461                                    .map(|message| message.message.clone())
 6462                                    .unwrap_or_default(),
 6463                                None,
 6464                                None,
 6465                                cx,
 6466                            )
 6467                        });
 6468                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6469                            position,
 6470                            hide_task: None,
 6471                            popover_bounds: None,
 6472                            popover_state: InlineBlamePopoverState {
 6473                                scroll_handle: ScrollHandle::new(),
 6474                                commit_message: details,
 6475                                markdown,
 6476                            },
 6477                        });
 6478                        cx.notify();
 6479                    })
 6480                    .ok();
 6481            });
 6482            self.inline_blame_popover_show_task = Some(show_task);
 6483        }
 6484    }
 6485
 6486    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6487        self.inline_blame_popover_show_task.take();
 6488        if let Some(state) = &mut self.inline_blame_popover {
 6489            let hide_task = cx.spawn(async move |editor, cx| {
 6490                cx.background_executor()
 6491                    .timer(std::time::Duration::from_millis(100))
 6492                    .await;
 6493                editor
 6494                    .update(cx, |editor, cx| {
 6495                        editor.inline_blame_popover.take();
 6496                        cx.notify();
 6497                    })
 6498                    .ok();
 6499            });
 6500            state.hide_task = Some(hide_task);
 6501        }
 6502    }
 6503
 6504    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6505        if self.pending_rename.is_some() {
 6506            return None;
 6507        }
 6508
 6509        let provider = self.semantics_provider.clone()?;
 6510        let buffer = self.buffer.read(cx);
 6511        let newest_selection = self.selections.newest_anchor().clone();
 6512        let cursor_position = newest_selection.head();
 6513        let (cursor_buffer, cursor_buffer_position) =
 6514            buffer.text_anchor_for_position(cursor_position, cx)?;
 6515        let (tail_buffer, tail_buffer_position) =
 6516            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6517        if cursor_buffer != tail_buffer {
 6518            return None;
 6519        }
 6520
 6521        let snapshot = cursor_buffer.read(cx).snapshot();
 6522        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6523        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6524        if start_word_range != end_word_range {
 6525            self.document_highlights_task.take();
 6526            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6527            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6528            return None;
 6529        }
 6530
 6531        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6532        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6533            cx.background_executor()
 6534                .timer(Duration::from_millis(debounce))
 6535                .await;
 6536
 6537            let highlights = if let Some(highlights) = cx
 6538                .update(|cx| {
 6539                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6540                })
 6541                .ok()
 6542                .flatten()
 6543            {
 6544                highlights.await.log_err()
 6545            } else {
 6546                None
 6547            };
 6548
 6549            if let Some(highlights) = highlights {
 6550                this.update(cx, |this, cx| {
 6551                    if this.pending_rename.is_some() {
 6552                        return;
 6553                    }
 6554
 6555                    let buffer_id = cursor_position.buffer_id;
 6556                    let buffer = this.buffer.read(cx);
 6557                    if !buffer
 6558                        .text_anchor_for_position(cursor_position, cx)
 6559                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6560                    {
 6561                        return;
 6562                    }
 6563
 6564                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6565                    let mut write_ranges = Vec::new();
 6566                    let mut read_ranges = Vec::new();
 6567                    for highlight in highlights {
 6568                        for (excerpt_id, excerpt_range) in
 6569                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6570                        {
 6571                            let start = highlight
 6572                                .range
 6573                                .start
 6574                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6575                            let end = highlight
 6576                                .range
 6577                                .end
 6578                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6579                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6580                                continue;
 6581                            }
 6582
 6583                            let range = Anchor {
 6584                                buffer_id,
 6585                                excerpt_id,
 6586                                text_anchor: start,
 6587                                diff_base_anchor: None,
 6588                            }..Anchor {
 6589                                buffer_id,
 6590                                excerpt_id,
 6591                                text_anchor: end,
 6592                                diff_base_anchor: None,
 6593                            };
 6594                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6595                                write_ranges.push(range);
 6596                            } else {
 6597                                read_ranges.push(range);
 6598                            }
 6599                        }
 6600                    }
 6601
 6602                    this.highlight_background::<DocumentHighlightRead>(
 6603                        &read_ranges,
 6604                        |theme| theme.colors().editor_document_highlight_read_background,
 6605                        cx,
 6606                    );
 6607                    this.highlight_background::<DocumentHighlightWrite>(
 6608                        &write_ranges,
 6609                        |theme| theme.colors().editor_document_highlight_write_background,
 6610                        cx,
 6611                    );
 6612                    cx.notify();
 6613                })
 6614                .log_err();
 6615            }
 6616        }));
 6617        None
 6618    }
 6619
 6620    fn prepare_highlight_query_from_selection(
 6621        &mut self,
 6622        cx: &mut Context<Editor>,
 6623    ) -> Option<(String, Range<Anchor>)> {
 6624        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6625            return None;
 6626        }
 6627        if !EditorSettings::get_global(cx).selection_highlight {
 6628            return None;
 6629        }
 6630        if self.selections.count() != 1 || self.selections.line_mode {
 6631            return None;
 6632        }
 6633        let selection = self.selections.newest::<Point>(cx);
 6634        if selection.is_empty() || selection.start.row != selection.end.row {
 6635            return None;
 6636        }
 6637        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6638        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6639        let query = multi_buffer_snapshot
 6640            .text_for_range(selection_anchor_range.clone())
 6641            .collect::<String>();
 6642        if query.trim().is_empty() {
 6643            return None;
 6644        }
 6645        Some((query, selection_anchor_range))
 6646    }
 6647
 6648    fn update_selection_occurrence_highlights(
 6649        &mut self,
 6650        query_text: String,
 6651        query_range: Range<Anchor>,
 6652        multi_buffer_range_to_query: Range<Point>,
 6653        use_debounce: bool,
 6654        window: &mut Window,
 6655        cx: &mut Context<Editor>,
 6656    ) -> Task<()> {
 6657        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6658        cx.spawn_in(window, async move |editor, cx| {
 6659            if use_debounce {
 6660                cx.background_executor()
 6661                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6662                    .await;
 6663            }
 6664            let match_task = cx.background_spawn(async move {
 6665                let buffer_ranges = multi_buffer_snapshot
 6666                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6667                    .into_iter()
 6668                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6669                let mut match_ranges = Vec::new();
 6670                let Ok(regex) = project::search::SearchQuery::text(
 6671                    query_text.clone(),
 6672                    false,
 6673                    false,
 6674                    false,
 6675                    Default::default(),
 6676                    Default::default(),
 6677                    false,
 6678                    None,
 6679                ) else {
 6680                    return Vec::default();
 6681                };
 6682                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6683                    match_ranges.extend(
 6684                        regex
 6685                            .search(&buffer_snapshot, Some(search_range.clone()))
 6686                            .await
 6687                            .into_iter()
 6688                            .filter_map(|match_range| {
 6689                                let match_start = buffer_snapshot
 6690                                    .anchor_after(search_range.start + match_range.start);
 6691                                let match_end = buffer_snapshot
 6692                                    .anchor_before(search_range.start + match_range.end);
 6693                                let match_anchor_range = Anchor::range_in_buffer(
 6694                                    excerpt_id,
 6695                                    buffer_snapshot.remote_id(),
 6696                                    match_start..match_end,
 6697                                );
 6698                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6699                            }),
 6700                    );
 6701                }
 6702                match_ranges
 6703            });
 6704            let match_ranges = match_task.await;
 6705            editor
 6706                .update_in(cx, |editor, _, cx| {
 6707                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6708                    if !match_ranges.is_empty() {
 6709                        editor.highlight_background::<SelectedTextHighlight>(
 6710                            &match_ranges,
 6711                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6712                            cx,
 6713                        )
 6714                    }
 6715                })
 6716                .log_err();
 6717        })
 6718    }
 6719
 6720    fn refresh_selected_text_highlights(
 6721        &mut self,
 6722        on_buffer_edit: bool,
 6723        window: &mut Window,
 6724        cx: &mut Context<Editor>,
 6725    ) {
 6726        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6727        else {
 6728            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6729            self.quick_selection_highlight_task.take();
 6730            self.debounced_selection_highlight_task.take();
 6731            return;
 6732        };
 6733        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6734        if on_buffer_edit
 6735            || self
 6736                .quick_selection_highlight_task
 6737                .as_ref()
 6738                .map_or(true, |(prev_anchor_range, _)| {
 6739                    prev_anchor_range != &query_range
 6740                })
 6741        {
 6742            let multi_buffer_visible_start = self
 6743                .scroll_manager
 6744                .anchor()
 6745                .anchor
 6746                .to_point(&multi_buffer_snapshot);
 6747            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6748                multi_buffer_visible_start
 6749                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6750                Bias::Left,
 6751            );
 6752            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6753            self.quick_selection_highlight_task = Some((
 6754                query_range.clone(),
 6755                self.update_selection_occurrence_highlights(
 6756                    query_text.clone(),
 6757                    query_range.clone(),
 6758                    multi_buffer_visible_range,
 6759                    false,
 6760                    window,
 6761                    cx,
 6762                ),
 6763            ));
 6764        }
 6765        if on_buffer_edit
 6766            || self
 6767                .debounced_selection_highlight_task
 6768                .as_ref()
 6769                .map_or(true, |(prev_anchor_range, _)| {
 6770                    prev_anchor_range != &query_range
 6771                })
 6772        {
 6773            let multi_buffer_start = multi_buffer_snapshot
 6774                .anchor_before(0)
 6775                .to_point(&multi_buffer_snapshot);
 6776            let multi_buffer_end = multi_buffer_snapshot
 6777                .anchor_after(multi_buffer_snapshot.len())
 6778                .to_point(&multi_buffer_snapshot);
 6779            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6780            self.debounced_selection_highlight_task = Some((
 6781                query_range.clone(),
 6782                self.update_selection_occurrence_highlights(
 6783                    query_text,
 6784                    query_range,
 6785                    multi_buffer_full_range,
 6786                    true,
 6787                    window,
 6788                    cx,
 6789                ),
 6790            ));
 6791        }
 6792    }
 6793
 6794    pub fn refresh_inline_completion(
 6795        &mut self,
 6796        debounce: bool,
 6797        user_requested: bool,
 6798        window: &mut Window,
 6799        cx: &mut Context<Self>,
 6800    ) -> Option<()> {
 6801        let provider = self.edit_prediction_provider()?;
 6802        let cursor = self.selections.newest_anchor().head();
 6803        let (buffer, cursor_buffer_position) =
 6804            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6805
 6806        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6807            self.discard_inline_completion(false, cx);
 6808            return None;
 6809        }
 6810
 6811        if !user_requested
 6812            && (!self.should_show_edit_predictions()
 6813                || !self.is_focused(window)
 6814                || buffer.read(cx).is_empty())
 6815        {
 6816            self.discard_inline_completion(false, cx);
 6817            return None;
 6818        }
 6819
 6820        self.update_visible_inline_completion(window, cx);
 6821        provider.refresh(
 6822            self.project.clone(),
 6823            buffer,
 6824            cursor_buffer_position,
 6825            debounce,
 6826            cx,
 6827        );
 6828        Some(())
 6829    }
 6830
 6831    fn show_edit_predictions_in_menu(&self) -> bool {
 6832        match self.edit_prediction_settings {
 6833            EditPredictionSettings::Disabled => false,
 6834            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6835        }
 6836    }
 6837
 6838    pub fn edit_predictions_enabled(&self) -> bool {
 6839        match self.edit_prediction_settings {
 6840            EditPredictionSettings::Disabled => false,
 6841            EditPredictionSettings::Enabled { .. } => true,
 6842        }
 6843    }
 6844
 6845    fn edit_prediction_requires_modifier(&self) -> bool {
 6846        match self.edit_prediction_settings {
 6847            EditPredictionSettings::Disabled => false,
 6848            EditPredictionSettings::Enabled {
 6849                preview_requires_modifier,
 6850                ..
 6851            } => preview_requires_modifier,
 6852        }
 6853    }
 6854
 6855    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6856        if self.edit_prediction_provider.is_none() {
 6857            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6858        } else {
 6859            let selection = self.selections.newest_anchor();
 6860            let cursor = selection.head();
 6861
 6862            if let Some((buffer, cursor_buffer_position)) =
 6863                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6864            {
 6865                self.edit_prediction_settings =
 6866                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6867            }
 6868        }
 6869    }
 6870
 6871    fn edit_prediction_settings_at_position(
 6872        &self,
 6873        buffer: &Entity<Buffer>,
 6874        buffer_position: language::Anchor,
 6875        cx: &App,
 6876    ) -> EditPredictionSettings {
 6877        if !self.mode.is_full()
 6878            || !self.show_inline_completions_override.unwrap_or(true)
 6879            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6880        {
 6881            return EditPredictionSettings::Disabled;
 6882        }
 6883
 6884        let buffer = buffer.read(cx);
 6885
 6886        let file = buffer.file();
 6887
 6888        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6889            return EditPredictionSettings::Disabled;
 6890        };
 6891
 6892        let by_provider = matches!(
 6893            self.menu_inline_completions_policy,
 6894            MenuInlineCompletionsPolicy::ByProvider
 6895        );
 6896
 6897        let show_in_menu = by_provider
 6898            && self
 6899                .edit_prediction_provider
 6900                .as_ref()
 6901                .map_or(false, |provider| {
 6902                    provider.provider.show_completions_in_menu()
 6903                });
 6904
 6905        let preview_requires_modifier =
 6906            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6907
 6908        EditPredictionSettings::Enabled {
 6909            show_in_menu,
 6910            preview_requires_modifier,
 6911        }
 6912    }
 6913
 6914    fn should_show_edit_predictions(&self) -> bool {
 6915        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6916    }
 6917
 6918    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6919        matches!(
 6920            self.edit_prediction_preview,
 6921            EditPredictionPreview::Active { .. }
 6922        )
 6923    }
 6924
 6925    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6926        let cursor = self.selections.newest_anchor().head();
 6927        if let Some((buffer, cursor_position)) =
 6928            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6929        {
 6930            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6931        } else {
 6932            false
 6933        }
 6934    }
 6935
 6936    pub fn supports_minimap(&self, cx: &App) -> bool {
 6937        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6938    }
 6939
 6940    fn edit_predictions_enabled_in_buffer(
 6941        &self,
 6942        buffer: &Entity<Buffer>,
 6943        buffer_position: language::Anchor,
 6944        cx: &App,
 6945    ) -> bool {
 6946        maybe!({
 6947            if self.read_only(cx) {
 6948                return Some(false);
 6949            }
 6950            let provider = self.edit_prediction_provider()?;
 6951            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6952                return Some(false);
 6953            }
 6954            let buffer = buffer.read(cx);
 6955            let Some(file) = buffer.file() else {
 6956                return Some(true);
 6957            };
 6958            let settings = all_language_settings(Some(file), cx);
 6959            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6960        })
 6961        .unwrap_or(false)
 6962    }
 6963
 6964    fn cycle_inline_completion(
 6965        &mut self,
 6966        direction: Direction,
 6967        window: &mut Window,
 6968        cx: &mut Context<Self>,
 6969    ) -> Option<()> {
 6970        let provider = self.edit_prediction_provider()?;
 6971        let cursor = self.selections.newest_anchor().head();
 6972        let (buffer, cursor_buffer_position) =
 6973            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6974        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6975            return None;
 6976        }
 6977
 6978        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6979        self.update_visible_inline_completion(window, cx);
 6980
 6981        Some(())
 6982    }
 6983
 6984    pub fn show_inline_completion(
 6985        &mut self,
 6986        _: &ShowEditPrediction,
 6987        window: &mut Window,
 6988        cx: &mut Context<Self>,
 6989    ) {
 6990        if !self.has_active_inline_completion() {
 6991            self.refresh_inline_completion(false, true, window, cx);
 6992            return;
 6993        }
 6994
 6995        self.update_visible_inline_completion(window, cx);
 6996    }
 6997
 6998    pub fn display_cursor_names(
 6999        &mut self,
 7000        _: &DisplayCursorNames,
 7001        window: &mut Window,
 7002        cx: &mut Context<Self>,
 7003    ) {
 7004        self.show_cursor_names(window, cx);
 7005    }
 7006
 7007    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7008        self.show_cursor_names = true;
 7009        cx.notify();
 7010        cx.spawn_in(window, async move |this, cx| {
 7011            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7012            this.update(cx, |this, cx| {
 7013                this.show_cursor_names = false;
 7014                cx.notify()
 7015            })
 7016            .ok()
 7017        })
 7018        .detach();
 7019    }
 7020
 7021    pub fn next_edit_prediction(
 7022        &mut self,
 7023        _: &NextEditPrediction,
 7024        window: &mut Window,
 7025        cx: &mut Context<Self>,
 7026    ) {
 7027        if self.has_active_inline_completion() {
 7028            self.cycle_inline_completion(Direction::Next, window, cx);
 7029        } else {
 7030            let is_copilot_disabled = self
 7031                .refresh_inline_completion(false, true, window, cx)
 7032                .is_none();
 7033            if is_copilot_disabled {
 7034                cx.propagate();
 7035            }
 7036        }
 7037    }
 7038
 7039    pub fn previous_edit_prediction(
 7040        &mut self,
 7041        _: &PreviousEditPrediction,
 7042        window: &mut Window,
 7043        cx: &mut Context<Self>,
 7044    ) {
 7045        if self.has_active_inline_completion() {
 7046            self.cycle_inline_completion(Direction::Prev, window, cx);
 7047        } else {
 7048            let is_copilot_disabled = self
 7049                .refresh_inline_completion(false, true, window, cx)
 7050                .is_none();
 7051            if is_copilot_disabled {
 7052                cx.propagate();
 7053            }
 7054        }
 7055    }
 7056
 7057    pub fn accept_edit_prediction(
 7058        &mut self,
 7059        _: &AcceptEditPrediction,
 7060        window: &mut Window,
 7061        cx: &mut Context<Self>,
 7062    ) {
 7063        if self.show_edit_predictions_in_menu() {
 7064            self.hide_context_menu(window, cx);
 7065        }
 7066
 7067        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7068            return;
 7069        };
 7070
 7071        self.report_inline_completion_event(
 7072            active_inline_completion.completion_id.clone(),
 7073            true,
 7074            cx,
 7075        );
 7076
 7077        match &active_inline_completion.completion {
 7078            InlineCompletion::Move { target, .. } => {
 7079                let target = *target;
 7080
 7081                if let Some(position_map) = &self.last_position_map {
 7082                    if position_map
 7083                        .visible_row_range
 7084                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7085                        || !self.edit_prediction_requires_modifier()
 7086                    {
 7087                        self.unfold_ranges(&[target..target], true, false, cx);
 7088                        // Note that this is also done in vim's handler of the Tab action.
 7089                        self.change_selections(
 7090                            Some(Autoscroll::newest()),
 7091                            window,
 7092                            cx,
 7093                            |selections| {
 7094                                selections.select_anchor_ranges([target..target]);
 7095                            },
 7096                        );
 7097                        self.clear_row_highlights::<EditPredictionPreview>();
 7098
 7099                        self.edit_prediction_preview
 7100                            .set_previous_scroll_position(None);
 7101                    } else {
 7102                        self.edit_prediction_preview
 7103                            .set_previous_scroll_position(Some(
 7104                                position_map.snapshot.scroll_anchor,
 7105                            ));
 7106
 7107                        self.highlight_rows::<EditPredictionPreview>(
 7108                            target..target,
 7109                            cx.theme().colors().editor_highlighted_line_background,
 7110                            RowHighlightOptions {
 7111                                autoscroll: true,
 7112                                ..Default::default()
 7113                            },
 7114                            cx,
 7115                        );
 7116                        self.request_autoscroll(Autoscroll::fit(), cx);
 7117                    }
 7118                }
 7119            }
 7120            InlineCompletion::Edit { edits, .. } => {
 7121                if let Some(provider) = self.edit_prediction_provider() {
 7122                    provider.accept(cx);
 7123                }
 7124
 7125                // Store the transaction ID and selections before applying the edit
 7126                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7127
 7128                let snapshot = self.buffer.read(cx).snapshot(cx);
 7129                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7130
 7131                self.buffer.update(cx, |buffer, cx| {
 7132                    buffer.edit(edits.iter().cloned(), None, cx)
 7133                });
 7134
 7135                self.change_selections(None, window, cx, |s| {
 7136                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7137                });
 7138
 7139                let selections = self.selections.disjoint_anchors();
 7140                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7141                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7142                    if has_new_transaction {
 7143                        self.selection_history
 7144                            .insert_transaction(transaction_id_now, selections);
 7145                    }
 7146                }
 7147
 7148                self.update_visible_inline_completion(window, cx);
 7149                if self.active_inline_completion.is_none() {
 7150                    self.refresh_inline_completion(true, true, window, cx);
 7151                }
 7152
 7153                cx.notify();
 7154            }
 7155        }
 7156
 7157        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7158    }
 7159
 7160    pub fn accept_partial_inline_completion(
 7161        &mut self,
 7162        _: &AcceptPartialEditPrediction,
 7163        window: &mut Window,
 7164        cx: &mut Context<Self>,
 7165    ) {
 7166        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7167            return;
 7168        };
 7169        if self.selections.count() != 1 {
 7170            return;
 7171        }
 7172
 7173        self.report_inline_completion_event(
 7174            active_inline_completion.completion_id.clone(),
 7175            true,
 7176            cx,
 7177        );
 7178
 7179        match &active_inline_completion.completion {
 7180            InlineCompletion::Move { target, .. } => {
 7181                let target = *target;
 7182                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7183                    selections.select_anchor_ranges([target..target]);
 7184                });
 7185            }
 7186            InlineCompletion::Edit { edits, .. } => {
 7187                // Find an insertion that starts at the cursor position.
 7188                let snapshot = self.buffer.read(cx).snapshot(cx);
 7189                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7190                let insertion = edits.iter().find_map(|(range, text)| {
 7191                    let range = range.to_offset(&snapshot);
 7192                    if range.is_empty() && range.start == cursor_offset {
 7193                        Some(text)
 7194                    } else {
 7195                        None
 7196                    }
 7197                });
 7198
 7199                if let Some(text) = insertion {
 7200                    let mut partial_completion = text
 7201                        .chars()
 7202                        .by_ref()
 7203                        .take_while(|c| c.is_alphabetic())
 7204                        .collect::<String>();
 7205                    if partial_completion.is_empty() {
 7206                        partial_completion = text
 7207                            .chars()
 7208                            .by_ref()
 7209                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7210                            .collect::<String>();
 7211                    }
 7212
 7213                    cx.emit(EditorEvent::InputHandled {
 7214                        utf16_range_to_replace: None,
 7215                        text: partial_completion.clone().into(),
 7216                    });
 7217
 7218                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7219
 7220                    self.refresh_inline_completion(true, true, window, cx);
 7221                    cx.notify();
 7222                } else {
 7223                    self.accept_edit_prediction(&Default::default(), window, cx);
 7224                }
 7225            }
 7226        }
 7227    }
 7228
 7229    fn discard_inline_completion(
 7230        &mut self,
 7231        should_report_inline_completion_event: bool,
 7232        cx: &mut Context<Self>,
 7233    ) -> bool {
 7234        if should_report_inline_completion_event {
 7235            let completion_id = self
 7236                .active_inline_completion
 7237                .as_ref()
 7238                .and_then(|active_completion| active_completion.completion_id.clone());
 7239
 7240            self.report_inline_completion_event(completion_id, false, cx);
 7241        }
 7242
 7243        if let Some(provider) = self.edit_prediction_provider() {
 7244            provider.discard(cx);
 7245        }
 7246
 7247        self.take_active_inline_completion(cx)
 7248    }
 7249
 7250    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7251        let Some(provider) = self.edit_prediction_provider() else {
 7252            return;
 7253        };
 7254
 7255        let Some((_, buffer, _)) = self
 7256            .buffer
 7257            .read(cx)
 7258            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7259        else {
 7260            return;
 7261        };
 7262
 7263        let extension = buffer
 7264            .read(cx)
 7265            .file()
 7266            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7267
 7268        let event_type = match accepted {
 7269            true => "Edit Prediction Accepted",
 7270            false => "Edit Prediction Discarded",
 7271        };
 7272        telemetry::event!(
 7273            event_type,
 7274            provider = provider.name(),
 7275            prediction_id = id,
 7276            suggestion_accepted = accepted,
 7277            file_extension = extension,
 7278        );
 7279    }
 7280
 7281    pub fn has_active_inline_completion(&self) -> bool {
 7282        self.active_inline_completion.is_some()
 7283    }
 7284
 7285    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7286        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7287            return false;
 7288        };
 7289
 7290        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7291        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7292        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7293        true
 7294    }
 7295
 7296    /// Returns true when we're displaying the edit prediction popover below the cursor
 7297    /// like we are not previewing and the LSP autocomplete menu is visible
 7298    /// or we are in `when_holding_modifier` mode.
 7299    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7300        if self.edit_prediction_preview_is_active()
 7301            || !self.show_edit_predictions_in_menu()
 7302            || !self.edit_predictions_enabled()
 7303        {
 7304            return false;
 7305        }
 7306
 7307        if self.has_visible_completions_menu() {
 7308            return true;
 7309        }
 7310
 7311        has_completion && self.edit_prediction_requires_modifier()
 7312    }
 7313
 7314    fn handle_modifiers_changed(
 7315        &mut self,
 7316        modifiers: Modifiers,
 7317        position_map: &PositionMap,
 7318        window: &mut Window,
 7319        cx: &mut Context<Self>,
 7320    ) {
 7321        if self.show_edit_predictions_in_menu() {
 7322            self.update_edit_prediction_preview(&modifiers, window, cx);
 7323        }
 7324
 7325        self.update_selection_mode(&modifiers, position_map, window, cx);
 7326
 7327        let mouse_position = window.mouse_position();
 7328        if !position_map.text_hitbox.is_hovered(window) {
 7329            return;
 7330        }
 7331
 7332        self.update_hovered_link(
 7333            position_map.point_for_position(mouse_position),
 7334            &position_map.snapshot,
 7335            modifiers,
 7336            window,
 7337            cx,
 7338        )
 7339    }
 7340
 7341    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7342        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7343        if invert {
 7344            match multi_cursor_setting {
 7345                MultiCursorModifier::Alt => modifiers.alt,
 7346                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7347            }
 7348        } else {
 7349            match multi_cursor_setting {
 7350                MultiCursorModifier::Alt => modifiers.secondary(),
 7351                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7352            }
 7353        }
 7354    }
 7355
 7356    fn columnar_selection_mode(
 7357        modifiers: &Modifiers,
 7358        cx: &mut Context<Self>,
 7359    ) -> Option<ColumnarMode> {
 7360        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7361            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7362                Some(ColumnarMode::FromMouse)
 7363            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7364                Some(ColumnarMode::FromSelection)
 7365            } else {
 7366                None
 7367            }
 7368        } else {
 7369            None
 7370        }
 7371    }
 7372
 7373    fn update_selection_mode(
 7374        &mut self,
 7375        modifiers: &Modifiers,
 7376        position_map: &PositionMap,
 7377        window: &mut Window,
 7378        cx: &mut Context<Self>,
 7379    ) {
 7380        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7381            return;
 7382        };
 7383        if self.selections.pending.is_none() {
 7384            return;
 7385        }
 7386
 7387        let mouse_position = window.mouse_position();
 7388        let point_for_position = position_map.point_for_position(mouse_position);
 7389        let position = point_for_position.previous_valid;
 7390
 7391        self.select(
 7392            SelectPhase::BeginColumnar {
 7393                position,
 7394                reset: false,
 7395                mode,
 7396                goal_column: point_for_position.exact_unclipped.column(),
 7397            },
 7398            window,
 7399            cx,
 7400        );
 7401    }
 7402
 7403    fn update_edit_prediction_preview(
 7404        &mut self,
 7405        modifiers: &Modifiers,
 7406        window: &mut Window,
 7407        cx: &mut Context<Self>,
 7408    ) {
 7409        let mut modifiers_held = false;
 7410        if let Some(accept_keystroke) = self
 7411            .accept_edit_prediction_keybind(false, window, cx)
 7412            .keystroke()
 7413        {
 7414            modifiers_held = modifiers_held
 7415                || (&accept_keystroke.modifiers == modifiers
 7416                    && accept_keystroke.modifiers.modified());
 7417        };
 7418        if let Some(accept_partial_keystroke) = self
 7419            .accept_edit_prediction_keybind(true, window, cx)
 7420            .keystroke()
 7421        {
 7422            modifiers_held = modifiers_held
 7423                || (&accept_partial_keystroke.modifiers == modifiers
 7424                    && accept_partial_keystroke.modifiers.modified());
 7425        }
 7426
 7427        if modifiers_held {
 7428            if matches!(
 7429                self.edit_prediction_preview,
 7430                EditPredictionPreview::Inactive { .. }
 7431            ) {
 7432                self.edit_prediction_preview = EditPredictionPreview::Active {
 7433                    previous_scroll_position: None,
 7434                    since: Instant::now(),
 7435                };
 7436
 7437                self.update_visible_inline_completion(window, cx);
 7438                cx.notify();
 7439            }
 7440        } else if let EditPredictionPreview::Active {
 7441            previous_scroll_position,
 7442            since,
 7443        } = self.edit_prediction_preview
 7444        {
 7445            if let (Some(previous_scroll_position), Some(position_map)) =
 7446                (previous_scroll_position, self.last_position_map.as_ref())
 7447            {
 7448                self.set_scroll_position(
 7449                    previous_scroll_position
 7450                        .scroll_position(&position_map.snapshot.display_snapshot),
 7451                    window,
 7452                    cx,
 7453                );
 7454            }
 7455
 7456            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7457                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7458            };
 7459            self.clear_row_highlights::<EditPredictionPreview>();
 7460            self.update_visible_inline_completion(window, cx);
 7461            cx.notify();
 7462        }
 7463    }
 7464
 7465    fn update_visible_inline_completion(
 7466        &mut self,
 7467        _window: &mut Window,
 7468        cx: &mut Context<Self>,
 7469    ) -> Option<()> {
 7470        let selection = self.selections.newest_anchor();
 7471        let cursor = selection.head();
 7472        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7473        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7474        let excerpt_id = cursor.excerpt_id;
 7475
 7476        let show_in_menu = self.show_edit_predictions_in_menu();
 7477        let completions_menu_has_precedence = !show_in_menu
 7478            && (self.context_menu.borrow().is_some()
 7479                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7480
 7481        if completions_menu_has_precedence
 7482            || !offset_selection.is_empty()
 7483            || self
 7484                .active_inline_completion
 7485                .as_ref()
 7486                .map_or(false, |completion| {
 7487                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7488                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7489                    !invalidation_range.contains(&offset_selection.head())
 7490                })
 7491        {
 7492            self.discard_inline_completion(false, cx);
 7493            return None;
 7494        }
 7495
 7496        self.take_active_inline_completion(cx);
 7497        let Some(provider) = self.edit_prediction_provider() else {
 7498            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7499            return None;
 7500        };
 7501
 7502        let (buffer, cursor_buffer_position) =
 7503            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7504
 7505        self.edit_prediction_settings =
 7506            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7507
 7508        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7509
 7510        if self.edit_prediction_indent_conflict {
 7511            let cursor_point = cursor.to_point(&multibuffer);
 7512
 7513            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7514
 7515            if let Some((_, indent)) = indents.iter().next() {
 7516                if indent.len == cursor_point.column {
 7517                    self.edit_prediction_indent_conflict = false;
 7518                }
 7519            }
 7520        }
 7521
 7522        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7523        let edits = inline_completion
 7524            .edits
 7525            .into_iter()
 7526            .flat_map(|(range, new_text)| {
 7527                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7528                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7529                Some((start..end, new_text))
 7530            })
 7531            .collect::<Vec<_>>();
 7532        if edits.is_empty() {
 7533            return None;
 7534        }
 7535
 7536        let first_edit_start = edits.first().unwrap().0.start;
 7537        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7538        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7539
 7540        let last_edit_end = edits.last().unwrap().0.end;
 7541        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7542        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7543
 7544        let cursor_row = cursor.to_point(&multibuffer).row;
 7545
 7546        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7547
 7548        let mut inlay_ids = Vec::new();
 7549        let invalidation_row_range;
 7550        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7551            Some(cursor_row..edit_end_row)
 7552        } else if cursor_row > edit_end_row {
 7553            Some(edit_start_row..cursor_row)
 7554        } else {
 7555            None
 7556        };
 7557        let is_move =
 7558            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7559        let completion = if is_move {
 7560            invalidation_row_range =
 7561                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7562            let target = first_edit_start;
 7563            InlineCompletion::Move { target, snapshot }
 7564        } else {
 7565            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7566                && !self.inline_completions_hidden_for_vim_mode;
 7567
 7568            if show_completions_in_buffer {
 7569                if edits
 7570                    .iter()
 7571                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7572                {
 7573                    let mut inlays = Vec::new();
 7574                    for (range, new_text) in &edits {
 7575                        let inlay = Inlay::inline_completion(
 7576                            post_inc(&mut self.next_inlay_id),
 7577                            range.start,
 7578                            new_text.as_str(),
 7579                        );
 7580                        inlay_ids.push(inlay.id);
 7581                        inlays.push(inlay);
 7582                    }
 7583
 7584                    self.splice_inlays(&[], inlays, cx);
 7585                } else {
 7586                    let background_color = cx.theme().status().deleted_background;
 7587                    self.highlight_text::<InlineCompletionHighlight>(
 7588                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7589                        HighlightStyle {
 7590                            background_color: Some(background_color),
 7591                            ..Default::default()
 7592                        },
 7593                        cx,
 7594                    );
 7595                }
 7596            }
 7597
 7598            invalidation_row_range = edit_start_row..edit_end_row;
 7599
 7600            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7601                if provider.show_tab_accept_marker() {
 7602                    EditDisplayMode::TabAccept
 7603                } else {
 7604                    EditDisplayMode::Inline
 7605                }
 7606            } else {
 7607                EditDisplayMode::DiffPopover
 7608            };
 7609
 7610            InlineCompletion::Edit {
 7611                edits,
 7612                edit_preview: inline_completion.edit_preview,
 7613                display_mode,
 7614                snapshot,
 7615            }
 7616        };
 7617
 7618        let invalidation_range = multibuffer
 7619            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7620            ..multibuffer.anchor_after(Point::new(
 7621                invalidation_row_range.end,
 7622                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7623            ));
 7624
 7625        self.stale_inline_completion_in_menu = None;
 7626        self.active_inline_completion = Some(InlineCompletionState {
 7627            inlay_ids,
 7628            completion,
 7629            completion_id: inline_completion.id,
 7630            invalidation_range,
 7631        });
 7632
 7633        cx.notify();
 7634
 7635        Some(())
 7636    }
 7637
 7638    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7639        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7640    }
 7641
 7642    fn clear_tasks(&mut self) {
 7643        self.tasks.clear()
 7644    }
 7645
 7646    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7647        if self.tasks.insert(key, value).is_some() {
 7648            // This case should hopefully be rare, but just in case...
 7649            log::error!(
 7650                "multiple different run targets found on a single line, only the last target will be rendered"
 7651            )
 7652        }
 7653    }
 7654
 7655    /// Get all display points of breakpoints that will be rendered within editor
 7656    ///
 7657    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7658    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7659    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7660    fn active_breakpoints(
 7661        &self,
 7662        range: Range<DisplayRow>,
 7663        window: &mut Window,
 7664        cx: &mut Context<Self>,
 7665    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7666        let mut breakpoint_display_points = HashMap::default();
 7667
 7668        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7669            return breakpoint_display_points;
 7670        };
 7671
 7672        let snapshot = self.snapshot(window, cx);
 7673
 7674        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7675        let Some(project) = self.project.as_ref() else {
 7676            return breakpoint_display_points;
 7677        };
 7678
 7679        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7680            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7681
 7682        for (buffer_snapshot, range, excerpt_id) in
 7683            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7684        {
 7685            let Some(buffer) = project
 7686                .read(cx)
 7687                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7688            else {
 7689                continue;
 7690            };
 7691            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7692                &buffer,
 7693                Some(
 7694                    buffer_snapshot.anchor_before(range.start)
 7695                        ..buffer_snapshot.anchor_after(range.end),
 7696                ),
 7697                buffer_snapshot,
 7698                cx,
 7699            );
 7700            for (breakpoint, state) in breakpoints {
 7701                let multi_buffer_anchor =
 7702                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7703                let position = multi_buffer_anchor
 7704                    .to_point(&multi_buffer_snapshot)
 7705                    .to_display_point(&snapshot);
 7706
 7707                breakpoint_display_points.insert(
 7708                    position.row(),
 7709                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7710                );
 7711            }
 7712        }
 7713
 7714        breakpoint_display_points
 7715    }
 7716
 7717    fn breakpoint_context_menu(
 7718        &self,
 7719        anchor: Anchor,
 7720        window: &mut Window,
 7721        cx: &mut Context<Self>,
 7722    ) -> Entity<ui::ContextMenu> {
 7723        let weak_editor = cx.weak_entity();
 7724        let focus_handle = self.focus_handle(cx);
 7725
 7726        let row = self
 7727            .buffer
 7728            .read(cx)
 7729            .snapshot(cx)
 7730            .summary_for_anchor::<Point>(&anchor)
 7731            .row;
 7732
 7733        let breakpoint = self
 7734            .breakpoint_at_row(row, window, cx)
 7735            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7736
 7737        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7738            "Edit Log Breakpoint"
 7739        } else {
 7740            "Set Log Breakpoint"
 7741        };
 7742
 7743        let condition_breakpoint_msg = if breakpoint
 7744            .as_ref()
 7745            .is_some_and(|bp| bp.1.condition.is_some())
 7746        {
 7747            "Edit Condition Breakpoint"
 7748        } else {
 7749            "Set Condition Breakpoint"
 7750        };
 7751
 7752        let hit_condition_breakpoint_msg = if breakpoint
 7753            .as_ref()
 7754            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7755        {
 7756            "Edit Hit Condition Breakpoint"
 7757        } else {
 7758            "Set Hit Condition Breakpoint"
 7759        };
 7760
 7761        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7762            "Unset Breakpoint"
 7763        } else {
 7764            "Set Breakpoint"
 7765        };
 7766
 7767        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7768
 7769        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7770            BreakpointState::Enabled => Some("Disable"),
 7771            BreakpointState::Disabled => Some("Enable"),
 7772        });
 7773
 7774        let (anchor, breakpoint) =
 7775            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7776
 7777        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7778            menu.on_blur_subscription(Subscription::new(|| {}))
 7779                .context(focus_handle)
 7780                .when(run_to_cursor, |this| {
 7781                    let weak_editor = weak_editor.clone();
 7782                    this.entry("Run to cursor", None, move |window, cx| {
 7783                        weak_editor
 7784                            .update(cx, |editor, cx| {
 7785                                editor.change_selections(None, window, cx, |s| {
 7786                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7787                                });
 7788                            })
 7789                            .ok();
 7790
 7791                        window.dispatch_action(Box::new(RunToCursor), cx);
 7792                    })
 7793                    .separator()
 7794                })
 7795                .when_some(toggle_state_msg, |this, msg| {
 7796                    this.entry(msg, None, {
 7797                        let weak_editor = weak_editor.clone();
 7798                        let breakpoint = breakpoint.clone();
 7799                        move |_window, cx| {
 7800                            weak_editor
 7801                                .update(cx, |this, cx| {
 7802                                    this.edit_breakpoint_at_anchor(
 7803                                        anchor,
 7804                                        breakpoint.as_ref().clone(),
 7805                                        BreakpointEditAction::InvertState,
 7806                                        cx,
 7807                                    );
 7808                                })
 7809                                .log_err();
 7810                        }
 7811                    })
 7812                })
 7813                .entry(set_breakpoint_msg, None, {
 7814                    let weak_editor = weak_editor.clone();
 7815                    let breakpoint = breakpoint.clone();
 7816                    move |_window, cx| {
 7817                        weak_editor
 7818                            .update(cx, |this, cx| {
 7819                                this.edit_breakpoint_at_anchor(
 7820                                    anchor,
 7821                                    breakpoint.as_ref().clone(),
 7822                                    BreakpointEditAction::Toggle,
 7823                                    cx,
 7824                                );
 7825                            })
 7826                            .log_err();
 7827                    }
 7828                })
 7829                .entry(log_breakpoint_msg, None, {
 7830                    let breakpoint = breakpoint.clone();
 7831                    let weak_editor = weak_editor.clone();
 7832                    move |window, cx| {
 7833                        weak_editor
 7834                            .update(cx, |this, cx| {
 7835                                this.add_edit_breakpoint_block(
 7836                                    anchor,
 7837                                    breakpoint.as_ref(),
 7838                                    BreakpointPromptEditAction::Log,
 7839                                    window,
 7840                                    cx,
 7841                                );
 7842                            })
 7843                            .log_err();
 7844                    }
 7845                })
 7846                .entry(condition_breakpoint_msg, None, {
 7847                    let breakpoint = breakpoint.clone();
 7848                    let weak_editor = weak_editor.clone();
 7849                    move |window, cx| {
 7850                        weak_editor
 7851                            .update(cx, |this, cx| {
 7852                                this.add_edit_breakpoint_block(
 7853                                    anchor,
 7854                                    breakpoint.as_ref(),
 7855                                    BreakpointPromptEditAction::Condition,
 7856                                    window,
 7857                                    cx,
 7858                                );
 7859                            })
 7860                            .log_err();
 7861                    }
 7862                })
 7863                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7864                    weak_editor
 7865                        .update(cx, |this, cx| {
 7866                            this.add_edit_breakpoint_block(
 7867                                anchor,
 7868                                breakpoint.as_ref(),
 7869                                BreakpointPromptEditAction::HitCondition,
 7870                                window,
 7871                                cx,
 7872                            );
 7873                        })
 7874                        .log_err();
 7875                })
 7876        })
 7877    }
 7878
 7879    fn render_breakpoint(
 7880        &self,
 7881        position: Anchor,
 7882        row: DisplayRow,
 7883        breakpoint: &Breakpoint,
 7884        state: Option<BreakpointSessionState>,
 7885        cx: &mut Context<Self>,
 7886    ) -> IconButton {
 7887        let is_rejected = state.is_some_and(|s| !s.verified);
 7888        // Is it a breakpoint that shows up when hovering over gutter?
 7889        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7890            (false, false),
 7891            |PhantomBreakpointIndicator {
 7892                 is_active,
 7893                 display_row,
 7894                 collides_with_existing_breakpoint,
 7895             }| {
 7896                (
 7897                    is_active && display_row == row,
 7898                    collides_with_existing_breakpoint,
 7899                )
 7900            },
 7901        );
 7902
 7903        let (color, icon) = {
 7904            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7905                (false, false) => ui::IconName::DebugBreakpoint,
 7906                (true, false) => ui::IconName::DebugLogBreakpoint,
 7907                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7908                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7909            };
 7910
 7911            let color = if is_phantom {
 7912                Color::Hint
 7913            } else if is_rejected {
 7914                Color::Disabled
 7915            } else {
 7916                Color::Debugger
 7917            };
 7918
 7919            (color, icon)
 7920        };
 7921
 7922        let breakpoint = Arc::from(breakpoint.clone());
 7923
 7924        let alt_as_text = gpui::Keystroke {
 7925            modifiers: Modifiers::secondary_key(),
 7926            ..Default::default()
 7927        };
 7928        let primary_action_text = if breakpoint.is_disabled() {
 7929            "Enable breakpoint"
 7930        } else if is_phantom && !collides_with_existing {
 7931            "Set breakpoint"
 7932        } else {
 7933            "Unset breakpoint"
 7934        };
 7935        let focus_handle = self.focus_handle.clone();
 7936
 7937        let meta = if is_rejected {
 7938            SharedString::from("No executable code is associated with this line.")
 7939        } else if collides_with_existing && !breakpoint.is_disabled() {
 7940            SharedString::from(format!(
 7941                "{alt_as_text}-click to disable,\nright-click for more options."
 7942            ))
 7943        } else {
 7944            SharedString::from("Right-click for more options.")
 7945        };
 7946        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7947            .icon_size(IconSize::XSmall)
 7948            .size(ui::ButtonSize::None)
 7949            .when(is_rejected, |this| {
 7950                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7951            })
 7952            .icon_color(color)
 7953            .style(ButtonStyle::Transparent)
 7954            .on_click(cx.listener({
 7955                let breakpoint = breakpoint.clone();
 7956
 7957                move |editor, event: &ClickEvent, window, cx| {
 7958                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7959                        BreakpointEditAction::InvertState
 7960                    } else {
 7961                        BreakpointEditAction::Toggle
 7962                    };
 7963
 7964                    window.focus(&editor.focus_handle(cx));
 7965                    editor.edit_breakpoint_at_anchor(
 7966                        position,
 7967                        breakpoint.as_ref().clone(),
 7968                        edit_action,
 7969                        cx,
 7970                    );
 7971                }
 7972            }))
 7973            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7974                editor.set_breakpoint_context_menu(
 7975                    row,
 7976                    Some(position),
 7977                    event.down.position,
 7978                    window,
 7979                    cx,
 7980                );
 7981            }))
 7982            .tooltip(move |window, cx| {
 7983                Tooltip::with_meta_in(
 7984                    primary_action_text,
 7985                    Some(&ToggleBreakpoint),
 7986                    meta.clone(),
 7987                    &focus_handle,
 7988                    window,
 7989                    cx,
 7990                )
 7991            })
 7992    }
 7993
 7994    fn build_tasks_context(
 7995        project: &Entity<Project>,
 7996        buffer: &Entity<Buffer>,
 7997        buffer_row: u32,
 7998        tasks: &Arc<RunnableTasks>,
 7999        cx: &mut Context<Self>,
 8000    ) -> Task<Option<task::TaskContext>> {
 8001        let position = Point::new(buffer_row, tasks.column);
 8002        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8003        let location = Location {
 8004            buffer: buffer.clone(),
 8005            range: range_start..range_start,
 8006        };
 8007        // Fill in the environmental variables from the tree-sitter captures
 8008        let mut captured_task_variables = TaskVariables::default();
 8009        for (capture_name, value) in tasks.extra_variables.clone() {
 8010            captured_task_variables.insert(
 8011                task::VariableName::Custom(capture_name.into()),
 8012                value.clone(),
 8013            );
 8014        }
 8015        project.update(cx, |project, cx| {
 8016            project.task_store().update(cx, |task_store, cx| {
 8017                task_store.task_context_for_location(captured_task_variables, location, cx)
 8018            })
 8019        })
 8020    }
 8021
 8022    pub fn spawn_nearest_task(
 8023        &mut self,
 8024        action: &SpawnNearestTask,
 8025        window: &mut Window,
 8026        cx: &mut Context<Self>,
 8027    ) {
 8028        let Some((workspace, _)) = self.workspace.clone() else {
 8029            return;
 8030        };
 8031        let Some(project) = self.project.clone() else {
 8032            return;
 8033        };
 8034
 8035        // Try to find a closest, enclosing node using tree-sitter that has a
 8036        // task
 8037        let Some((buffer, buffer_row, tasks)) = self
 8038            .find_enclosing_node_task(cx)
 8039            // Or find the task that's closest in row-distance.
 8040            .or_else(|| self.find_closest_task(cx))
 8041        else {
 8042            return;
 8043        };
 8044
 8045        let reveal_strategy = action.reveal;
 8046        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8047        cx.spawn_in(window, async move |_, cx| {
 8048            let context = task_context.await?;
 8049            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8050
 8051            let resolved = &mut resolved_task.resolved;
 8052            resolved.reveal = reveal_strategy;
 8053
 8054            workspace
 8055                .update_in(cx, |workspace, window, cx| {
 8056                    workspace.schedule_resolved_task(
 8057                        task_source_kind,
 8058                        resolved_task,
 8059                        false,
 8060                        window,
 8061                        cx,
 8062                    );
 8063                })
 8064                .ok()
 8065        })
 8066        .detach();
 8067    }
 8068
 8069    fn find_closest_task(
 8070        &mut self,
 8071        cx: &mut Context<Self>,
 8072    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8073        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8074
 8075        let ((buffer_id, row), tasks) = self
 8076            .tasks
 8077            .iter()
 8078            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8079
 8080        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8081        let tasks = Arc::new(tasks.to_owned());
 8082        Some((buffer, *row, tasks))
 8083    }
 8084
 8085    fn find_enclosing_node_task(
 8086        &mut self,
 8087        cx: &mut Context<Self>,
 8088    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8089        let snapshot = self.buffer.read(cx).snapshot(cx);
 8090        let offset = self.selections.newest::<usize>(cx).head();
 8091        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8092        let buffer_id = excerpt.buffer().remote_id();
 8093
 8094        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8095        let mut cursor = layer.node().walk();
 8096
 8097        while cursor.goto_first_child_for_byte(offset).is_some() {
 8098            if cursor.node().end_byte() == offset {
 8099                cursor.goto_next_sibling();
 8100            }
 8101        }
 8102
 8103        // Ascend to the smallest ancestor that contains the range and has a task.
 8104        loop {
 8105            let node = cursor.node();
 8106            let node_range = node.byte_range();
 8107            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8108
 8109            // Check if this node contains our offset
 8110            if node_range.start <= offset && node_range.end >= offset {
 8111                // If it contains offset, check for task
 8112                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8113                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8114                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8115                }
 8116            }
 8117
 8118            if !cursor.goto_parent() {
 8119                break;
 8120            }
 8121        }
 8122        None
 8123    }
 8124
 8125    fn render_run_indicator(
 8126        &self,
 8127        _style: &EditorStyle,
 8128        is_active: bool,
 8129        row: DisplayRow,
 8130        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8131        cx: &mut Context<Self>,
 8132    ) -> IconButton {
 8133        let color = Color::Muted;
 8134        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8135
 8136        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8137            .shape(ui::IconButtonShape::Square)
 8138            .icon_size(IconSize::XSmall)
 8139            .icon_color(color)
 8140            .toggle_state(is_active)
 8141            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8142                let quick_launch = e.down.button == MouseButton::Left;
 8143                window.focus(&editor.focus_handle(cx));
 8144                editor.toggle_code_actions(
 8145                    &ToggleCodeActions {
 8146                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8147                        quick_launch,
 8148                    },
 8149                    window,
 8150                    cx,
 8151                );
 8152            }))
 8153            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8154                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8155            }))
 8156    }
 8157
 8158    pub fn context_menu_visible(&self) -> bool {
 8159        !self.edit_prediction_preview_is_active()
 8160            && self
 8161                .context_menu
 8162                .borrow()
 8163                .as_ref()
 8164                .map_or(false, |menu| menu.visible())
 8165    }
 8166
 8167    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8168        self.context_menu
 8169            .borrow()
 8170            .as_ref()
 8171            .map(|menu| menu.origin())
 8172    }
 8173
 8174    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8175        self.context_menu_options = Some(options);
 8176    }
 8177
 8178    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8179    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8180
 8181    fn render_edit_prediction_popover(
 8182        &mut self,
 8183        text_bounds: &Bounds<Pixels>,
 8184        content_origin: gpui::Point<Pixels>,
 8185        right_margin: Pixels,
 8186        editor_snapshot: &EditorSnapshot,
 8187        visible_row_range: Range<DisplayRow>,
 8188        scroll_top: f32,
 8189        scroll_bottom: f32,
 8190        line_layouts: &[LineWithInvisibles],
 8191        line_height: Pixels,
 8192        scroll_pixel_position: gpui::Point<Pixels>,
 8193        newest_selection_head: Option<DisplayPoint>,
 8194        editor_width: Pixels,
 8195        style: &EditorStyle,
 8196        window: &mut Window,
 8197        cx: &mut App,
 8198    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8199        if self.mode().is_minimap() {
 8200            return None;
 8201        }
 8202        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8203
 8204        if self.edit_prediction_visible_in_cursor_popover(true) {
 8205            return None;
 8206        }
 8207
 8208        match &active_inline_completion.completion {
 8209            InlineCompletion::Move { target, .. } => {
 8210                let target_display_point = target.to_display_point(editor_snapshot);
 8211
 8212                if self.edit_prediction_requires_modifier() {
 8213                    if !self.edit_prediction_preview_is_active() {
 8214                        return None;
 8215                    }
 8216
 8217                    self.render_edit_prediction_modifier_jump_popover(
 8218                        text_bounds,
 8219                        content_origin,
 8220                        visible_row_range,
 8221                        line_layouts,
 8222                        line_height,
 8223                        scroll_pixel_position,
 8224                        newest_selection_head,
 8225                        target_display_point,
 8226                        window,
 8227                        cx,
 8228                    )
 8229                } else {
 8230                    self.render_edit_prediction_eager_jump_popover(
 8231                        text_bounds,
 8232                        content_origin,
 8233                        editor_snapshot,
 8234                        visible_row_range,
 8235                        scroll_top,
 8236                        scroll_bottom,
 8237                        line_height,
 8238                        scroll_pixel_position,
 8239                        target_display_point,
 8240                        editor_width,
 8241                        window,
 8242                        cx,
 8243                    )
 8244                }
 8245            }
 8246            InlineCompletion::Edit {
 8247                display_mode: EditDisplayMode::Inline,
 8248                ..
 8249            } => None,
 8250            InlineCompletion::Edit {
 8251                display_mode: EditDisplayMode::TabAccept,
 8252                edits,
 8253                ..
 8254            } => {
 8255                let range = &edits.first()?.0;
 8256                let target_display_point = range.end.to_display_point(editor_snapshot);
 8257
 8258                self.render_edit_prediction_end_of_line_popover(
 8259                    "Accept",
 8260                    editor_snapshot,
 8261                    visible_row_range,
 8262                    target_display_point,
 8263                    line_height,
 8264                    scroll_pixel_position,
 8265                    content_origin,
 8266                    editor_width,
 8267                    window,
 8268                    cx,
 8269                )
 8270            }
 8271            InlineCompletion::Edit {
 8272                edits,
 8273                edit_preview,
 8274                display_mode: EditDisplayMode::DiffPopover,
 8275                snapshot,
 8276            } => self.render_edit_prediction_diff_popover(
 8277                text_bounds,
 8278                content_origin,
 8279                right_margin,
 8280                editor_snapshot,
 8281                visible_row_range,
 8282                line_layouts,
 8283                line_height,
 8284                scroll_pixel_position,
 8285                newest_selection_head,
 8286                editor_width,
 8287                style,
 8288                edits,
 8289                edit_preview,
 8290                snapshot,
 8291                window,
 8292                cx,
 8293            ),
 8294        }
 8295    }
 8296
 8297    fn render_edit_prediction_modifier_jump_popover(
 8298        &mut self,
 8299        text_bounds: &Bounds<Pixels>,
 8300        content_origin: gpui::Point<Pixels>,
 8301        visible_row_range: Range<DisplayRow>,
 8302        line_layouts: &[LineWithInvisibles],
 8303        line_height: Pixels,
 8304        scroll_pixel_position: gpui::Point<Pixels>,
 8305        newest_selection_head: Option<DisplayPoint>,
 8306        target_display_point: DisplayPoint,
 8307        window: &mut Window,
 8308        cx: &mut App,
 8309    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8310        let scrolled_content_origin =
 8311            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8312
 8313        const SCROLL_PADDING_Y: Pixels = px(12.);
 8314
 8315        if target_display_point.row() < visible_row_range.start {
 8316            return self.render_edit_prediction_scroll_popover(
 8317                |_| SCROLL_PADDING_Y,
 8318                IconName::ArrowUp,
 8319                visible_row_range,
 8320                line_layouts,
 8321                newest_selection_head,
 8322                scrolled_content_origin,
 8323                window,
 8324                cx,
 8325            );
 8326        } else if target_display_point.row() >= visible_row_range.end {
 8327            return self.render_edit_prediction_scroll_popover(
 8328                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8329                IconName::ArrowDown,
 8330                visible_row_range,
 8331                line_layouts,
 8332                newest_selection_head,
 8333                scrolled_content_origin,
 8334                window,
 8335                cx,
 8336            );
 8337        }
 8338
 8339        const POLE_WIDTH: Pixels = px(2.);
 8340
 8341        let line_layout =
 8342            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8343        let target_column = target_display_point.column() as usize;
 8344
 8345        let target_x = line_layout.x_for_index(target_column);
 8346        let target_y =
 8347            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8348
 8349        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8350
 8351        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8352        border_color.l += 0.001;
 8353
 8354        let mut element = v_flex()
 8355            .items_end()
 8356            .when(flag_on_right, |el| el.items_start())
 8357            .child(if flag_on_right {
 8358                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8359                    .rounded_bl(px(0.))
 8360                    .rounded_tl(px(0.))
 8361                    .border_l_2()
 8362                    .border_color(border_color)
 8363            } else {
 8364                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8365                    .rounded_br(px(0.))
 8366                    .rounded_tr(px(0.))
 8367                    .border_r_2()
 8368                    .border_color(border_color)
 8369            })
 8370            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8371            .into_any();
 8372
 8373        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8374
 8375        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8376            - point(
 8377                if flag_on_right {
 8378                    POLE_WIDTH
 8379                } else {
 8380                    size.width - POLE_WIDTH
 8381                },
 8382                size.height - line_height,
 8383            );
 8384
 8385        origin.x = origin.x.max(content_origin.x);
 8386
 8387        element.prepaint_at(origin, window, cx);
 8388
 8389        Some((element, origin))
 8390    }
 8391
 8392    fn render_edit_prediction_scroll_popover(
 8393        &mut self,
 8394        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8395        scroll_icon: IconName,
 8396        visible_row_range: Range<DisplayRow>,
 8397        line_layouts: &[LineWithInvisibles],
 8398        newest_selection_head: Option<DisplayPoint>,
 8399        scrolled_content_origin: gpui::Point<Pixels>,
 8400        window: &mut Window,
 8401        cx: &mut App,
 8402    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8403        let mut element = self
 8404            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8405            .into_any();
 8406
 8407        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8408
 8409        let cursor = newest_selection_head?;
 8410        let cursor_row_layout =
 8411            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8412        let cursor_column = cursor.column() as usize;
 8413
 8414        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8415
 8416        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8417
 8418        element.prepaint_at(origin, window, cx);
 8419        Some((element, origin))
 8420    }
 8421
 8422    fn render_edit_prediction_eager_jump_popover(
 8423        &mut self,
 8424        text_bounds: &Bounds<Pixels>,
 8425        content_origin: gpui::Point<Pixels>,
 8426        editor_snapshot: &EditorSnapshot,
 8427        visible_row_range: Range<DisplayRow>,
 8428        scroll_top: f32,
 8429        scroll_bottom: f32,
 8430        line_height: Pixels,
 8431        scroll_pixel_position: gpui::Point<Pixels>,
 8432        target_display_point: DisplayPoint,
 8433        editor_width: Pixels,
 8434        window: &mut Window,
 8435        cx: &mut App,
 8436    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8437        if target_display_point.row().as_f32() < scroll_top {
 8438            let mut element = self
 8439                .render_edit_prediction_line_popover(
 8440                    "Jump to Edit",
 8441                    Some(IconName::ArrowUp),
 8442                    window,
 8443                    cx,
 8444                )?
 8445                .into_any();
 8446
 8447            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8448            let offset = point(
 8449                (text_bounds.size.width - size.width) / 2.,
 8450                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8451            );
 8452
 8453            let origin = text_bounds.origin + offset;
 8454            element.prepaint_at(origin, window, cx);
 8455            Some((element, origin))
 8456        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8457            let mut element = self
 8458                .render_edit_prediction_line_popover(
 8459                    "Jump to Edit",
 8460                    Some(IconName::ArrowDown),
 8461                    window,
 8462                    cx,
 8463                )?
 8464                .into_any();
 8465
 8466            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8467            let offset = point(
 8468                (text_bounds.size.width - size.width) / 2.,
 8469                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8470            );
 8471
 8472            let origin = text_bounds.origin + offset;
 8473            element.prepaint_at(origin, window, cx);
 8474            Some((element, origin))
 8475        } else {
 8476            self.render_edit_prediction_end_of_line_popover(
 8477                "Jump to Edit",
 8478                editor_snapshot,
 8479                visible_row_range,
 8480                target_display_point,
 8481                line_height,
 8482                scroll_pixel_position,
 8483                content_origin,
 8484                editor_width,
 8485                window,
 8486                cx,
 8487            )
 8488        }
 8489    }
 8490
 8491    fn render_edit_prediction_end_of_line_popover(
 8492        self: &mut Editor,
 8493        label: &'static str,
 8494        editor_snapshot: &EditorSnapshot,
 8495        visible_row_range: Range<DisplayRow>,
 8496        target_display_point: DisplayPoint,
 8497        line_height: Pixels,
 8498        scroll_pixel_position: gpui::Point<Pixels>,
 8499        content_origin: gpui::Point<Pixels>,
 8500        editor_width: Pixels,
 8501        window: &mut Window,
 8502        cx: &mut App,
 8503    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8504        let target_line_end = DisplayPoint::new(
 8505            target_display_point.row(),
 8506            editor_snapshot.line_len(target_display_point.row()),
 8507        );
 8508
 8509        let mut element = self
 8510            .render_edit_prediction_line_popover(label, None, window, cx)?
 8511            .into_any();
 8512
 8513        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8514
 8515        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8516
 8517        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8518        let mut origin = start_point
 8519            + line_origin
 8520            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8521        origin.x = origin.x.max(content_origin.x);
 8522
 8523        let max_x = content_origin.x + editor_width - size.width;
 8524
 8525        if origin.x > max_x {
 8526            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8527
 8528            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8529                origin.y += offset;
 8530                IconName::ArrowUp
 8531            } else {
 8532                origin.y -= offset;
 8533                IconName::ArrowDown
 8534            };
 8535
 8536            element = self
 8537                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8538                .into_any();
 8539
 8540            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8541
 8542            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8543        }
 8544
 8545        element.prepaint_at(origin, window, cx);
 8546        Some((element, origin))
 8547    }
 8548
 8549    fn render_edit_prediction_diff_popover(
 8550        self: &Editor,
 8551        text_bounds: &Bounds<Pixels>,
 8552        content_origin: gpui::Point<Pixels>,
 8553        right_margin: Pixels,
 8554        editor_snapshot: &EditorSnapshot,
 8555        visible_row_range: Range<DisplayRow>,
 8556        line_layouts: &[LineWithInvisibles],
 8557        line_height: Pixels,
 8558        scroll_pixel_position: gpui::Point<Pixels>,
 8559        newest_selection_head: Option<DisplayPoint>,
 8560        editor_width: Pixels,
 8561        style: &EditorStyle,
 8562        edits: &Vec<(Range<Anchor>, String)>,
 8563        edit_preview: &Option<language::EditPreview>,
 8564        snapshot: &language::BufferSnapshot,
 8565        window: &mut Window,
 8566        cx: &mut App,
 8567    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8568        let edit_start = edits
 8569            .first()
 8570            .unwrap()
 8571            .0
 8572            .start
 8573            .to_display_point(editor_snapshot);
 8574        let edit_end = edits
 8575            .last()
 8576            .unwrap()
 8577            .0
 8578            .end
 8579            .to_display_point(editor_snapshot);
 8580
 8581        let is_visible = visible_row_range.contains(&edit_start.row())
 8582            || visible_row_range.contains(&edit_end.row());
 8583        if !is_visible {
 8584            return None;
 8585        }
 8586
 8587        let highlighted_edits =
 8588            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8589
 8590        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8591        let line_count = highlighted_edits.text.lines().count();
 8592
 8593        const BORDER_WIDTH: Pixels = px(1.);
 8594
 8595        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8596        let has_keybind = keybind.is_some();
 8597
 8598        let mut element = h_flex()
 8599            .items_start()
 8600            .child(
 8601                h_flex()
 8602                    .bg(cx.theme().colors().editor_background)
 8603                    .border(BORDER_WIDTH)
 8604                    .shadow_sm()
 8605                    .border_color(cx.theme().colors().border)
 8606                    .rounded_l_lg()
 8607                    .when(line_count > 1, |el| el.rounded_br_lg())
 8608                    .pr_1()
 8609                    .child(styled_text),
 8610            )
 8611            .child(
 8612                h_flex()
 8613                    .h(line_height + BORDER_WIDTH * 2.)
 8614                    .px_1p5()
 8615                    .gap_1()
 8616                    // Workaround: For some reason, there's a gap if we don't do this
 8617                    .ml(-BORDER_WIDTH)
 8618                    .shadow(vec![gpui::BoxShadow {
 8619                        color: gpui::black().opacity(0.05),
 8620                        offset: point(px(1.), px(1.)),
 8621                        blur_radius: px(2.),
 8622                        spread_radius: px(0.),
 8623                    }])
 8624                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8625                    .border(BORDER_WIDTH)
 8626                    .border_color(cx.theme().colors().border)
 8627                    .rounded_r_lg()
 8628                    .id("edit_prediction_diff_popover_keybind")
 8629                    .when(!has_keybind, |el| {
 8630                        let status_colors = cx.theme().status();
 8631
 8632                        el.bg(status_colors.error_background)
 8633                            .border_color(status_colors.error.opacity(0.6))
 8634                            .child(Icon::new(IconName::Info).color(Color::Error))
 8635                            .cursor_default()
 8636                            .hoverable_tooltip(move |_window, cx| {
 8637                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8638                            })
 8639                    })
 8640                    .children(keybind),
 8641            )
 8642            .into_any();
 8643
 8644        let longest_row =
 8645            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8646        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8647            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8648        } else {
 8649            layout_line(
 8650                longest_row,
 8651                editor_snapshot,
 8652                style,
 8653                editor_width,
 8654                |_| false,
 8655                window,
 8656                cx,
 8657            )
 8658            .width
 8659        };
 8660
 8661        let viewport_bounds =
 8662            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8663                right: -right_margin,
 8664                ..Default::default()
 8665            });
 8666
 8667        let x_after_longest =
 8668            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8669                - scroll_pixel_position.x;
 8670
 8671        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8672
 8673        // Fully visible if it can be displayed within the window (allow overlapping other
 8674        // panes). However, this is only allowed if the popover starts within text_bounds.
 8675        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8676            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8677
 8678        let mut origin = if can_position_to_the_right {
 8679            point(
 8680                x_after_longest,
 8681                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8682                    - scroll_pixel_position.y,
 8683            )
 8684        } else {
 8685            let cursor_row = newest_selection_head.map(|head| head.row());
 8686            let above_edit = edit_start
 8687                .row()
 8688                .0
 8689                .checked_sub(line_count as u32)
 8690                .map(DisplayRow);
 8691            let below_edit = Some(edit_end.row() + 1);
 8692            let above_cursor =
 8693                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8694            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8695
 8696            // Place the edit popover adjacent to the edit if there is a location
 8697            // available that is onscreen and does not obscure the cursor. Otherwise,
 8698            // place it adjacent to the cursor.
 8699            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8700                .into_iter()
 8701                .flatten()
 8702                .find(|&start_row| {
 8703                    let end_row = start_row + line_count as u32;
 8704                    visible_row_range.contains(&start_row)
 8705                        && visible_row_range.contains(&end_row)
 8706                        && cursor_row.map_or(true, |cursor_row| {
 8707                            !((start_row..end_row).contains(&cursor_row))
 8708                        })
 8709                })?;
 8710
 8711            content_origin
 8712                + point(
 8713                    -scroll_pixel_position.x,
 8714                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8715                )
 8716        };
 8717
 8718        origin.x -= BORDER_WIDTH;
 8719
 8720        window.defer_draw(element, origin, 1);
 8721
 8722        // Do not return an element, since it will already be drawn due to defer_draw.
 8723        None
 8724    }
 8725
 8726    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8727        px(30.)
 8728    }
 8729
 8730    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8731        if self.read_only(cx) {
 8732            cx.theme().players().read_only()
 8733        } else {
 8734            self.style.as_ref().unwrap().local_player
 8735        }
 8736    }
 8737
 8738    fn render_edit_prediction_accept_keybind(
 8739        &self,
 8740        window: &mut Window,
 8741        cx: &App,
 8742    ) -> Option<AnyElement> {
 8743        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8744        let accept_keystroke = accept_binding.keystroke()?;
 8745
 8746        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8747
 8748        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8749            Color::Accent
 8750        } else {
 8751            Color::Muted
 8752        };
 8753
 8754        h_flex()
 8755            .px_0p5()
 8756            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8757            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8758            .text_size(TextSize::XSmall.rems(cx))
 8759            .child(h_flex().children(ui::render_modifiers(
 8760                &accept_keystroke.modifiers,
 8761                PlatformStyle::platform(),
 8762                Some(modifiers_color),
 8763                Some(IconSize::XSmall.rems().into()),
 8764                true,
 8765            )))
 8766            .when(is_platform_style_mac, |parent| {
 8767                parent.child(accept_keystroke.key.clone())
 8768            })
 8769            .when(!is_platform_style_mac, |parent| {
 8770                parent.child(
 8771                    Key::new(
 8772                        util::capitalize(&accept_keystroke.key),
 8773                        Some(Color::Default),
 8774                    )
 8775                    .size(Some(IconSize::XSmall.rems().into())),
 8776                )
 8777            })
 8778            .into_any()
 8779            .into()
 8780    }
 8781
 8782    fn render_edit_prediction_line_popover(
 8783        &self,
 8784        label: impl Into<SharedString>,
 8785        icon: Option<IconName>,
 8786        window: &mut Window,
 8787        cx: &App,
 8788    ) -> Option<Stateful<Div>> {
 8789        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8790
 8791        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8792        let has_keybind = keybind.is_some();
 8793
 8794        let result = h_flex()
 8795            .id("ep-line-popover")
 8796            .py_0p5()
 8797            .pl_1()
 8798            .pr(padding_right)
 8799            .gap_1()
 8800            .rounded_md()
 8801            .border_1()
 8802            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8803            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8804            .shadow_sm()
 8805            .when(!has_keybind, |el| {
 8806                let status_colors = cx.theme().status();
 8807
 8808                el.bg(status_colors.error_background)
 8809                    .border_color(status_colors.error.opacity(0.6))
 8810                    .pl_2()
 8811                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8812                    .cursor_default()
 8813                    .hoverable_tooltip(move |_window, cx| {
 8814                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8815                    })
 8816            })
 8817            .children(keybind)
 8818            .child(
 8819                Label::new(label)
 8820                    .size(LabelSize::Small)
 8821                    .when(!has_keybind, |el| {
 8822                        el.color(cx.theme().status().error.into()).strikethrough()
 8823                    }),
 8824            )
 8825            .when(!has_keybind, |el| {
 8826                el.child(
 8827                    h_flex().ml_1().child(
 8828                        Icon::new(IconName::Info)
 8829                            .size(IconSize::Small)
 8830                            .color(cx.theme().status().error.into()),
 8831                    ),
 8832                )
 8833            })
 8834            .when_some(icon, |element, icon| {
 8835                element.child(
 8836                    div()
 8837                        .mt(px(1.5))
 8838                        .child(Icon::new(icon).size(IconSize::Small)),
 8839                )
 8840            });
 8841
 8842        Some(result)
 8843    }
 8844
 8845    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8846        let accent_color = cx.theme().colors().text_accent;
 8847        let editor_bg_color = cx.theme().colors().editor_background;
 8848        editor_bg_color.blend(accent_color.opacity(0.1))
 8849    }
 8850
 8851    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8852        let accent_color = cx.theme().colors().text_accent;
 8853        let editor_bg_color = cx.theme().colors().editor_background;
 8854        editor_bg_color.blend(accent_color.opacity(0.6))
 8855    }
 8856
 8857    fn render_edit_prediction_cursor_popover(
 8858        &self,
 8859        min_width: Pixels,
 8860        max_width: Pixels,
 8861        cursor_point: Point,
 8862        style: &EditorStyle,
 8863        accept_keystroke: Option<&gpui::Keystroke>,
 8864        _window: &Window,
 8865        cx: &mut Context<Editor>,
 8866    ) -> Option<AnyElement> {
 8867        let provider = self.edit_prediction_provider.as_ref()?;
 8868
 8869        if provider.provider.needs_terms_acceptance(cx) {
 8870            return Some(
 8871                h_flex()
 8872                    .min_w(min_width)
 8873                    .flex_1()
 8874                    .px_2()
 8875                    .py_1()
 8876                    .gap_3()
 8877                    .elevation_2(cx)
 8878                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8879                    .id("accept-terms")
 8880                    .cursor_pointer()
 8881                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8882                    .on_click(cx.listener(|this, _event, window, cx| {
 8883                        cx.stop_propagation();
 8884                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8885                        window.dispatch_action(
 8886                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8887                            cx,
 8888                        );
 8889                    }))
 8890                    .child(
 8891                        h_flex()
 8892                            .flex_1()
 8893                            .gap_2()
 8894                            .child(Icon::new(IconName::ZedPredict))
 8895                            .child(Label::new("Accept Terms of Service"))
 8896                            .child(div().w_full())
 8897                            .child(
 8898                                Icon::new(IconName::ArrowUpRight)
 8899                                    .color(Color::Muted)
 8900                                    .size(IconSize::Small),
 8901                            )
 8902                            .into_any_element(),
 8903                    )
 8904                    .into_any(),
 8905            );
 8906        }
 8907
 8908        let is_refreshing = provider.provider.is_refreshing(cx);
 8909
 8910        fn pending_completion_container() -> Div {
 8911            h_flex()
 8912                .h_full()
 8913                .flex_1()
 8914                .gap_2()
 8915                .child(Icon::new(IconName::ZedPredict))
 8916        }
 8917
 8918        let completion = match &self.active_inline_completion {
 8919            Some(prediction) => {
 8920                if !self.has_visible_completions_menu() {
 8921                    const RADIUS: Pixels = px(6.);
 8922                    const BORDER_WIDTH: Pixels = px(1.);
 8923
 8924                    return Some(
 8925                        h_flex()
 8926                            .elevation_2(cx)
 8927                            .border(BORDER_WIDTH)
 8928                            .border_color(cx.theme().colors().border)
 8929                            .when(accept_keystroke.is_none(), |el| {
 8930                                el.border_color(cx.theme().status().error)
 8931                            })
 8932                            .rounded(RADIUS)
 8933                            .rounded_tl(px(0.))
 8934                            .overflow_hidden()
 8935                            .child(div().px_1p5().child(match &prediction.completion {
 8936                                InlineCompletion::Move { target, snapshot } => {
 8937                                    use text::ToPoint as _;
 8938                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8939                                    {
 8940                                        Icon::new(IconName::ZedPredictDown)
 8941                                    } else {
 8942                                        Icon::new(IconName::ZedPredictUp)
 8943                                    }
 8944                                }
 8945                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8946                            }))
 8947                            .child(
 8948                                h_flex()
 8949                                    .gap_1()
 8950                                    .py_1()
 8951                                    .px_2()
 8952                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8953                                    .border_l_1()
 8954                                    .border_color(cx.theme().colors().border)
 8955                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8956                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8957                                        el.child(
 8958                                            Label::new("Hold")
 8959                                                .size(LabelSize::Small)
 8960                                                .when(accept_keystroke.is_none(), |el| {
 8961                                                    el.strikethrough()
 8962                                                })
 8963                                                .line_height_style(LineHeightStyle::UiLabel),
 8964                                        )
 8965                                    })
 8966                                    .id("edit_prediction_cursor_popover_keybind")
 8967                                    .when(accept_keystroke.is_none(), |el| {
 8968                                        let status_colors = cx.theme().status();
 8969
 8970                                        el.bg(status_colors.error_background)
 8971                                            .border_color(status_colors.error.opacity(0.6))
 8972                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8973                                            .cursor_default()
 8974                                            .hoverable_tooltip(move |_window, cx| {
 8975                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8976                                                    .into()
 8977                                            })
 8978                                    })
 8979                                    .when_some(
 8980                                        accept_keystroke.as_ref(),
 8981                                        |el, accept_keystroke| {
 8982                                            el.child(h_flex().children(ui::render_modifiers(
 8983                                                &accept_keystroke.modifiers,
 8984                                                PlatformStyle::platform(),
 8985                                                Some(Color::Default),
 8986                                                Some(IconSize::XSmall.rems().into()),
 8987                                                false,
 8988                                            )))
 8989                                        },
 8990                                    ),
 8991                            )
 8992                            .into_any(),
 8993                    );
 8994                }
 8995
 8996                self.render_edit_prediction_cursor_popover_preview(
 8997                    prediction,
 8998                    cursor_point,
 8999                    style,
 9000                    cx,
 9001                )?
 9002            }
 9003
 9004            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9005                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9006                    stale_completion,
 9007                    cursor_point,
 9008                    style,
 9009                    cx,
 9010                )?,
 9011
 9012                None => {
 9013                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9014                }
 9015            },
 9016
 9017            None => pending_completion_container().child(Label::new("No Prediction")),
 9018        };
 9019
 9020        let completion = if is_refreshing {
 9021            completion
 9022                .with_animation(
 9023                    "loading-completion",
 9024                    Animation::new(Duration::from_secs(2))
 9025                        .repeat()
 9026                        .with_easing(pulsating_between(0.4, 0.8)),
 9027                    |label, delta| label.opacity(delta),
 9028                )
 9029                .into_any_element()
 9030        } else {
 9031            completion.into_any_element()
 9032        };
 9033
 9034        let has_completion = self.active_inline_completion.is_some();
 9035
 9036        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9037        Some(
 9038            h_flex()
 9039                .min_w(min_width)
 9040                .max_w(max_width)
 9041                .flex_1()
 9042                .elevation_2(cx)
 9043                .border_color(cx.theme().colors().border)
 9044                .child(
 9045                    div()
 9046                        .flex_1()
 9047                        .py_1()
 9048                        .px_2()
 9049                        .overflow_hidden()
 9050                        .child(completion),
 9051                )
 9052                .when_some(accept_keystroke, |el, accept_keystroke| {
 9053                    if !accept_keystroke.modifiers.modified() {
 9054                        return el;
 9055                    }
 9056
 9057                    el.child(
 9058                        h_flex()
 9059                            .h_full()
 9060                            .border_l_1()
 9061                            .rounded_r_lg()
 9062                            .border_color(cx.theme().colors().border)
 9063                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9064                            .gap_1()
 9065                            .py_1()
 9066                            .px_2()
 9067                            .child(
 9068                                h_flex()
 9069                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9070                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9071                                    .child(h_flex().children(ui::render_modifiers(
 9072                                        &accept_keystroke.modifiers,
 9073                                        PlatformStyle::platform(),
 9074                                        Some(if !has_completion {
 9075                                            Color::Muted
 9076                                        } else {
 9077                                            Color::Default
 9078                                        }),
 9079                                        None,
 9080                                        false,
 9081                                    ))),
 9082                            )
 9083                            .child(Label::new("Preview").into_any_element())
 9084                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9085                    )
 9086                })
 9087                .into_any(),
 9088        )
 9089    }
 9090
 9091    fn render_edit_prediction_cursor_popover_preview(
 9092        &self,
 9093        completion: &InlineCompletionState,
 9094        cursor_point: Point,
 9095        style: &EditorStyle,
 9096        cx: &mut Context<Editor>,
 9097    ) -> Option<Div> {
 9098        use text::ToPoint as _;
 9099
 9100        fn render_relative_row_jump(
 9101            prefix: impl Into<String>,
 9102            current_row: u32,
 9103            target_row: u32,
 9104        ) -> Div {
 9105            let (row_diff, arrow) = if target_row < current_row {
 9106                (current_row - target_row, IconName::ArrowUp)
 9107            } else {
 9108                (target_row - current_row, IconName::ArrowDown)
 9109            };
 9110
 9111            h_flex()
 9112                .child(
 9113                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9114                        .color(Color::Muted)
 9115                        .size(LabelSize::Small),
 9116                )
 9117                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9118        }
 9119
 9120        match &completion.completion {
 9121            InlineCompletion::Move {
 9122                target, snapshot, ..
 9123            } => Some(
 9124                h_flex()
 9125                    .px_2()
 9126                    .gap_2()
 9127                    .flex_1()
 9128                    .child(
 9129                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9130                            Icon::new(IconName::ZedPredictDown)
 9131                        } else {
 9132                            Icon::new(IconName::ZedPredictUp)
 9133                        },
 9134                    )
 9135                    .child(Label::new("Jump to Edit")),
 9136            ),
 9137
 9138            InlineCompletion::Edit {
 9139                edits,
 9140                edit_preview,
 9141                snapshot,
 9142                display_mode: _,
 9143            } => {
 9144                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9145
 9146                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9147                    &snapshot,
 9148                    &edits,
 9149                    edit_preview.as_ref()?,
 9150                    true,
 9151                    cx,
 9152                )
 9153                .first_line_preview();
 9154
 9155                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9156                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9157
 9158                let preview = h_flex()
 9159                    .gap_1()
 9160                    .min_w_16()
 9161                    .child(styled_text)
 9162                    .when(has_more_lines, |parent| parent.child(""));
 9163
 9164                let left = if first_edit_row != cursor_point.row {
 9165                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9166                        .into_any_element()
 9167                } else {
 9168                    Icon::new(IconName::ZedPredict).into_any_element()
 9169                };
 9170
 9171                Some(
 9172                    h_flex()
 9173                        .h_full()
 9174                        .flex_1()
 9175                        .gap_2()
 9176                        .pr_1()
 9177                        .overflow_x_hidden()
 9178                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9179                        .child(left)
 9180                        .child(preview),
 9181                )
 9182            }
 9183        }
 9184    }
 9185
 9186    pub fn render_context_menu(
 9187        &self,
 9188        style: &EditorStyle,
 9189        max_height_in_lines: u32,
 9190        window: &mut Window,
 9191        cx: &mut Context<Editor>,
 9192    ) -> Option<AnyElement> {
 9193        let menu = self.context_menu.borrow();
 9194        let menu = menu.as_ref()?;
 9195        if !menu.visible() {
 9196            return None;
 9197        };
 9198        Some(menu.render(style, max_height_in_lines, window, cx))
 9199    }
 9200
 9201    fn render_context_menu_aside(
 9202        &mut self,
 9203        max_size: Size<Pixels>,
 9204        window: &mut Window,
 9205        cx: &mut Context<Editor>,
 9206    ) -> Option<AnyElement> {
 9207        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9208            if menu.visible() {
 9209                menu.render_aside(max_size, window, cx)
 9210            } else {
 9211                None
 9212            }
 9213        })
 9214    }
 9215
 9216    fn hide_context_menu(
 9217        &mut self,
 9218        window: &mut Window,
 9219        cx: &mut Context<Self>,
 9220    ) -> Option<CodeContextMenu> {
 9221        cx.notify();
 9222        self.completion_tasks.clear();
 9223        let context_menu = self.context_menu.borrow_mut().take();
 9224        self.stale_inline_completion_in_menu.take();
 9225        self.update_visible_inline_completion(window, cx);
 9226        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9227            if let Some(completion_provider) = &self.completion_provider {
 9228                completion_provider.selection_changed(None, window, cx);
 9229            }
 9230        }
 9231        context_menu
 9232    }
 9233
 9234    fn show_snippet_choices(
 9235        &mut self,
 9236        choices: &Vec<String>,
 9237        selection: Range<Anchor>,
 9238        cx: &mut Context<Self>,
 9239    ) {
 9240        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9241            (Some(a), Some(b)) if a == b => a,
 9242            _ => {
 9243                log::error!("expected anchor range to have matching buffer IDs");
 9244                return;
 9245            }
 9246        };
 9247        let multi_buffer = self.buffer().read(cx);
 9248        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9249            return;
 9250        };
 9251
 9252        let id = post_inc(&mut self.next_completion_id);
 9253        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9254        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9255            CompletionsMenu::new_snippet_choices(
 9256                id,
 9257                true,
 9258                choices,
 9259                selection,
 9260                buffer,
 9261                snippet_sort_order,
 9262            ),
 9263        ));
 9264    }
 9265
 9266    pub fn insert_snippet(
 9267        &mut self,
 9268        insertion_ranges: &[Range<usize>],
 9269        snippet: Snippet,
 9270        window: &mut Window,
 9271        cx: &mut Context<Self>,
 9272    ) -> Result<()> {
 9273        struct Tabstop<T> {
 9274            is_end_tabstop: bool,
 9275            ranges: Vec<Range<T>>,
 9276            choices: Option<Vec<String>>,
 9277        }
 9278
 9279        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9280            let snippet_text: Arc<str> = snippet.text.clone().into();
 9281            let edits = insertion_ranges
 9282                .iter()
 9283                .cloned()
 9284                .map(|range| (range, snippet_text.clone()));
 9285            let autoindent_mode = AutoindentMode::Block {
 9286                original_indent_columns: Vec::new(),
 9287            };
 9288            buffer.edit(edits, Some(autoindent_mode), cx);
 9289
 9290            let snapshot = &*buffer.read(cx);
 9291            let snippet = &snippet;
 9292            snippet
 9293                .tabstops
 9294                .iter()
 9295                .map(|tabstop| {
 9296                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9297                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9298                    });
 9299                    let mut tabstop_ranges = tabstop
 9300                        .ranges
 9301                        .iter()
 9302                        .flat_map(|tabstop_range| {
 9303                            let mut delta = 0_isize;
 9304                            insertion_ranges.iter().map(move |insertion_range| {
 9305                                let insertion_start = insertion_range.start as isize + delta;
 9306                                delta +=
 9307                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9308
 9309                                let start = ((insertion_start + tabstop_range.start) as usize)
 9310                                    .min(snapshot.len());
 9311                                let end = ((insertion_start + tabstop_range.end) as usize)
 9312                                    .min(snapshot.len());
 9313                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9314                            })
 9315                        })
 9316                        .collect::<Vec<_>>();
 9317                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9318
 9319                    Tabstop {
 9320                        is_end_tabstop,
 9321                        ranges: tabstop_ranges,
 9322                        choices: tabstop.choices.clone(),
 9323                    }
 9324                })
 9325                .collect::<Vec<_>>()
 9326        });
 9327        if let Some(tabstop) = tabstops.first() {
 9328            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9329                // Reverse order so that the first range is the newest created selection.
 9330                // Completions will use it and autoscroll will prioritize it.
 9331                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9332            });
 9333
 9334            if let Some(choices) = &tabstop.choices {
 9335                if let Some(selection) = tabstop.ranges.first() {
 9336                    self.show_snippet_choices(choices, selection.clone(), cx)
 9337                }
 9338            }
 9339
 9340            // If we're already at the last tabstop and it's at the end of the snippet,
 9341            // we're done, we don't need to keep the state around.
 9342            if !tabstop.is_end_tabstop {
 9343                let choices = tabstops
 9344                    .iter()
 9345                    .map(|tabstop| tabstop.choices.clone())
 9346                    .collect();
 9347
 9348                let ranges = tabstops
 9349                    .into_iter()
 9350                    .map(|tabstop| tabstop.ranges)
 9351                    .collect::<Vec<_>>();
 9352
 9353                self.snippet_stack.push(SnippetState {
 9354                    active_index: 0,
 9355                    ranges,
 9356                    choices,
 9357                });
 9358            }
 9359
 9360            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9361            if self.autoclose_regions.is_empty() {
 9362                let snapshot = self.buffer.read(cx).snapshot(cx);
 9363                for selection in &mut self.selections.all::<Point>(cx) {
 9364                    let selection_head = selection.head();
 9365                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9366                        continue;
 9367                    };
 9368
 9369                    let mut bracket_pair = None;
 9370                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9371                    let prev_chars = snapshot
 9372                        .reversed_chars_at(selection_head)
 9373                        .collect::<String>();
 9374                    for (pair, enabled) in scope.brackets() {
 9375                        if enabled
 9376                            && pair.close
 9377                            && prev_chars.starts_with(pair.start.as_str())
 9378                            && next_chars.starts_with(pair.end.as_str())
 9379                        {
 9380                            bracket_pair = Some(pair.clone());
 9381                            break;
 9382                        }
 9383                    }
 9384                    if let Some(pair) = bracket_pair {
 9385                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9386                        let autoclose_enabled =
 9387                            self.use_autoclose && snapshot_settings.use_autoclose;
 9388                        if autoclose_enabled {
 9389                            let start = snapshot.anchor_after(selection_head);
 9390                            let end = snapshot.anchor_after(selection_head);
 9391                            self.autoclose_regions.push(AutocloseRegion {
 9392                                selection_id: selection.id,
 9393                                range: start..end,
 9394                                pair,
 9395                            });
 9396                        }
 9397                    }
 9398                }
 9399            }
 9400        }
 9401        Ok(())
 9402    }
 9403
 9404    pub fn move_to_next_snippet_tabstop(
 9405        &mut self,
 9406        window: &mut Window,
 9407        cx: &mut Context<Self>,
 9408    ) -> bool {
 9409        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9410    }
 9411
 9412    pub fn move_to_prev_snippet_tabstop(
 9413        &mut self,
 9414        window: &mut Window,
 9415        cx: &mut Context<Self>,
 9416    ) -> bool {
 9417        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9418    }
 9419
 9420    pub fn move_to_snippet_tabstop(
 9421        &mut self,
 9422        bias: Bias,
 9423        window: &mut Window,
 9424        cx: &mut Context<Self>,
 9425    ) -> bool {
 9426        if let Some(mut snippet) = self.snippet_stack.pop() {
 9427            match bias {
 9428                Bias::Left => {
 9429                    if snippet.active_index > 0 {
 9430                        snippet.active_index -= 1;
 9431                    } else {
 9432                        self.snippet_stack.push(snippet);
 9433                        return false;
 9434                    }
 9435                }
 9436                Bias::Right => {
 9437                    if snippet.active_index + 1 < snippet.ranges.len() {
 9438                        snippet.active_index += 1;
 9439                    } else {
 9440                        self.snippet_stack.push(snippet);
 9441                        return false;
 9442                    }
 9443                }
 9444            }
 9445            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9446                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9447                    // Reverse order so that the first range is the newest created selection.
 9448                    // Completions will use it and autoscroll will prioritize it.
 9449                    s.select_ranges(current_ranges.iter().rev().cloned())
 9450                });
 9451
 9452                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9453                    if let Some(selection) = current_ranges.first() {
 9454                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9455                    }
 9456                }
 9457
 9458                // If snippet state is not at the last tabstop, push it back on the stack
 9459                if snippet.active_index + 1 < snippet.ranges.len() {
 9460                    self.snippet_stack.push(snippet);
 9461                }
 9462                return true;
 9463            }
 9464        }
 9465
 9466        false
 9467    }
 9468
 9469    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9470        self.transact(window, cx, |this, window, cx| {
 9471            this.select_all(&SelectAll, window, cx);
 9472            this.insert("", window, cx);
 9473        });
 9474    }
 9475
 9476    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9477        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9478        self.transact(window, cx, |this, window, cx| {
 9479            this.select_autoclose_pair(window, cx);
 9480            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9481            if !this.linked_edit_ranges.is_empty() {
 9482                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9483                let snapshot = this.buffer.read(cx).snapshot(cx);
 9484
 9485                for selection in selections.iter() {
 9486                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9487                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9488                    if selection_start.buffer_id != selection_end.buffer_id {
 9489                        continue;
 9490                    }
 9491                    if let Some(ranges) =
 9492                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9493                    {
 9494                        for (buffer, entries) in ranges {
 9495                            linked_ranges.entry(buffer).or_default().extend(entries);
 9496                        }
 9497                    }
 9498                }
 9499            }
 9500
 9501            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9502            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9503            for selection in &mut selections {
 9504                if selection.is_empty() {
 9505                    let old_head = selection.head();
 9506                    let mut new_head =
 9507                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9508                            .to_point(&display_map);
 9509                    if let Some((buffer, line_buffer_range)) = display_map
 9510                        .buffer_snapshot
 9511                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9512                    {
 9513                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9514                        let indent_len = match indent_size.kind {
 9515                            IndentKind::Space => {
 9516                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9517                            }
 9518                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9519                        };
 9520                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9521                            let indent_len = indent_len.get();
 9522                            new_head = cmp::min(
 9523                                new_head,
 9524                                MultiBufferPoint::new(
 9525                                    old_head.row,
 9526                                    ((old_head.column - 1) / indent_len) * indent_len,
 9527                                ),
 9528                            );
 9529                        }
 9530                    }
 9531
 9532                    selection.set_head(new_head, SelectionGoal::None);
 9533                }
 9534            }
 9535
 9536            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9537                s.select(selections)
 9538            });
 9539            this.insert("", window, cx);
 9540            let empty_str: Arc<str> = Arc::from("");
 9541            for (buffer, edits) in linked_ranges {
 9542                let snapshot = buffer.read(cx).snapshot();
 9543                use text::ToPoint as TP;
 9544
 9545                let edits = edits
 9546                    .into_iter()
 9547                    .map(|range| {
 9548                        let end_point = TP::to_point(&range.end, &snapshot);
 9549                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9550
 9551                        if end_point == start_point {
 9552                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9553                                .saturating_sub(1);
 9554                            start_point =
 9555                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9556                        };
 9557
 9558                        (start_point..end_point, empty_str.clone())
 9559                    })
 9560                    .sorted_by_key(|(range, _)| range.start)
 9561                    .collect::<Vec<_>>();
 9562                buffer.update(cx, |this, cx| {
 9563                    this.edit(edits, None, cx);
 9564                })
 9565            }
 9566            this.refresh_inline_completion(true, false, window, cx);
 9567            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9568        });
 9569    }
 9570
 9571    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9572        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9573        self.transact(window, cx, |this, window, cx| {
 9574            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9575                s.move_with(|map, selection| {
 9576                    if selection.is_empty() {
 9577                        let cursor = movement::right(map, selection.head());
 9578                        selection.end = cursor;
 9579                        selection.reversed = true;
 9580                        selection.goal = SelectionGoal::None;
 9581                    }
 9582                })
 9583            });
 9584            this.insert("", window, cx);
 9585            this.refresh_inline_completion(true, false, window, cx);
 9586        });
 9587    }
 9588
 9589    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9590        if self.mode.is_single_line() {
 9591            cx.propagate();
 9592            return;
 9593        }
 9594
 9595        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9596        if self.move_to_prev_snippet_tabstop(window, cx) {
 9597            return;
 9598        }
 9599        self.outdent(&Outdent, window, cx);
 9600    }
 9601
 9602    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9603        if self.mode.is_single_line() {
 9604            cx.propagate();
 9605            return;
 9606        }
 9607
 9608        if self.move_to_next_snippet_tabstop(window, cx) {
 9609            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9610            return;
 9611        }
 9612        if self.read_only(cx) {
 9613            return;
 9614        }
 9615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9616        let mut selections = self.selections.all_adjusted(cx);
 9617        let buffer = self.buffer.read(cx);
 9618        let snapshot = buffer.snapshot(cx);
 9619        let rows_iter = selections.iter().map(|s| s.head().row);
 9620        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9621
 9622        let has_some_cursor_in_whitespace = selections
 9623            .iter()
 9624            .filter(|selection| selection.is_empty())
 9625            .any(|selection| {
 9626                let cursor = selection.head();
 9627                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9628                cursor.column < current_indent.len
 9629            });
 9630
 9631        let mut edits = Vec::new();
 9632        let mut prev_edited_row = 0;
 9633        let mut row_delta = 0;
 9634        for selection in &mut selections {
 9635            if selection.start.row != prev_edited_row {
 9636                row_delta = 0;
 9637            }
 9638            prev_edited_row = selection.end.row;
 9639
 9640            // If the selection is non-empty, then increase the indentation of the selected lines.
 9641            if !selection.is_empty() {
 9642                row_delta =
 9643                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9644                continue;
 9645            }
 9646
 9647            let cursor = selection.head();
 9648            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9649            if let Some(suggested_indent) =
 9650                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9651            {
 9652                // Don't do anything if already at suggested indent
 9653                // and there is any other cursor which is not
 9654                if has_some_cursor_in_whitespace
 9655                    && cursor.column == current_indent.len
 9656                    && current_indent.len == suggested_indent.len
 9657                {
 9658                    continue;
 9659                }
 9660
 9661                // Adjust line and move cursor to suggested indent
 9662                // if cursor is not at suggested indent
 9663                if cursor.column < suggested_indent.len
 9664                    && cursor.column <= current_indent.len
 9665                    && current_indent.len <= suggested_indent.len
 9666                {
 9667                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9668                    selection.end = selection.start;
 9669                    if row_delta == 0 {
 9670                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9671                            cursor.row,
 9672                            current_indent,
 9673                            suggested_indent,
 9674                        ));
 9675                        row_delta = suggested_indent.len - current_indent.len;
 9676                    }
 9677                    continue;
 9678                }
 9679
 9680                // If current indent is more than suggested indent
 9681                // only move cursor to current indent and skip indent
 9682                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9683                    selection.start = Point::new(cursor.row, current_indent.len);
 9684                    selection.end = selection.start;
 9685                    continue;
 9686                }
 9687            }
 9688
 9689            // Otherwise, insert a hard or soft tab.
 9690            let settings = buffer.language_settings_at(cursor, cx);
 9691            let tab_size = if settings.hard_tabs {
 9692                IndentSize::tab()
 9693            } else {
 9694                let tab_size = settings.tab_size.get();
 9695                let indent_remainder = snapshot
 9696                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9697                    .flat_map(str::chars)
 9698                    .fold(row_delta % tab_size, |counter: u32, c| {
 9699                        if c == '\t' {
 9700                            0
 9701                        } else {
 9702                            (counter + 1) % tab_size
 9703                        }
 9704                    });
 9705
 9706                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9707                IndentSize::spaces(chars_to_next_tab_stop)
 9708            };
 9709            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9710            selection.end = selection.start;
 9711            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9712            row_delta += tab_size.len;
 9713        }
 9714
 9715        self.transact(window, cx, |this, window, cx| {
 9716            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9717            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9718                s.select(selections)
 9719            });
 9720            this.refresh_inline_completion(true, false, window, cx);
 9721        });
 9722    }
 9723
 9724    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9725        if self.read_only(cx) {
 9726            return;
 9727        }
 9728        if self.mode.is_single_line() {
 9729            cx.propagate();
 9730            return;
 9731        }
 9732
 9733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9734        let mut selections = self.selections.all::<Point>(cx);
 9735        let mut prev_edited_row = 0;
 9736        let mut row_delta = 0;
 9737        let mut edits = Vec::new();
 9738        let buffer = self.buffer.read(cx);
 9739        let snapshot = buffer.snapshot(cx);
 9740        for selection in &mut selections {
 9741            if selection.start.row != prev_edited_row {
 9742                row_delta = 0;
 9743            }
 9744            prev_edited_row = selection.end.row;
 9745
 9746            row_delta =
 9747                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9748        }
 9749
 9750        self.transact(window, cx, |this, window, cx| {
 9751            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9752            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9753                s.select(selections)
 9754            });
 9755        });
 9756    }
 9757
 9758    fn indent_selection(
 9759        buffer: &MultiBuffer,
 9760        snapshot: &MultiBufferSnapshot,
 9761        selection: &mut Selection<Point>,
 9762        edits: &mut Vec<(Range<Point>, String)>,
 9763        delta_for_start_row: u32,
 9764        cx: &App,
 9765    ) -> u32 {
 9766        let settings = buffer.language_settings_at(selection.start, cx);
 9767        let tab_size = settings.tab_size.get();
 9768        let indent_kind = if settings.hard_tabs {
 9769            IndentKind::Tab
 9770        } else {
 9771            IndentKind::Space
 9772        };
 9773        let mut start_row = selection.start.row;
 9774        let mut end_row = selection.end.row + 1;
 9775
 9776        // If a selection ends at the beginning of a line, don't indent
 9777        // that last line.
 9778        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9779            end_row -= 1;
 9780        }
 9781
 9782        // Avoid re-indenting a row that has already been indented by a
 9783        // previous selection, but still update this selection's column
 9784        // to reflect that indentation.
 9785        if delta_for_start_row > 0 {
 9786            start_row += 1;
 9787            selection.start.column += delta_for_start_row;
 9788            if selection.end.row == selection.start.row {
 9789                selection.end.column += delta_for_start_row;
 9790            }
 9791        }
 9792
 9793        let mut delta_for_end_row = 0;
 9794        let has_multiple_rows = start_row + 1 != end_row;
 9795        for row in start_row..end_row {
 9796            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9797            let indent_delta = match (current_indent.kind, indent_kind) {
 9798                (IndentKind::Space, IndentKind::Space) => {
 9799                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9800                    IndentSize::spaces(columns_to_next_tab_stop)
 9801                }
 9802                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9803                (_, IndentKind::Tab) => IndentSize::tab(),
 9804            };
 9805
 9806            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9807                0
 9808            } else {
 9809                selection.start.column
 9810            };
 9811            let row_start = Point::new(row, start);
 9812            edits.push((
 9813                row_start..row_start,
 9814                indent_delta.chars().collect::<String>(),
 9815            ));
 9816
 9817            // Update this selection's endpoints to reflect the indentation.
 9818            if row == selection.start.row {
 9819                selection.start.column += indent_delta.len;
 9820            }
 9821            if row == selection.end.row {
 9822                selection.end.column += indent_delta.len;
 9823                delta_for_end_row = indent_delta.len;
 9824            }
 9825        }
 9826
 9827        if selection.start.row == selection.end.row {
 9828            delta_for_start_row + delta_for_end_row
 9829        } else {
 9830            delta_for_end_row
 9831        }
 9832    }
 9833
 9834    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9835        if self.read_only(cx) {
 9836            return;
 9837        }
 9838        if self.mode.is_single_line() {
 9839            cx.propagate();
 9840            return;
 9841        }
 9842
 9843        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9844        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9845        let selections = self.selections.all::<Point>(cx);
 9846        let mut deletion_ranges = Vec::new();
 9847        let mut last_outdent = None;
 9848        {
 9849            let buffer = self.buffer.read(cx);
 9850            let snapshot = buffer.snapshot(cx);
 9851            for selection in &selections {
 9852                let settings = buffer.language_settings_at(selection.start, cx);
 9853                let tab_size = settings.tab_size.get();
 9854                let mut rows = selection.spanned_rows(false, &display_map);
 9855
 9856                // Avoid re-outdenting a row that has already been outdented by a
 9857                // previous selection.
 9858                if let Some(last_row) = last_outdent {
 9859                    if last_row == rows.start {
 9860                        rows.start = rows.start.next_row();
 9861                    }
 9862                }
 9863                let has_multiple_rows = rows.len() > 1;
 9864                for row in rows.iter_rows() {
 9865                    let indent_size = snapshot.indent_size_for_line(row);
 9866                    if indent_size.len > 0 {
 9867                        let deletion_len = match indent_size.kind {
 9868                            IndentKind::Space => {
 9869                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9870                                if columns_to_prev_tab_stop == 0 {
 9871                                    tab_size
 9872                                } else {
 9873                                    columns_to_prev_tab_stop
 9874                                }
 9875                            }
 9876                            IndentKind::Tab => 1,
 9877                        };
 9878                        let start = if has_multiple_rows
 9879                            || deletion_len > selection.start.column
 9880                            || indent_size.len < selection.start.column
 9881                        {
 9882                            0
 9883                        } else {
 9884                            selection.start.column - deletion_len
 9885                        };
 9886                        deletion_ranges.push(
 9887                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9888                        );
 9889                        last_outdent = Some(row);
 9890                    }
 9891                }
 9892            }
 9893        }
 9894
 9895        self.transact(window, cx, |this, window, cx| {
 9896            this.buffer.update(cx, |buffer, cx| {
 9897                let empty_str: Arc<str> = Arc::default();
 9898                buffer.edit(
 9899                    deletion_ranges
 9900                        .into_iter()
 9901                        .map(|range| (range, empty_str.clone())),
 9902                    None,
 9903                    cx,
 9904                );
 9905            });
 9906            let selections = this.selections.all::<usize>(cx);
 9907            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9908                s.select(selections)
 9909            });
 9910        });
 9911    }
 9912
 9913    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9914        if self.read_only(cx) {
 9915            return;
 9916        }
 9917        if self.mode.is_single_line() {
 9918            cx.propagate();
 9919            return;
 9920        }
 9921
 9922        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9923        let selections = self
 9924            .selections
 9925            .all::<usize>(cx)
 9926            .into_iter()
 9927            .map(|s| s.range());
 9928
 9929        self.transact(window, cx, |this, window, cx| {
 9930            this.buffer.update(cx, |buffer, cx| {
 9931                buffer.autoindent_ranges(selections, cx);
 9932            });
 9933            let selections = this.selections.all::<usize>(cx);
 9934            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9935                s.select(selections)
 9936            });
 9937        });
 9938    }
 9939
 9940    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9941        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9942        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9943        let selections = self.selections.all::<Point>(cx);
 9944
 9945        let mut new_cursors = Vec::new();
 9946        let mut edit_ranges = Vec::new();
 9947        let mut selections = selections.iter().peekable();
 9948        while let Some(selection) = selections.next() {
 9949            let mut rows = selection.spanned_rows(false, &display_map);
 9950            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9951
 9952            // Accumulate contiguous regions of rows that we want to delete.
 9953            while let Some(next_selection) = selections.peek() {
 9954                let next_rows = next_selection.spanned_rows(false, &display_map);
 9955                if next_rows.start <= rows.end {
 9956                    rows.end = next_rows.end;
 9957                    selections.next().unwrap();
 9958                } else {
 9959                    break;
 9960                }
 9961            }
 9962
 9963            let buffer = &display_map.buffer_snapshot;
 9964            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9965            let edit_end;
 9966            let cursor_buffer_row;
 9967            if buffer.max_point().row >= rows.end.0 {
 9968                // If there's a line after the range, delete the \n from the end of the row range
 9969                // and position the cursor on the next line.
 9970                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9971                cursor_buffer_row = rows.end;
 9972            } else {
 9973                // If there isn't a line after the range, delete the \n from the line before the
 9974                // start of the row range and position the cursor there.
 9975                edit_start = edit_start.saturating_sub(1);
 9976                edit_end = buffer.len();
 9977                cursor_buffer_row = rows.start.previous_row();
 9978            }
 9979
 9980            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9981            *cursor.column_mut() =
 9982                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9983
 9984            new_cursors.push((
 9985                selection.id,
 9986                buffer.anchor_after(cursor.to_point(&display_map)),
 9987            ));
 9988            edit_ranges.push(edit_start..edit_end);
 9989        }
 9990
 9991        self.transact(window, cx, |this, window, cx| {
 9992            let buffer = this.buffer.update(cx, |buffer, cx| {
 9993                let empty_str: Arc<str> = Arc::default();
 9994                buffer.edit(
 9995                    edit_ranges
 9996                        .into_iter()
 9997                        .map(|range| (range, empty_str.clone())),
 9998                    None,
 9999                    cx,
10000                );
10001                buffer.snapshot(cx)
10002            });
10003            let new_selections = new_cursors
10004                .into_iter()
10005                .map(|(id, cursor)| {
10006                    let cursor = cursor.to_point(&buffer);
10007                    Selection {
10008                        id,
10009                        start: cursor,
10010                        end: cursor,
10011                        reversed: false,
10012                        goal: SelectionGoal::None,
10013                    }
10014                })
10015                .collect();
10016
10017            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10018                s.select(new_selections);
10019            });
10020        });
10021    }
10022
10023    pub fn join_lines_impl(
10024        &mut self,
10025        insert_whitespace: bool,
10026        window: &mut Window,
10027        cx: &mut Context<Self>,
10028    ) {
10029        if self.read_only(cx) {
10030            return;
10031        }
10032        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10033        for selection in self.selections.all::<Point>(cx) {
10034            let start = MultiBufferRow(selection.start.row);
10035            // Treat single line selections as if they include the next line. Otherwise this action
10036            // would do nothing for single line selections individual cursors.
10037            let end = if selection.start.row == selection.end.row {
10038                MultiBufferRow(selection.start.row + 1)
10039            } else {
10040                MultiBufferRow(selection.end.row)
10041            };
10042
10043            if let Some(last_row_range) = row_ranges.last_mut() {
10044                if start <= last_row_range.end {
10045                    last_row_range.end = end;
10046                    continue;
10047                }
10048            }
10049            row_ranges.push(start..end);
10050        }
10051
10052        let snapshot = self.buffer.read(cx).snapshot(cx);
10053        let mut cursor_positions = Vec::new();
10054        for row_range in &row_ranges {
10055            let anchor = snapshot.anchor_before(Point::new(
10056                row_range.end.previous_row().0,
10057                snapshot.line_len(row_range.end.previous_row()),
10058            ));
10059            cursor_positions.push(anchor..anchor);
10060        }
10061
10062        self.transact(window, cx, |this, window, cx| {
10063            for row_range in row_ranges.into_iter().rev() {
10064                for row in row_range.iter_rows().rev() {
10065                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10066                    let next_line_row = row.next_row();
10067                    let indent = snapshot.indent_size_for_line(next_line_row);
10068                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10069
10070                    let replace =
10071                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10072                            " "
10073                        } else {
10074                            ""
10075                        };
10076
10077                    this.buffer.update(cx, |buffer, cx| {
10078                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10079                    });
10080                }
10081            }
10082
10083            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10084                s.select_anchor_ranges(cursor_positions)
10085            });
10086        });
10087    }
10088
10089    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10090        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10091        self.join_lines_impl(true, window, cx);
10092    }
10093
10094    pub fn sort_lines_case_sensitive(
10095        &mut self,
10096        _: &SortLinesCaseSensitive,
10097        window: &mut Window,
10098        cx: &mut Context<Self>,
10099    ) {
10100        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10101    }
10102
10103    pub fn sort_lines_case_insensitive(
10104        &mut self,
10105        _: &SortLinesCaseInsensitive,
10106        window: &mut Window,
10107        cx: &mut Context<Self>,
10108    ) {
10109        self.manipulate_immutable_lines(window, cx, |lines| {
10110            lines.sort_by_key(|line| line.to_lowercase())
10111        })
10112    }
10113
10114    pub fn unique_lines_case_insensitive(
10115        &mut self,
10116        _: &UniqueLinesCaseInsensitive,
10117        window: &mut Window,
10118        cx: &mut Context<Self>,
10119    ) {
10120        self.manipulate_immutable_lines(window, cx, |lines| {
10121            let mut seen = HashSet::default();
10122            lines.retain(|line| seen.insert(line.to_lowercase()));
10123        })
10124    }
10125
10126    pub fn unique_lines_case_sensitive(
10127        &mut self,
10128        _: &UniqueLinesCaseSensitive,
10129        window: &mut Window,
10130        cx: &mut Context<Self>,
10131    ) {
10132        self.manipulate_immutable_lines(window, cx, |lines| {
10133            let mut seen = HashSet::default();
10134            lines.retain(|line| seen.insert(*line));
10135        })
10136    }
10137
10138    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10139        let Some(project) = self.project.clone() else {
10140            return;
10141        };
10142        self.reload(project, window, cx)
10143            .detach_and_notify_err(window, cx);
10144    }
10145
10146    pub fn restore_file(
10147        &mut self,
10148        _: &::git::RestoreFile,
10149        window: &mut Window,
10150        cx: &mut Context<Self>,
10151    ) {
10152        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10153        let mut buffer_ids = HashSet::default();
10154        let snapshot = self.buffer().read(cx).snapshot(cx);
10155        for selection in self.selections.all::<usize>(cx) {
10156            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10157        }
10158
10159        let buffer = self.buffer().read(cx);
10160        let ranges = buffer_ids
10161            .into_iter()
10162            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10163            .collect::<Vec<_>>();
10164
10165        self.restore_hunks_in_ranges(ranges, window, cx);
10166    }
10167
10168    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10169        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10170        let selections = self
10171            .selections
10172            .all(cx)
10173            .into_iter()
10174            .map(|s| s.range())
10175            .collect();
10176        self.restore_hunks_in_ranges(selections, window, cx);
10177    }
10178
10179    pub fn restore_hunks_in_ranges(
10180        &mut self,
10181        ranges: Vec<Range<Point>>,
10182        window: &mut Window,
10183        cx: &mut Context<Editor>,
10184    ) {
10185        let mut revert_changes = HashMap::default();
10186        let chunk_by = self
10187            .snapshot(window, cx)
10188            .hunks_for_ranges(ranges)
10189            .into_iter()
10190            .chunk_by(|hunk| hunk.buffer_id);
10191        for (buffer_id, hunks) in &chunk_by {
10192            let hunks = hunks.collect::<Vec<_>>();
10193            for hunk in &hunks {
10194                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10195            }
10196            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10197        }
10198        drop(chunk_by);
10199        if !revert_changes.is_empty() {
10200            self.transact(window, cx, |editor, window, cx| {
10201                editor.restore(revert_changes, window, cx);
10202            });
10203        }
10204    }
10205
10206    pub fn open_active_item_in_terminal(
10207        &mut self,
10208        _: &OpenInTerminal,
10209        window: &mut Window,
10210        cx: &mut Context<Self>,
10211    ) {
10212        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10213            let project_path = buffer.read(cx).project_path(cx)?;
10214            let project = self.project.as_ref()?.read(cx);
10215            let entry = project.entry_for_path(&project_path, cx)?;
10216            let parent = match &entry.canonical_path {
10217                Some(canonical_path) => canonical_path.to_path_buf(),
10218                None => project.absolute_path(&project_path, cx)?,
10219            }
10220            .parent()?
10221            .to_path_buf();
10222            Some(parent)
10223        }) {
10224            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10225        }
10226    }
10227
10228    fn set_breakpoint_context_menu(
10229        &mut self,
10230        display_row: DisplayRow,
10231        position: Option<Anchor>,
10232        clicked_point: gpui::Point<Pixels>,
10233        window: &mut Window,
10234        cx: &mut Context<Self>,
10235    ) {
10236        let source = self
10237            .buffer
10238            .read(cx)
10239            .snapshot(cx)
10240            .anchor_before(Point::new(display_row.0, 0u32));
10241
10242        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10243
10244        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10245            self,
10246            source,
10247            clicked_point,
10248            context_menu,
10249            window,
10250            cx,
10251        );
10252    }
10253
10254    fn add_edit_breakpoint_block(
10255        &mut self,
10256        anchor: Anchor,
10257        breakpoint: &Breakpoint,
10258        edit_action: BreakpointPromptEditAction,
10259        window: &mut Window,
10260        cx: &mut Context<Self>,
10261    ) {
10262        let weak_editor = cx.weak_entity();
10263        let bp_prompt = cx.new(|cx| {
10264            BreakpointPromptEditor::new(
10265                weak_editor,
10266                anchor,
10267                breakpoint.clone(),
10268                edit_action,
10269                window,
10270                cx,
10271            )
10272        });
10273
10274        let height = bp_prompt.update(cx, |this, cx| {
10275            this.prompt
10276                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10277        });
10278        let cloned_prompt = bp_prompt.clone();
10279        let blocks = vec![BlockProperties {
10280            style: BlockStyle::Sticky,
10281            placement: BlockPlacement::Above(anchor),
10282            height: Some(height),
10283            render: Arc::new(move |cx| {
10284                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10285                cloned_prompt.clone().into_any_element()
10286            }),
10287            priority: 0,
10288            render_in_minimap: true,
10289        }];
10290
10291        let focus_handle = bp_prompt.focus_handle(cx);
10292        window.focus(&focus_handle);
10293
10294        let block_ids = self.insert_blocks(blocks, None, cx);
10295        bp_prompt.update(cx, |prompt, _| {
10296            prompt.add_block_ids(block_ids);
10297        });
10298    }
10299
10300    pub(crate) fn breakpoint_at_row(
10301        &self,
10302        row: u32,
10303        window: &mut Window,
10304        cx: &mut Context<Self>,
10305    ) -> Option<(Anchor, Breakpoint)> {
10306        let snapshot = self.snapshot(window, cx);
10307        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10308
10309        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10310    }
10311
10312    pub(crate) fn breakpoint_at_anchor(
10313        &self,
10314        breakpoint_position: Anchor,
10315        snapshot: &EditorSnapshot,
10316        cx: &mut Context<Self>,
10317    ) -> Option<(Anchor, Breakpoint)> {
10318        let project = self.project.clone()?;
10319
10320        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10321            snapshot
10322                .buffer_snapshot
10323                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10324        })?;
10325
10326        let enclosing_excerpt = breakpoint_position.excerpt_id;
10327        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10328        let buffer_snapshot = buffer.read(cx).snapshot();
10329
10330        let row = buffer_snapshot
10331            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10332            .row;
10333
10334        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10335        let anchor_end = snapshot
10336            .buffer_snapshot
10337            .anchor_after(Point::new(row, line_len));
10338
10339        let bp = self
10340            .breakpoint_store
10341            .as_ref()?
10342            .read_with(cx, |breakpoint_store, cx| {
10343                breakpoint_store
10344                    .breakpoints(
10345                        &buffer,
10346                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10347                        &buffer_snapshot,
10348                        cx,
10349                    )
10350                    .next()
10351                    .and_then(|(bp, _)| {
10352                        let breakpoint_row = buffer_snapshot
10353                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10354                            .row;
10355
10356                        if breakpoint_row == row {
10357                            snapshot
10358                                .buffer_snapshot
10359                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10360                                .map(|position| (position, bp.bp.clone()))
10361                        } else {
10362                            None
10363                        }
10364                    })
10365            });
10366        bp
10367    }
10368
10369    pub fn edit_log_breakpoint(
10370        &mut self,
10371        _: &EditLogBreakpoint,
10372        window: &mut Window,
10373        cx: &mut Context<Self>,
10374    ) {
10375        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10376            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10377                message: None,
10378                state: BreakpointState::Enabled,
10379                condition: None,
10380                hit_condition: None,
10381            });
10382
10383            self.add_edit_breakpoint_block(
10384                anchor,
10385                &breakpoint,
10386                BreakpointPromptEditAction::Log,
10387                window,
10388                cx,
10389            );
10390        }
10391    }
10392
10393    fn breakpoints_at_cursors(
10394        &self,
10395        window: &mut Window,
10396        cx: &mut Context<Self>,
10397    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10398        let snapshot = self.snapshot(window, cx);
10399        let cursors = self
10400            .selections
10401            .disjoint_anchors()
10402            .into_iter()
10403            .map(|selection| {
10404                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10405
10406                let breakpoint_position = self
10407                    .breakpoint_at_row(cursor_position.row, window, cx)
10408                    .map(|bp| bp.0)
10409                    .unwrap_or_else(|| {
10410                        snapshot
10411                            .display_snapshot
10412                            .buffer_snapshot
10413                            .anchor_after(Point::new(cursor_position.row, 0))
10414                    });
10415
10416                let breakpoint = self
10417                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10418                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10419
10420                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10421            })
10422            // 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.
10423            .collect::<HashMap<Anchor, _>>();
10424
10425        cursors.into_iter().collect()
10426    }
10427
10428    pub fn enable_breakpoint(
10429        &mut self,
10430        _: &crate::actions::EnableBreakpoint,
10431        window: &mut Window,
10432        cx: &mut Context<Self>,
10433    ) {
10434        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10435            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10436                continue;
10437            };
10438            self.edit_breakpoint_at_anchor(
10439                anchor,
10440                breakpoint,
10441                BreakpointEditAction::InvertState,
10442                cx,
10443            );
10444        }
10445    }
10446
10447    pub fn disable_breakpoint(
10448        &mut self,
10449        _: &crate::actions::DisableBreakpoint,
10450        window: &mut Window,
10451        cx: &mut Context<Self>,
10452    ) {
10453        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10454            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10455                continue;
10456            };
10457            self.edit_breakpoint_at_anchor(
10458                anchor,
10459                breakpoint,
10460                BreakpointEditAction::InvertState,
10461                cx,
10462            );
10463        }
10464    }
10465
10466    pub fn toggle_breakpoint(
10467        &mut self,
10468        _: &crate::actions::ToggleBreakpoint,
10469        window: &mut Window,
10470        cx: &mut Context<Self>,
10471    ) {
10472        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10473            if let Some(breakpoint) = breakpoint {
10474                self.edit_breakpoint_at_anchor(
10475                    anchor,
10476                    breakpoint,
10477                    BreakpointEditAction::Toggle,
10478                    cx,
10479                );
10480            } else {
10481                self.edit_breakpoint_at_anchor(
10482                    anchor,
10483                    Breakpoint::new_standard(),
10484                    BreakpointEditAction::Toggle,
10485                    cx,
10486                );
10487            }
10488        }
10489    }
10490
10491    pub fn edit_breakpoint_at_anchor(
10492        &mut self,
10493        breakpoint_position: Anchor,
10494        breakpoint: Breakpoint,
10495        edit_action: BreakpointEditAction,
10496        cx: &mut Context<Self>,
10497    ) {
10498        let Some(breakpoint_store) = &self.breakpoint_store else {
10499            return;
10500        };
10501
10502        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10503            if breakpoint_position == Anchor::min() {
10504                self.buffer()
10505                    .read(cx)
10506                    .excerpt_buffer_ids()
10507                    .into_iter()
10508                    .next()
10509            } else {
10510                None
10511            }
10512        }) else {
10513            return;
10514        };
10515
10516        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10517            return;
10518        };
10519
10520        breakpoint_store.update(cx, |breakpoint_store, cx| {
10521            breakpoint_store.toggle_breakpoint(
10522                buffer,
10523                BreakpointWithPosition {
10524                    position: breakpoint_position.text_anchor,
10525                    bp: breakpoint,
10526                },
10527                edit_action,
10528                cx,
10529            );
10530        });
10531
10532        cx.notify();
10533    }
10534
10535    #[cfg(any(test, feature = "test-support"))]
10536    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10537        self.breakpoint_store.clone()
10538    }
10539
10540    pub fn prepare_restore_change(
10541        &self,
10542        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10543        hunk: &MultiBufferDiffHunk,
10544        cx: &mut App,
10545    ) -> Option<()> {
10546        if hunk.is_created_file() {
10547            return None;
10548        }
10549        let buffer = self.buffer.read(cx);
10550        let diff = buffer.diff_for(hunk.buffer_id)?;
10551        let buffer = buffer.buffer(hunk.buffer_id)?;
10552        let buffer = buffer.read(cx);
10553        let original_text = diff
10554            .read(cx)
10555            .base_text()
10556            .as_rope()
10557            .slice(hunk.diff_base_byte_range.clone());
10558        let buffer_snapshot = buffer.snapshot();
10559        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10560        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10561            probe
10562                .0
10563                .start
10564                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10565                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10566        }) {
10567            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10568            Some(())
10569        } else {
10570            None
10571        }
10572    }
10573
10574    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10575        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10576    }
10577
10578    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10579        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10580    }
10581
10582    fn manipulate_lines<M>(
10583        &mut self,
10584        window: &mut Window,
10585        cx: &mut Context<Self>,
10586        mut manipulate: M,
10587    ) where
10588        M: FnMut(&str) -> LineManipulationResult,
10589    {
10590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10591
10592        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10593        let buffer = self.buffer.read(cx).snapshot(cx);
10594
10595        let mut edits = Vec::new();
10596
10597        let selections = self.selections.all::<Point>(cx);
10598        let mut selections = selections.iter().peekable();
10599        let mut contiguous_row_selections = Vec::new();
10600        let mut new_selections = Vec::new();
10601        let mut added_lines = 0;
10602        let mut removed_lines = 0;
10603
10604        while let Some(selection) = selections.next() {
10605            let (start_row, end_row) = consume_contiguous_rows(
10606                &mut contiguous_row_selections,
10607                selection,
10608                &display_map,
10609                &mut selections,
10610            );
10611
10612            let start_point = Point::new(start_row.0, 0);
10613            let end_point = Point::new(
10614                end_row.previous_row().0,
10615                buffer.line_len(end_row.previous_row()),
10616            );
10617            let text = buffer
10618                .text_for_range(start_point..end_point)
10619                .collect::<String>();
10620
10621            let LineManipulationResult {
10622                new_text,
10623                line_count_before,
10624                line_count_after,
10625            } = manipulate(&text);
10626
10627            edits.push((start_point..end_point, new_text));
10628
10629            // Selections must change based on added and removed line count
10630            let start_row =
10631                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10632            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10633            new_selections.push(Selection {
10634                id: selection.id,
10635                start: start_row,
10636                end: end_row,
10637                goal: SelectionGoal::None,
10638                reversed: selection.reversed,
10639            });
10640
10641            if line_count_after > line_count_before {
10642                added_lines += line_count_after - line_count_before;
10643            } else if line_count_before > line_count_after {
10644                removed_lines += line_count_before - line_count_after;
10645            }
10646        }
10647
10648        self.transact(window, cx, |this, window, cx| {
10649            let buffer = this.buffer.update(cx, |buffer, cx| {
10650                buffer.edit(edits, None, cx);
10651                buffer.snapshot(cx)
10652            });
10653
10654            // Recalculate offsets on newly edited buffer
10655            let new_selections = new_selections
10656                .iter()
10657                .map(|s| {
10658                    let start_point = Point::new(s.start.0, 0);
10659                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10660                    Selection {
10661                        id: s.id,
10662                        start: buffer.point_to_offset(start_point),
10663                        end: buffer.point_to_offset(end_point),
10664                        goal: s.goal,
10665                        reversed: s.reversed,
10666                    }
10667                })
10668                .collect();
10669
10670            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10671                s.select(new_selections);
10672            });
10673
10674            this.request_autoscroll(Autoscroll::fit(), cx);
10675        });
10676    }
10677
10678    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10679        self.manipulate_text(window, cx, |text| {
10680            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10681            if has_upper_case_characters {
10682                text.to_lowercase()
10683            } else {
10684                text.to_uppercase()
10685            }
10686        })
10687    }
10688
10689    fn manipulate_immutable_lines<Fn>(
10690        &mut self,
10691        window: &mut Window,
10692        cx: &mut Context<Self>,
10693        mut callback: Fn,
10694    ) where
10695        Fn: FnMut(&mut Vec<&str>),
10696    {
10697        self.manipulate_lines(window, cx, |text| {
10698            let mut lines: Vec<&str> = text.split('\n').collect();
10699            let line_count_before = lines.len();
10700
10701            callback(&mut lines);
10702
10703            LineManipulationResult {
10704                new_text: lines.join("\n"),
10705                line_count_before,
10706                line_count_after: lines.len(),
10707            }
10708        });
10709    }
10710
10711    fn manipulate_mutable_lines<Fn>(
10712        &mut self,
10713        window: &mut Window,
10714        cx: &mut Context<Self>,
10715        mut callback: Fn,
10716    ) where
10717        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10718    {
10719        self.manipulate_lines(window, cx, |text| {
10720            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10721            let line_count_before = lines.len();
10722
10723            callback(&mut lines);
10724
10725            LineManipulationResult {
10726                new_text: lines.join("\n"),
10727                line_count_before,
10728                line_count_after: lines.len(),
10729            }
10730        });
10731    }
10732
10733    pub fn convert_indentation_to_spaces(
10734        &mut self,
10735        _: &ConvertIndentationToSpaces,
10736        window: &mut Window,
10737        cx: &mut Context<Self>,
10738    ) {
10739        let settings = self.buffer.read(cx).language_settings(cx);
10740        let tab_size = settings.tab_size.get() as usize;
10741
10742        self.manipulate_mutable_lines(window, cx, |lines| {
10743            // Allocates a reasonably sized scratch buffer once for the whole loop
10744            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10745            // Avoids recomputing spaces that could be inserted many times
10746            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10747                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10748                .collect();
10749
10750            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10751                let mut chars = line.as_ref().chars();
10752                let mut col = 0;
10753                let mut changed = false;
10754
10755                while let Some(ch) = chars.next() {
10756                    match ch {
10757                        ' ' => {
10758                            reindented_line.push(' ');
10759                            col += 1;
10760                        }
10761                        '\t' => {
10762                            // \t are converted to spaces depending on the current column
10763                            let spaces_len = tab_size - (col % tab_size);
10764                            reindented_line.extend(&space_cache[spaces_len - 1]);
10765                            col += spaces_len;
10766                            changed = true;
10767                        }
10768                        _ => {
10769                            // If we dont append before break, the character is consumed
10770                            reindented_line.push(ch);
10771                            break;
10772                        }
10773                    }
10774                }
10775
10776                if !changed {
10777                    reindented_line.clear();
10778                    continue;
10779                }
10780                // Append the rest of the line and replace old reference with new one
10781                reindented_line.extend(chars);
10782                *line = Cow::Owned(reindented_line.clone());
10783                reindented_line.clear();
10784            }
10785        });
10786    }
10787
10788    pub fn convert_indentation_to_tabs(
10789        &mut self,
10790        _: &ConvertIndentationToTabs,
10791        window: &mut Window,
10792        cx: &mut Context<Self>,
10793    ) {
10794        let settings = self.buffer.read(cx).language_settings(cx);
10795        let tab_size = settings.tab_size.get() as usize;
10796
10797        self.manipulate_mutable_lines(window, cx, |lines| {
10798            // Allocates a reasonably sized buffer once for the whole loop
10799            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10800            // Avoids recomputing spaces that could be inserted many times
10801            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10802                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10803                .collect();
10804
10805            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10806                let mut chars = line.chars();
10807                let mut spaces_count = 0;
10808                let mut first_non_indent_char = None;
10809                let mut changed = false;
10810
10811                while let Some(ch) = chars.next() {
10812                    match ch {
10813                        ' ' => {
10814                            // Keep track of spaces. Append \t when we reach tab_size
10815                            spaces_count += 1;
10816                            changed = true;
10817                            if spaces_count == tab_size {
10818                                reindented_line.push('\t');
10819                                spaces_count = 0;
10820                            }
10821                        }
10822                        '\t' => {
10823                            reindented_line.push('\t');
10824                            spaces_count = 0;
10825                        }
10826                        _ => {
10827                            // Dont append it yet, we might have remaining spaces
10828                            first_non_indent_char = Some(ch);
10829                            break;
10830                        }
10831                    }
10832                }
10833
10834                if !changed {
10835                    reindented_line.clear();
10836                    continue;
10837                }
10838                // Remaining spaces that didn't make a full tab stop
10839                if spaces_count > 0 {
10840                    reindented_line.extend(&space_cache[spaces_count - 1]);
10841                }
10842                // If we consume an extra character that was not indentation, add it back
10843                if let Some(extra_char) = first_non_indent_char {
10844                    reindented_line.push(extra_char);
10845                }
10846                // Append the rest of the line and replace old reference with new one
10847                reindented_line.extend(chars);
10848                *line = Cow::Owned(reindented_line.clone());
10849                reindented_line.clear();
10850            }
10851        });
10852    }
10853
10854    pub fn convert_to_upper_case(
10855        &mut self,
10856        _: &ConvertToUpperCase,
10857        window: &mut Window,
10858        cx: &mut Context<Self>,
10859    ) {
10860        self.manipulate_text(window, cx, |text| text.to_uppercase())
10861    }
10862
10863    pub fn convert_to_lower_case(
10864        &mut self,
10865        _: &ConvertToLowerCase,
10866        window: &mut Window,
10867        cx: &mut Context<Self>,
10868    ) {
10869        self.manipulate_text(window, cx, |text| text.to_lowercase())
10870    }
10871
10872    pub fn convert_to_title_case(
10873        &mut self,
10874        _: &ConvertToTitleCase,
10875        window: &mut Window,
10876        cx: &mut Context<Self>,
10877    ) {
10878        self.manipulate_text(window, cx, |text| {
10879            text.split('\n')
10880                .map(|line| line.to_case(Case::Title))
10881                .join("\n")
10882        })
10883    }
10884
10885    pub fn convert_to_snake_case(
10886        &mut self,
10887        _: &ConvertToSnakeCase,
10888        window: &mut Window,
10889        cx: &mut Context<Self>,
10890    ) {
10891        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10892    }
10893
10894    pub fn convert_to_kebab_case(
10895        &mut self,
10896        _: &ConvertToKebabCase,
10897        window: &mut Window,
10898        cx: &mut Context<Self>,
10899    ) {
10900        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10901    }
10902
10903    pub fn convert_to_upper_camel_case(
10904        &mut self,
10905        _: &ConvertToUpperCamelCase,
10906        window: &mut Window,
10907        cx: &mut Context<Self>,
10908    ) {
10909        self.manipulate_text(window, cx, |text| {
10910            text.split('\n')
10911                .map(|line| line.to_case(Case::UpperCamel))
10912                .join("\n")
10913        })
10914    }
10915
10916    pub fn convert_to_lower_camel_case(
10917        &mut self,
10918        _: &ConvertToLowerCamelCase,
10919        window: &mut Window,
10920        cx: &mut Context<Self>,
10921    ) {
10922        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10923    }
10924
10925    pub fn convert_to_opposite_case(
10926        &mut self,
10927        _: &ConvertToOppositeCase,
10928        window: &mut Window,
10929        cx: &mut Context<Self>,
10930    ) {
10931        self.manipulate_text(window, cx, |text| {
10932            text.chars()
10933                .fold(String::with_capacity(text.len()), |mut t, c| {
10934                    if c.is_uppercase() {
10935                        t.extend(c.to_lowercase());
10936                    } else {
10937                        t.extend(c.to_uppercase());
10938                    }
10939                    t
10940                })
10941        })
10942    }
10943
10944    pub fn convert_to_rot13(
10945        &mut self,
10946        _: &ConvertToRot13,
10947        window: &mut Window,
10948        cx: &mut Context<Self>,
10949    ) {
10950        self.manipulate_text(window, cx, |text| {
10951            text.chars()
10952                .map(|c| match c {
10953                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10954                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10955                    _ => c,
10956                })
10957                .collect()
10958        })
10959    }
10960
10961    pub fn convert_to_rot47(
10962        &mut self,
10963        _: &ConvertToRot47,
10964        window: &mut Window,
10965        cx: &mut Context<Self>,
10966    ) {
10967        self.manipulate_text(window, cx, |text| {
10968            text.chars()
10969                .map(|c| {
10970                    let code_point = c as u32;
10971                    if code_point >= 33 && code_point <= 126 {
10972                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10973                    }
10974                    c
10975                })
10976                .collect()
10977        })
10978    }
10979
10980    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10981    where
10982        Fn: FnMut(&str) -> String,
10983    {
10984        let buffer = self.buffer.read(cx).snapshot(cx);
10985
10986        let mut new_selections = Vec::new();
10987        let mut edits = Vec::new();
10988        let mut selection_adjustment = 0i32;
10989
10990        for selection in self.selections.all::<usize>(cx) {
10991            let selection_is_empty = selection.is_empty();
10992
10993            let (start, end) = if selection_is_empty {
10994                let (word_range, _) = buffer.surrounding_word(selection.start, false);
10995                (word_range.start, word_range.end)
10996            } else {
10997                (selection.start, selection.end)
10998            };
10999
11000            let text = buffer.text_for_range(start..end).collect::<String>();
11001            let old_length = text.len() as i32;
11002            let text = callback(&text);
11003
11004            new_selections.push(Selection {
11005                start: (start as i32 - selection_adjustment) as usize,
11006                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11007                goal: SelectionGoal::None,
11008                ..selection
11009            });
11010
11011            selection_adjustment += old_length - text.len() as i32;
11012
11013            edits.push((start..end, text));
11014        }
11015
11016        self.transact(window, cx, |this, window, cx| {
11017            this.buffer.update(cx, |buffer, cx| {
11018                buffer.edit(edits, None, cx);
11019            });
11020
11021            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11022                s.select(new_selections);
11023            });
11024
11025            this.request_autoscroll(Autoscroll::fit(), cx);
11026        });
11027    }
11028
11029    pub fn move_selection_on_drop(
11030        &mut self,
11031        selection: &Selection<Anchor>,
11032        target: DisplayPoint,
11033        is_cut: bool,
11034        window: &mut Window,
11035        cx: &mut Context<Self>,
11036    ) {
11037        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11038        let buffer = &display_map.buffer_snapshot;
11039        let mut edits = Vec::new();
11040        let insert_point = display_map
11041            .clip_point(target, Bias::Left)
11042            .to_point(&display_map);
11043        let text = buffer
11044            .text_for_range(selection.start..selection.end)
11045            .collect::<String>();
11046        if is_cut {
11047            edits.push(((selection.start..selection.end), String::new()));
11048        }
11049        let insert_anchor = buffer.anchor_before(insert_point);
11050        edits.push(((insert_anchor..insert_anchor), text));
11051        let last_edit_start = insert_anchor.bias_left(buffer);
11052        let last_edit_end = insert_anchor.bias_right(buffer);
11053        self.transact(window, cx, |this, window, cx| {
11054            this.buffer.update(cx, |buffer, cx| {
11055                buffer.edit(edits, None, cx);
11056            });
11057            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11058                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11059            });
11060        });
11061    }
11062
11063    pub fn clear_selection_drag_state(&mut self) {
11064        self.selection_drag_state = SelectionDragState::None;
11065    }
11066
11067    pub fn duplicate(
11068        &mut self,
11069        upwards: bool,
11070        whole_lines: bool,
11071        window: &mut Window,
11072        cx: &mut Context<Self>,
11073    ) {
11074        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11075
11076        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11077        let buffer = &display_map.buffer_snapshot;
11078        let selections = self.selections.all::<Point>(cx);
11079
11080        let mut edits = Vec::new();
11081        let mut selections_iter = selections.iter().peekable();
11082        while let Some(selection) = selections_iter.next() {
11083            let mut rows = selection.spanned_rows(false, &display_map);
11084            // duplicate line-wise
11085            if whole_lines || selection.start == selection.end {
11086                // Avoid duplicating the same lines twice.
11087                while let Some(next_selection) = selections_iter.peek() {
11088                    let next_rows = next_selection.spanned_rows(false, &display_map);
11089                    if next_rows.start < rows.end {
11090                        rows.end = next_rows.end;
11091                        selections_iter.next().unwrap();
11092                    } else {
11093                        break;
11094                    }
11095                }
11096
11097                // Copy the text from the selected row region and splice it either at the start
11098                // or end of the region.
11099                let start = Point::new(rows.start.0, 0);
11100                let end = Point::new(
11101                    rows.end.previous_row().0,
11102                    buffer.line_len(rows.end.previous_row()),
11103                );
11104                let text = buffer
11105                    .text_for_range(start..end)
11106                    .chain(Some("\n"))
11107                    .collect::<String>();
11108                let insert_location = if upwards {
11109                    Point::new(rows.end.0, 0)
11110                } else {
11111                    start
11112                };
11113                edits.push((insert_location..insert_location, text));
11114            } else {
11115                // duplicate character-wise
11116                let start = selection.start;
11117                let end = selection.end;
11118                let text = buffer.text_for_range(start..end).collect::<String>();
11119                edits.push((selection.end..selection.end, text));
11120            }
11121        }
11122
11123        self.transact(window, cx, |this, _, cx| {
11124            this.buffer.update(cx, |buffer, cx| {
11125                buffer.edit(edits, None, cx);
11126            });
11127
11128            this.request_autoscroll(Autoscroll::fit(), cx);
11129        });
11130    }
11131
11132    pub fn duplicate_line_up(
11133        &mut self,
11134        _: &DuplicateLineUp,
11135        window: &mut Window,
11136        cx: &mut Context<Self>,
11137    ) {
11138        self.duplicate(true, true, window, cx);
11139    }
11140
11141    pub fn duplicate_line_down(
11142        &mut self,
11143        _: &DuplicateLineDown,
11144        window: &mut Window,
11145        cx: &mut Context<Self>,
11146    ) {
11147        self.duplicate(false, true, window, cx);
11148    }
11149
11150    pub fn duplicate_selection(
11151        &mut self,
11152        _: &DuplicateSelection,
11153        window: &mut Window,
11154        cx: &mut Context<Self>,
11155    ) {
11156        self.duplicate(false, false, window, cx);
11157    }
11158
11159    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11160        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11161        if self.mode.is_single_line() {
11162            cx.propagate();
11163            return;
11164        }
11165
11166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11167        let buffer = self.buffer.read(cx).snapshot(cx);
11168
11169        let mut edits = Vec::new();
11170        let mut unfold_ranges = Vec::new();
11171        let mut refold_creases = Vec::new();
11172
11173        let selections = self.selections.all::<Point>(cx);
11174        let mut selections = selections.iter().peekable();
11175        let mut contiguous_row_selections = Vec::new();
11176        let mut new_selections = Vec::new();
11177
11178        while let Some(selection) = selections.next() {
11179            // Find all the selections that span a contiguous row range
11180            let (start_row, end_row) = consume_contiguous_rows(
11181                &mut contiguous_row_selections,
11182                selection,
11183                &display_map,
11184                &mut selections,
11185            );
11186
11187            // Move the text spanned by the row range to be before the line preceding the row range
11188            if start_row.0 > 0 {
11189                let range_to_move = Point::new(
11190                    start_row.previous_row().0,
11191                    buffer.line_len(start_row.previous_row()),
11192                )
11193                    ..Point::new(
11194                        end_row.previous_row().0,
11195                        buffer.line_len(end_row.previous_row()),
11196                    );
11197                let insertion_point = display_map
11198                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11199                    .0;
11200
11201                // Don't move lines across excerpts
11202                if buffer
11203                    .excerpt_containing(insertion_point..range_to_move.end)
11204                    .is_some()
11205                {
11206                    let text = buffer
11207                        .text_for_range(range_to_move.clone())
11208                        .flat_map(|s| s.chars())
11209                        .skip(1)
11210                        .chain(['\n'])
11211                        .collect::<String>();
11212
11213                    edits.push((
11214                        buffer.anchor_after(range_to_move.start)
11215                            ..buffer.anchor_before(range_to_move.end),
11216                        String::new(),
11217                    ));
11218                    let insertion_anchor = buffer.anchor_after(insertion_point);
11219                    edits.push((insertion_anchor..insertion_anchor, text));
11220
11221                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11222
11223                    // Move selections up
11224                    new_selections.extend(contiguous_row_selections.drain(..).map(
11225                        |mut selection| {
11226                            selection.start.row -= row_delta;
11227                            selection.end.row -= row_delta;
11228                            selection
11229                        },
11230                    ));
11231
11232                    // Move folds up
11233                    unfold_ranges.push(range_to_move.clone());
11234                    for fold in display_map.folds_in_range(
11235                        buffer.anchor_before(range_to_move.start)
11236                            ..buffer.anchor_after(range_to_move.end),
11237                    ) {
11238                        let mut start = fold.range.start.to_point(&buffer);
11239                        let mut end = fold.range.end.to_point(&buffer);
11240                        start.row -= row_delta;
11241                        end.row -= row_delta;
11242                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11243                    }
11244                }
11245            }
11246
11247            // If we didn't move line(s), preserve the existing selections
11248            new_selections.append(&mut contiguous_row_selections);
11249        }
11250
11251        self.transact(window, cx, |this, window, cx| {
11252            this.unfold_ranges(&unfold_ranges, true, true, cx);
11253            this.buffer.update(cx, |buffer, cx| {
11254                for (range, text) in edits {
11255                    buffer.edit([(range, text)], None, cx);
11256                }
11257            });
11258            this.fold_creases(refold_creases, true, window, cx);
11259            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11260                s.select(new_selections);
11261            })
11262        });
11263    }
11264
11265    pub fn move_line_down(
11266        &mut self,
11267        _: &MoveLineDown,
11268        window: &mut Window,
11269        cx: &mut Context<Self>,
11270    ) {
11271        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11272        if self.mode.is_single_line() {
11273            cx.propagate();
11274            return;
11275        }
11276
11277        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11278        let buffer = self.buffer.read(cx).snapshot(cx);
11279
11280        let mut edits = Vec::new();
11281        let mut unfold_ranges = Vec::new();
11282        let mut refold_creases = Vec::new();
11283
11284        let selections = self.selections.all::<Point>(cx);
11285        let mut selections = selections.iter().peekable();
11286        let mut contiguous_row_selections = Vec::new();
11287        let mut new_selections = Vec::new();
11288
11289        while let Some(selection) = selections.next() {
11290            // Find all the selections that span a contiguous row range
11291            let (start_row, end_row) = consume_contiguous_rows(
11292                &mut contiguous_row_selections,
11293                selection,
11294                &display_map,
11295                &mut selections,
11296            );
11297
11298            // Move the text spanned by the row range to be after the last line of the row range
11299            if end_row.0 <= buffer.max_point().row {
11300                let range_to_move =
11301                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11302                let insertion_point = display_map
11303                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11304                    .0;
11305
11306                // Don't move lines across excerpt boundaries
11307                if buffer
11308                    .excerpt_containing(range_to_move.start..insertion_point)
11309                    .is_some()
11310                {
11311                    let mut text = String::from("\n");
11312                    text.extend(buffer.text_for_range(range_to_move.clone()));
11313                    text.pop(); // Drop trailing newline
11314                    edits.push((
11315                        buffer.anchor_after(range_to_move.start)
11316                            ..buffer.anchor_before(range_to_move.end),
11317                        String::new(),
11318                    ));
11319                    let insertion_anchor = buffer.anchor_after(insertion_point);
11320                    edits.push((insertion_anchor..insertion_anchor, text));
11321
11322                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11323
11324                    // Move selections down
11325                    new_selections.extend(contiguous_row_selections.drain(..).map(
11326                        |mut selection| {
11327                            selection.start.row += row_delta;
11328                            selection.end.row += row_delta;
11329                            selection
11330                        },
11331                    ));
11332
11333                    // Move folds down
11334                    unfold_ranges.push(range_to_move.clone());
11335                    for fold in display_map.folds_in_range(
11336                        buffer.anchor_before(range_to_move.start)
11337                            ..buffer.anchor_after(range_to_move.end),
11338                    ) {
11339                        let mut start = fold.range.start.to_point(&buffer);
11340                        let mut end = fold.range.end.to_point(&buffer);
11341                        start.row += row_delta;
11342                        end.row += row_delta;
11343                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11344                    }
11345                }
11346            }
11347
11348            // If we didn't move line(s), preserve the existing selections
11349            new_selections.append(&mut contiguous_row_selections);
11350        }
11351
11352        self.transact(window, cx, |this, window, cx| {
11353            this.unfold_ranges(&unfold_ranges, true, true, cx);
11354            this.buffer.update(cx, |buffer, cx| {
11355                for (range, text) in edits {
11356                    buffer.edit([(range, text)], None, cx);
11357                }
11358            });
11359            this.fold_creases(refold_creases, true, window, cx);
11360            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11361                s.select(new_selections)
11362            });
11363        });
11364    }
11365
11366    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11367        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11368        let text_layout_details = &self.text_layout_details(window);
11369        self.transact(window, cx, |this, window, cx| {
11370            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11371                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11372                s.move_with(|display_map, selection| {
11373                    if !selection.is_empty() {
11374                        return;
11375                    }
11376
11377                    let mut head = selection.head();
11378                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11379                    if head.column() == display_map.line_len(head.row()) {
11380                        transpose_offset = display_map
11381                            .buffer_snapshot
11382                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11383                    }
11384
11385                    if transpose_offset == 0 {
11386                        return;
11387                    }
11388
11389                    *head.column_mut() += 1;
11390                    head = display_map.clip_point(head, Bias::Right);
11391                    let goal = SelectionGoal::HorizontalPosition(
11392                        display_map
11393                            .x_for_display_point(head, text_layout_details)
11394                            .into(),
11395                    );
11396                    selection.collapse_to(head, goal);
11397
11398                    let transpose_start = display_map
11399                        .buffer_snapshot
11400                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11401                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11402                        let transpose_end = display_map
11403                            .buffer_snapshot
11404                            .clip_offset(transpose_offset + 1, Bias::Right);
11405                        if let Some(ch) =
11406                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11407                        {
11408                            edits.push((transpose_start..transpose_offset, String::new()));
11409                            edits.push((transpose_end..transpose_end, ch.to_string()));
11410                        }
11411                    }
11412                });
11413                edits
11414            });
11415            this.buffer
11416                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11417            let selections = this.selections.all::<usize>(cx);
11418            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11419                s.select(selections);
11420            });
11421        });
11422    }
11423
11424    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11425        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11426        if self.mode.is_single_line() {
11427            cx.propagate();
11428            return;
11429        }
11430
11431        self.rewrap_impl(RewrapOptions::default(), cx)
11432    }
11433
11434    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11435        let buffer = self.buffer.read(cx).snapshot(cx);
11436        let selections = self.selections.all::<Point>(cx);
11437
11438        // Shrink and split selections to respect paragraph boundaries.
11439        let ranges = selections.into_iter().flat_map(|selection| {
11440            let language_settings = buffer.language_settings_at(selection.head(), cx);
11441            let language_scope = buffer.language_scope_at(selection.head());
11442
11443            let Some(start_row) = (selection.start.row..=selection.end.row)
11444                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11445            else {
11446                return vec![];
11447            };
11448            let Some(end_row) = (selection.start.row..=selection.end.row)
11449                .rev()
11450                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11451            else {
11452                return vec![];
11453            };
11454
11455            let mut row = start_row;
11456            let mut ranges = Vec::new();
11457            while let Some(blank_row) =
11458                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11459            {
11460                let next_paragraph_start = (blank_row + 1..=end_row)
11461                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11462                    .unwrap();
11463                ranges.push((
11464                    language_settings.clone(),
11465                    language_scope.clone(),
11466                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11467                ));
11468                row = next_paragraph_start;
11469            }
11470            ranges.push((
11471                language_settings.clone(),
11472                language_scope.clone(),
11473                Point::new(row, 0)..Point::new(end_row, 0),
11474            ));
11475
11476            ranges
11477        });
11478
11479        let mut edits = Vec::new();
11480        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11481
11482        for (language_settings, language_scope, range) in ranges {
11483            let mut start_row = range.start.row;
11484            let mut end_row = range.end.row;
11485
11486            // Skip selections that overlap with a range that has already been rewrapped.
11487            let selection_range = start_row..end_row;
11488            if rewrapped_row_ranges
11489                .iter()
11490                .any(|range| range.overlaps(&selection_range))
11491            {
11492                continue;
11493            }
11494
11495            let tab_size = language_settings.tab_size;
11496
11497            // Since not all lines in the selection may be at the same indent
11498            // level, choose the indent size that is the most common between all
11499            // of the lines.
11500            //
11501            // If there is a tie, we use the deepest indent.
11502            let (indent_size, indent_end) = {
11503                let mut indent_size_occurrences = HashMap::default();
11504                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11505
11506                for row in start_row..=end_row {
11507                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11508                    rows_by_indent_size.entry(indent).or_default().push(row);
11509                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11510                }
11511
11512                let indent_size = indent_size_occurrences
11513                    .into_iter()
11514                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11515                    .map(|(indent, _)| indent)
11516                    .unwrap_or_default();
11517                let row = rows_by_indent_size[&indent_size][0];
11518                let indent_end = Point::new(row, indent_size.len);
11519
11520                (indent_size, indent_end)
11521            };
11522
11523            let mut line_prefix = indent_size.chars().collect::<String>();
11524
11525            let mut inside_comment = false;
11526            if let Some(comment_prefix) = language_scope.and_then(|language| {
11527                language
11528                    .line_comment_prefixes()
11529                    .iter()
11530                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11531                    .cloned()
11532            }) {
11533                line_prefix.push_str(&comment_prefix);
11534                inside_comment = true;
11535            }
11536
11537            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11538                RewrapBehavior::InComments => inside_comment,
11539                RewrapBehavior::InSelections => !range.is_empty(),
11540                RewrapBehavior::Anywhere => true,
11541            };
11542
11543            let should_rewrap = options.override_language_settings
11544                || allow_rewrap_based_on_language
11545                || self.hard_wrap.is_some();
11546            if !should_rewrap {
11547                continue;
11548            }
11549
11550            if range.is_empty() {
11551                'expand_upwards: while start_row > 0 {
11552                    let prev_row = start_row - 1;
11553                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11554                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11555                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11556                    {
11557                        start_row = prev_row;
11558                    } else {
11559                        break 'expand_upwards;
11560                    }
11561                }
11562
11563                'expand_downwards: while end_row < buffer.max_point().row {
11564                    let next_row = end_row + 1;
11565                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11566                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11567                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11568                    {
11569                        end_row = next_row;
11570                    } else {
11571                        break 'expand_downwards;
11572                    }
11573                }
11574            }
11575
11576            let start = Point::new(start_row, 0);
11577            let start_offset = start.to_offset(&buffer);
11578            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11579            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11580            let Some(lines_without_prefixes) = selection_text
11581                .lines()
11582                .map(|line| {
11583                    line.strip_prefix(&line_prefix)
11584                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11585                        .with_context(|| {
11586                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11587                        })
11588                })
11589                .collect::<Result<Vec<_>, _>>()
11590                .log_err()
11591            else {
11592                continue;
11593            };
11594
11595            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11596                buffer
11597                    .language_settings_at(Point::new(start_row, 0), cx)
11598                    .preferred_line_length as usize
11599            });
11600            let wrapped_text = wrap_with_prefix(
11601                line_prefix,
11602                lines_without_prefixes.join("\n"),
11603                wrap_column,
11604                tab_size,
11605                options.preserve_existing_whitespace,
11606            );
11607
11608            // TODO: should always use char-based diff while still supporting cursor behavior that
11609            // matches vim.
11610            let mut diff_options = DiffOptions::default();
11611            if options.override_language_settings {
11612                diff_options.max_word_diff_len = 0;
11613                diff_options.max_word_diff_line_count = 0;
11614            } else {
11615                diff_options.max_word_diff_len = usize::MAX;
11616                diff_options.max_word_diff_line_count = usize::MAX;
11617            }
11618
11619            for (old_range, new_text) in
11620                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11621            {
11622                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11623                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11624                edits.push((edit_start..edit_end, new_text));
11625            }
11626
11627            rewrapped_row_ranges.push(start_row..=end_row);
11628        }
11629
11630        self.buffer
11631            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11632    }
11633
11634    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11635        let mut text = String::new();
11636        let buffer = self.buffer.read(cx).snapshot(cx);
11637        let mut selections = self.selections.all::<Point>(cx);
11638        let mut clipboard_selections = Vec::with_capacity(selections.len());
11639        {
11640            let max_point = buffer.max_point();
11641            let mut is_first = true;
11642            for selection in &mut selections {
11643                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11644                if is_entire_line {
11645                    selection.start = Point::new(selection.start.row, 0);
11646                    if !selection.is_empty() && selection.end.column == 0 {
11647                        selection.end = cmp::min(max_point, selection.end);
11648                    } else {
11649                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11650                    }
11651                    selection.goal = SelectionGoal::None;
11652                }
11653                if is_first {
11654                    is_first = false;
11655                } else {
11656                    text += "\n";
11657                }
11658                let mut len = 0;
11659                for chunk in buffer.text_for_range(selection.start..selection.end) {
11660                    text.push_str(chunk);
11661                    len += chunk.len();
11662                }
11663                clipboard_selections.push(ClipboardSelection {
11664                    len,
11665                    is_entire_line,
11666                    first_line_indent: buffer
11667                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11668                        .len,
11669                });
11670            }
11671        }
11672
11673        self.transact(window, cx, |this, window, cx| {
11674            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11675                s.select(selections);
11676            });
11677            this.insert("", window, cx);
11678        });
11679        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11680    }
11681
11682    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11683        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11684        let item = self.cut_common(window, cx);
11685        cx.write_to_clipboard(item);
11686    }
11687
11688    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11689        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11690        self.change_selections(None, window, cx, |s| {
11691            s.move_with(|snapshot, sel| {
11692                if sel.is_empty() {
11693                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11694                }
11695            });
11696        });
11697        let item = self.cut_common(window, cx);
11698        cx.set_global(KillRing(item))
11699    }
11700
11701    pub fn kill_ring_yank(
11702        &mut self,
11703        _: &KillRingYank,
11704        window: &mut Window,
11705        cx: &mut Context<Self>,
11706    ) {
11707        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11708        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11709            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11710                (kill_ring.text().to_string(), kill_ring.metadata_json())
11711            } else {
11712                return;
11713            }
11714        } else {
11715            return;
11716        };
11717        self.do_paste(&text, metadata, false, window, cx);
11718    }
11719
11720    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11721        self.do_copy(true, cx);
11722    }
11723
11724    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11725        self.do_copy(false, cx);
11726    }
11727
11728    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11729        let selections = self.selections.all::<Point>(cx);
11730        let buffer = self.buffer.read(cx).read(cx);
11731        let mut text = String::new();
11732
11733        let mut clipboard_selections = Vec::with_capacity(selections.len());
11734        {
11735            let max_point = buffer.max_point();
11736            let mut is_first = true;
11737            for selection in &selections {
11738                let mut start = selection.start;
11739                let mut end = selection.end;
11740                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11741                if is_entire_line {
11742                    start = Point::new(start.row, 0);
11743                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11744                }
11745
11746                let mut trimmed_selections = Vec::new();
11747                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11748                    let row = MultiBufferRow(start.row);
11749                    let first_indent = buffer.indent_size_for_line(row);
11750                    if first_indent.len == 0 || start.column > first_indent.len {
11751                        trimmed_selections.push(start..end);
11752                    } else {
11753                        trimmed_selections.push(
11754                            Point::new(row.0, first_indent.len)
11755                                ..Point::new(row.0, buffer.line_len(row)),
11756                        );
11757                        for row in start.row + 1..=end.row {
11758                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11759                            if row == end.row {
11760                                line_len = end.column;
11761                            }
11762                            if line_len == 0 {
11763                                trimmed_selections
11764                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11765                                continue;
11766                            }
11767                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11768                            if row_indent_size.len >= first_indent.len {
11769                                trimmed_selections.push(
11770                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11771                                );
11772                            } else {
11773                                trimmed_selections.clear();
11774                                trimmed_selections.push(start..end);
11775                                break;
11776                            }
11777                        }
11778                    }
11779                } else {
11780                    trimmed_selections.push(start..end);
11781                }
11782
11783                for trimmed_range in trimmed_selections {
11784                    if is_first {
11785                        is_first = false;
11786                    } else {
11787                        text += "\n";
11788                    }
11789                    let mut len = 0;
11790                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11791                        text.push_str(chunk);
11792                        len += chunk.len();
11793                    }
11794                    clipboard_selections.push(ClipboardSelection {
11795                        len,
11796                        is_entire_line,
11797                        first_line_indent: buffer
11798                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11799                            .len,
11800                    });
11801                }
11802            }
11803        }
11804
11805        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11806            text,
11807            clipboard_selections,
11808        ));
11809    }
11810
11811    pub fn do_paste(
11812        &mut self,
11813        text: &String,
11814        clipboard_selections: Option<Vec<ClipboardSelection>>,
11815        handle_entire_lines: bool,
11816        window: &mut Window,
11817        cx: &mut Context<Self>,
11818    ) {
11819        if self.read_only(cx) {
11820            return;
11821        }
11822
11823        let clipboard_text = Cow::Borrowed(text);
11824
11825        self.transact(window, cx, |this, window, cx| {
11826            if let Some(mut clipboard_selections) = clipboard_selections {
11827                let old_selections = this.selections.all::<usize>(cx);
11828                let all_selections_were_entire_line =
11829                    clipboard_selections.iter().all(|s| s.is_entire_line);
11830                let first_selection_indent_column =
11831                    clipboard_selections.first().map(|s| s.first_line_indent);
11832                if clipboard_selections.len() != old_selections.len() {
11833                    clipboard_selections.drain(..);
11834                }
11835                let cursor_offset = this.selections.last::<usize>(cx).head();
11836                let mut auto_indent_on_paste = true;
11837
11838                this.buffer.update(cx, |buffer, cx| {
11839                    let snapshot = buffer.read(cx);
11840                    auto_indent_on_paste = snapshot
11841                        .language_settings_at(cursor_offset, cx)
11842                        .auto_indent_on_paste;
11843
11844                    let mut start_offset = 0;
11845                    let mut edits = Vec::new();
11846                    let mut original_indent_columns = Vec::new();
11847                    for (ix, selection) in old_selections.iter().enumerate() {
11848                        let to_insert;
11849                        let entire_line;
11850                        let original_indent_column;
11851                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11852                            let end_offset = start_offset + clipboard_selection.len;
11853                            to_insert = &clipboard_text[start_offset..end_offset];
11854                            entire_line = clipboard_selection.is_entire_line;
11855                            start_offset = end_offset + 1;
11856                            original_indent_column = Some(clipboard_selection.first_line_indent);
11857                        } else {
11858                            to_insert = clipboard_text.as_str();
11859                            entire_line = all_selections_were_entire_line;
11860                            original_indent_column = first_selection_indent_column
11861                        }
11862
11863                        // If the corresponding selection was empty when this slice of the
11864                        // clipboard text was written, then the entire line containing the
11865                        // selection was copied. If this selection is also currently empty,
11866                        // then paste the line before the current line of the buffer.
11867                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11868                            let column = selection.start.to_point(&snapshot).column as usize;
11869                            let line_start = selection.start - column;
11870                            line_start..line_start
11871                        } else {
11872                            selection.range()
11873                        };
11874
11875                        edits.push((range, to_insert));
11876                        original_indent_columns.push(original_indent_column);
11877                    }
11878                    drop(snapshot);
11879
11880                    buffer.edit(
11881                        edits,
11882                        if auto_indent_on_paste {
11883                            Some(AutoindentMode::Block {
11884                                original_indent_columns,
11885                            })
11886                        } else {
11887                            None
11888                        },
11889                        cx,
11890                    );
11891                });
11892
11893                let selections = this.selections.all::<usize>(cx);
11894                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11895                    s.select(selections)
11896                });
11897            } else {
11898                this.insert(&clipboard_text, window, cx);
11899            }
11900        });
11901    }
11902
11903    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11904        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11905        if let Some(item) = cx.read_from_clipboard() {
11906            let entries = item.entries();
11907
11908            match entries.first() {
11909                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11910                // of all the pasted entries.
11911                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11912                    .do_paste(
11913                        clipboard_string.text(),
11914                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11915                        true,
11916                        window,
11917                        cx,
11918                    ),
11919                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11920            }
11921        }
11922    }
11923
11924    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11925        if self.read_only(cx) {
11926            return;
11927        }
11928
11929        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11930
11931        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11932            if let Some((selections, _)) =
11933                self.selection_history.transaction(transaction_id).cloned()
11934            {
11935                self.change_selections(None, window, cx, |s| {
11936                    s.select_anchors(selections.to_vec());
11937                });
11938            } else {
11939                log::error!(
11940                    "No entry in selection_history found for undo. \
11941                     This may correspond to a bug where undo does not update the selection. \
11942                     If this is occurring, please add details to \
11943                     https://github.com/zed-industries/zed/issues/22692"
11944                );
11945            }
11946            self.request_autoscroll(Autoscroll::fit(), cx);
11947            self.unmark_text(window, cx);
11948            self.refresh_inline_completion(true, false, window, cx);
11949            cx.emit(EditorEvent::Edited { transaction_id });
11950            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11951        }
11952    }
11953
11954    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11955        if self.read_only(cx) {
11956            return;
11957        }
11958
11959        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11960
11961        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11962            if let Some((_, Some(selections))) =
11963                self.selection_history.transaction(transaction_id).cloned()
11964            {
11965                self.change_selections(None, window, cx, |s| {
11966                    s.select_anchors(selections.to_vec());
11967                });
11968            } else {
11969                log::error!(
11970                    "No entry in selection_history found for redo. \
11971                     This may correspond to a bug where undo does not update the selection. \
11972                     If this is occurring, please add details to \
11973                     https://github.com/zed-industries/zed/issues/22692"
11974                );
11975            }
11976            self.request_autoscroll(Autoscroll::fit(), cx);
11977            self.unmark_text(window, cx);
11978            self.refresh_inline_completion(true, false, window, cx);
11979            cx.emit(EditorEvent::Edited { transaction_id });
11980        }
11981    }
11982
11983    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11984        self.buffer
11985            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11986    }
11987
11988    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11989        self.buffer
11990            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11991    }
11992
11993    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11994        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11995        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11996            s.move_with(|map, selection| {
11997                let cursor = if selection.is_empty() {
11998                    movement::left(map, selection.start)
11999                } else {
12000                    selection.start
12001                };
12002                selection.collapse_to(cursor, SelectionGoal::None);
12003            });
12004        })
12005    }
12006
12007    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12008        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12009        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12010            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12011        })
12012    }
12013
12014    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12016        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12017            s.move_with(|map, selection| {
12018                let cursor = if selection.is_empty() {
12019                    movement::right(map, selection.end)
12020                } else {
12021                    selection.end
12022                };
12023                selection.collapse_to(cursor, SelectionGoal::None)
12024            });
12025        })
12026    }
12027
12028    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12030        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12031            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12032        })
12033    }
12034
12035    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12036        if self.take_rename(true, window, cx).is_some() {
12037            return;
12038        }
12039
12040        if self.mode.is_single_line() {
12041            cx.propagate();
12042            return;
12043        }
12044
12045        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12046
12047        let text_layout_details = &self.text_layout_details(window);
12048        let selection_count = self.selections.count();
12049        let first_selection = self.selections.first_anchor();
12050
12051        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12052            s.move_with(|map, selection| {
12053                if !selection.is_empty() {
12054                    selection.goal = SelectionGoal::None;
12055                }
12056                let (cursor, goal) = movement::up(
12057                    map,
12058                    selection.start,
12059                    selection.goal,
12060                    false,
12061                    text_layout_details,
12062                );
12063                selection.collapse_to(cursor, goal);
12064            });
12065        });
12066
12067        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12068        {
12069            cx.propagate();
12070        }
12071    }
12072
12073    pub fn move_up_by_lines(
12074        &mut self,
12075        action: &MoveUpByLines,
12076        window: &mut Window,
12077        cx: &mut Context<Self>,
12078    ) {
12079        if self.take_rename(true, window, cx).is_some() {
12080            return;
12081        }
12082
12083        if self.mode.is_single_line() {
12084            cx.propagate();
12085            return;
12086        }
12087
12088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12089
12090        let text_layout_details = &self.text_layout_details(window);
12091
12092        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12093            s.move_with(|map, selection| {
12094                if !selection.is_empty() {
12095                    selection.goal = SelectionGoal::None;
12096                }
12097                let (cursor, goal) = movement::up_by_rows(
12098                    map,
12099                    selection.start,
12100                    action.lines,
12101                    selection.goal,
12102                    false,
12103                    text_layout_details,
12104                );
12105                selection.collapse_to(cursor, goal);
12106            });
12107        })
12108    }
12109
12110    pub fn move_down_by_lines(
12111        &mut self,
12112        action: &MoveDownByLines,
12113        window: &mut Window,
12114        cx: &mut Context<Self>,
12115    ) {
12116        if self.take_rename(true, window, cx).is_some() {
12117            return;
12118        }
12119
12120        if self.mode.is_single_line() {
12121            cx.propagate();
12122            return;
12123        }
12124
12125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12126
12127        let text_layout_details = &self.text_layout_details(window);
12128
12129        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12130            s.move_with(|map, selection| {
12131                if !selection.is_empty() {
12132                    selection.goal = SelectionGoal::None;
12133                }
12134                let (cursor, goal) = movement::down_by_rows(
12135                    map,
12136                    selection.start,
12137                    action.lines,
12138                    selection.goal,
12139                    false,
12140                    text_layout_details,
12141                );
12142                selection.collapse_to(cursor, goal);
12143            });
12144        })
12145    }
12146
12147    pub fn select_down_by_lines(
12148        &mut self,
12149        action: &SelectDownByLines,
12150        window: &mut Window,
12151        cx: &mut Context<Self>,
12152    ) {
12153        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12154        let text_layout_details = &self.text_layout_details(window);
12155        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12156            s.move_heads_with(|map, head, goal| {
12157                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12158            })
12159        })
12160    }
12161
12162    pub fn select_up_by_lines(
12163        &mut self,
12164        action: &SelectUpByLines,
12165        window: &mut Window,
12166        cx: &mut Context<Self>,
12167    ) {
12168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12169        let text_layout_details = &self.text_layout_details(window);
12170        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12171            s.move_heads_with(|map, head, goal| {
12172                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12173            })
12174        })
12175    }
12176
12177    pub fn select_page_up(
12178        &mut self,
12179        _: &SelectPageUp,
12180        window: &mut Window,
12181        cx: &mut Context<Self>,
12182    ) {
12183        let Some(row_count) = self.visible_row_count() else {
12184            return;
12185        };
12186
12187        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12188
12189        let text_layout_details = &self.text_layout_details(window);
12190
12191        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12192            s.move_heads_with(|map, head, goal| {
12193                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12194            })
12195        })
12196    }
12197
12198    pub fn move_page_up(
12199        &mut self,
12200        action: &MovePageUp,
12201        window: &mut Window,
12202        cx: &mut Context<Self>,
12203    ) {
12204        if self.take_rename(true, window, cx).is_some() {
12205            return;
12206        }
12207
12208        if self
12209            .context_menu
12210            .borrow_mut()
12211            .as_mut()
12212            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12213            .unwrap_or(false)
12214        {
12215            return;
12216        }
12217
12218        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12219            cx.propagate();
12220            return;
12221        }
12222
12223        let Some(row_count) = self.visible_row_count() else {
12224            return;
12225        };
12226
12227        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12228
12229        let autoscroll = if action.center_cursor {
12230            Autoscroll::center()
12231        } else {
12232            Autoscroll::fit()
12233        };
12234
12235        let text_layout_details = &self.text_layout_details(window);
12236
12237        self.change_selections(Some(autoscroll), window, cx, |s| {
12238            s.move_with(|map, selection| {
12239                if !selection.is_empty() {
12240                    selection.goal = SelectionGoal::None;
12241                }
12242                let (cursor, goal) = movement::up_by_rows(
12243                    map,
12244                    selection.end,
12245                    row_count,
12246                    selection.goal,
12247                    false,
12248                    text_layout_details,
12249                );
12250                selection.collapse_to(cursor, goal);
12251            });
12252        });
12253    }
12254
12255    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12257        let text_layout_details = &self.text_layout_details(window);
12258        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12259            s.move_heads_with(|map, head, goal| {
12260                movement::up(map, head, goal, false, text_layout_details)
12261            })
12262        })
12263    }
12264
12265    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12266        self.take_rename(true, window, cx);
12267
12268        if self.mode.is_single_line() {
12269            cx.propagate();
12270            return;
12271        }
12272
12273        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12274
12275        let text_layout_details = &self.text_layout_details(window);
12276        let selection_count = self.selections.count();
12277        let first_selection = self.selections.first_anchor();
12278
12279        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12280            s.move_with(|map, selection| {
12281                if !selection.is_empty() {
12282                    selection.goal = SelectionGoal::None;
12283                }
12284                let (cursor, goal) = movement::down(
12285                    map,
12286                    selection.end,
12287                    selection.goal,
12288                    false,
12289                    text_layout_details,
12290                );
12291                selection.collapse_to(cursor, goal);
12292            });
12293        });
12294
12295        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12296        {
12297            cx.propagate();
12298        }
12299    }
12300
12301    pub fn select_page_down(
12302        &mut self,
12303        _: &SelectPageDown,
12304        window: &mut Window,
12305        cx: &mut Context<Self>,
12306    ) {
12307        let Some(row_count) = self.visible_row_count() else {
12308            return;
12309        };
12310
12311        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12312
12313        let text_layout_details = &self.text_layout_details(window);
12314
12315        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12316            s.move_heads_with(|map, head, goal| {
12317                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12318            })
12319        })
12320    }
12321
12322    pub fn move_page_down(
12323        &mut self,
12324        action: &MovePageDown,
12325        window: &mut Window,
12326        cx: &mut Context<Self>,
12327    ) {
12328        if self.take_rename(true, window, cx).is_some() {
12329            return;
12330        }
12331
12332        if self
12333            .context_menu
12334            .borrow_mut()
12335            .as_mut()
12336            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12337            .unwrap_or(false)
12338        {
12339            return;
12340        }
12341
12342        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12343            cx.propagate();
12344            return;
12345        }
12346
12347        let Some(row_count) = self.visible_row_count() else {
12348            return;
12349        };
12350
12351        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12352
12353        let autoscroll = if action.center_cursor {
12354            Autoscroll::center()
12355        } else {
12356            Autoscroll::fit()
12357        };
12358
12359        let text_layout_details = &self.text_layout_details(window);
12360        self.change_selections(Some(autoscroll), window, cx, |s| {
12361            s.move_with(|map, selection| {
12362                if !selection.is_empty() {
12363                    selection.goal = SelectionGoal::None;
12364                }
12365                let (cursor, goal) = movement::down_by_rows(
12366                    map,
12367                    selection.end,
12368                    row_count,
12369                    selection.goal,
12370                    false,
12371                    text_layout_details,
12372                );
12373                selection.collapse_to(cursor, goal);
12374            });
12375        });
12376    }
12377
12378    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12380        let text_layout_details = &self.text_layout_details(window);
12381        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12382            s.move_heads_with(|map, head, goal| {
12383                movement::down(map, head, goal, false, text_layout_details)
12384            })
12385        });
12386    }
12387
12388    pub fn context_menu_first(
12389        &mut self,
12390        _: &ContextMenuFirst,
12391        window: &mut Window,
12392        cx: &mut Context<Self>,
12393    ) {
12394        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12395            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12396        }
12397    }
12398
12399    pub fn context_menu_prev(
12400        &mut self,
12401        _: &ContextMenuPrevious,
12402        window: &mut Window,
12403        cx: &mut Context<Self>,
12404    ) {
12405        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12406            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12407        }
12408    }
12409
12410    pub fn context_menu_next(
12411        &mut self,
12412        _: &ContextMenuNext,
12413        window: &mut Window,
12414        cx: &mut Context<Self>,
12415    ) {
12416        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12417            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12418        }
12419    }
12420
12421    pub fn context_menu_last(
12422        &mut self,
12423        _: &ContextMenuLast,
12424        window: &mut Window,
12425        cx: &mut Context<Self>,
12426    ) {
12427        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12428            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12429        }
12430    }
12431
12432    pub fn move_to_previous_word_start(
12433        &mut self,
12434        _: &MoveToPreviousWordStart,
12435        window: &mut Window,
12436        cx: &mut Context<Self>,
12437    ) {
12438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12439        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12440            s.move_cursors_with(|map, head, _| {
12441                (
12442                    movement::previous_word_start(map, head),
12443                    SelectionGoal::None,
12444                )
12445            });
12446        })
12447    }
12448
12449    pub fn move_to_previous_subword_start(
12450        &mut self,
12451        _: &MoveToPreviousSubwordStart,
12452        window: &mut Window,
12453        cx: &mut Context<Self>,
12454    ) {
12455        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12456        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12457            s.move_cursors_with(|map, head, _| {
12458                (
12459                    movement::previous_subword_start(map, head),
12460                    SelectionGoal::None,
12461                )
12462            });
12463        })
12464    }
12465
12466    pub fn select_to_previous_word_start(
12467        &mut self,
12468        _: &SelectToPreviousWordStart,
12469        window: &mut Window,
12470        cx: &mut Context<Self>,
12471    ) {
12472        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12473        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12474            s.move_heads_with(|map, head, _| {
12475                (
12476                    movement::previous_word_start(map, head),
12477                    SelectionGoal::None,
12478                )
12479            });
12480        })
12481    }
12482
12483    pub fn select_to_previous_subword_start(
12484        &mut self,
12485        _: &SelectToPreviousSubwordStart,
12486        window: &mut Window,
12487        cx: &mut Context<Self>,
12488    ) {
12489        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12490        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12491            s.move_heads_with(|map, head, _| {
12492                (
12493                    movement::previous_subword_start(map, head),
12494                    SelectionGoal::None,
12495                )
12496            });
12497        })
12498    }
12499
12500    pub fn delete_to_previous_word_start(
12501        &mut self,
12502        action: &DeleteToPreviousWordStart,
12503        window: &mut Window,
12504        cx: &mut Context<Self>,
12505    ) {
12506        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12507        self.transact(window, cx, |this, window, cx| {
12508            this.select_autoclose_pair(window, cx);
12509            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12510                s.move_with(|map, selection| {
12511                    if selection.is_empty() {
12512                        let cursor = if action.ignore_newlines {
12513                            movement::previous_word_start(map, selection.head())
12514                        } else {
12515                            movement::previous_word_start_or_newline(map, selection.head())
12516                        };
12517                        selection.set_head(cursor, SelectionGoal::None);
12518                    }
12519                });
12520            });
12521            this.insert("", window, cx);
12522        });
12523    }
12524
12525    pub fn delete_to_previous_subword_start(
12526        &mut self,
12527        _: &DeleteToPreviousSubwordStart,
12528        window: &mut Window,
12529        cx: &mut Context<Self>,
12530    ) {
12531        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12532        self.transact(window, cx, |this, window, cx| {
12533            this.select_autoclose_pair(window, cx);
12534            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12535                s.move_with(|map, selection| {
12536                    if selection.is_empty() {
12537                        let cursor = movement::previous_subword_start(map, selection.head());
12538                        selection.set_head(cursor, SelectionGoal::None);
12539                    }
12540                });
12541            });
12542            this.insert("", window, cx);
12543        });
12544    }
12545
12546    pub fn move_to_next_word_end(
12547        &mut self,
12548        _: &MoveToNextWordEnd,
12549        window: &mut Window,
12550        cx: &mut Context<Self>,
12551    ) {
12552        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12553        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12554            s.move_cursors_with(|map, head, _| {
12555                (movement::next_word_end(map, head), SelectionGoal::None)
12556            });
12557        })
12558    }
12559
12560    pub fn move_to_next_subword_end(
12561        &mut self,
12562        _: &MoveToNextSubwordEnd,
12563        window: &mut Window,
12564        cx: &mut Context<Self>,
12565    ) {
12566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12567        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12568            s.move_cursors_with(|map, head, _| {
12569                (movement::next_subword_end(map, head), SelectionGoal::None)
12570            });
12571        })
12572    }
12573
12574    pub fn select_to_next_word_end(
12575        &mut self,
12576        _: &SelectToNextWordEnd,
12577        window: &mut Window,
12578        cx: &mut Context<Self>,
12579    ) {
12580        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12581        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12582            s.move_heads_with(|map, head, _| {
12583                (movement::next_word_end(map, head), SelectionGoal::None)
12584            });
12585        })
12586    }
12587
12588    pub fn select_to_next_subword_end(
12589        &mut self,
12590        _: &SelectToNextSubwordEnd,
12591        window: &mut Window,
12592        cx: &mut Context<Self>,
12593    ) {
12594        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12595        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12596            s.move_heads_with(|map, head, _| {
12597                (movement::next_subword_end(map, head), SelectionGoal::None)
12598            });
12599        })
12600    }
12601
12602    pub fn delete_to_next_word_end(
12603        &mut self,
12604        action: &DeleteToNextWordEnd,
12605        window: &mut Window,
12606        cx: &mut Context<Self>,
12607    ) {
12608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12609        self.transact(window, cx, |this, window, cx| {
12610            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12611                s.move_with(|map, selection| {
12612                    if selection.is_empty() {
12613                        let cursor = if action.ignore_newlines {
12614                            movement::next_word_end(map, selection.head())
12615                        } else {
12616                            movement::next_word_end_or_newline(map, selection.head())
12617                        };
12618                        selection.set_head(cursor, SelectionGoal::None);
12619                    }
12620                });
12621            });
12622            this.insert("", window, cx);
12623        });
12624    }
12625
12626    pub fn delete_to_next_subword_end(
12627        &mut self,
12628        _: &DeleteToNextSubwordEnd,
12629        window: &mut Window,
12630        cx: &mut Context<Self>,
12631    ) {
12632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12633        self.transact(window, cx, |this, window, cx| {
12634            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12635                s.move_with(|map, selection| {
12636                    if selection.is_empty() {
12637                        let cursor = movement::next_subword_end(map, selection.head());
12638                        selection.set_head(cursor, SelectionGoal::None);
12639                    }
12640                });
12641            });
12642            this.insert("", window, cx);
12643        });
12644    }
12645
12646    pub fn move_to_beginning_of_line(
12647        &mut self,
12648        action: &MoveToBeginningOfLine,
12649        window: &mut Window,
12650        cx: &mut Context<Self>,
12651    ) {
12652        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12653        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12654            s.move_cursors_with(|map, head, _| {
12655                (
12656                    movement::indented_line_beginning(
12657                        map,
12658                        head,
12659                        action.stop_at_soft_wraps,
12660                        action.stop_at_indent,
12661                    ),
12662                    SelectionGoal::None,
12663                )
12664            });
12665        })
12666    }
12667
12668    pub fn select_to_beginning_of_line(
12669        &mut self,
12670        action: &SelectToBeginningOfLine,
12671        window: &mut Window,
12672        cx: &mut Context<Self>,
12673    ) {
12674        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12675        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12676            s.move_heads_with(|map, head, _| {
12677                (
12678                    movement::indented_line_beginning(
12679                        map,
12680                        head,
12681                        action.stop_at_soft_wraps,
12682                        action.stop_at_indent,
12683                    ),
12684                    SelectionGoal::None,
12685                )
12686            });
12687        });
12688    }
12689
12690    pub fn delete_to_beginning_of_line(
12691        &mut self,
12692        action: &DeleteToBeginningOfLine,
12693        window: &mut Window,
12694        cx: &mut Context<Self>,
12695    ) {
12696        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12697        self.transact(window, cx, |this, window, cx| {
12698            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12699                s.move_with(|_, selection| {
12700                    selection.reversed = true;
12701                });
12702            });
12703
12704            this.select_to_beginning_of_line(
12705                &SelectToBeginningOfLine {
12706                    stop_at_soft_wraps: false,
12707                    stop_at_indent: action.stop_at_indent,
12708                },
12709                window,
12710                cx,
12711            );
12712            this.backspace(&Backspace, window, cx);
12713        });
12714    }
12715
12716    pub fn move_to_end_of_line(
12717        &mut self,
12718        action: &MoveToEndOfLine,
12719        window: &mut Window,
12720        cx: &mut Context<Self>,
12721    ) {
12722        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12723        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12724            s.move_cursors_with(|map, head, _| {
12725                (
12726                    movement::line_end(map, head, action.stop_at_soft_wraps),
12727                    SelectionGoal::None,
12728                )
12729            });
12730        })
12731    }
12732
12733    pub fn select_to_end_of_line(
12734        &mut self,
12735        action: &SelectToEndOfLine,
12736        window: &mut Window,
12737        cx: &mut Context<Self>,
12738    ) {
12739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12740        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12741            s.move_heads_with(|map, head, _| {
12742                (
12743                    movement::line_end(map, head, action.stop_at_soft_wraps),
12744                    SelectionGoal::None,
12745                )
12746            });
12747        })
12748    }
12749
12750    pub fn delete_to_end_of_line(
12751        &mut self,
12752        _: &DeleteToEndOfLine,
12753        window: &mut Window,
12754        cx: &mut Context<Self>,
12755    ) {
12756        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12757        self.transact(window, cx, |this, window, cx| {
12758            this.select_to_end_of_line(
12759                &SelectToEndOfLine {
12760                    stop_at_soft_wraps: false,
12761                },
12762                window,
12763                cx,
12764            );
12765            this.delete(&Delete, window, cx);
12766        });
12767    }
12768
12769    pub fn cut_to_end_of_line(
12770        &mut self,
12771        _: &CutToEndOfLine,
12772        window: &mut Window,
12773        cx: &mut Context<Self>,
12774    ) {
12775        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12776        self.transact(window, cx, |this, window, cx| {
12777            this.select_to_end_of_line(
12778                &SelectToEndOfLine {
12779                    stop_at_soft_wraps: false,
12780                },
12781                window,
12782                cx,
12783            );
12784            this.cut(&Cut, window, cx);
12785        });
12786    }
12787
12788    pub fn move_to_start_of_paragraph(
12789        &mut self,
12790        _: &MoveToStartOfParagraph,
12791        window: &mut Window,
12792        cx: &mut Context<Self>,
12793    ) {
12794        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12795            cx.propagate();
12796            return;
12797        }
12798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12799        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12800            s.move_with(|map, selection| {
12801                selection.collapse_to(
12802                    movement::start_of_paragraph(map, selection.head(), 1),
12803                    SelectionGoal::None,
12804                )
12805            });
12806        })
12807    }
12808
12809    pub fn move_to_end_of_paragraph(
12810        &mut self,
12811        _: &MoveToEndOfParagraph,
12812        window: &mut Window,
12813        cx: &mut Context<Self>,
12814    ) {
12815        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12816            cx.propagate();
12817            return;
12818        }
12819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12820        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12821            s.move_with(|map, selection| {
12822                selection.collapse_to(
12823                    movement::end_of_paragraph(map, selection.head(), 1),
12824                    SelectionGoal::None,
12825                )
12826            });
12827        })
12828    }
12829
12830    pub fn select_to_start_of_paragraph(
12831        &mut self,
12832        _: &SelectToStartOfParagraph,
12833        window: &mut Window,
12834        cx: &mut Context<Self>,
12835    ) {
12836        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12837            cx.propagate();
12838            return;
12839        }
12840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12841        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12842            s.move_heads_with(|map, head, _| {
12843                (
12844                    movement::start_of_paragraph(map, head, 1),
12845                    SelectionGoal::None,
12846                )
12847            });
12848        })
12849    }
12850
12851    pub fn select_to_end_of_paragraph(
12852        &mut self,
12853        _: &SelectToEndOfParagraph,
12854        window: &mut Window,
12855        cx: &mut Context<Self>,
12856    ) {
12857        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12858            cx.propagate();
12859            return;
12860        }
12861        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12862        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12863            s.move_heads_with(|map, head, _| {
12864                (
12865                    movement::end_of_paragraph(map, head, 1),
12866                    SelectionGoal::None,
12867                )
12868            });
12869        })
12870    }
12871
12872    pub fn move_to_start_of_excerpt(
12873        &mut self,
12874        _: &MoveToStartOfExcerpt,
12875        window: &mut Window,
12876        cx: &mut Context<Self>,
12877    ) {
12878        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12879            cx.propagate();
12880            return;
12881        }
12882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12883        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12884            s.move_with(|map, selection| {
12885                selection.collapse_to(
12886                    movement::start_of_excerpt(
12887                        map,
12888                        selection.head(),
12889                        workspace::searchable::Direction::Prev,
12890                    ),
12891                    SelectionGoal::None,
12892                )
12893            });
12894        })
12895    }
12896
12897    pub fn move_to_start_of_next_excerpt(
12898        &mut self,
12899        _: &MoveToStartOfNextExcerpt,
12900        window: &mut Window,
12901        cx: &mut Context<Self>,
12902    ) {
12903        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12904            cx.propagate();
12905            return;
12906        }
12907
12908        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12909            s.move_with(|map, selection| {
12910                selection.collapse_to(
12911                    movement::start_of_excerpt(
12912                        map,
12913                        selection.head(),
12914                        workspace::searchable::Direction::Next,
12915                    ),
12916                    SelectionGoal::None,
12917                )
12918            });
12919        })
12920    }
12921
12922    pub fn move_to_end_of_excerpt(
12923        &mut self,
12924        _: &MoveToEndOfExcerpt,
12925        window: &mut Window,
12926        cx: &mut Context<Self>,
12927    ) {
12928        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12929            cx.propagate();
12930            return;
12931        }
12932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12933        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12934            s.move_with(|map, selection| {
12935                selection.collapse_to(
12936                    movement::end_of_excerpt(
12937                        map,
12938                        selection.head(),
12939                        workspace::searchable::Direction::Next,
12940                    ),
12941                    SelectionGoal::None,
12942                )
12943            });
12944        })
12945    }
12946
12947    pub fn move_to_end_of_previous_excerpt(
12948        &mut self,
12949        _: &MoveToEndOfPreviousExcerpt,
12950        window: &mut Window,
12951        cx: &mut Context<Self>,
12952    ) {
12953        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12954            cx.propagate();
12955            return;
12956        }
12957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12958        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12959            s.move_with(|map, selection| {
12960                selection.collapse_to(
12961                    movement::end_of_excerpt(
12962                        map,
12963                        selection.head(),
12964                        workspace::searchable::Direction::Prev,
12965                    ),
12966                    SelectionGoal::None,
12967                )
12968            });
12969        })
12970    }
12971
12972    pub fn select_to_start_of_excerpt(
12973        &mut self,
12974        _: &SelectToStartOfExcerpt,
12975        window: &mut Window,
12976        cx: &mut Context<Self>,
12977    ) {
12978        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12979            cx.propagate();
12980            return;
12981        }
12982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12983        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12984            s.move_heads_with(|map, head, _| {
12985                (
12986                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12987                    SelectionGoal::None,
12988                )
12989            });
12990        })
12991    }
12992
12993    pub fn select_to_start_of_next_excerpt(
12994        &mut self,
12995        _: &SelectToStartOfNextExcerpt,
12996        window: &mut Window,
12997        cx: &mut Context<Self>,
12998    ) {
12999        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13000            cx.propagate();
13001            return;
13002        }
13003        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13004        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13005            s.move_heads_with(|map, head, _| {
13006                (
13007                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13008                    SelectionGoal::None,
13009                )
13010            });
13011        })
13012    }
13013
13014    pub fn select_to_end_of_excerpt(
13015        &mut self,
13016        _: &SelectToEndOfExcerpt,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) {
13020        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13021            cx.propagate();
13022            return;
13023        }
13024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13025        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13026            s.move_heads_with(|map, head, _| {
13027                (
13028                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13029                    SelectionGoal::None,
13030                )
13031            });
13032        })
13033    }
13034
13035    pub fn select_to_end_of_previous_excerpt(
13036        &mut self,
13037        _: &SelectToEndOfPreviousExcerpt,
13038        window: &mut Window,
13039        cx: &mut Context<Self>,
13040    ) {
13041        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13042            cx.propagate();
13043            return;
13044        }
13045        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13046        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13047            s.move_heads_with(|map, head, _| {
13048                (
13049                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13050                    SelectionGoal::None,
13051                )
13052            });
13053        })
13054    }
13055
13056    pub fn move_to_beginning(
13057        &mut self,
13058        _: &MoveToBeginning,
13059        window: &mut Window,
13060        cx: &mut Context<Self>,
13061    ) {
13062        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13063            cx.propagate();
13064            return;
13065        }
13066        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13067        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13068            s.select_ranges(vec![0..0]);
13069        });
13070    }
13071
13072    pub fn select_to_beginning(
13073        &mut self,
13074        _: &SelectToBeginning,
13075        window: &mut Window,
13076        cx: &mut Context<Self>,
13077    ) {
13078        let mut selection = self.selections.last::<Point>(cx);
13079        selection.set_head(Point::zero(), SelectionGoal::None);
13080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13081        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13082            s.select(vec![selection]);
13083        });
13084    }
13085
13086    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13087        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13088            cx.propagate();
13089            return;
13090        }
13091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13092        let cursor = self.buffer.read(cx).read(cx).len();
13093        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13094            s.select_ranges(vec![cursor..cursor])
13095        });
13096    }
13097
13098    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13099        self.nav_history = nav_history;
13100    }
13101
13102    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13103        self.nav_history.as_ref()
13104    }
13105
13106    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13107        self.push_to_nav_history(
13108            self.selections.newest_anchor().head(),
13109            None,
13110            false,
13111            true,
13112            cx,
13113        );
13114    }
13115
13116    fn push_to_nav_history(
13117        &mut self,
13118        cursor_anchor: Anchor,
13119        new_position: Option<Point>,
13120        is_deactivate: bool,
13121        always: bool,
13122        cx: &mut Context<Self>,
13123    ) {
13124        if let Some(nav_history) = self.nav_history.as_mut() {
13125            let buffer = self.buffer.read(cx).read(cx);
13126            let cursor_position = cursor_anchor.to_point(&buffer);
13127            let scroll_state = self.scroll_manager.anchor();
13128            let scroll_top_row = scroll_state.top_row(&buffer);
13129            drop(buffer);
13130
13131            if let Some(new_position) = new_position {
13132                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13133                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13134                    return;
13135                }
13136            }
13137
13138            nav_history.push(
13139                Some(NavigationData {
13140                    cursor_anchor,
13141                    cursor_position,
13142                    scroll_anchor: scroll_state,
13143                    scroll_top_row,
13144                }),
13145                cx,
13146            );
13147            cx.emit(EditorEvent::PushedToNavHistory {
13148                anchor: cursor_anchor,
13149                is_deactivate,
13150            })
13151        }
13152    }
13153
13154    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13156        let buffer = self.buffer.read(cx).snapshot(cx);
13157        let mut selection = self.selections.first::<usize>(cx);
13158        selection.set_head(buffer.len(), SelectionGoal::None);
13159        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13160            s.select(vec![selection]);
13161        });
13162    }
13163
13164    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13165        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13166        let end = self.buffer.read(cx).read(cx).len();
13167        self.change_selections(None, window, cx, |s| {
13168            s.select_ranges(vec![0..end]);
13169        });
13170    }
13171
13172    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13173        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13174        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13175        let mut selections = self.selections.all::<Point>(cx);
13176        let max_point = display_map.buffer_snapshot.max_point();
13177        for selection in &mut selections {
13178            let rows = selection.spanned_rows(true, &display_map);
13179            selection.start = Point::new(rows.start.0, 0);
13180            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13181            selection.reversed = false;
13182        }
13183        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13184            s.select(selections);
13185        });
13186    }
13187
13188    pub fn split_selection_into_lines(
13189        &mut self,
13190        _: &SplitSelectionIntoLines,
13191        window: &mut Window,
13192        cx: &mut Context<Self>,
13193    ) {
13194        let selections = self
13195            .selections
13196            .all::<Point>(cx)
13197            .into_iter()
13198            .map(|selection| selection.start..selection.end)
13199            .collect::<Vec<_>>();
13200        self.unfold_ranges(&selections, true, true, cx);
13201
13202        let mut new_selection_ranges = Vec::new();
13203        {
13204            let buffer = self.buffer.read(cx).read(cx);
13205            for selection in selections {
13206                for row in selection.start.row..selection.end.row {
13207                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13208                    new_selection_ranges.push(cursor..cursor);
13209                }
13210
13211                let is_multiline_selection = selection.start.row != selection.end.row;
13212                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13213                // so this action feels more ergonomic when paired with other selection operations
13214                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13215                if !should_skip_last {
13216                    new_selection_ranges.push(selection.end..selection.end);
13217                }
13218            }
13219        }
13220        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13221            s.select_ranges(new_selection_ranges);
13222        });
13223    }
13224
13225    pub fn add_selection_above(
13226        &mut self,
13227        _: &AddSelectionAbove,
13228        window: &mut Window,
13229        cx: &mut Context<Self>,
13230    ) {
13231        self.add_selection(true, window, cx);
13232    }
13233
13234    pub fn add_selection_below(
13235        &mut self,
13236        _: &AddSelectionBelow,
13237        window: &mut Window,
13238        cx: &mut Context<Self>,
13239    ) {
13240        self.add_selection(false, window, cx);
13241    }
13242
13243    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13245
13246        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13247        let all_selections = self.selections.all::<Point>(cx);
13248        let text_layout_details = self.text_layout_details(window);
13249
13250        let (mut columnar_selections, new_selections_to_columnarize) = {
13251            if let Some(state) = self.add_selections_state.as_ref() {
13252                let columnar_selection_ids: HashSet<_> = state
13253                    .groups
13254                    .iter()
13255                    .flat_map(|group| group.stack.iter())
13256                    .copied()
13257                    .collect();
13258
13259                all_selections
13260                    .into_iter()
13261                    .partition(|s| columnar_selection_ids.contains(&s.id))
13262            } else {
13263                (Vec::new(), all_selections)
13264            }
13265        };
13266
13267        let mut state = self
13268            .add_selections_state
13269            .take()
13270            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13271
13272        for selection in new_selections_to_columnarize {
13273            let range = selection.display_range(&display_map).sorted();
13274            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13275            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13276            let positions = start_x.min(end_x)..start_x.max(end_x);
13277            let mut stack = Vec::new();
13278            for row in range.start.row().0..=range.end.row().0 {
13279                if let Some(selection) = self.selections.build_columnar_selection(
13280                    &display_map,
13281                    DisplayRow(row),
13282                    &positions,
13283                    selection.reversed,
13284                    &text_layout_details,
13285                ) {
13286                    stack.push(selection.id);
13287                    columnar_selections.push(selection);
13288                }
13289            }
13290            if !stack.is_empty() {
13291                if above {
13292                    stack.reverse();
13293                }
13294                state.groups.push(AddSelectionsGroup { above, stack });
13295            }
13296        }
13297
13298        let mut final_selections = Vec::new();
13299        let end_row = if above {
13300            DisplayRow(0)
13301        } else {
13302            display_map.max_point().row()
13303        };
13304
13305        let mut last_added_item_per_group = HashMap::default();
13306        for group in state.groups.iter_mut() {
13307            if let Some(last_id) = group.stack.last() {
13308                last_added_item_per_group.insert(*last_id, group);
13309            }
13310        }
13311
13312        for selection in columnar_selections {
13313            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13314                if above == group.above {
13315                    let range = selection.display_range(&display_map).sorted();
13316                    debug_assert_eq!(range.start.row(), range.end.row());
13317                    let mut row = range.start.row();
13318                    let positions =
13319                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13320                            px(start)..px(end)
13321                        } else {
13322                            let start_x =
13323                                display_map.x_for_display_point(range.start, &text_layout_details);
13324                            let end_x =
13325                                display_map.x_for_display_point(range.end, &text_layout_details);
13326                            start_x.min(end_x)..start_x.max(end_x)
13327                        };
13328
13329                    let mut maybe_new_selection = None;
13330                    while row != end_row {
13331                        if above {
13332                            row.0 -= 1;
13333                        } else {
13334                            row.0 += 1;
13335                        }
13336                        if let Some(new_selection) = self.selections.build_columnar_selection(
13337                            &display_map,
13338                            row,
13339                            &positions,
13340                            selection.reversed,
13341                            &text_layout_details,
13342                        ) {
13343                            maybe_new_selection = Some(new_selection);
13344                            break;
13345                        }
13346                    }
13347
13348                    if let Some(new_selection) = maybe_new_selection {
13349                        group.stack.push(new_selection.id);
13350                        if above {
13351                            final_selections.push(new_selection);
13352                            final_selections.push(selection);
13353                        } else {
13354                            final_selections.push(selection);
13355                            final_selections.push(new_selection);
13356                        }
13357                    } else {
13358                        final_selections.push(selection);
13359                    }
13360                } else {
13361                    group.stack.pop();
13362                }
13363            } else {
13364                final_selections.push(selection);
13365            }
13366        }
13367
13368        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13369            s.select(final_selections);
13370        });
13371
13372        let final_selection_ids: HashSet<_> = self
13373            .selections
13374            .all::<Point>(cx)
13375            .iter()
13376            .map(|s| s.id)
13377            .collect();
13378        state.groups.retain_mut(|group| {
13379            // selections might get merged above so we remove invalid items from stacks
13380            group.stack.retain(|id| final_selection_ids.contains(id));
13381
13382            // single selection in stack can be treated as initial state
13383            group.stack.len() > 1
13384        });
13385
13386        if !state.groups.is_empty() {
13387            self.add_selections_state = Some(state);
13388        }
13389    }
13390
13391    fn select_match_ranges(
13392        &mut self,
13393        range: Range<usize>,
13394        reversed: bool,
13395        replace_newest: bool,
13396        auto_scroll: Option<Autoscroll>,
13397        window: &mut Window,
13398        cx: &mut Context<Editor>,
13399    ) {
13400        self.unfold_ranges(
13401            std::slice::from_ref(&range),
13402            false,
13403            auto_scroll.is_some(),
13404            cx,
13405        );
13406        self.change_selections(auto_scroll, window, cx, |s| {
13407            if replace_newest {
13408                s.delete(s.newest_anchor().id);
13409            }
13410            if reversed {
13411                s.insert_range(range.end..range.start);
13412            } else {
13413                s.insert_range(range);
13414            }
13415        });
13416    }
13417
13418    pub fn select_next_match_internal(
13419        &mut self,
13420        display_map: &DisplaySnapshot,
13421        replace_newest: bool,
13422        autoscroll: Option<Autoscroll>,
13423        window: &mut Window,
13424        cx: &mut Context<Self>,
13425    ) -> Result<()> {
13426        let buffer = &display_map.buffer_snapshot;
13427        let mut selections = self.selections.all::<usize>(cx);
13428        if let Some(mut select_next_state) = self.select_next_state.take() {
13429            let query = &select_next_state.query;
13430            if !select_next_state.done {
13431                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13432                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13433                let mut next_selected_range = None;
13434
13435                let bytes_after_last_selection =
13436                    buffer.bytes_in_range(last_selection.end..buffer.len());
13437                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13438                let query_matches = query
13439                    .stream_find_iter(bytes_after_last_selection)
13440                    .map(|result| (last_selection.end, result))
13441                    .chain(
13442                        query
13443                            .stream_find_iter(bytes_before_first_selection)
13444                            .map(|result| (0, result)),
13445                    );
13446
13447                for (start_offset, query_match) in query_matches {
13448                    let query_match = query_match.unwrap(); // can only fail due to I/O
13449                    let offset_range =
13450                        start_offset + query_match.start()..start_offset + query_match.end();
13451
13452                    if !select_next_state.wordwise
13453                        || (!buffer.is_inside_word(offset_range.start, false)
13454                            && !buffer.is_inside_word(offset_range.end, false))
13455                    {
13456                        // TODO: This is n^2, because we might check all the selections
13457                        if !selections
13458                            .iter()
13459                            .any(|selection| selection.range().overlaps(&offset_range))
13460                        {
13461                            next_selected_range = Some(offset_range);
13462                            break;
13463                        }
13464                    }
13465                }
13466
13467                if let Some(next_selected_range) = next_selected_range {
13468                    self.select_match_ranges(
13469                        next_selected_range,
13470                        last_selection.reversed,
13471                        replace_newest,
13472                        autoscroll,
13473                        window,
13474                        cx,
13475                    );
13476                } else {
13477                    select_next_state.done = true;
13478                }
13479            }
13480
13481            self.select_next_state = Some(select_next_state);
13482        } else {
13483            let mut only_carets = true;
13484            let mut same_text_selected = true;
13485            let mut selected_text = None;
13486
13487            let mut selections_iter = selections.iter().peekable();
13488            while let Some(selection) = selections_iter.next() {
13489                if selection.start != selection.end {
13490                    only_carets = false;
13491                }
13492
13493                if same_text_selected {
13494                    if selected_text.is_none() {
13495                        selected_text =
13496                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13497                    }
13498
13499                    if let Some(next_selection) = selections_iter.peek() {
13500                        if next_selection.range().len() == selection.range().len() {
13501                            let next_selected_text = buffer
13502                                .text_for_range(next_selection.range())
13503                                .collect::<String>();
13504                            if Some(next_selected_text) != selected_text {
13505                                same_text_selected = false;
13506                                selected_text = None;
13507                            }
13508                        } else {
13509                            same_text_selected = false;
13510                            selected_text = None;
13511                        }
13512                    }
13513                }
13514            }
13515
13516            if only_carets {
13517                for selection in &mut selections {
13518                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13519                    selection.start = word_range.start;
13520                    selection.end = word_range.end;
13521                    selection.goal = SelectionGoal::None;
13522                    selection.reversed = false;
13523                    self.select_match_ranges(
13524                        selection.start..selection.end,
13525                        selection.reversed,
13526                        replace_newest,
13527                        autoscroll,
13528                        window,
13529                        cx,
13530                    );
13531                }
13532
13533                if selections.len() == 1 {
13534                    let selection = selections
13535                        .last()
13536                        .expect("ensured that there's only one selection");
13537                    let query = buffer
13538                        .text_for_range(selection.start..selection.end)
13539                        .collect::<String>();
13540                    let is_empty = query.is_empty();
13541                    let select_state = SelectNextState {
13542                        query: AhoCorasick::new(&[query])?,
13543                        wordwise: true,
13544                        done: is_empty,
13545                    };
13546                    self.select_next_state = Some(select_state);
13547                } else {
13548                    self.select_next_state = None;
13549                }
13550            } else if let Some(selected_text) = selected_text {
13551                self.select_next_state = Some(SelectNextState {
13552                    query: AhoCorasick::new(&[selected_text])?,
13553                    wordwise: false,
13554                    done: false,
13555                });
13556                self.select_next_match_internal(
13557                    display_map,
13558                    replace_newest,
13559                    autoscroll,
13560                    window,
13561                    cx,
13562                )?;
13563            }
13564        }
13565        Ok(())
13566    }
13567
13568    pub fn select_all_matches(
13569        &mut self,
13570        _action: &SelectAllMatches,
13571        window: &mut Window,
13572        cx: &mut Context<Self>,
13573    ) -> Result<()> {
13574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13575
13576        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13577
13578        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13579        let Some(select_next_state) = self.select_next_state.as_mut() else {
13580            return Ok(());
13581        };
13582        if select_next_state.done {
13583            return Ok(());
13584        }
13585
13586        let mut new_selections = Vec::new();
13587
13588        let reversed = self.selections.oldest::<usize>(cx).reversed;
13589        let buffer = &display_map.buffer_snapshot;
13590        let query_matches = select_next_state
13591            .query
13592            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13593
13594        for query_match in query_matches.into_iter() {
13595            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13596            let offset_range = if reversed {
13597                query_match.end()..query_match.start()
13598            } else {
13599                query_match.start()..query_match.end()
13600            };
13601
13602            if !select_next_state.wordwise
13603                || (!buffer.is_inside_word(offset_range.start, false)
13604                    && !buffer.is_inside_word(offset_range.end, false))
13605            {
13606                new_selections.push(offset_range.start..offset_range.end);
13607            }
13608        }
13609
13610        select_next_state.done = true;
13611
13612        if new_selections.is_empty() {
13613            log::error!("bug: new_selections is empty in select_all_matches");
13614            return Ok(());
13615        }
13616
13617        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13618        self.change_selections(None, window, cx, |selections| {
13619            selections.select_ranges(new_selections)
13620        });
13621
13622        Ok(())
13623    }
13624
13625    pub fn select_next(
13626        &mut self,
13627        action: &SelectNext,
13628        window: &mut Window,
13629        cx: &mut Context<Self>,
13630    ) -> Result<()> {
13631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13632        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13633        self.select_next_match_internal(
13634            &display_map,
13635            action.replace_newest,
13636            Some(Autoscroll::newest()),
13637            window,
13638            cx,
13639        )?;
13640        Ok(())
13641    }
13642
13643    pub fn select_previous(
13644        &mut self,
13645        action: &SelectPrevious,
13646        window: &mut Window,
13647        cx: &mut Context<Self>,
13648    ) -> Result<()> {
13649        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13650        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13651        let buffer = &display_map.buffer_snapshot;
13652        let mut selections = self.selections.all::<usize>(cx);
13653        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13654            let query = &select_prev_state.query;
13655            if !select_prev_state.done {
13656                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13657                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13658                let mut next_selected_range = None;
13659                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13660                let bytes_before_last_selection =
13661                    buffer.reversed_bytes_in_range(0..last_selection.start);
13662                let bytes_after_first_selection =
13663                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13664                let query_matches = query
13665                    .stream_find_iter(bytes_before_last_selection)
13666                    .map(|result| (last_selection.start, result))
13667                    .chain(
13668                        query
13669                            .stream_find_iter(bytes_after_first_selection)
13670                            .map(|result| (buffer.len(), result)),
13671                    );
13672                for (end_offset, query_match) in query_matches {
13673                    let query_match = query_match.unwrap(); // can only fail due to I/O
13674                    let offset_range =
13675                        end_offset - query_match.end()..end_offset - query_match.start();
13676
13677                    if !select_prev_state.wordwise
13678                        || (!buffer.is_inside_word(offset_range.start, false)
13679                            && !buffer.is_inside_word(offset_range.end, false))
13680                    {
13681                        next_selected_range = Some(offset_range);
13682                        break;
13683                    }
13684                }
13685
13686                if let Some(next_selected_range) = next_selected_range {
13687                    self.select_match_ranges(
13688                        next_selected_range,
13689                        last_selection.reversed,
13690                        action.replace_newest,
13691                        Some(Autoscroll::newest()),
13692                        window,
13693                        cx,
13694                    );
13695                } else {
13696                    select_prev_state.done = true;
13697                }
13698            }
13699
13700            self.select_prev_state = Some(select_prev_state);
13701        } else {
13702            let mut only_carets = true;
13703            let mut same_text_selected = true;
13704            let mut selected_text = None;
13705
13706            let mut selections_iter = selections.iter().peekable();
13707            while let Some(selection) = selections_iter.next() {
13708                if selection.start != selection.end {
13709                    only_carets = false;
13710                }
13711
13712                if same_text_selected {
13713                    if selected_text.is_none() {
13714                        selected_text =
13715                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13716                    }
13717
13718                    if let Some(next_selection) = selections_iter.peek() {
13719                        if next_selection.range().len() == selection.range().len() {
13720                            let next_selected_text = buffer
13721                                .text_for_range(next_selection.range())
13722                                .collect::<String>();
13723                            if Some(next_selected_text) != selected_text {
13724                                same_text_selected = false;
13725                                selected_text = None;
13726                            }
13727                        } else {
13728                            same_text_selected = false;
13729                            selected_text = None;
13730                        }
13731                    }
13732                }
13733            }
13734
13735            if only_carets {
13736                for selection in &mut selections {
13737                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13738                    selection.start = word_range.start;
13739                    selection.end = word_range.end;
13740                    selection.goal = SelectionGoal::None;
13741                    selection.reversed = false;
13742                    self.select_match_ranges(
13743                        selection.start..selection.end,
13744                        selection.reversed,
13745                        action.replace_newest,
13746                        Some(Autoscroll::newest()),
13747                        window,
13748                        cx,
13749                    );
13750                }
13751                if selections.len() == 1 {
13752                    let selection = selections
13753                        .last()
13754                        .expect("ensured that there's only one selection");
13755                    let query = buffer
13756                        .text_for_range(selection.start..selection.end)
13757                        .collect::<String>();
13758                    let is_empty = query.is_empty();
13759                    let select_state = SelectNextState {
13760                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13761                        wordwise: true,
13762                        done: is_empty,
13763                    };
13764                    self.select_prev_state = Some(select_state);
13765                } else {
13766                    self.select_prev_state = None;
13767                }
13768            } else if let Some(selected_text) = selected_text {
13769                self.select_prev_state = Some(SelectNextState {
13770                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13771                    wordwise: false,
13772                    done: false,
13773                });
13774                self.select_previous(action, window, cx)?;
13775            }
13776        }
13777        Ok(())
13778    }
13779
13780    pub fn find_next_match(
13781        &mut self,
13782        _: &FindNextMatch,
13783        window: &mut Window,
13784        cx: &mut Context<Self>,
13785    ) -> Result<()> {
13786        let selections = self.selections.disjoint_anchors();
13787        match selections.first() {
13788            Some(first) if selections.len() >= 2 => {
13789                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13790                    s.select_ranges([first.range()]);
13791                });
13792            }
13793            _ => self.select_next(
13794                &SelectNext {
13795                    replace_newest: true,
13796                },
13797                window,
13798                cx,
13799            )?,
13800        }
13801        Ok(())
13802    }
13803
13804    pub fn find_previous_match(
13805        &mut self,
13806        _: &FindPreviousMatch,
13807        window: &mut Window,
13808        cx: &mut Context<Self>,
13809    ) -> Result<()> {
13810        let selections = self.selections.disjoint_anchors();
13811        match selections.last() {
13812            Some(last) if selections.len() >= 2 => {
13813                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13814                    s.select_ranges([last.range()]);
13815                });
13816            }
13817            _ => self.select_previous(
13818                &SelectPrevious {
13819                    replace_newest: true,
13820                },
13821                window,
13822                cx,
13823            )?,
13824        }
13825        Ok(())
13826    }
13827
13828    pub fn toggle_comments(
13829        &mut self,
13830        action: &ToggleComments,
13831        window: &mut Window,
13832        cx: &mut Context<Self>,
13833    ) {
13834        if self.read_only(cx) {
13835            return;
13836        }
13837        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13838        let text_layout_details = &self.text_layout_details(window);
13839        self.transact(window, cx, |this, window, cx| {
13840            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13841            let mut edits = Vec::new();
13842            let mut selection_edit_ranges = Vec::new();
13843            let mut last_toggled_row = None;
13844            let snapshot = this.buffer.read(cx).read(cx);
13845            let empty_str: Arc<str> = Arc::default();
13846            let mut suffixes_inserted = Vec::new();
13847            let ignore_indent = action.ignore_indent;
13848
13849            fn comment_prefix_range(
13850                snapshot: &MultiBufferSnapshot,
13851                row: MultiBufferRow,
13852                comment_prefix: &str,
13853                comment_prefix_whitespace: &str,
13854                ignore_indent: bool,
13855            ) -> Range<Point> {
13856                let indent_size = if ignore_indent {
13857                    0
13858                } else {
13859                    snapshot.indent_size_for_line(row).len
13860                };
13861
13862                let start = Point::new(row.0, indent_size);
13863
13864                let mut line_bytes = snapshot
13865                    .bytes_in_range(start..snapshot.max_point())
13866                    .flatten()
13867                    .copied();
13868
13869                // If this line currently begins with the line comment prefix, then record
13870                // the range containing the prefix.
13871                if line_bytes
13872                    .by_ref()
13873                    .take(comment_prefix.len())
13874                    .eq(comment_prefix.bytes())
13875                {
13876                    // Include any whitespace that matches the comment prefix.
13877                    let matching_whitespace_len = line_bytes
13878                        .zip(comment_prefix_whitespace.bytes())
13879                        .take_while(|(a, b)| a == b)
13880                        .count() as u32;
13881                    let end = Point::new(
13882                        start.row,
13883                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13884                    );
13885                    start..end
13886                } else {
13887                    start..start
13888                }
13889            }
13890
13891            fn comment_suffix_range(
13892                snapshot: &MultiBufferSnapshot,
13893                row: MultiBufferRow,
13894                comment_suffix: &str,
13895                comment_suffix_has_leading_space: bool,
13896            ) -> Range<Point> {
13897                let end = Point::new(row.0, snapshot.line_len(row));
13898                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13899
13900                let mut line_end_bytes = snapshot
13901                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13902                    .flatten()
13903                    .copied();
13904
13905                let leading_space_len = if suffix_start_column > 0
13906                    && line_end_bytes.next() == Some(b' ')
13907                    && comment_suffix_has_leading_space
13908                {
13909                    1
13910                } else {
13911                    0
13912                };
13913
13914                // If this line currently begins with the line comment prefix, then record
13915                // the range containing the prefix.
13916                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13917                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13918                    start..end
13919                } else {
13920                    end..end
13921                }
13922            }
13923
13924            // TODO: Handle selections that cross excerpts
13925            for selection in &mut selections {
13926                let start_column = snapshot
13927                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13928                    .len;
13929                let language = if let Some(language) =
13930                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13931                {
13932                    language
13933                } else {
13934                    continue;
13935                };
13936
13937                selection_edit_ranges.clear();
13938
13939                // If multiple selections contain a given row, avoid processing that
13940                // row more than once.
13941                let mut start_row = MultiBufferRow(selection.start.row);
13942                if last_toggled_row == Some(start_row) {
13943                    start_row = start_row.next_row();
13944                }
13945                let end_row =
13946                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13947                        MultiBufferRow(selection.end.row - 1)
13948                    } else {
13949                        MultiBufferRow(selection.end.row)
13950                    };
13951                last_toggled_row = Some(end_row);
13952
13953                if start_row > end_row {
13954                    continue;
13955                }
13956
13957                // If the language has line comments, toggle those.
13958                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13959
13960                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13961                if ignore_indent {
13962                    full_comment_prefixes = full_comment_prefixes
13963                        .into_iter()
13964                        .map(|s| Arc::from(s.trim_end()))
13965                        .collect();
13966                }
13967
13968                if !full_comment_prefixes.is_empty() {
13969                    let first_prefix = full_comment_prefixes
13970                        .first()
13971                        .expect("prefixes is non-empty");
13972                    let prefix_trimmed_lengths = full_comment_prefixes
13973                        .iter()
13974                        .map(|p| p.trim_end_matches(' ').len())
13975                        .collect::<SmallVec<[usize; 4]>>();
13976
13977                    let mut all_selection_lines_are_comments = true;
13978
13979                    for row in start_row.0..=end_row.0 {
13980                        let row = MultiBufferRow(row);
13981                        if start_row < end_row && snapshot.is_line_blank(row) {
13982                            continue;
13983                        }
13984
13985                        let prefix_range = full_comment_prefixes
13986                            .iter()
13987                            .zip(prefix_trimmed_lengths.iter().copied())
13988                            .map(|(prefix, trimmed_prefix_len)| {
13989                                comment_prefix_range(
13990                                    snapshot.deref(),
13991                                    row,
13992                                    &prefix[..trimmed_prefix_len],
13993                                    &prefix[trimmed_prefix_len..],
13994                                    ignore_indent,
13995                                )
13996                            })
13997                            .max_by_key(|range| range.end.column - range.start.column)
13998                            .expect("prefixes is non-empty");
13999
14000                        if prefix_range.is_empty() {
14001                            all_selection_lines_are_comments = false;
14002                        }
14003
14004                        selection_edit_ranges.push(prefix_range);
14005                    }
14006
14007                    if all_selection_lines_are_comments {
14008                        edits.extend(
14009                            selection_edit_ranges
14010                                .iter()
14011                                .cloned()
14012                                .map(|range| (range, empty_str.clone())),
14013                        );
14014                    } else {
14015                        let min_column = selection_edit_ranges
14016                            .iter()
14017                            .map(|range| range.start.column)
14018                            .min()
14019                            .unwrap_or(0);
14020                        edits.extend(selection_edit_ranges.iter().map(|range| {
14021                            let position = Point::new(range.start.row, min_column);
14022                            (position..position, first_prefix.clone())
14023                        }));
14024                    }
14025                } else if let Some((full_comment_prefix, comment_suffix)) =
14026                    language.block_comment_delimiters()
14027                {
14028                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14029                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14030                    let prefix_range = comment_prefix_range(
14031                        snapshot.deref(),
14032                        start_row,
14033                        comment_prefix,
14034                        comment_prefix_whitespace,
14035                        ignore_indent,
14036                    );
14037                    let suffix_range = comment_suffix_range(
14038                        snapshot.deref(),
14039                        end_row,
14040                        comment_suffix.trim_start_matches(' '),
14041                        comment_suffix.starts_with(' '),
14042                    );
14043
14044                    if prefix_range.is_empty() || suffix_range.is_empty() {
14045                        edits.push((
14046                            prefix_range.start..prefix_range.start,
14047                            full_comment_prefix.clone(),
14048                        ));
14049                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14050                        suffixes_inserted.push((end_row, comment_suffix.len()));
14051                    } else {
14052                        edits.push((prefix_range, empty_str.clone()));
14053                        edits.push((suffix_range, empty_str.clone()));
14054                    }
14055                } else {
14056                    continue;
14057                }
14058            }
14059
14060            drop(snapshot);
14061            this.buffer.update(cx, |buffer, cx| {
14062                buffer.edit(edits, None, cx);
14063            });
14064
14065            // Adjust selections so that they end before any comment suffixes that
14066            // were inserted.
14067            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14068            let mut selections = this.selections.all::<Point>(cx);
14069            let snapshot = this.buffer.read(cx).read(cx);
14070            for selection in &mut selections {
14071                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14072                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14073                        Ordering::Less => {
14074                            suffixes_inserted.next();
14075                            continue;
14076                        }
14077                        Ordering::Greater => break,
14078                        Ordering::Equal => {
14079                            if selection.end.column == snapshot.line_len(row) {
14080                                if selection.is_empty() {
14081                                    selection.start.column -= suffix_len as u32;
14082                                }
14083                                selection.end.column -= suffix_len as u32;
14084                            }
14085                            break;
14086                        }
14087                    }
14088                }
14089            }
14090
14091            drop(snapshot);
14092            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14093                s.select(selections)
14094            });
14095
14096            let selections = this.selections.all::<Point>(cx);
14097            let selections_on_single_row = selections.windows(2).all(|selections| {
14098                selections[0].start.row == selections[1].start.row
14099                    && selections[0].end.row == selections[1].end.row
14100                    && selections[0].start.row == selections[0].end.row
14101            });
14102            let selections_selecting = selections
14103                .iter()
14104                .any(|selection| selection.start != selection.end);
14105            let advance_downwards = action.advance_downwards
14106                && selections_on_single_row
14107                && !selections_selecting
14108                && !matches!(this.mode, EditorMode::SingleLine { .. });
14109
14110            if advance_downwards {
14111                let snapshot = this.buffer.read(cx).snapshot(cx);
14112
14113                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14114                    s.move_cursors_with(|display_snapshot, display_point, _| {
14115                        let mut point = display_point.to_point(display_snapshot);
14116                        point.row += 1;
14117                        point = snapshot.clip_point(point, Bias::Left);
14118                        let display_point = point.to_display_point(display_snapshot);
14119                        let goal = SelectionGoal::HorizontalPosition(
14120                            display_snapshot
14121                                .x_for_display_point(display_point, text_layout_details)
14122                                .into(),
14123                        );
14124                        (display_point, goal)
14125                    })
14126                });
14127            }
14128        });
14129    }
14130
14131    pub fn select_enclosing_symbol(
14132        &mut self,
14133        _: &SelectEnclosingSymbol,
14134        window: &mut Window,
14135        cx: &mut Context<Self>,
14136    ) {
14137        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14138
14139        let buffer = self.buffer.read(cx).snapshot(cx);
14140        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14141
14142        fn update_selection(
14143            selection: &Selection<usize>,
14144            buffer_snap: &MultiBufferSnapshot,
14145        ) -> Option<Selection<usize>> {
14146            let cursor = selection.head();
14147            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14148            for symbol in symbols.iter().rev() {
14149                let start = symbol.range.start.to_offset(buffer_snap);
14150                let end = symbol.range.end.to_offset(buffer_snap);
14151                let new_range = start..end;
14152                if start < selection.start || end > selection.end {
14153                    return Some(Selection {
14154                        id: selection.id,
14155                        start: new_range.start,
14156                        end: new_range.end,
14157                        goal: SelectionGoal::None,
14158                        reversed: selection.reversed,
14159                    });
14160                }
14161            }
14162            None
14163        }
14164
14165        let mut selected_larger_symbol = false;
14166        let new_selections = old_selections
14167            .iter()
14168            .map(|selection| match update_selection(selection, &buffer) {
14169                Some(new_selection) => {
14170                    if new_selection.range() != selection.range() {
14171                        selected_larger_symbol = true;
14172                    }
14173                    new_selection
14174                }
14175                None => selection.clone(),
14176            })
14177            .collect::<Vec<_>>();
14178
14179        if selected_larger_symbol {
14180            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14181                s.select(new_selections);
14182            });
14183        }
14184    }
14185
14186    pub fn select_larger_syntax_node(
14187        &mut self,
14188        _: &SelectLargerSyntaxNode,
14189        window: &mut Window,
14190        cx: &mut Context<Self>,
14191    ) {
14192        let Some(visible_row_count) = self.visible_row_count() else {
14193            return;
14194        };
14195        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14196        if old_selections.is_empty() {
14197            return;
14198        }
14199
14200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14201
14202        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14203        let buffer = self.buffer.read(cx).snapshot(cx);
14204
14205        let mut selected_larger_node = false;
14206        let mut new_selections = old_selections
14207            .iter()
14208            .map(|selection| {
14209                let old_range = selection.start..selection.end;
14210
14211                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14212                    // manually select word at selection
14213                    if ["string_content", "inline"].contains(&node.kind()) {
14214                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14215                        // ignore if word is already selected
14216                        if !word_range.is_empty() && old_range != word_range {
14217                            let (last_word_range, _) =
14218                                buffer.surrounding_word(old_range.end, false);
14219                            // only select word if start and end point belongs to same word
14220                            if word_range == last_word_range {
14221                                selected_larger_node = true;
14222                                return Selection {
14223                                    id: selection.id,
14224                                    start: word_range.start,
14225                                    end: word_range.end,
14226                                    goal: SelectionGoal::None,
14227                                    reversed: selection.reversed,
14228                                };
14229                            }
14230                        }
14231                    }
14232                }
14233
14234                let mut new_range = old_range.clone();
14235                while let Some((_node, containing_range)) =
14236                    buffer.syntax_ancestor(new_range.clone())
14237                {
14238                    new_range = match containing_range {
14239                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14240                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14241                    };
14242                    if !display_map.intersects_fold(new_range.start)
14243                        && !display_map.intersects_fold(new_range.end)
14244                    {
14245                        break;
14246                    }
14247                }
14248
14249                selected_larger_node |= new_range != old_range;
14250                Selection {
14251                    id: selection.id,
14252                    start: new_range.start,
14253                    end: new_range.end,
14254                    goal: SelectionGoal::None,
14255                    reversed: selection.reversed,
14256                }
14257            })
14258            .collect::<Vec<_>>();
14259
14260        if !selected_larger_node {
14261            return; // don't put this call in the history
14262        }
14263
14264        // scroll based on transformation done to the last selection created by the user
14265        let (last_old, last_new) = old_selections
14266            .last()
14267            .zip(new_selections.last().cloned())
14268            .expect("old_selections isn't empty");
14269
14270        // revert selection
14271        let is_selection_reversed = {
14272            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14273            new_selections.last_mut().expect("checked above").reversed =
14274                should_newest_selection_be_reversed;
14275            should_newest_selection_be_reversed
14276        };
14277
14278        if selected_larger_node {
14279            self.select_syntax_node_history.disable_clearing = true;
14280            self.change_selections(None, window, cx, |s| {
14281                s.select(new_selections.clone());
14282            });
14283            self.select_syntax_node_history.disable_clearing = false;
14284        }
14285
14286        let start_row = last_new.start.to_display_point(&display_map).row().0;
14287        let end_row = last_new.end.to_display_point(&display_map).row().0;
14288        let selection_height = end_row - start_row + 1;
14289        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14290
14291        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14292        let scroll_behavior = if fits_on_the_screen {
14293            self.request_autoscroll(Autoscroll::fit(), cx);
14294            SelectSyntaxNodeScrollBehavior::FitSelection
14295        } else if is_selection_reversed {
14296            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14297            SelectSyntaxNodeScrollBehavior::CursorTop
14298        } else {
14299            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14300            SelectSyntaxNodeScrollBehavior::CursorBottom
14301        };
14302
14303        self.select_syntax_node_history.push((
14304            old_selections,
14305            scroll_behavior,
14306            is_selection_reversed,
14307        ));
14308    }
14309
14310    pub fn select_smaller_syntax_node(
14311        &mut self,
14312        _: &SelectSmallerSyntaxNode,
14313        window: &mut Window,
14314        cx: &mut Context<Self>,
14315    ) {
14316        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14317
14318        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14319            self.select_syntax_node_history.pop()
14320        {
14321            if let Some(selection) = selections.last_mut() {
14322                selection.reversed = is_selection_reversed;
14323            }
14324
14325            self.select_syntax_node_history.disable_clearing = true;
14326            self.change_selections(None, window, cx, |s| {
14327                s.select(selections.to_vec());
14328            });
14329            self.select_syntax_node_history.disable_clearing = false;
14330
14331            match scroll_behavior {
14332                SelectSyntaxNodeScrollBehavior::CursorTop => {
14333                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14334                }
14335                SelectSyntaxNodeScrollBehavior::FitSelection => {
14336                    self.request_autoscroll(Autoscroll::fit(), cx);
14337                }
14338                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14339                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14340                }
14341            }
14342        }
14343    }
14344
14345    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14346        if !EditorSettings::get_global(cx).gutter.runnables {
14347            self.clear_tasks();
14348            return Task::ready(());
14349        }
14350        let project = self.project.as_ref().map(Entity::downgrade);
14351        let task_sources = self.lsp_task_sources(cx);
14352        let multi_buffer = self.buffer.downgrade();
14353        cx.spawn_in(window, async move |editor, cx| {
14354            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14355            let Some(project) = project.and_then(|p| p.upgrade()) else {
14356                return;
14357            };
14358            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14359                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14360            }) else {
14361                return;
14362            };
14363
14364            let hide_runnables = project
14365                .update(cx, |project, cx| {
14366                    // Do not display any test indicators in non-dev server remote projects.
14367                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14368                })
14369                .unwrap_or(true);
14370            if hide_runnables {
14371                return;
14372            }
14373            let new_rows =
14374                cx.background_spawn({
14375                    let snapshot = display_snapshot.clone();
14376                    async move {
14377                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14378                    }
14379                })
14380                    .await;
14381            let Ok(lsp_tasks) =
14382                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14383            else {
14384                return;
14385            };
14386            let lsp_tasks = lsp_tasks.await;
14387
14388            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14389                lsp_tasks
14390                    .into_iter()
14391                    .flat_map(|(kind, tasks)| {
14392                        tasks.into_iter().filter_map(move |(location, task)| {
14393                            Some((kind.clone(), location?, task))
14394                        })
14395                    })
14396                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14397                        let buffer = location.target.buffer;
14398                        let buffer_snapshot = buffer.read(cx).snapshot();
14399                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14400                            |(excerpt_id, snapshot, _)| {
14401                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14402                                    display_snapshot
14403                                        .buffer_snapshot
14404                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14405                                } else {
14406                                    None
14407                                }
14408                            },
14409                        );
14410                        if let Some(offset) = offset {
14411                            let task_buffer_range =
14412                                location.target.range.to_point(&buffer_snapshot);
14413                            let context_buffer_range =
14414                                task_buffer_range.to_offset(&buffer_snapshot);
14415                            let context_range = BufferOffset(context_buffer_range.start)
14416                                ..BufferOffset(context_buffer_range.end);
14417
14418                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14419                                .or_insert_with(|| RunnableTasks {
14420                                    templates: Vec::new(),
14421                                    offset,
14422                                    column: task_buffer_range.start.column,
14423                                    extra_variables: HashMap::default(),
14424                                    context_range,
14425                                })
14426                                .templates
14427                                .push((kind, task.original_task().clone()));
14428                        }
14429
14430                        acc
14431                    })
14432            }) else {
14433                return;
14434            };
14435
14436            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14437                buffer.language_settings(cx).tasks.prefer_lsp
14438            }) else {
14439                return;
14440            };
14441
14442            let rows = Self::runnable_rows(
14443                project,
14444                display_snapshot,
14445                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14446                new_rows,
14447                cx.clone(),
14448            )
14449            .await;
14450            editor
14451                .update(cx, |editor, _| {
14452                    editor.clear_tasks();
14453                    for (key, mut value) in rows {
14454                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14455                            value.templates.extend(lsp_tasks.templates);
14456                        }
14457
14458                        editor.insert_tasks(key, value);
14459                    }
14460                    for (key, value) in lsp_tasks_by_rows {
14461                        editor.insert_tasks(key, value);
14462                    }
14463                })
14464                .ok();
14465        })
14466    }
14467    fn fetch_runnable_ranges(
14468        snapshot: &DisplaySnapshot,
14469        range: Range<Anchor>,
14470    ) -> Vec<language::RunnableRange> {
14471        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14472    }
14473
14474    fn runnable_rows(
14475        project: Entity<Project>,
14476        snapshot: DisplaySnapshot,
14477        prefer_lsp: bool,
14478        runnable_ranges: Vec<RunnableRange>,
14479        cx: AsyncWindowContext,
14480    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14481        cx.spawn(async move |cx| {
14482            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14483            for mut runnable in runnable_ranges {
14484                let Some(tasks) = cx
14485                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14486                    .ok()
14487                else {
14488                    continue;
14489                };
14490                let mut tasks = tasks.await;
14491
14492                if prefer_lsp {
14493                    tasks.retain(|(task_kind, _)| {
14494                        !matches!(task_kind, TaskSourceKind::Language { .. })
14495                    });
14496                }
14497                if tasks.is_empty() {
14498                    continue;
14499                }
14500
14501                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14502                let Some(row) = snapshot
14503                    .buffer_snapshot
14504                    .buffer_line_for_row(MultiBufferRow(point.row))
14505                    .map(|(_, range)| range.start.row)
14506                else {
14507                    continue;
14508                };
14509
14510                let context_range =
14511                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14512                runnable_rows.push((
14513                    (runnable.buffer_id, row),
14514                    RunnableTasks {
14515                        templates: tasks,
14516                        offset: snapshot
14517                            .buffer_snapshot
14518                            .anchor_before(runnable.run_range.start),
14519                        context_range,
14520                        column: point.column,
14521                        extra_variables: runnable.extra_captures,
14522                    },
14523                ));
14524            }
14525            runnable_rows
14526        })
14527    }
14528
14529    fn templates_with_tags(
14530        project: &Entity<Project>,
14531        runnable: &mut Runnable,
14532        cx: &mut App,
14533    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14534        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14535            let (worktree_id, file) = project
14536                .buffer_for_id(runnable.buffer, cx)
14537                .and_then(|buffer| buffer.read(cx).file())
14538                .map(|file| (file.worktree_id(cx), file.clone()))
14539                .unzip();
14540
14541            (
14542                project.task_store().read(cx).task_inventory().cloned(),
14543                worktree_id,
14544                file,
14545            )
14546        });
14547
14548        let tags = mem::take(&mut runnable.tags);
14549        let language = runnable.language.clone();
14550        cx.spawn(async move |cx| {
14551            let mut templates_with_tags = Vec::new();
14552            if let Some(inventory) = inventory {
14553                for RunnableTag(tag) in tags {
14554                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14555                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14556                    }) else {
14557                        return templates_with_tags;
14558                    };
14559                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14560                        move |(_, template)| {
14561                            template.tags.iter().any(|source_tag| source_tag == &tag)
14562                        },
14563                    ));
14564                }
14565            }
14566            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14567
14568            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14569                // Strongest source wins; if we have worktree tag binding, prefer that to
14570                // global and language bindings;
14571                // if we have a global binding, prefer that to language binding.
14572                let first_mismatch = templates_with_tags
14573                    .iter()
14574                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14575                if let Some(index) = first_mismatch {
14576                    templates_with_tags.truncate(index);
14577                }
14578            }
14579
14580            templates_with_tags
14581        })
14582    }
14583
14584    pub fn move_to_enclosing_bracket(
14585        &mut self,
14586        _: &MoveToEnclosingBracket,
14587        window: &mut Window,
14588        cx: &mut Context<Self>,
14589    ) {
14590        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14591        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14592            s.move_offsets_with(|snapshot, selection| {
14593                let Some(enclosing_bracket_ranges) =
14594                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14595                else {
14596                    return;
14597                };
14598
14599                let mut best_length = usize::MAX;
14600                let mut best_inside = false;
14601                let mut best_in_bracket_range = false;
14602                let mut best_destination = None;
14603                for (open, close) in enclosing_bracket_ranges {
14604                    let close = close.to_inclusive();
14605                    let length = close.end() - open.start;
14606                    let inside = selection.start >= open.end && selection.end <= *close.start();
14607                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14608                        || close.contains(&selection.head());
14609
14610                    // If best is next to a bracket and current isn't, skip
14611                    if !in_bracket_range && best_in_bracket_range {
14612                        continue;
14613                    }
14614
14615                    // Prefer smaller lengths unless best is inside and current isn't
14616                    if length > best_length && (best_inside || !inside) {
14617                        continue;
14618                    }
14619
14620                    best_length = length;
14621                    best_inside = inside;
14622                    best_in_bracket_range = in_bracket_range;
14623                    best_destination = Some(
14624                        if close.contains(&selection.start) && close.contains(&selection.end) {
14625                            if inside { open.end } else { open.start }
14626                        } else if inside {
14627                            *close.start()
14628                        } else {
14629                            *close.end()
14630                        },
14631                    );
14632                }
14633
14634                if let Some(destination) = best_destination {
14635                    selection.collapse_to(destination, SelectionGoal::None);
14636                }
14637            })
14638        });
14639    }
14640
14641    pub fn undo_selection(
14642        &mut self,
14643        _: &UndoSelection,
14644        window: &mut Window,
14645        cx: &mut Context<Self>,
14646    ) {
14647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14648        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14649            self.selection_history.mode = SelectionHistoryMode::Undoing;
14650            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14651                this.end_selection(window, cx);
14652                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14653                    s.select_anchors(entry.selections.to_vec())
14654                });
14655            });
14656            self.selection_history.mode = SelectionHistoryMode::Normal;
14657
14658            self.select_next_state = entry.select_next_state;
14659            self.select_prev_state = entry.select_prev_state;
14660            self.add_selections_state = entry.add_selections_state;
14661        }
14662    }
14663
14664    pub fn redo_selection(
14665        &mut self,
14666        _: &RedoSelection,
14667        window: &mut Window,
14668        cx: &mut Context<Self>,
14669    ) {
14670        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14671        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14672            self.selection_history.mode = SelectionHistoryMode::Redoing;
14673            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14674                this.end_selection(window, cx);
14675                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14676                    s.select_anchors(entry.selections.to_vec())
14677                });
14678            });
14679            self.selection_history.mode = SelectionHistoryMode::Normal;
14680
14681            self.select_next_state = entry.select_next_state;
14682            self.select_prev_state = entry.select_prev_state;
14683            self.add_selections_state = entry.add_selections_state;
14684        }
14685    }
14686
14687    pub fn expand_excerpts(
14688        &mut self,
14689        action: &ExpandExcerpts,
14690        _: &mut Window,
14691        cx: &mut Context<Self>,
14692    ) {
14693        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14694    }
14695
14696    pub fn expand_excerpts_down(
14697        &mut self,
14698        action: &ExpandExcerptsDown,
14699        _: &mut Window,
14700        cx: &mut Context<Self>,
14701    ) {
14702        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14703    }
14704
14705    pub fn expand_excerpts_up(
14706        &mut self,
14707        action: &ExpandExcerptsUp,
14708        _: &mut Window,
14709        cx: &mut Context<Self>,
14710    ) {
14711        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14712    }
14713
14714    pub fn expand_excerpts_for_direction(
14715        &mut self,
14716        lines: u32,
14717        direction: ExpandExcerptDirection,
14718
14719        cx: &mut Context<Self>,
14720    ) {
14721        let selections = self.selections.disjoint_anchors();
14722
14723        let lines = if lines == 0 {
14724            EditorSettings::get_global(cx).expand_excerpt_lines
14725        } else {
14726            lines
14727        };
14728
14729        self.buffer.update(cx, |buffer, cx| {
14730            let snapshot = buffer.snapshot(cx);
14731            let mut excerpt_ids = selections
14732                .iter()
14733                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14734                .collect::<Vec<_>>();
14735            excerpt_ids.sort();
14736            excerpt_ids.dedup();
14737            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14738        })
14739    }
14740
14741    pub fn expand_excerpt(
14742        &mut self,
14743        excerpt: ExcerptId,
14744        direction: ExpandExcerptDirection,
14745        window: &mut Window,
14746        cx: &mut Context<Self>,
14747    ) {
14748        let current_scroll_position = self.scroll_position(cx);
14749        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14750        let mut should_scroll_up = false;
14751
14752        if direction == ExpandExcerptDirection::Down {
14753            let multi_buffer = self.buffer.read(cx);
14754            let snapshot = multi_buffer.snapshot(cx);
14755            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14756                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14757                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14758                        let buffer_snapshot = buffer.read(cx).snapshot();
14759                        let excerpt_end_row =
14760                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14761                        let last_row = buffer_snapshot.max_point().row;
14762                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14763                        should_scroll_up = lines_below >= lines_to_expand;
14764                    }
14765                }
14766            }
14767        }
14768
14769        self.buffer.update(cx, |buffer, cx| {
14770            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14771        });
14772
14773        if should_scroll_up {
14774            let new_scroll_position =
14775                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14776            self.set_scroll_position(new_scroll_position, window, cx);
14777        }
14778    }
14779
14780    pub fn go_to_singleton_buffer_point(
14781        &mut self,
14782        point: Point,
14783        window: &mut Window,
14784        cx: &mut Context<Self>,
14785    ) {
14786        self.go_to_singleton_buffer_range(point..point, window, cx);
14787    }
14788
14789    pub fn go_to_singleton_buffer_range(
14790        &mut self,
14791        range: Range<Point>,
14792        window: &mut Window,
14793        cx: &mut Context<Self>,
14794    ) {
14795        let multibuffer = self.buffer().read(cx);
14796        let Some(buffer) = multibuffer.as_singleton() else {
14797            return;
14798        };
14799        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14800            return;
14801        };
14802        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14803            return;
14804        };
14805        self.change_selections(
14806            SelectionEffects::default().nav_history(true),
14807            window,
14808            cx,
14809            |s| s.select_anchor_ranges([start..end]),
14810        );
14811    }
14812
14813    pub fn go_to_diagnostic(
14814        &mut self,
14815        _: &GoToDiagnostic,
14816        window: &mut Window,
14817        cx: &mut Context<Self>,
14818    ) {
14819        if !self.diagnostics_enabled() {
14820            return;
14821        }
14822        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14823        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14824    }
14825
14826    pub fn go_to_prev_diagnostic(
14827        &mut self,
14828        _: &GoToPreviousDiagnostic,
14829        window: &mut Window,
14830        cx: &mut Context<Self>,
14831    ) {
14832        if !self.diagnostics_enabled() {
14833            return;
14834        }
14835        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14836        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14837    }
14838
14839    pub fn go_to_diagnostic_impl(
14840        &mut self,
14841        direction: Direction,
14842        window: &mut Window,
14843        cx: &mut Context<Self>,
14844    ) {
14845        let buffer = self.buffer.read(cx).snapshot(cx);
14846        let selection = self.selections.newest::<usize>(cx);
14847
14848        let mut active_group_id = None;
14849        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14850            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14851                active_group_id = Some(active_group.group_id);
14852            }
14853        }
14854
14855        fn filtered(
14856            snapshot: EditorSnapshot,
14857            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14858        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14859            diagnostics
14860                .filter(|entry| entry.range.start != entry.range.end)
14861                .filter(|entry| !entry.diagnostic.is_unnecessary)
14862                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14863        }
14864
14865        let snapshot = self.snapshot(window, cx);
14866        let before = filtered(
14867            snapshot.clone(),
14868            buffer
14869                .diagnostics_in_range(0..selection.start)
14870                .filter(|entry| entry.range.start <= selection.start),
14871        );
14872        let after = filtered(
14873            snapshot,
14874            buffer
14875                .diagnostics_in_range(selection.start..buffer.len())
14876                .filter(|entry| entry.range.start >= selection.start),
14877        );
14878
14879        let mut found: Option<DiagnosticEntry<usize>> = None;
14880        if direction == Direction::Prev {
14881            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14882            {
14883                for diagnostic in prev_diagnostics.into_iter().rev() {
14884                    if diagnostic.range.start != selection.start
14885                        || active_group_id
14886                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14887                    {
14888                        found = Some(diagnostic);
14889                        break 'outer;
14890                    }
14891                }
14892            }
14893        } else {
14894            for diagnostic in after.chain(before) {
14895                if diagnostic.range.start != selection.start
14896                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14897                {
14898                    found = Some(diagnostic);
14899                    break;
14900                }
14901            }
14902        }
14903        let Some(next_diagnostic) = found else {
14904            return;
14905        };
14906
14907        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14908            return;
14909        };
14910        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14911            s.select_ranges(vec![
14912                next_diagnostic.range.start..next_diagnostic.range.start,
14913            ])
14914        });
14915        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14916        self.refresh_inline_completion(false, true, window, cx);
14917    }
14918
14919    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14920        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14921        let snapshot = self.snapshot(window, cx);
14922        let selection = self.selections.newest::<Point>(cx);
14923        self.go_to_hunk_before_or_after_position(
14924            &snapshot,
14925            selection.head(),
14926            Direction::Next,
14927            window,
14928            cx,
14929        );
14930    }
14931
14932    pub fn go_to_hunk_before_or_after_position(
14933        &mut self,
14934        snapshot: &EditorSnapshot,
14935        position: Point,
14936        direction: Direction,
14937        window: &mut Window,
14938        cx: &mut Context<Editor>,
14939    ) {
14940        let row = if direction == Direction::Next {
14941            self.hunk_after_position(snapshot, position)
14942                .map(|hunk| hunk.row_range.start)
14943        } else {
14944            self.hunk_before_position(snapshot, position)
14945        };
14946
14947        if let Some(row) = row {
14948            let destination = Point::new(row.0, 0);
14949            let autoscroll = Autoscroll::center();
14950
14951            self.unfold_ranges(&[destination..destination], false, false, cx);
14952            self.change_selections(Some(autoscroll), window, cx, |s| {
14953                s.select_ranges([destination..destination]);
14954            });
14955        }
14956    }
14957
14958    fn hunk_after_position(
14959        &mut self,
14960        snapshot: &EditorSnapshot,
14961        position: Point,
14962    ) -> Option<MultiBufferDiffHunk> {
14963        snapshot
14964            .buffer_snapshot
14965            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14966            .find(|hunk| hunk.row_range.start.0 > position.row)
14967            .or_else(|| {
14968                snapshot
14969                    .buffer_snapshot
14970                    .diff_hunks_in_range(Point::zero()..position)
14971                    .find(|hunk| hunk.row_range.end.0 < position.row)
14972            })
14973    }
14974
14975    fn go_to_prev_hunk(
14976        &mut self,
14977        _: &GoToPreviousHunk,
14978        window: &mut Window,
14979        cx: &mut Context<Self>,
14980    ) {
14981        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14982        let snapshot = self.snapshot(window, cx);
14983        let selection = self.selections.newest::<Point>(cx);
14984        self.go_to_hunk_before_or_after_position(
14985            &snapshot,
14986            selection.head(),
14987            Direction::Prev,
14988            window,
14989            cx,
14990        );
14991    }
14992
14993    fn hunk_before_position(
14994        &mut self,
14995        snapshot: &EditorSnapshot,
14996        position: Point,
14997    ) -> Option<MultiBufferRow> {
14998        snapshot
14999            .buffer_snapshot
15000            .diff_hunk_before(position)
15001            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15002    }
15003
15004    fn go_to_next_change(
15005        &mut self,
15006        _: &GoToNextChange,
15007        window: &mut Window,
15008        cx: &mut Context<Self>,
15009    ) {
15010        if let Some(selections) = self
15011            .change_list
15012            .next_change(1, Direction::Next)
15013            .map(|s| s.to_vec())
15014        {
15015            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15016                let map = s.display_map();
15017                s.select_display_ranges(selections.iter().map(|a| {
15018                    let point = a.to_display_point(&map);
15019                    point..point
15020                }))
15021            })
15022        }
15023    }
15024
15025    fn go_to_previous_change(
15026        &mut self,
15027        _: &GoToPreviousChange,
15028        window: &mut Window,
15029        cx: &mut Context<Self>,
15030    ) {
15031        if let Some(selections) = self
15032            .change_list
15033            .next_change(1, Direction::Prev)
15034            .map(|s| s.to_vec())
15035        {
15036            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15037                let map = s.display_map();
15038                s.select_display_ranges(selections.iter().map(|a| {
15039                    let point = a.to_display_point(&map);
15040                    point..point
15041                }))
15042            })
15043        }
15044    }
15045
15046    fn go_to_line<T: 'static>(
15047        &mut self,
15048        position: Anchor,
15049        highlight_color: Option<Hsla>,
15050        window: &mut Window,
15051        cx: &mut Context<Self>,
15052    ) {
15053        let snapshot = self.snapshot(window, cx).display_snapshot;
15054        let position = position.to_point(&snapshot.buffer_snapshot);
15055        let start = snapshot
15056            .buffer_snapshot
15057            .clip_point(Point::new(position.row, 0), Bias::Left);
15058        let end = start + Point::new(1, 0);
15059        let start = snapshot.buffer_snapshot.anchor_before(start);
15060        let end = snapshot.buffer_snapshot.anchor_before(end);
15061
15062        self.highlight_rows::<T>(
15063            start..end,
15064            highlight_color
15065                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15066            Default::default(),
15067            cx,
15068        );
15069
15070        if self.buffer.read(cx).is_singleton() {
15071            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15072        }
15073    }
15074
15075    pub fn go_to_definition(
15076        &mut self,
15077        _: &GoToDefinition,
15078        window: &mut Window,
15079        cx: &mut Context<Self>,
15080    ) -> Task<Result<Navigated>> {
15081        let definition =
15082            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15083        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15084        cx.spawn_in(window, async move |editor, cx| {
15085            if definition.await? == Navigated::Yes {
15086                return Ok(Navigated::Yes);
15087            }
15088            match fallback_strategy {
15089                GoToDefinitionFallback::None => Ok(Navigated::No),
15090                GoToDefinitionFallback::FindAllReferences => {
15091                    match editor.update_in(cx, |editor, window, cx| {
15092                        editor.find_all_references(&FindAllReferences, window, cx)
15093                    })? {
15094                        Some(references) => references.await,
15095                        None => Ok(Navigated::No),
15096                    }
15097                }
15098            }
15099        })
15100    }
15101
15102    pub fn go_to_declaration(
15103        &mut self,
15104        _: &GoToDeclaration,
15105        window: &mut Window,
15106        cx: &mut Context<Self>,
15107    ) -> Task<Result<Navigated>> {
15108        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15109    }
15110
15111    pub fn go_to_declaration_split(
15112        &mut self,
15113        _: &GoToDeclaration,
15114        window: &mut Window,
15115        cx: &mut Context<Self>,
15116    ) -> Task<Result<Navigated>> {
15117        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15118    }
15119
15120    pub fn go_to_implementation(
15121        &mut self,
15122        _: &GoToImplementation,
15123        window: &mut Window,
15124        cx: &mut Context<Self>,
15125    ) -> Task<Result<Navigated>> {
15126        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15127    }
15128
15129    pub fn go_to_implementation_split(
15130        &mut self,
15131        _: &GoToImplementationSplit,
15132        window: &mut Window,
15133        cx: &mut Context<Self>,
15134    ) -> Task<Result<Navigated>> {
15135        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15136    }
15137
15138    pub fn go_to_type_definition(
15139        &mut self,
15140        _: &GoToTypeDefinition,
15141        window: &mut Window,
15142        cx: &mut Context<Self>,
15143    ) -> Task<Result<Navigated>> {
15144        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15145    }
15146
15147    pub fn go_to_definition_split(
15148        &mut self,
15149        _: &GoToDefinitionSplit,
15150        window: &mut Window,
15151        cx: &mut Context<Self>,
15152    ) -> Task<Result<Navigated>> {
15153        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15154    }
15155
15156    pub fn go_to_type_definition_split(
15157        &mut self,
15158        _: &GoToTypeDefinitionSplit,
15159        window: &mut Window,
15160        cx: &mut Context<Self>,
15161    ) -> Task<Result<Navigated>> {
15162        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15163    }
15164
15165    fn go_to_definition_of_kind(
15166        &mut self,
15167        kind: GotoDefinitionKind,
15168        split: bool,
15169        window: &mut Window,
15170        cx: &mut Context<Self>,
15171    ) -> Task<Result<Navigated>> {
15172        let Some(provider) = self.semantics_provider.clone() else {
15173            return Task::ready(Ok(Navigated::No));
15174        };
15175        let head = self.selections.newest::<usize>(cx).head();
15176        let buffer = self.buffer.read(cx);
15177        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15178            text_anchor
15179        } else {
15180            return Task::ready(Ok(Navigated::No));
15181        };
15182
15183        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15184            return Task::ready(Ok(Navigated::No));
15185        };
15186
15187        cx.spawn_in(window, async move |editor, cx| {
15188            let definitions = definitions.await?;
15189            let navigated = editor
15190                .update_in(cx, |editor, window, cx| {
15191                    editor.navigate_to_hover_links(
15192                        Some(kind),
15193                        definitions
15194                            .into_iter()
15195                            .filter(|location| {
15196                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15197                            })
15198                            .map(HoverLink::Text)
15199                            .collect::<Vec<_>>(),
15200                        split,
15201                        window,
15202                        cx,
15203                    )
15204                })?
15205                .await?;
15206            anyhow::Ok(navigated)
15207        })
15208    }
15209
15210    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15211        let selection = self.selections.newest_anchor();
15212        let head = selection.head();
15213        let tail = selection.tail();
15214
15215        let Some((buffer, start_position)) =
15216            self.buffer.read(cx).text_anchor_for_position(head, cx)
15217        else {
15218            return;
15219        };
15220
15221        let end_position = if head != tail {
15222            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15223                return;
15224            };
15225            Some(pos)
15226        } else {
15227            None
15228        };
15229
15230        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15231            let url = if let Some(end_pos) = end_position {
15232                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15233            } else {
15234                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15235            };
15236
15237            if let Some(url) = url {
15238                editor.update(cx, |_, cx| {
15239                    cx.open_url(&url);
15240                })
15241            } else {
15242                Ok(())
15243            }
15244        });
15245
15246        url_finder.detach();
15247    }
15248
15249    pub fn open_selected_filename(
15250        &mut self,
15251        _: &OpenSelectedFilename,
15252        window: &mut Window,
15253        cx: &mut Context<Self>,
15254    ) {
15255        let Some(workspace) = self.workspace() else {
15256            return;
15257        };
15258
15259        let position = self.selections.newest_anchor().head();
15260
15261        let Some((buffer, buffer_position)) =
15262            self.buffer.read(cx).text_anchor_for_position(position, cx)
15263        else {
15264            return;
15265        };
15266
15267        let project = self.project.clone();
15268
15269        cx.spawn_in(window, async move |_, cx| {
15270            let result = find_file(&buffer, project, buffer_position, cx).await;
15271
15272            if let Some((_, path)) = result {
15273                workspace
15274                    .update_in(cx, |workspace, window, cx| {
15275                        workspace.open_resolved_path(path, window, cx)
15276                    })?
15277                    .await?;
15278            }
15279            anyhow::Ok(())
15280        })
15281        .detach();
15282    }
15283
15284    pub(crate) fn navigate_to_hover_links(
15285        &mut self,
15286        kind: Option<GotoDefinitionKind>,
15287        mut definitions: Vec<HoverLink>,
15288        split: bool,
15289        window: &mut Window,
15290        cx: &mut Context<Editor>,
15291    ) -> Task<Result<Navigated>> {
15292        // If there is one definition, just open it directly
15293        if definitions.len() == 1 {
15294            let definition = definitions.pop().unwrap();
15295
15296            enum TargetTaskResult {
15297                Location(Option<Location>),
15298                AlreadyNavigated,
15299            }
15300
15301            let target_task = match definition {
15302                HoverLink::Text(link) => {
15303                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15304                }
15305                HoverLink::InlayHint(lsp_location, server_id) => {
15306                    let computation =
15307                        self.compute_target_location(lsp_location, server_id, window, cx);
15308                    cx.background_spawn(async move {
15309                        let location = computation.await?;
15310                        Ok(TargetTaskResult::Location(location))
15311                    })
15312                }
15313                HoverLink::Url(url) => {
15314                    cx.open_url(&url);
15315                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15316                }
15317                HoverLink::File(path) => {
15318                    if let Some(workspace) = self.workspace() {
15319                        cx.spawn_in(window, async move |_, cx| {
15320                            workspace
15321                                .update_in(cx, |workspace, window, cx| {
15322                                    workspace.open_resolved_path(path, window, cx)
15323                                })?
15324                                .await
15325                                .map(|_| TargetTaskResult::AlreadyNavigated)
15326                        })
15327                    } else {
15328                        Task::ready(Ok(TargetTaskResult::Location(None)))
15329                    }
15330                }
15331            };
15332            cx.spawn_in(window, async move |editor, cx| {
15333                let target = match target_task.await.context("target resolution task")? {
15334                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15335                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15336                    TargetTaskResult::Location(Some(target)) => target,
15337                };
15338
15339                editor.update_in(cx, |editor, window, cx| {
15340                    let Some(workspace) = editor.workspace() else {
15341                        return Navigated::No;
15342                    };
15343                    let pane = workspace.read(cx).active_pane().clone();
15344
15345                    let range = target.range.to_point(target.buffer.read(cx));
15346                    let range = editor.range_for_match(&range);
15347                    let range = collapse_multiline_range(range);
15348
15349                    if !split
15350                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15351                    {
15352                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15353                    } else {
15354                        window.defer(cx, move |window, cx| {
15355                            let target_editor: Entity<Self> =
15356                                workspace.update(cx, |workspace, cx| {
15357                                    let pane = if split {
15358                                        workspace.adjacent_pane(window, cx)
15359                                    } else {
15360                                        workspace.active_pane().clone()
15361                                    };
15362
15363                                    workspace.open_project_item(
15364                                        pane,
15365                                        target.buffer.clone(),
15366                                        true,
15367                                        true,
15368                                        window,
15369                                        cx,
15370                                    )
15371                                });
15372                            target_editor.update(cx, |target_editor, cx| {
15373                                // When selecting a definition in a different buffer, disable the nav history
15374                                // to avoid creating a history entry at the previous cursor location.
15375                                pane.update(cx, |pane, _| pane.disable_history());
15376                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15377                                pane.update(cx, |pane, _| pane.enable_history());
15378                            });
15379                        });
15380                    }
15381                    Navigated::Yes
15382                })
15383            })
15384        } else if !definitions.is_empty() {
15385            cx.spawn_in(window, async move |editor, cx| {
15386                let (title, location_tasks, workspace) = editor
15387                    .update_in(cx, |editor, window, cx| {
15388                        let tab_kind = match kind {
15389                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15390                            _ => "Definitions",
15391                        };
15392                        let title = definitions
15393                            .iter()
15394                            .find_map(|definition| match definition {
15395                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15396                                    let buffer = origin.buffer.read(cx);
15397                                    format!(
15398                                        "{} for {}",
15399                                        tab_kind,
15400                                        buffer
15401                                            .text_for_range(origin.range.clone())
15402                                            .collect::<String>()
15403                                    )
15404                                }),
15405                                HoverLink::InlayHint(_, _) => None,
15406                                HoverLink::Url(_) => None,
15407                                HoverLink::File(_) => None,
15408                            })
15409                            .unwrap_or(tab_kind.to_string());
15410                        let location_tasks = definitions
15411                            .into_iter()
15412                            .map(|definition| match definition {
15413                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15414                                HoverLink::InlayHint(lsp_location, server_id) => editor
15415                                    .compute_target_location(lsp_location, server_id, window, cx),
15416                                HoverLink::Url(_) => Task::ready(Ok(None)),
15417                                HoverLink::File(_) => Task::ready(Ok(None)),
15418                            })
15419                            .collect::<Vec<_>>();
15420                        (title, location_tasks, editor.workspace().clone())
15421                    })
15422                    .context("location tasks preparation")?;
15423
15424                let locations: Vec<Location> = future::join_all(location_tasks)
15425                    .await
15426                    .into_iter()
15427                    .filter_map(|location| location.transpose())
15428                    .collect::<Result<_>>()
15429                    .context("location tasks")?;
15430
15431                if locations.is_empty() {
15432                    return Ok(Navigated::No);
15433                }
15434
15435                let Some(workspace) = workspace else {
15436                    return Ok(Navigated::No);
15437                };
15438
15439                let opened = workspace
15440                    .update_in(cx, |workspace, window, cx| {
15441                        Self::open_locations_in_multibuffer(
15442                            workspace,
15443                            locations,
15444                            title,
15445                            split,
15446                            MultibufferSelectionMode::First,
15447                            window,
15448                            cx,
15449                        )
15450                    })
15451                    .ok();
15452
15453                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15454            })
15455        } else {
15456            Task::ready(Ok(Navigated::No))
15457        }
15458    }
15459
15460    fn compute_target_location(
15461        &self,
15462        lsp_location: lsp::Location,
15463        server_id: LanguageServerId,
15464        window: &mut Window,
15465        cx: &mut Context<Self>,
15466    ) -> Task<anyhow::Result<Option<Location>>> {
15467        let Some(project) = self.project.clone() else {
15468            return Task::ready(Ok(None));
15469        };
15470
15471        cx.spawn_in(window, async move |editor, cx| {
15472            let location_task = editor.update(cx, |_, cx| {
15473                project.update(cx, |project, cx| {
15474                    let language_server_name = project
15475                        .language_server_statuses(cx)
15476                        .find(|(id, _)| server_id == *id)
15477                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15478                    language_server_name.map(|language_server_name| {
15479                        project.open_local_buffer_via_lsp(
15480                            lsp_location.uri.clone(),
15481                            server_id,
15482                            language_server_name,
15483                            cx,
15484                        )
15485                    })
15486                })
15487            })?;
15488            let location = match location_task {
15489                Some(task) => Some({
15490                    let target_buffer_handle = task.await.context("open local buffer")?;
15491                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15492                        let target_start = target_buffer
15493                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15494                        let target_end = target_buffer
15495                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15496                        target_buffer.anchor_after(target_start)
15497                            ..target_buffer.anchor_before(target_end)
15498                    })?;
15499                    Location {
15500                        buffer: target_buffer_handle,
15501                        range,
15502                    }
15503                }),
15504                None => None,
15505            };
15506            Ok(location)
15507        })
15508    }
15509
15510    pub fn find_all_references(
15511        &mut self,
15512        _: &FindAllReferences,
15513        window: &mut Window,
15514        cx: &mut Context<Self>,
15515    ) -> Option<Task<Result<Navigated>>> {
15516        let selection = self.selections.newest::<usize>(cx);
15517        let multi_buffer = self.buffer.read(cx);
15518        let head = selection.head();
15519
15520        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15521        let head_anchor = multi_buffer_snapshot.anchor_at(
15522            head,
15523            if head < selection.tail() {
15524                Bias::Right
15525            } else {
15526                Bias::Left
15527            },
15528        );
15529
15530        match self
15531            .find_all_references_task_sources
15532            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15533        {
15534            Ok(_) => {
15535                log::info!(
15536                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15537                );
15538                return None;
15539            }
15540            Err(i) => {
15541                self.find_all_references_task_sources.insert(i, head_anchor);
15542            }
15543        }
15544
15545        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15546        let workspace = self.workspace()?;
15547        let project = workspace.read(cx).project().clone();
15548        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15549        Some(cx.spawn_in(window, async move |editor, cx| {
15550            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15551                if let Ok(i) = editor
15552                    .find_all_references_task_sources
15553                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15554                {
15555                    editor.find_all_references_task_sources.remove(i);
15556                }
15557            });
15558
15559            let locations = references.await?;
15560            if locations.is_empty() {
15561                return anyhow::Ok(Navigated::No);
15562            }
15563
15564            workspace.update_in(cx, |workspace, window, cx| {
15565                let title = locations
15566                    .first()
15567                    .as_ref()
15568                    .map(|location| {
15569                        let buffer = location.buffer.read(cx);
15570                        format!(
15571                            "References to `{}`",
15572                            buffer
15573                                .text_for_range(location.range.clone())
15574                                .collect::<String>()
15575                        )
15576                    })
15577                    .unwrap();
15578                Self::open_locations_in_multibuffer(
15579                    workspace,
15580                    locations,
15581                    title,
15582                    false,
15583                    MultibufferSelectionMode::First,
15584                    window,
15585                    cx,
15586                );
15587                Navigated::Yes
15588            })
15589        }))
15590    }
15591
15592    /// Opens a multibuffer with the given project locations in it
15593    pub fn open_locations_in_multibuffer(
15594        workspace: &mut Workspace,
15595        mut locations: Vec<Location>,
15596        title: String,
15597        split: bool,
15598        multibuffer_selection_mode: MultibufferSelectionMode,
15599        window: &mut Window,
15600        cx: &mut Context<Workspace>,
15601    ) {
15602        if locations.is_empty() {
15603            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15604            return;
15605        }
15606
15607        // If there are multiple definitions, open them in a multibuffer
15608        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15609        let mut locations = locations.into_iter().peekable();
15610        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15611        let capability = workspace.project().read(cx).capability();
15612
15613        let excerpt_buffer = cx.new(|cx| {
15614            let mut multibuffer = MultiBuffer::new(capability);
15615            while let Some(location) = locations.next() {
15616                let buffer = location.buffer.read(cx);
15617                let mut ranges_for_buffer = Vec::new();
15618                let range = location.range.to_point(buffer);
15619                ranges_for_buffer.push(range.clone());
15620
15621                while let Some(next_location) = locations.peek() {
15622                    if next_location.buffer == location.buffer {
15623                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15624                        locations.next();
15625                    } else {
15626                        break;
15627                    }
15628                }
15629
15630                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15631                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15632                    PathKey::for_buffer(&location.buffer, cx),
15633                    location.buffer.clone(),
15634                    ranges_for_buffer,
15635                    DEFAULT_MULTIBUFFER_CONTEXT,
15636                    cx,
15637                );
15638                ranges.extend(new_ranges)
15639            }
15640
15641            multibuffer.with_title(title)
15642        });
15643
15644        let editor = cx.new(|cx| {
15645            Editor::for_multibuffer(
15646                excerpt_buffer,
15647                Some(workspace.project().clone()),
15648                window,
15649                cx,
15650            )
15651        });
15652        editor.update(cx, |editor, cx| {
15653            match multibuffer_selection_mode {
15654                MultibufferSelectionMode::First => {
15655                    if let Some(first_range) = ranges.first() {
15656                        editor.change_selections(None, window, cx, |selections| {
15657                            selections.clear_disjoint();
15658                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15659                        });
15660                    }
15661                    editor.highlight_background::<Self>(
15662                        &ranges,
15663                        |theme| theme.colors().editor_highlighted_line_background,
15664                        cx,
15665                    );
15666                }
15667                MultibufferSelectionMode::All => {
15668                    editor.change_selections(None, window, cx, |selections| {
15669                        selections.clear_disjoint();
15670                        selections.select_anchor_ranges(ranges);
15671                    });
15672                }
15673            }
15674            editor.register_buffers_with_language_servers(cx);
15675        });
15676
15677        let item = Box::new(editor);
15678        let item_id = item.item_id();
15679
15680        if split {
15681            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15682        } else {
15683            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15684                let (preview_item_id, preview_item_idx) =
15685                    workspace.active_pane().read_with(cx, |pane, _| {
15686                        (pane.preview_item_id(), pane.preview_item_idx())
15687                    });
15688
15689                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15690
15691                if let Some(preview_item_id) = preview_item_id {
15692                    workspace.active_pane().update(cx, |pane, cx| {
15693                        pane.remove_item(preview_item_id, false, false, window, cx);
15694                    });
15695                }
15696            } else {
15697                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15698            }
15699        }
15700        workspace.active_pane().update(cx, |pane, cx| {
15701            pane.set_preview_item_id(Some(item_id), cx);
15702        });
15703    }
15704
15705    pub fn rename(
15706        &mut self,
15707        _: &Rename,
15708        window: &mut Window,
15709        cx: &mut Context<Self>,
15710    ) -> Option<Task<Result<()>>> {
15711        use language::ToOffset as _;
15712
15713        let provider = self.semantics_provider.clone()?;
15714        let selection = self.selections.newest_anchor().clone();
15715        let (cursor_buffer, cursor_buffer_position) = self
15716            .buffer
15717            .read(cx)
15718            .text_anchor_for_position(selection.head(), cx)?;
15719        let (tail_buffer, cursor_buffer_position_end) = self
15720            .buffer
15721            .read(cx)
15722            .text_anchor_for_position(selection.tail(), cx)?;
15723        if tail_buffer != cursor_buffer {
15724            return None;
15725        }
15726
15727        let snapshot = cursor_buffer.read(cx).snapshot();
15728        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15729        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15730        let prepare_rename = provider
15731            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15732            .unwrap_or_else(|| Task::ready(Ok(None)));
15733        drop(snapshot);
15734
15735        Some(cx.spawn_in(window, async move |this, cx| {
15736            let rename_range = if let Some(range) = prepare_rename.await? {
15737                Some(range)
15738            } else {
15739                this.update(cx, |this, cx| {
15740                    let buffer = this.buffer.read(cx).snapshot(cx);
15741                    let mut buffer_highlights = this
15742                        .document_highlights_for_position(selection.head(), &buffer)
15743                        .filter(|highlight| {
15744                            highlight.start.excerpt_id == selection.head().excerpt_id
15745                                && highlight.end.excerpt_id == selection.head().excerpt_id
15746                        });
15747                    buffer_highlights
15748                        .next()
15749                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15750                })?
15751            };
15752            if let Some(rename_range) = rename_range {
15753                this.update_in(cx, |this, window, cx| {
15754                    let snapshot = cursor_buffer.read(cx).snapshot();
15755                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15756                    let cursor_offset_in_rename_range =
15757                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15758                    let cursor_offset_in_rename_range_end =
15759                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15760
15761                    this.take_rename(false, window, cx);
15762                    let buffer = this.buffer.read(cx).read(cx);
15763                    let cursor_offset = selection.head().to_offset(&buffer);
15764                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15765                    let rename_end = rename_start + rename_buffer_range.len();
15766                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15767                    let mut old_highlight_id = None;
15768                    let old_name: Arc<str> = buffer
15769                        .chunks(rename_start..rename_end, true)
15770                        .map(|chunk| {
15771                            if old_highlight_id.is_none() {
15772                                old_highlight_id = chunk.syntax_highlight_id;
15773                            }
15774                            chunk.text
15775                        })
15776                        .collect::<String>()
15777                        .into();
15778
15779                    drop(buffer);
15780
15781                    // Position the selection in the rename editor so that it matches the current selection.
15782                    this.show_local_selections = false;
15783                    let rename_editor = cx.new(|cx| {
15784                        let mut editor = Editor::single_line(window, cx);
15785                        editor.buffer.update(cx, |buffer, cx| {
15786                            buffer.edit([(0..0, old_name.clone())], None, cx)
15787                        });
15788                        let rename_selection_range = match cursor_offset_in_rename_range
15789                            .cmp(&cursor_offset_in_rename_range_end)
15790                        {
15791                            Ordering::Equal => {
15792                                editor.select_all(&SelectAll, window, cx);
15793                                return editor;
15794                            }
15795                            Ordering::Less => {
15796                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15797                            }
15798                            Ordering::Greater => {
15799                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15800                            }
15801                        };
15802                        if rename_selection_range.end > old_name.len() {
15803                            editor.select_all(&SelectAll, window, cx);
15804                        } else {
15805                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15806                                s.select_ranges([rename_selection_range]);
15807                            });
15808                        }
15809                        editor
15810                    });
15811                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15812                        if e == &EditorEvent::Focused {
15813                            cx.emit(EditorEvent::FocusedIn)
15814                        }
15815                    })
15816                    .detach();
15817
15818                    let write_highlights =
15819                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15820                    let read_highlights =
15821                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15822                    let ranges = write_highlights
15823                        .iter()
15824                        .flat_map(|(_, ranges)| ranges.iter())
15825                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15826                        .cloned()
15827                        .collect();
15828
15829                    this.highlight_text::<Rename>(
15830                        ranges,
15831                        HighlightStyle {
15832                            fade_out: Some(0.6),
15833                            ..Default::default()
15834                        },
15835                        cx,
15836                    );
15837                    let rename_focus_handle = rename_editor.focus_handle(cx);
15838                    window.focus(&rename_focus_handle);
15839                    let block_id = this.insert_blocks(
15840                        [BlockProperties {
15841                            style: BlockStyle::Flex,
15842                            placement: BlockPlacement::Below(range.start),
15843                            height: Some(1),
15844                            render: Arc::new({
15845                                let rename_editor = rename_editor.clone();
15846                                move |cx: &mut BlockContext| {
15847                                    let mut text_style = cx.editor_style.text.clone();
15848                                    if let Some(highlight_style) = old_highlight_id
15849                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15850                                    {
15851                                        text_style = text_style.highlight(highlight_style);
15852                                    }
15853                                    div()
15854                                        .block_mouse_except_scroll()
15855                                        .pl(cx.anchor_x)
15856                                        .child(EditorElement::new(
15857                                            &rename_editor,
15858                                            EditorStyle {
15859                                                background: cx.theme().system().transparent,
15860                                                local_player: cx.editor_style.local_player,
15861                                                text: text_style,
15862                                                scrollbar_width: cx.editor_style.scrollbar_width,
15863                                                syntax: cx.editor_style.syntax.clone(),
15864                                                status: cx.editor_style.status.clone(),
15865                                                inlay_hints_style: HighlightStyle {
15866                                                    font_weight: Some(FontWeight::BOLD),
15867                                                    ..make_inlay_hints_style(cx.app)
15868                                                },
15869                                                inline_completion_styles: make_suggestion_styles(
15870                                                    cx.app,
15871                                                ),
15872                                                ..EditorStyle::default()
15873                                            },
15874                                        ))
15875                                        .into_any_element()
15876                                }
15877                            }),
15878                            priority: 0,
15879                            render_in_minimap: true,
15880                        }],
15881                        Some(Autoscroll::fit()),
15882                        cx,
15883                    )[0];
15884                    this.pending_rename = Some(RenameState {
15885                        range,
15886                        old_name,
15887                        editor: rename_editor,
15888                        block_id,
15889                    });
15890                })?;
15891            }
15892
15893            Ok(())
15894        }))
15895    }
15896
15897    pub fn confirm_rename(
15898        &mut self,
15899        _: &ConfirmRename,
15900        window: &mut Window,
15901        cx: &mut Context<Self>,
15902    ) -> Option<Task<Result<()>>> {
15903        let rename = self.take_rename(false, window, cx)?;
15904        let workspace = self.workspace()?.downgrade();
15905        let (buffer, start) = self
15906            .buffer
15907            .read(cx)
15908            .text_anchor_for_position(rename.range.start, cx)?;
15909        let (end_buffer, _) = self
15910            .buffer
15911            .read(cx)
15912            .text_anchor_for_position(rename.range.end, cx)?;
15913        if buffer != end_buffer {
15914            return None;
15915        }
15916
15917        let old_name = rename.old_name;
15918        let new_name = rename.editor.read(cx).text(cx);
15919
15920        let rename = self.semantics_provider.as_ref()?.perform_rename(
15921            &buffer,
15922            start,
15923            new_name.clone(),
15924            cx,
15925        )?;
15926
15927        Some(cx.spawn_in(window, async move |editor, cx| {
15928            let project_transaction = rename.await?;
15929            Self::open_project_transaction(
15930                &editor,
15931                workspace,
15932                project_transaction,
15933                format!("Rename: {}{}", old_name, new_name),
15934                cx,
15935            )
15936            .await?;
15937
15938            editor.update(cx, |editor, cx| {
15939                editor.refresh_document_highlights(cx);
15940            })?;
15941            Ok(())
15942        }))
15943    }
15944
15945    fn take_rename(
15946        &mut self,
15947        moving_cursor: bool,
15948        window: &mut Window,
15949        cx: &mut Context<Self>,
15950    ) -> Option<RenameState> {
15951        let rename = self.pending_rename.take()?;
15952        if rename.editor.focus_handle(cx).is_focused(window) {
15953            window.focus(&self.focus_handle);
15954        }
15955
15956        self.remove_blocks(
15957            [rename.block_id].into_iter().collect(),
15958            Some(Autoscroll::fit()),
15959            cx,
15960        );
15961        self.clear_highlights::<Rename>(cx);
15962        self.show_local_selections = true;
15963
15964        if moving_cursor {
15965            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15966                editor.selections.newest::<usize>(cx).head()
15967            });
15968
15969            // Update the selection to match the position of the selection inside
15970            // the rename editor.
15971            let snapshot = self.buffer.read(cx).read(cx);
15972            let rename_range = rename.range.to_offset(&snapshot);
15973            let cursor_in_editor = snapshot
15974                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15975                .min(rename_range.end);
15976            drop(snapshot);
15977
15978            self.change_selections(None, window, cx, |s| {
15979                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15980            });
15981        } else {
15982            self.refresh_document_highlights(cx);
15983        }
15984
15985        Some(rename)
15986    }
15987
15988    pub fn pending_rename(&self) -> Option<&RenameState> {
15989        self.pending_rename.as_ref()
15990    }
15991
15992    fn format(
15993        &mut self,
15994        _: &Format,
15995        window: &mut Window,
15996        cx: &mut Context<Self>,
15997    ) -> Option<Task<Result<()>>> {
15998        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15999
16000        let project = match &self.project {
16001            Some(project) => project.clone(),
16002            None => return None,
16003        };
16004
16005        Some(self.perform_format(
16006            project,
16007            FormatTrigger::Manual,
16008            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16009            window,
16010            cx,
16011        ))
16012    }
16013
16014    fn format_selections(
16015        &mut self,
16016        _: &FormatSelections,
16017        window: &mut Window,
16018        cx: &mut Context<Self>,
16019    ) -> Option<Task<Result<()>>> {
16020        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16021
16022        let project = match &self.project {
16023            Some(project) => project.clone(),
16024            None => return None,
16025        };
16026
16027        let ranges = self
16028            .selections
16029            .all_adjusted(cx)
16030            .into_iter()
16031            .map(|selection| selection.range())
16032            .collect_vec();
16033
16034        Some(self.perform_format(
16035            project,
16036            FormatTrigger::Manual,
16037            FormatTarget::Ranges(ranges),
16038            window,
16039            cx,
16040        ))
16041    }
16042
16043    fn perform_format(
16044        &mut self,
16045        project: Entity<Project>,
16046        trigger: FormatTrigger,
16047        target: FormatTarget,
16048        window: &mut Window,
16049        cx: &mut Context<Self>,
16050    ) -> Task<Result<()>> {
16051        let buffer = self.buffer.clone();
16052        let (buffers, target) = match target {
16053            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16054            FormatTarget::Ranges(selection_ranges) => {
16055                let multi_buffer = buffer.read(cx);
16056                let snapshot = multi_buffer.read(cx);
16057                let mut buffers = HashSet::default();
16058                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16059                    BTreeMap::new();
16060                for selection_range in selection_ranges {
16061                    for (buffer, buffer_range, _) in
16062                        snapshot.range_to_buffer_ranges(selection_range)
16063                    {
16064                        let buffer_id = buffer.remote_id();
16065                        let start = buffer.anchor_before(buffer_range.start);
16066                        let end = buffer.anchor_after(buffer_range.end);
16067                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16068                        buffer_id_to_ranges
16069                            .entry(buffer_id)
16070                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16071                            .or_insert_with(|| vec![start..end]);
16072                    }
16073                }
16074                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16075            }
16076        };
16077
16078        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16079        let selections_prev = transaction_id_prev
16080            .and_then(|transaction_id_prev| {
16081                // default to selections as they were after the last edit, if we have them,
16082                // instead of how they are now.
16083                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16084                // will take you back to where you made the last edit, instead of staying where you scrolled
16085                self.selection_history
16086                    .transaction(transaction_id_prev)
16087                    .map(|t| t.0.clone())
16088            })
16089            .unwrap_or_else(|| {
16090                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16091                self.selections.disjoint_anchors()
16092            });
16093
16094        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16095        let format = project.update(cx, |project, cx| {
16096            project.format(buffers, target, true, trigger, cx)
16097        });
16098
16099        cx.spawn_in(window, async move |editor, cx| {
16100            let transaction = futures::select_biased! {
16101                transaction = format.log_err().fuse() => transaction,
16102                () = timeout => {
16103                    log::warn!("timed out waiting for formatting");
16104                    None
16105                }
16106            };
16107
16108            buffer
16109                .update(cx, |buffer, cx| {
16110                    if let Some(transaction) = transaction {
16111                        if !buffer.is_singleton() {
16112                            buffer.push_transaction(&transaction.0, cx);
16113                        }
16114                    }
16115                    cx.notify();
16116                })
16117                .ok();
16118
16119            if let Some(transaction_id_now) =
16120                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16121            {
16122                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16123                if has_new_transaction {
16124                    _ = editor.update(cx, |editor, _| {
16125                        editor
16126                            .selection_history
16127                            .insert_transaction(transaction_id_now, selections_prev);
16128                    });
16129                }
16130            }
16131
16132            Ok(())
16133        })
16134    }
16135
16136    fn organize_imports(
16137        &mut self,
16138        _: &OrganizeImports,
16139        window: &mut Window,
16140        cx: &mut Context<Self>,
16141    ) -> Option<Task<Result<()>>> {
16142        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16143        let project = match &self.project {
16144            Some(project) => project.clone(),
16145            None => return None,
16146        };
16147        Some(self.perform_code_action_kind(
16148            project,
16149            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16150            window,
16151            cx,
16152        ))
16153    }
16154
16155    fn perform_code_action_kind(
16156        &mut self,
16157        project: Entity<Project>,
16158        kind: CodeActionKind,
16159        window: &mut Window,
16160        cx: &mut Context<Self>,
16161    ) -> Task<Result<()>> {
16162        let buffer = self.buffer.clone();
16163        let buffers = buffer.read(cx).all_buffers();
16164        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16165        let apply_action = project.update(cx, |project, cx| {
16166            project.apply_code_action_kind(buffers, kind, true, cx)
16167        });
16168        cx.spawn_in(window, async move |_, cx| {
16169            let transaction = futures::select_biased! {
16170                () = timeout => {
16171                    log::warn!("timed out waiting for executing code action");
16172                    None
16173                }
16174                transaction = apply_action.log_err().fuse() => transaction,
16175            };
16176            buffer
16177                .update(cx, |buffer, cx| {
16178                    // check if we need this
16179                    if let Some(transaction) = transaction {
16180                        if !buffer.is_singleton() {
16181                            buffer.push_transaction(&transaction.0, cx);
16182                        }
16183                    }
16184                    cx.notify();
16185                })
16186                .ok();
16187            Ok(())
16188        })
16189    }
16190
16191    pub fn restart_language_server(
16192        &mut self,
16193        _: &RestartLanguageServer,
16194        _: &mut Window,
16195        cx: &mut Context<Self>,
16196    ) {
16197        if let Some(project) = self.project.clone() {
16198            self.buffer.update(cx, |multi_buffer, cx| {
16199                project.update(cx, |project, cx| {
16200                    project.restart_language_servers_for_buffers(
16201                        multi_buffer.all_buffers().into_iter().collect(),
16202                        HashSet::default(),
16203                        cx,
16204                    );
16205                });
16206            })
16207        }
16208    }
16209
16210    pub fn stop_language_server(
16211        &mut self,
16212        _: &StopLanguageServer,
16213        _: &mut Window,
16214        cx: &mut Context<Self>,
16215    ) {
16216        if let Some(project) = self.project.clone() {
16217            self.buffer.update(cx, |multi_buffer, cx| {
16218                project.update(cx, |project, cx| {
16219                    project.stop_language_servers_for_buffers(
16220                        multi_buffer.all_buffers().into_iter().collect(),
16221                        HashSet::default(),
16222                        cx,
16223                    );
16224                    cx.emit(project::Event::RefreshInlayHints);
16225                });
16226            });
16227        }
16228    }
16229
16230    fn cancel_language_server_work(
16231        workspace: &mut Workspace,
16232        _: &actions::CancelLanguageServerWork,
16233        _: &mut Window,
16234        cx: &mut Context<Workspace>,
16235    ) {
16236        let project = workspace.project();
16237        let buffers = workspace
16238            .active_item(cx)
16239            .and_then(|item| item.act_as::<Editor>(cx))
16240            .map_or(HashSet::default(), |editor| {
16241                editor.read(cx).buffer.read(cx).all_buffers()
16242            });
16243        project.update(cx, |project, cx| {
16244            project.cancel_language_server_work_for_buffers(buffers, cx);
16245        });
16246    }
16247
16248    fn show_character_palette(
16249        &mut self,
16250        _: &ShowCharacterPalette,
16251        window: &mut Window,
16252        _: &mut Context<Self>,
16253    ) {
16254        window.show_character_palette();
16255    }
16256
16257    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16258        if !self.diagnostics_enabled() {
16259            return;
16260        }
16261
16262        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16263            let buffer = self.buffer.read(cx).snapshot(cx);
16264            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16265            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16266            let is_valid = buffer
16267                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16268                .any(|entry| {
16269                    entry.diagnostic.is_primary
16270                        && !entry.range.is_empty()
16271                        && entry.range.start == primary_range_start
16272                        && entry.diagnostic.message == active_diagnostics.active_message
16273                });
16274
16275            if !is_valid {
16276                self.dismiss_diagnostics(cx);
16277            }
16278        }
16279    }
16280
16281    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16282        match &self.active_diagnostics {
16283            ActiveDiagnostic::Group(group) => Some(group),
16284            _ => None,
16285        }
16286    }
16287
16288    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16289        if !self.diagnostics_enabled() {
16290            return;
16291        }
16292        self.dismiss_diagnostics(cx);
16293        self.active_diagnostics = ActiveDiagnostic::All;
16294    }
16295
16296    fn activate_diagnostics(
16297        &mut self,
16298        buffer_id: BufferId,
16299        diagnostic: DiagnosticEntry<usize>,
16300        window: &mut Window,
16301        cx: &mut Context<Self>,
16302    ) {
16303        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16304            return;
16305        }
16306        self.dismiss_diagnostics(cx);
16307        let snapshot = self.snapshot(window, cx);
16308        let buffer = self.buffer.read(cx).snapshot(cx);
16309        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16310            return;
16311        };
16312
16313        let diagnostic_group = buffer
16314            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16315            .collect::<Vec<_>>();
16316
16317        let blocks =
16318            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16319
16320        let blocks = self.display_map.update(cx, |display_map, cx| {
16321            display_map.insert_blocks(blocks, cx).into_iter().collect()
16322        });
16323        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16324            active_range: buffer.anchor_before(diagnostic.range.start)
16325                ..buffer.anchor_after(diagnostic.range.end),
16326            active_message: diagnostic.diagnostic.message.clone(),
16327            group_id: diagnostic.diagnostic.group_id,
16328            blocks,
16329        });
16330        cx.notify();
16331    }
16332
16333    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16334        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16335            return;
16336        };
16337
16338        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16339        if let ActiveDiagnostic::Group(group) = prev {
16340            self.display_map.update(cx, |display_map, cx| {
16341                display_map.remove_blocks(group.blocks, cx);
16342            });
16343            cx.notify();
16344        }
16345    }
16346
16347    /// Disable inline diagnostics rendering for this editor.
16348    pub fn disable_inline_diagnostics(&mut self) {
16349        self.inline_diagnostics_enabled = false;
16350        self.inline_diagnostics_update = Task::ready(());
16351        self.inline_diagnostics.clear();
16352    }
16353
16354    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16355        self.diagnostics_enabled = false;
16356        self.dismiss_diagnostics(cx);
16357        self.inline_diagnostics_update = Task::ready(());
16358        self.inline_diagnostics.clear();
16359    }
16360
16361    pub fn diagnostics_enabled(&self) -> bool {
16362        self.diagnostics_enabled && self.mode.is_full()
16363    }
16364
16365    pub fn inline_diagnostics_enabled(&self) -> bool {
16366        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16367    }
16368
16369    pub fn show_inline_diagnostics(&self) -> bool {
16370        self.show_inline_diagnostics
16371    }
16372
16373    pub fn toggle_inline_diagnostics(
16374        &mut self,
16375        _: &ToggleInlineDiagnostics,
16376        window: &mut Window,
16377        cx: &mut Context<Editor>,
16378    ) {
16379        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16380        self.refresh_inline_diagnostics(false, window, cx);
16381    }
16382
16383    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16384        self.diagnostics_max_severity = severity;
16385        self.display_map.update(cx, |display_map, _| {
16386            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16387        });
16388    }
16389
16390    pub fn toggle_diagnostics(
16391        &mut self,
16392        _: &ToggleDiagnostics,
16393        window: &mut Window,
16394        cx: &mut Context<Editor>,
16395    ) {
16396        if !self.diagnostics_enabled() {
16397            return;
16398        }
16399
16400        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16401            EditorSettings::get_global(cx)
16402                .diagnostics_max_severity
16403                .filter(|severity| severity != &DiagnosticSeverity::Off)
16404                .unwrap_or(DiagnosticSeverity::Hint)
16405        } else {
16406            DiagnosticSeverity::Off
16407        };
16408        self.set_max_diagnostics_severity(new_severity, cx);
16409        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16410            self.active_diagnostics = ActiveDiagnostic::None;
16411            self.inline_diagnostics_update = Task::ready(());
16412            self.inline_diagnostics.clear();
16413        } else {
16414            self.refresh_inline_diagnostics(false, window, cx);
16415        }
16416
16417        cx.notify();
16418    }
16419
16420    pub fn toggle_minimap(
16421        &mut self,
16422        _: &ToggleMinimap,
16423        window: &mut Window,
16424        cx: &mut Context<Editor>,
16425    ) {
16426        if self.supports_minimap(cx) {
16427            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16428        }
16429    }
16430
16431    fn refresh_inline_diagnostics(
16432        &mut self,
16433        debounce: bool,
16434        window: &mut Window,
16435        cx: &mut Context<Self>,
16436    ) {
16437        let max_severity = ProjectSettings::get_global(cx)
16438            .diagnostics
16439            .inline
16440            .max_severity
16441            .unwrap_or(self.diagnostics_max_severity);
16442
16443        if !self.inline_diagnostics_enabled()
16444            || !self.show_inline_diagnostics
16445            || max_severity == DiagnosticSeverity::Off
16446        {
16447            self.inline_diagnostics_update = Task::ready(());
16448            self.inline_diagnostics.clear();
16449            return;
16450        }
16451
16452        let debounce_ms = ProjectSettings::get_global(cx)
16453            .diagnostics
16454            .inline
16455            .update_debounce_ms;
16456        let debounce = if debounce && debounce_ms > 0 {
16457            Some(Duration::from_millis(debounce_ms))
16458        } else {
16459            None
16460        };
16461        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16462            if let Some(debounce) = debounce {
16463                cx.background_executor().timer(debounce).await;
16464            }
16465            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16466                editor
16467                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16468                    .ok()
16469            }) else {
16470                return;
16471            };
16472
16473            let new_inline_diagnostics = cx
16474                .background_spawn(async move {
16475                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16476                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16477                        let message = diagnostic_entry
16478                            .diagnostic
16479                            .message
16480                            .split_once('\n')
16481                            .map(|(line, _)| line)
16482                            .map(SharedString::new)
16483                            .unwrap_or_else(|| {
16484                                SharedString::from(diagnostic_entry.diagnostic.message)
16485                            });
16486                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16487                        let (Ok(i) | Err(i)) = inline_diagnostics
16488                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16489                        inline_diagnostics.insert(
16490                            i,
16491                            (
16492                                start_anchor,
16493                                InlineDiagnostic {
16494                                    message,
16495                                    group_id: diagnostic_entry.diagnostic.group_id,
16496                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16497                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16498                                    severity: diagnostic_entry.diagnostic.severity,
16499                                },
16500                            ),
16501                        );
16502                    }
16503                    inline_diagnostics
16504                })
16505                .await;
16506
16507            editor
16508                .update(cx, |editor, cx| {
16509                    editor.inline_diagnostics = new_inline_diagnostics;
16510                    cx.notify();
16511                })
16512                .ok();
16513        });
16514    }
16515
16516    fn pull_diagnostics(
16517        &mut self,
16518        buffer_id: Option<BufferId>,
16519        window: &Window,
16520        cx: &mut Context<Self>,
16521    ) -> Option<()> {
16522        if !self.mode().is_full() {
16523            return None;
16524        }
16525        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16526            .diagnostics
16527            .lsp_pull_diagnostics;
16528        if !pull_diagnostics_settings.enabled {
16529            return None;
16530        }
16531        let project = self.project.as_ref()?.downgrade();
16532        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16533        let mut buffers = self.buffer.read(cx).all_buffers();
16534        if let Some(buffer_id) = buffer_id {
16535            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16536        }
16537
16538        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16539            cx.background_executor().timer(debounce).await;
16540
16541            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16542                buffers
16543                    .into_iter()
16544                    .filter_map(|buffer| {
16545                        project
16546                            .update(cx, |project, cx| {
16547                                project.lsp_store().update(cx, |lsp_store, cx| {
16548                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16549                                })
16550                            })
16551                            .ok()
16552                    })
16553                    .collect::<FuturesUnordered<_>>()
16554            }) else {
16555                return;
16556            };
16557
16558            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16559                match pull_task {
16560                    Ok(()) => {
16561                        if editor
16562                            .update_in(cx, |editor, window, cx| {
16563                                editor.update_diagnostics_state(window, cx);
16564                            })
16565                            .is_err()
16566                        {
16567                            return;
16568                        }
16569                    }
16570                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16571                }
16572            }
16573        });
16574
16575        Some(())
16576    }
16577
16578    pub fn set_selections_from_remote(
16579        &mut self,
16580        selections: Vec<Selection<Anchor>>,
16581        pending_selection: Option<Selection<Anchor>>,
16582        window: &mut Window,
16583        cx: &mut Context<Self>,
16584    ) {
16585        let old_cursor_position = self.selections.newest_anchor().head();
16586        self.selections.change_with(cx, |s| {
16587            s.select_anchors(selections);
16588            if let Some(pending_selection) = pending_selection {
16589                s.set_pending(pending_selection, SelectMode::Character);
16590            } else {
16591                s.clear_pending();
16592            }
16593        });
16594        self.selections_did_change(
16595            false,
16596            &old_cursor_position,
16597            SelectionEffects::default(),
16598            window,
16599            cx,
16600        );
16601    }
16602
16603    pub fn transact(
16604        &mut self,
16605        window: &mut Window,
16606        cx: &mut Context<Self>,
16607        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16608    ) -> Option<TransactionId> {
16609        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16610            this.start_transaction_at(Instant::now(), window, cx);
16611            update(this, window, cx);
16612            this.end_transaction_at(Instant::now(), cx)
16613        })
16614    }
16615
16616    pub fn start_transaction_at(
16617        &mut self,
16618        now: Instant,
16619        window: &mut Window,
16620        cx: &mut Context<Self>,
16621    ) {
16622        self.end_selection(window, cx);
16623        if let Some(tx_id) = self
16624            .buffer
16625            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16626        {
16627            self.selection_history
16628                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16629            cx.emit(EditorEvent::TransactionBegun {
16630                transaction_id: tx_id,
16631            })
16632        }
16633    }
16634
16635    pub fn end_transaction_at(
16636        &mut self,
16637        now: Instant,
16638        cx: &mut Context<Self>,
16639    ) -> Option<TransactionId> {
16640        if let Some(transaction_id) = self
16641            .buffer
16642            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16643        {
16644            if let Some((_, end_selections)) =
16645                self.selection_history.transaction_mut(transaction_id)
16646            {
16647                *end_selections = Some(self.selections.disjoint_anchors());
16648            } else {
16649                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16650            }
16651
16652            cx.emit(EditorEvent::Edited { transaction_id });
16653            Some(transaction_id)
16654        } else {
16655            None
16656        }
16657    }
16658
16659    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16660        if self.selection_mark_mode {
16661            self.change_selections(None, window, cx, |s| {
16662                s.move_with(|_, sel| {
16663                    sel.collapse_to(sel.head(), SelectionGoal::None);
16664                });
16665            })
16666        }
16667        self.selection_mark_mode = true;
16668        cx.notify();
16669    }
16670
16671    pub fn swap_selection_ends(
16672        &mut self,
16673        _: &actions::SwapSelectionEnds,
16674        window: &mut Window,
16675        cx: &mut Context<Self>,
16676    ) {
16677        self.change_selections(None, window, cx, |s| {
16678            s.move_with(|_, sel| {
16679                if sel.start != sel.end {
16680                    sel.reversed = !sel.reversed
16681                }
16682            });
16683        });
16684        self.request_autoscroll(Autoscroll::newest(), cx);
16685        cx.notify();
16686    }
16687
16688    pub fn toggle_fold(
16689        &mut self,
16690        _: &actions::ToggleFold,
16691        window: &mut Window,
16692        cx: &mut Context<Self>,
16693    ) {
16694        if self.is_singleton(cx) {
16695            let selection = self.selections.newest::<Point>(cx);
16696
16697            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16698            let range = if selection.is_empty() {
16699                let point = selection.head().to_display_point(&display_map);
16700                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16701                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16702                    .to_point(&display_map);
16703                start..end
16704            } else {
16705                selection.range()
16706            };
16707            if display_map.folds_in_range(range).next().is_some() {
16708                self.unfold_lines(&Default::default(), window, cx)
16709            } else {
16710                self.fold(&Default::default(), window, cx)
16711            }
16712        } else {
16713            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16714            let buffer_ids: HashSet<_> = self
16715                .selections
16716                .disjoint_anchor_ranges()
16717                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16718                .collect();
16719
16720            let should_unfold = buffer_ids
16721                .iter()
16722                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16723
16724            for buffer_id in buffer_ids {
16725                if should_unfold {
16726                    self.unfold_buffer(buffer_id, cx);
16727                } else {
16728                    self.fold_buffer(buffer_id, cx);
16729                }
16730            }
16731        }
16732    }
16733
16734    pub fn toggle_fold_recursive(
16735        &mut self,
16736        _: &actions::ToggleFoldRecursive,
16737        window: &mut Window,
16738        cx: &mut Context<Self>,
16739    ) {
16740        let selection = self.selections.newest::<Point>(cx);
16741
16742        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16743        let range = if selection.is_empty() {
16744            let point = selection.head().to_display_point(&display_map);
16745            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16746            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16747                .to_point(&display_map);
16748            start..end
16749        } else {
16750            selection.range()
16751        };
16752        if display_map.folds_in_range(range).next().is_some() {
16753            self.unfold_recursive(&Default::default(), window, cx)
16754        } else {
16755            self.fold_recursive(&Default::default(), window, cx)
16756        }
16757    }
16758
16759    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16760        if self.is_singleton(cx) {
16761            let mut to_fold = Vec::new();
16762            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16763            let selections = self.selections.all_adjusted(cx);
16764
16765            for selection in selections {
16766                let range = selection.range().sorted();
16767                let buffer_start_row = range.start.row;
16768
16769                if range.start.row != range.end.row {
16770                    let mut found = false;
16771                    let mut row = range.start.row;
16772                    while row <= range.end.row {
16773                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16774                        {
16775                            found = true;
16776                            row = crease.range().end.row + 1;
16777                            to_fold.push(crease);
16778                        } else {
16779                            row += 1
16780                        }
16781                    }
16782                    if found {
16783                        continue;
16784                    }
16785                }
16786
16787                for row in (0..=range.start.row).rev() {
16788                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16789                        if crease.range().end.row >= buffer_start_row {
16790                            to_fold.push(crease);
16791                            if row <= range.start.row {
16792                                break;
16793                            }
16794                        }
16795                    }
16796                }
16797            }
16798
16799            self.fold_creases(to_fold, true, window, cx);
16800        } else {
16801            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16802            let buffer_ids = self
16803                .selections
16804                .disjoint_anchor_ranges()
16805                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16806                .collect::<HashSet<_>>();
16807            for buffer_id in buffer_ids {
16808                self.fold_buffer(buffer_id, cx);
16809            }
16810        }
16811    }
16812
16813    fn fold_at_level(
16814        &mut self,
16815        fold_at: &FoldAtLevel,
16816        window: &mut Window,
16817        cx: &mut Context<Self>,
16818    ) {
16819        if !self.buffer.read(cx).is_singleton() {
16820            return;
16821        }
16822
16823        let fold_at_level = fold_at.0;
16824        let snapshot = self.buffer.read(cx).snapshot(cx);
16825        let mut to_fold = Vec::new();
16826        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16827
16828        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16829            while start_row < end_row {
16830                match self
16831                    .snapshot(window, cx)
16832                    .crease_for_buffer_row(MultiBufferRow(start_row))
16833                {
16834                    Some(crease) => {
16835                        let nested_start_row = crease.range().start.row + 1;
16836                        let nested_end_row = crease.range().end.row;
16837
16838                        if current_level < fold_at_level {
16839                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16840                        } else if current_level == fold_at_level {
16841                            to_fold.push(crease);
16842                        }
16843
16844                        start_row = nested_end_row + 1;
16845                    }
16846                    None => start_row += 1,
16847                }
16848            }
16849        }
16850
16851        self.fold_creases(to_fold, true, window, cx);
16852    }
16853
16854    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16855        if self.buffer.read(cx).is_singleton() {
16856            let mut fold_ranges = Vec::new();
16857            let snapshot = self.buffer.read(cx).snapshot(cx);
16858
16859            for row in 0..snapshot.max_row().0 {
16860                if let Some(foldable_range) = self
16861                    .snapshot(window, cx)
16862                    .crease_for_buffer_row(MultiBufferRow(row))
16863                {
16864                    fold_ranges.push(foldable_range);
16865                }
16866            }
16867
16868            self.fold_creases(fold_ranges, true, window, cx);
16869        } else {
16870            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16871                editor
16872                    .update_in(cx, |editor, _, cx| {
16873                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16874                            editor.fold_buffer(buffer_id, cx);
16875                        }
16876                    })
16877                    .ok();
16878            });
16879        }
16880    }
16881
16882    pub fn fold_function_bodies(
16883        &mut self,
16884        _: &actions::FoldFunctionBodies,
16885        window: &mut Window,
16886        cx: &mut Context<Self>,
16887    ) {
16888        let snapshot = self.buffer.read(cx).snapshot(cx);
16889
16890        let ranges = snapshot
16891            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16892            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16893            .collect::<Vec<_>>();
16894
16895        let creases = ranges
16896            .into_iter()
16897            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16898            .collect();
16899
16900        self.fold_creases(creases, true, window, cx);
16901    }
16902
16903    pub fn fold_recursive(
16904        &mut self,
16905        _: &actions::FoldRecursive,
16906        window: &mut Window,
16907        cx: &mut Context<Self>,
16908    ) {
16909        let mut to_fold = Vec::new();
16910        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16911        let selections = self.selections.all_adjusted(cx);
16912
16913        for selection in selections {
16914            let range = selection.range().sorted();
16915            let buffer_start_row = range.start.row;
16916
16917            if range.start.row != range.end.row {
16918                let mut found = false;
16919                for row in range.start.row..=range.end.row {
16920                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16921                        found = true;
16922                        to_fold.push(crease);
16923                    }
16924                }
16925                if found {
16926                    continue;
16927                }
16928            }
16929
16930            for row in (0..=range.start.row).rev() {
16931                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16932                    if crease.range().end.row >= buffer_start_row {
16933                        to_fold.push(crease);
16934                    } else {
16935                        break;
16936                    }
16937                }
16938            }
16939        }
16940
16941        self.fold_creases(to_fold, true, window, cx);
16942    }
16943
16944    pub fn fold_at(
16945        &mut self,
16946        buffer_row: MultiBufferRow,
16947        window: &mut Window,
16948        cx: &mut Context<Self>,
16949    ) {
16950        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16951
16952        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16953            let autoscroll = self
16954                .selections
16955                .all::<Point>(cx)
16956                .iter()
16957                .any(|selection| crease.range().overlaps(&selection.range()));
16958
16959            self.fold_creases(vec![crease], autoscroll, window, cx);
16960        }
16961    }
16962
16963    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16964        if self.is_singleton(cx) {
16965            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16966            let buffer = &display_map.buffer_snapshot;
16967            let selections = self.selections.all::<Point>(cx);
16968            let ranges = selections
16969                .iter()
16970                .map(|s| {
16971                    let range = s.display_range(&display_map).sorted();
16972                    let mut start = range.start.to_point(&display_map);
16973                    let mut end = range.end.to_point(&display_map);
16974                    start.column = 0;
16975                    end.column = buffer.line_len(MultiBufferRow(end.row));
16976                    start..end
16977                })
16978                .collect::<Vec<_>>();
16979
16980            self.unfold_ranges(&ranges, true, true, cx);
16981        } else {
16982            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16983            let buffer_ids = self
16984                .selections
16985                .disjoint_anchor_ranges()
16986                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16987                .collect::<HashSet<_>>();
16988            for buffer_id in buffer_ids {
16989                self.unfold_buffer(buffer_id, cx);
16990            }
16991        }
16992    }
16993
16994    pub fn unfold_recursive(
16995        &mut self,
16996        _: &UnfoldRecursive,
16997        _window: &mut Window,
16998        cx: &mut Context<Self>,
16999    ) {
17000        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17001        let selections = self.selections.all::<Point>(cx);
17002        let ranges = selections
17003            .iter()
17004            .map(|s| {
17005                let mut range = s.display_range(&display_map).sorted();
17006                *range.start.column_mut() = 0;
17007                *range.end.column_mut() = display_map.line_len(range.end.row());
17008                let start = range.start.to_point(&display_map);
17009                let end = range.end.to_point(&display_map);
17010                start..end
17011            })
17012            .collect::<Vec<_>>();
17013
17014        self.unfold_ranges(&ranges, true, true, cx);
17015    }
17016
17017    pub fn unfold_at(
17018        &mut self,
17019        buffer_row: MultiBufferRow,
17020        _window: &mut Window,
17021        cx: &mut Context<Self>,
17022    ) {
17023        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17024
17025        let intersection_range = Point::new(buffer_row.0, 0)
17026            ..Point::new(
17027                buffer_row.0,
17028                display_map.buffer_snapshot.line_len(buffer_row),
17029            );
17030
17031        let autoscroll = self
17032            .selections
17033            .all::<Point>(cx)
17034            .iter()
17035            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17036
17037        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17038    }
17039
17040    pub fn unfold_all(
17041        &mut self,
17042        _: &actions::UnfoldAll,
17043        _window: &mut Window,
17044        cx: &mut Context<Self>,
17045    ) {
17046        if self.buffer.read(cx).is_singleton() {
17047            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17048            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17049        } else {
17050            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17051                editor
17052                    .update(cx, |editor, cx| {
17053                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17054                            editor.unfold_buffer(buffer_id, cx);
17055                        }
17056                    })
17057                    .ok();
17058            });
17059        }
17060    }
17061
17062    pub fn fold_selected_ranges(
17063        &mut self,
17064        _: &FoldSelectedRanges,
17065        window: &mut Window,
17066        cx: &mut Context<Self>,
17067    ) {
17068        let selections = self.selections.all_adjusted(cx);
17069        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17070        let ranges = selections
17071            .into_iter()
17072            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17073            .collect::<Vec<_>>();
17074        self.fold_creases(ranges, true, window, cx);
17075    }
17076
17077    pub fn fold_ranges<T: ToOffset + Clone>(
17078        &mut self,
17079        ranges: Vec<Range<T>>,
17080        auto_scroll: bool,
17081        window: &mut Window,
17082        cx: &mut Context<Self>,
17083    ) {
17084        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17085        let ranges = ranges
17086            .into_iter()
17087            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17088            .collect::<Vec<_>>();
17089        self.fold_creases(ranges, auto_scroll, window, cx);
17090    }
17091
17092    pub fn fold_creases<T: ToOffset + Clone>(
17093        &mut self,
17094        creases: Vec<Crease<T>>,
17095        auto_scroll: bool,
17096        _window: &mut Window,
17097        cx: &mut Context<Self>,
17098    ) {
17099        if creases.is_empty() {
17100            return;
17101        }
17102
17103        let mut buffers_affected = HashSet::default();
17104        let multi_buffer = self.buffer().read(cx);
17105        for crease in &creases {
17106            if let Some((_, buffer, _)) =
17107                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
17108            {
17109                buffers_affected.insert(buffer.read(cx).remote_id());
17110            };
17111        }
17112
17113        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17114
17115        if auto_scroll {
17116            self.request_autoscroll(Autoscroll::fit(), cx);
17117        }
17118
17119        cx.notify();
17120
17121        self.scrollbar_marker_state.dirty = true;
17122        self.folds_did_change(cx);
17123    }
17124
17125    /// Removes any folds whose ranges intersect any of the given ranges.
17126    pub fn unfold_ranges<T: ToOffset + Clone>(
17127        &mut self,
17128        ranges: &[Range<T>],
17129        inclusive: bool,
17130        auto_scroll: bool,
17131        cx: &mut Context<Self>,
17132    ) {
17133        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17134            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17135        });
17136        self.folds_did_change(cx);
17137    }
17138
17139    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17140        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17141            return;
17142        }
17143        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17144        self.display_map.update(cx, |display_map, cx| {
17145            display_map.fold_buffers([buffer_id], cx)
17146        });
17147        cx.emit(EditorEvent::BufferFoldToggled {
17148            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17149            folded: true,
17150        });
17151        cx.notify();
17152    }
17153
17154    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17155        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17156            return;
17157        }
17158        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17159        self.display_map.update(cx, |display_map, cx| {
17160            display_map.unfold_buffers([buffer_id], cx);
17161        });
17162        cx.emit(EditorEvent::BufferFoldToggled {
17163            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17164            folded: false,
17165        });
17166        cx.notify();
17167    }
17168
17169    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17170        self.display_map.read(cx).is_buffer_folded(buffer)
17171    }
17172
17173    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17174        self.display_map.read(cx).folded_buffers()
17175    }
17176
17177    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17178        self.display_map.update(cx, |display_map, cx| {
17179            display_map.disable_header_for_buffer(buffer_id, cx);
17180        });
17181        cx.notify();
17182    }
17183
17184    /// Removes any folds with the given ranges.
17185    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17186        &mut self,
17187        ranges: &[Range<T>],
17188        type_id: TypeId,
17189        auto_scroll: bool,
17190        cx: &mut Context<Self>,
17191    ) {
17192        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17193            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17194        });
17195        self.folds_did_change(cx);
17196    }
17197
17198    fn remove_folds_with<T: ToOffset + Clone>(
17199        &mut self,
17200        ranges: &[Range<T>],
17201        auto_scroll: bool,
17202        cx: &mut Context<Self>,
17203        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17204    ) {
17205        if ranges.is_empty() {
17206            return;
17207        }
17208
17209        let mut buffers_affected = HashSet::default();
17210        let multi_buffer = self.buffer().read(cx);
17211        for range in ranges {
17212            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17213                buffers_affected.insert(buffer.read(cx).remote_id());
17214            };
17215        }
17216
17217        self.display_map.update(cx, update);
17218
17219        if auto_scroll {
17220            self.request_autoscroll(Autoscroll::fit(), cx);
17221        }
17222
17223        cx.notify();
17224        self.scrollbar_marker_state.dirty = true;
17225        self.active_indent_guides_state.dirty = true;
17226    }
17227
17228    pub fn update_fold_widths(
17229        &mut self,
17230        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
17231        cx: &mut Context<Self>,
17232    ) -> bool {
17233        self.display_map
17234            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17235    }
17236
17237    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17238        self.display_map.read(cx).fold_placeholder.clone()
17239    }
17240
17241    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17242        self.buffer.update(cx, |buffer, cx| {
17243            buffer.set_all_diff_hunks_expanded(cx);
17244        });
17245    }
17246
17247    pub fn expand_all_diff_hunks(
17248        &mut self,
17249        _: &ExpandAllDiffHunks,
17250        _window: &mut Window,
17251        cx: &mut Context<Self>,
17252    ) {
17253        self.buffer.update(cx, |buffer, cx| {
17254            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17255        });
17256    }
17257
17258    pub fn toggle_selected_diff_hunks(
17259        &mut self,
17260        _: &ToggleSelectedDiffHunks,
17261        _window: &mut Window,
17262        cx: &mut Context<Self>,
17263    ) {
17264        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17265        self.toggle_diff_hunks_in_ranges(ranges, cx);
17266    }
17267
17268    pub fn diff_hunks_in_ranges<'a>(
17269        &'a self,
17270        ranges: &'a [Range<Anchor>],
17271        buffer: &'a MultiBufferSnapshot,
17272    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17273        ranges.iter().flat_map(move |range| {
17274            let end_excerpt_id = range.end.excerpt_id;
17275            let range = range.to_point(buffer);
17276            let mut peek_end = range.end;
17277            if range.end.row < buffer.max_row().0 {
17278                peek_end = Point::new(range.end.row + 1, 0);
17279            }
17280            buffer
17281                .diff_hunks_in_range(range.start..peek_end)
17282                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17283        })
17284    }
17285
17286    pub fn has_stageable_diff_hunks_in_ranges(
17287        &self,
17288        ranges: &[Range<Anchor>],
17289        snapshot: &MultiBufferSnapshot,
17290    ) -> bool {
17291        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17292        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17293    }
17294
17295    pub fn toggle_staged_selected_diff_hunks(
17296        &mut self,
17297        _: &::git::ToggleStaged,
17298        _: &mut Window,
17299        cx: &mut Context<Self>,
17300    ) {
17301        let snapshot = self.buffer.read(cx).snapshot(cx);
17302        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17303        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17304        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17305    }
17306
17307    pub fn set_render_diff_hunk_controls(
17308        &mut self,
17309        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17310        cx: &mut Context<Self>,
17311    ) {
17312        self.render_diff_hunk_controls = render_diff_hunk_controls;
17313        cx.notify();
17314    }
17315
17316    pub fn stage_and_next(
17317        &mut self,
17318        _: &::git::StageAndNext,
17319        window: &mut Window,
17320        cx: &mut Context<Self>,
17321    ) {
17322        self.do_stage_or_unstage_and_next(true, window, cx);
17323    }
17324
17325    pub fn unstage_and_next(
17326        &mut self,
17327        _: &::git::UnstageAndNext,
17328        window: &mut Window,
17329        cx: &mut Context<Self>,
17330    ) {
17331        self.do_stage_or_unstage_and_next(false, window, cx);
17332    }
17333
17334    pub fn stage_or_unstage_diff_hunks(
17335        &mut self,
17336        stage: bool,
17337        ranges: Vec<Range<Anchor>>,
17338        cx: &mut Context<Self>,
17339    ) {
17340        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17341        cx.spawn(async move |this, cx| {
17342            task.await?;
17343            this.update(cx, |this, cx| {
17344                let snapshot = this.buffer.read(cx).snapshot(cx);
17345                let chunk_by = this
17346                    .diff_hunks_in_ranges(&ranges, &snapshot)
17347                    .chunk_by(|hunk| hunk.buffer_id);
17348                for (buffer_id, hunks) in &chunk_by {
17349                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17350                }
17351            })
17352        })
17353        .detach_and_log_err(cx);
17354    }
17355
17356    fn save_buffers_for_ranges_if_needed(
17357        &mut self,
17358        ranges: &[Range<Anchor>],
17359        cx: &mut Context<Editor>,
17360    ) -> Task<Result<()>> {
17361        let multibuffer = self.buffer.read(cx);
17362        let snapshot = multibuffer.read(cx);
17363        let buffer_ids: HashSet<_> = ranges
17364            .iter()
17365            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17366            .collect();
17367        drop(snapshot);
17368
17369        let mut buffers = HashSet::default();
17370        for buffer_id in buffer_ids {
17371            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17372                let buffer = buffer_entity.read(cx);
17373                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17374                {
17375                    buffers.insert(buffer_entity);
17376                }
17377            }
17378        }
17379
17380        if let Some(project) = &self.project {
17381            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17382        } else {
17383            Task::ready(Ok(()))
17384        }
17385    }
17386
17387    fn do_stage_or_unstage_and_next(
17388        &mut self,
17389        stage: bool,
17390        window: &mut Window,
17391        cx: &mut Context<Self>,
17392    ) {
17393        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17394
17395        if ranges.iter().any(|range| range.start != range.end) {
17396            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17397            return;
17398        }
17399
17400        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17401        let snapshot = self.snapshot(window, cx);
17402        let position = self.selections.newest::<Point>(cx).head();
17403        let mut row = snapshot
17404            .buffer_snapshot
17405            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17406            .find(|hunk| hunk.row_range.start.0 > position.row)
17407            .map(|hunk| hunk.row_range.start);
17408
17409        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17410        // Outside of the project diff editor, wrap around to the beginning.
17411        if !all_diff_hunks_expanded {
17412            row = row.or_else(|| {
17413                snapshot
17414                    .buffer_snapshot
17415                    .diff_hunks_in_range(Point::zero()..position)
17416                    .find(|hunk| hunk.row_range.end.0 < position.row)
17417                    .map(|hunk| hunk.row_range.start)
17418            });
17419        }
17420
17421        if let Some(row) = row {
17422            let destination = Point::new(row.0, 0);
17423            let autoscroll = Autoscroll::center();
17424
17425            self.unfold_ranges(&[destination..destination], false, false, cx);
17426            self.change_selections(Some(autoscroll), window, cx, |s| {
17427                s.select_ranges([destination..destination]);
17428            });
17429        }
17430    }
17431
17432    fn do_stage_or_unstage(
17433        &self,
17434        stage: bool,
17435        buffer_id: BufferId,
17436        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17437        cx: &mut App,
17438    ) -> Option<()> {
17439        let project = self.project.as_ref()?;
17440        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17441        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17442        let buffer_snapshot = buffer.read(cx).snapshot();
17443        let file_exists = buffer_snapshot
17444            .file()
17445            .is_some_and(|file| file.disk_state().exists());
17446        diff.update(cx, |diff, cx| {
17447            diff.stage_or_unstage_hunks(
17448                stage,
17449                &hunks
17450                    .map(|hunk| buffer_diff::DiffHunk {
17451                        buffer_range: hunk.buffer_range,
17452                        diff_base_byte_range: hunk.diff_base_byte_range,
17453                        secondary_status: hunk.secondary_status,
17454                        range: Point::zero()..Point::zero(), // unused
17455                    })
17456                    .collect::<Vec<_>>(),
17457                &buffer_snapshot,
17458                file_exists,
17459                cx,
17460            )
17461        });
17462        None
17463    }
17464
17465    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17466        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17467        self.buffer
17468            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17469    }
17470
17471    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17472        self.buffer.update(cx, |buffer, cx| {
17473            let ranges = vec![Anchor::min()..Anchor::max()];
17474            if !buffer.all_diff_hunks_expanded()
17475                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17476            {
17477                buffer.collapse_diff_hunks(ranges, cx);
17478                true
17479            } else {
17480                false
17481            }
17482        })
17483    }
17484
17485    fn toggle_diff_hunks_in_ranges(
17486        &mut self,
17487        ranges: Vec<Range<Anchor>>,
17488        cx: &mut Context<Editor>,
17489    ) {
17490        self.buffer.update(cx, |buffer, cx| {
17491            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17492            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17493        })
17494    }
17495
17496    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17497        self.buffer.update(cx, |buffer, cx| {
17498            let snapshot = buffer.snapshot(cx);
17499            let excerpt_id = range.end.excerpt_id;
17500            let point_range = range.to_point(&snapshot);
17501            let expand = !buffer.single_hunk_is_expanded(range, cx);
17502            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17503        })
17504    }
17505
17506    pub(crate) fn apply_all_diff_hunks(
17507        &mut self,
17508        _: &ApplyAllDiffHunks,
17509        window: &mut Window,
17510        cx: &mut Context<Self>,
17511    ) {
17512        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17513
17514        let buffers = self.buffer.read(cx).all_buffers();
17515        for branch_buffer in buffers {
17516            branch_buffer.update(cx, |branch_buffer, cx| {
17517                branch_buffer.merge_into_base(Vec::new(), cx);
17518            });
17519        }
17520
17521        if let Some(project) = self.project.clone() {
17522            self.save(
17523                SaveOptions {
17524                    format: true,
17525                    autosave: false,
17526                },
17527                project,
17528                window,
17529                cx,
17530            )
17531            .detach_and_log_err(cx);
17532        }
17533    }
17534
17535    pub(crate) fn apply_selected_diff_hunks(
17536        &mut self,
17537        _: &ApplyDiffHunk,
17538        window: &mut Window,
17539        cx: &mut Context<Self>,
17540    ) {
17541        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17542        let snapshot = self.snapshot(window, cx);
17543        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17544        let mut ranges_by_buffer = HashMap::default();
17545        self.transact(window, cx, |editor, _window, cx| {
17546            for hunk in hunks {
17547                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17548                    ranges_by_buffer
17549                        .entry(buffer.clone())
17550                        .or_insert_with(Vec::new)
17551                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17552                }
17553            }
17554
17555            for (buffer, ranges) in ranges_by_buffer {
17556                buffer.update(cx, |buffer, cx| {
17557                    buffer.merge_into_base(ranges, cx);
17558                });
17559            }
17560        });
17561
17562        if let Some(project) = self.project.clone() {
17563            self.save(
17564                SaveOptions {
17565                    format: true,
17566                    autosave: false,
17567                },
17568                project,
17569                window,
17570                cx,
17571            )
17572            .detach_and_log_err(cx);
17573        }
17574    }
17575
17576    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17577        if hovered != self.gutter_hovered {
17578            self.gutter_hovered = hovered;
17579            cx.notify();
17580        }
17581    }
17582
17583    pub fn insert_blocks(
17584        &mut self,
17585        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17586        autoscroll: Option<Autoscroll>,
17587        cx: &mut Context<Self>,
17588    ) -> Vec<CustomBlockId> {
17589        let blocks = self
17590            .display_map
17591            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17592        if let Some(autoscroll) = autoscroll {
17593            self.request_autoscroll(autoscroll, cx);
17594        }
17595        cx.notify();
17596        blocks
17597    }
17598
17599    pub fn resize_blocks(
17600        &mut self,
17601        heights: HashMap<CustomBlockId, u32>,
17602        autoscroll: Option<Autoscroll>,
17603        cx: &mut Context<Self>,
17604    ) {
17605        self.display_map
17606            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17607        if let Some(autoscroll) = autoscroll {
17608            self.request_autoscroll(autoscroll, cx);
17609        }
17610        cx.notify();
17611    }
17612
17613    pub fn replace_blocks(
17614        &mut self,
17615        renderers: HashMap<CustomBlockId, RenderBlock>,
17616        autoscroll: Option<Autoscroll>,
17617        cx: &mut Context<Self>,
17618    ) {
17619        self.display_map
17620            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17621        if let Some(autoscroll) = autoscroll {
17622            self.request_autoscroll(autoscroll, cx);
17623        }
17624        cx.notify();
17625    }
17626
17627    pub fn remove_blocks(
17628        &mut self,
17629        block_ids: HashSet<CustomBlockId>,
17630        autoscroll: Option<Autoscroll>,
17631        cx: &mut Context<Self>,
17632    ) {
17633        self.display_map.update(cx, |display_map, cx| {
17634            display_map.remove_blocks(block_ids, cx)
17635        });
17636        if let Some(autoscroll) = autoscroll {
17637            self.request_autoscroll(autoscroll, cx);
17638        }
17639        cx.notify();
17640    }
17641
17642    pub fn row_for_block(
17643        &self,
17644        block_id: CustomBlockId,
17645        cx: &mut Context<Self>,
17646    ) -> Option<DisplayRow> {
17647        self.display_map
17648            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17649    }
17650
17651    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17652        self.focused_block = Some(focused_block);
17653    }
17654
17655    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17656        self.focused_block.take()
17657    }
17658
17659    pub fn insert_creases(
17660        &mut self,
17661        creases: impl IntoIterator<Item = Crease<Anchor>>,
17662        cx: &mut Context<Self>,
17663    ) -> Vec<CreaseId> {
17664        self.display_map
17665            .update(cx, |map, cx| map.insert_creases(creases, cx))
17666    }
17667
17668    pub fn remove_creases(
17669        &mut self,
17670        ids: impl IntoIterator<Item = CreaseId>,
17671        cx: &mut Context<Self>,
17672    ) -> Vec<(CreaseId, Range<Anchor>)> {
17673        self.display_map
17674            .update(cx, |map, cx| map.remove_creases(ids, cx))
17675    }
17676
17677    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17678        self.display_map
17679            .update(cx, |map, cx| map.snapshot(cx))
17680            .longest_row()
17681    }
17682
17683    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17684        self.display_map
17685            .update(cx, |map, cx| map.snapshot(cx))
17686            .max_point()
17687    }
17688
17689    pub fn text(&self, cx: &App) -> String {
17690        self.buffer.read(cx).read(cx).text()
17691    }
17692
17693    pub fn is_empty(&self, cx: &App) -> bool {
17694        self.buffer.read(cx).read(cx).is_empty()
17695    }
17696
17697    pub fn text_option(&self, cx: &App) -> Option<String> {
17698        let text = self.text(cx);
17699        let text = text.trim();
17700
17701        if text.is_empty() {
17702            return None;
17703        }
17704
17705        Some(text.to_string())
17706    }
17707
17708    pub fn set_text(
17709        &mut self,
17710        text: impl Into<Arc<str>>,
17711        window: &mut Window,
17712        cx: &mut Context<Self>,
17713    ) {
17714        self.transact(window, cx, |this, _, cx| {
17715            this.buffer
17716                .read(cx)
17717                .as_singleton()
17718                .expect("you can only call set_text on editors for singleton buffers")
17719                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17720        });
17721    }
17722
17723    pub fn display_text(&self, cx: &mut App) -> String {
17724        self.display_map
17725            .update(cx, |map, cx| map.snapshot(cx))
17726            .text()
17727    }
17728
17729    fn create_minimap(
17730        &self,
17731        minimap_settings: MinimapSettings,
17732        window: &mut Window,
17733        cx: &mut Context<Self>,
17734    ) -> Option<Entity<Self>> {
17735        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17736            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17737    }
17738
17739    fn initialize_new_minimap(
17740        &self,
17741        minimap_settings: MinimapSettings,
17742        window: &mut Window,
17743        cx: &mut Context<Self>,
17744    ) -> Entity<Self> {
17745        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17746
17747        let mut minimap = Editor::new_internal(
17748            EditorMode::Minimap {
17749                parent: cx.weak_entity(),
17750            },
17751            self.buffer.clone(),
17752            self.project.clone(),
17753            Some(self.display_map.clone()),
17754            window,
17755            cx,
17756        );
17757        minimap.scroll_manager.clone_state(&self.scroll_manager);
17758        minimap.set_text_style_refinement(TextStyleRefinement {
17759            font_size: Some(MINIMAP_FONT_SIZE),
17760            font_weight: Some(MINIMAP_FONT_WEIGHT),
17761            ..Default::default()
17762        });
17763        minimap.update_minimap_configuration(minimap_settings, cx);
17764        cx.new(|_| minimap)
17765    }
17766
17767    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17768        let current_line_highlight = minimap_settings
17769            .current_line_highlight
17770            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17771        self.set_current_line_highlight(Some(current_line_highlight));
17772    }
17773
17774    pub fn minimap(&self) -> Option<&Entity<Self>> {
17775        self.minimap
17776            .as_ref()
17777            .filter(|_| self.minimap_visibility.visible())
17778    }
17779
17780    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17781        let mut wrap_guides = smallvec![];
17782
17783        if self.show_wrap_guides == Some(false) {
17784            return wrap_guides;
17785        }
17786
17787        let settings = self.buffer.read(cx).language_settings(cx);
17788        if settings.show_wrap_guides {
17789            match self.soft_wrap_mode(cx) {
17790                SoftWrap::Column(soft_wrap) => {
17791                    wrap_guides.push((soft_wrap as usize, true));
17792                }
17793                SoftWrap::Bounded(soft_wrap) => {
17794                    wrap_guides.push((soft_wrap as usize, true));
17795                }
17796                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17797            }
17798            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17799        }
17800
17801        wrap_guides
17802    }
17803
17804    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17805        let settings = self.buffer.read(cx).language_settings(cx);
17806        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17807        match mode {
17808            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17809                SoftWrap::None
17810            }
17811            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17812            language_settings::SoftWrap::PreferredLineLength => {
17813                SoftWrap::Column(settings.preferred_line_length)
17814            }
17815            language_settings::SoftWrap::Bounded => {
17816                SoftWrap::Bounded(settings.preferred_line_length)
17817            }
17818        }
17819    }
17820
17821    pub fn set_soft_wrap_mode(
17822        &mut self,
17823        mode: language_settings::SoftWrap,
17824
17825        cx: &mut Context<Self>,
17826    ) {
17827        self.soft_wrap_mode_override = Some(mode);
17828        cx.notify();
17829    }
17830
17831    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17832        self.hard_wrap = hard_wrap;
17833        cx.notify();
17834    }
17835
17836    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17837        self.text_style_refinement = Some(style);
17838    }
17839
17840    /// called by the Element so we know what style we were most recently rendered with.
17841    pub(crate) fn set_style(
17842        &mut self,
17843        style: EditorStyle,
17844        window: &mut Window,
17845        cx: &mut Context<Self>,
17846    ) {
17847        // We intentionally do not inform the display map about the minimap style
17848        // so that wrapping is not recalculated and stays consistent for the editor
17849        // and its linked minimap.
17850        if !self.mode.is_minimap() {
17851            let rem_size = window.rem_size();
17852            self.display_map.update(cx, |map, cx| {
17853                map.set_font(
17854                    style.text.font(),
17855                    style.text.font_size.to_pixels(rem_size),
17856                    cx,
17857                )
17858            });
17859        }
17860        self.style = Some(style);
17861    }
17862
17863    pub fn style(&self) -> Option<&EditorStyle> {
17864        self.style.as_ref()
17865    }
17866
17867    // Called by the element. This method is not designed to be called outside of the editor
17868    // element's layout code because it does not notify when rewrapping is computed synchronously.
17869    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17870        self.display_map
17871            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17872    }
17873
17874    pub fn set_soft_wrap(&mut self) {
17875        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17876    }
17877
17878    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17879        if self.soft_wrap_mode_override.is_some() {
17880            self.soft_wrap_mode_override.take();
17881        } else {
17882            let soft_wrap = match self.soft_wrap_mode(cx) {
17883                SoftWrap::GitDiff => return,
17884                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17885                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17886                    language_settings::SoftWrap::None
17887                }
17888            };
17889            self.soft_wrap_mode_override = Some(soft_wrap);
17890        }
17891        cx.notify();
17892    }
17893
17894    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17895        let Some(workspace) = self.workspace() else {
17896            return;
17897        };
17898        let fs = workspace.read(cx).app_state().fs.clone();
17899        let current_show = TabBarSettings::get_global(cx).show;
17900        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17901            setting.show = Some(!current_show);
17902        });
17903    }
17904
17905    pub fn toggle_indent_guides(
17906        &mut self,
17907        _: &ToggleIndentGuides,
17908        _: &mut Window,
17909        cx: &mut Context<Self>,
17910    ) {
17911        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17912            self.buffer
17913                .read(cx)
17914                .language_settings(cx)
17915                .indent_guides
17916                .enabled
17917        });
17918        self.show_indent_guides = Some(!currently_enabled);
17919        cx.notify();
17920    }
17921
17922    fn should_show_indent_guides(&self) -> Option<bool> {
17923        self.show_indent_guides
17924    }
17925
17926    pub fn toggle_line_numbers(
17927        &mut self,
17928        _: &ToggleLineNumbers,
17929        _: &mut Window,
17930        cx: &mut Context<Self>,
17931    ) {
17932        let mut editor_settings = EditorSettings::get_global(cx).clone();
17933        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17934        EditorSettings::override_global(editor_settings, cx);
17935    }
17936
17937    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17938        if let Some(show_line_numbers) = self.show_line_numbers {
17939            return show_line_numbers;
17940        }
17941        EditorSettings::get_global(cx).gutter.line_numbers
17942    }
17943
17944    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17945        self.use_relative_line_numbers
17946            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17947    }
17948
17949    pub fn toggle_relative_line_numbers(
17950        &mut self,
17951        _: &ToggleRelativeLineNumbers,
17952        _: &mut Window,
17953        cx: &mut Context<Self>,
17954    ) {
17955        let is_relative = self.should_use_relative_line_numbers(cx);
17956        self.set_relative_line_number(Some(!is_relative), cx)
17957    }
17958
17959    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17960        self.use_relative_line_numbers = is_relative;
17961        cx.notify();
17962    }
17963
17964    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17965        self.show_gutter = show_gutter;
17966        cx.notify();
17967    }
17968
17969    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17970        self.show_scrollbars = ScrollbarAxes {
17971            horizontal: show,
17972            vertical: show,
17973        };
17974        cx.notify();
17975    }
17976
17977    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17978        self.show_scrollbars.vertical = show;
17979        cx.notify();
17980    }
17981
17982    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17983        self.show_scrollbars.horizontal = show;
17984        cx.notify();
17985    }
17986
17987    pub fn set_minimap_visibility(
17988        &mut self,
17989        minimap_visibility: MinimapVisibility,
17990        window: &mut Window,
17991        cx: &mut Context<Self>,
17992    ) {
17993        if self.minimap_visibility != minimap_visibility {
17994            if minimap_visibility.visible() && self.minimap.is_none() {
17995                let minimap_settings = EditorSettings::get_global(cx).minimap;
17996                self.minimap =
17997                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17998            }
17999            self.minimap_visibility = minimap_visibility;
18000            cx.notify();
18001        }
18002    }
18003
18004    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18005        self.set_show_scrollbars(false, cx);
18006        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18007    }
18008
18009    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18010        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18011    }
18012
18013    /// Normally the text in full mode and auto height editors is padded on the
18014    /// left side by roughly half a character width for improved hit testing.
18015    ///
18016    /// Use this method to disable this for cases where this is not wanted (e.g.
18017    /// if you want to align the editor text with some other text above or below)
18018    /// or if you want to add this padding to single-line editors.
18019    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18020        self.offset_content = offset_content;
18021        cx.notify();
18022    }
18023
18024    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18025        self.show_line_numbers = Some(show_line_numbers);
18026        cx.notify();
18027    }
18028
18029    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18030        self.disable_expand_excerpt_buttons = true;
18031        cx.notify();
18032    }
18033
18034    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18035        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18036        cx.notify();
18037    }
18038
18039    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18040        self.show_code_actions = Some(show_code_actions);
18041        cx.notify();
18042    }
18043
18044    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18045        self.show_runnables = Some(show_runnables);
18046        cx.notify();
18047    }
18048
18049    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18050        self.show_breakpoints = Some(show_breakpoints);
18051        cx.notify();
18052    }
18053
18054    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18055        if self.display_map.read(cx).masked != masked {
18056            self.display_map.update(cx, |map, _| map.masked = masked);
18057        }
18058        cx.notify()
18059    }
18060
18061    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18062        self.show_wrap_guides = Some(show_wrap_guides);
18063        cx.notify();
18064    }
18065
18066    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18067        self.show_indent_guides = Some(show_indent_guides);
18068        cx.notify();
18069    }
18070
18071    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18072        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18073            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18074                if let Some(dir) = file.abs_path(cx).parent() {
18075                    return Some(dir.to_owned());
18076                }
18077            }
18078
18079            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18080                return Some(project_path.path.to_path_buf());
18081            }
18082        }
18083
18084        None
18085    }
18086
18087    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18088        self.active_excerpt(cx)?
18089            .1
18090            .read(cx)
18091            .file()
18092            .and_then(|f| f.as_local())
18093    }
18094
18095    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18096        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18097            let buffer = buffer.read(cx);
18098            if let Some(project_path) = buffer.project_path(cx) {
18099                let project = self.project.as_ref()?.read(cx);
18100                project.absolute_path(&project_path, cx)
18101            } else {
18102                buffer
18103                    .file()
18104                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18105            }
18106        })
18107    }
18108
18109    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18110        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18111            let project_path = buffer.read(cx).project_path(cx)?;
18112            let project = self.project.as_ref()?.read(cx);
18113            let entry = project.entry_for_path(&project_path, cx)?;
18114            let path = entry.path.to_path_buf();
18115            Some(path)
18116        })
18117    }
18118
18119    pub fn reveal_in_finder(
18120        &mut self,
18121        _: &RevealInFileManager,
18122        _window: &mut Window,
18123        cx: &mut Context<Self>,
18124    ) {
18125        if let Some(target) = self.target_file(cx) {
18126            cx.reveal_path(&target.abs_path(cx));
18127        }
18128    }
18129
18130    pub fn copy_path(
18131        &mut self,
18132        _: &zed_actions::workspace::CopyPath,
18133        _window: &mut Window,
18134        cx: &mut Context<Self>,
18135    ) {
18136        if let Some(path) = self.target_file_abs_path(cx) {
18137            if let Some(path) = path.to_str() {
18138                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18139            }
18140        }
18141    }
18142
18143    pub fn copy_relative_path(
18144        &mut self,
18145        _: &zed_actions::workspace::CopyRelativePath,
18146        _window: &mut Window,
18147        cx: &mut Context<Self>,
18148    ) {
18149        if let Some(path) = self.target_file_path(cx) {
18150            if let Some(path) = path.to_str() {
18151                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18152            }
18153        }
18154    }
18155
18156    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18157        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18158            buffer.read(cx).project_path(cx)
18159        } else {
18160            None
18161        }
18162    }
18163
18164    // Returns true if the editor handled a go-to-line request
18165    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18166        maybe!({
18167            let breakpoint_store = self.breakpoint_store.as_ref()?;
18168
18169            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18170            else {
18171                self.clear_row_highlights::<ActiveDebugLine>();
18172                return None;
18173            };
18174
18175            let position = active_stack_frame.position;
18176            let buffer_id = position.buffer_id?;
18177            let snapshot = self
18178                .project
18179                .as_ref()?
18180                .read(cx)
18181                .buffer_for_id(buffer_id, cx)?
18182                .read(cx)
18183                .snapshot();
18184
18185            let mut handled = false;
18186            for (id, ExcerptRange { context, .. }) in
18187                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18188            {
18189                if context.start.cmp(&position, &snapshot).is_ge()
18190                    || context.end.cmp(&position, &snapshot).is_lt()
18191                {
18192                    continue;
18193                }
18194                let snapshot = self.buffer.read(cx).snapshot(cx);
18195                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18196
18197                handled = true;
18198                self.clear_row_highlights::<ActiveDebugLine>();
18199
18200                self.go_to_line::<ActiveDebugLine>(
18201                    multibuffer_anchor,
18202                    Some(cx.theme().colors().editor_debugger_active_line_background),
18203                    window,
18204                    cx,
18205                );
18206
18207                cx.notify();
18208            }
18209
18210            handled.then_some(())
18211        })
18212        .is_some()
18213    }
18214
18215    pub fn copy_file_name_without_extension(
18216        &mut self,
18217        _: &CopyFileNameWithoutExtension,
18218        _: &mut Window,
18219        cx: &mut Context<Self>,
18220    ) {
18221        if let Some(file) = self.target_file(cx) {
18222            if let Some(file_stem) = file.path().file_stem() {
18223                if let Some(name) = file_stem.to_str() {
18224                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18225                }
18226            }
18227        }
18228    }
18229
18230    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18231        if let Some(file) = self.target_file(cx) {
18232            if let Some(file_name) = file.path().file_name() {
18233                if let Some(name) = file_name.to_str() {
18234                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18235                }
18236            }
18237        }
18238    }
18239
18240    pub fn toggle_git_blame(
18241        &mut self,
18242        _: &::git::Blame,
18243        window: &mut Window,
18244        cx: &mut Context<Self>,
18245    ) {
18246        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18247
18248        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18249            self.start_git_blame(true, window, cx);
18250        }
18251
18252        cx.notify();
18253    }
18254
18255    pub fn toggle_git_blame_inline(
18256        &mut self,
18257        _: &ToggleGitBlameInline,
18258        window: &mut Window,
18259        cx: &mut Context<Self>,
18260    ) {
18261        self.toggle_git_blame_inline_internal(true, window, cx);
18262        cx.notify();
18263    }
18264
18265    pub fn open_git_blame_commit(
18266        &mut self,
18267        _: &OpenGitBlameCommit,
18268        window: &mut Window,
18269        cx: &mut Context<Self>,
18270    ) {
18271        self.open_git_blame_commit_internal(window, cx);
18272    }
18273
18274    fn open_git_blame_commit_internal(
18275        &mut self,
18276        window: &mut Window,
18277        cx: &mut Context<Self>,
18278    ) -> Option<()> {
18279        let blame = self.blame.as_ref()?;
18280        let snapshot = self.snapshot(window, cx);
18281        let cursor = self.selections.newest::<Point>(cx).head();
18282        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18283        let blame_entry = blame
18284            .update(cx, |blame, cx| {
18285                blame
18286                    .blame_for_rows(
18287                        &[RowInfo {
18288                            buffer_id: Some(buffer.remote_id()),
18289                            buffer_row: Some(point.row),
18290                            ..Default::default()
18291                        }],
18292                        cx,
18293                    )
18294                    .next()
18295            })
18296            .flatten()?;
18297        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18298        let repo = blame.read(cx).repository(cx)?;
18299        let workspace = self.workspace()?.downgrade();
18300        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18301        None
18302    }
18303
18304    pub fn git_blame_inline_enabled(&self) -> bool {
18305        self.git_blame_inline_enabled
18306    }
18307
18308    pub fn toggle_selection_menu(
18309        &mut self,
18310        _: &ToggleSelectionMenu,
18311        _: &mut Window,
18312        cx: &mut Context<Self>,
18313    ) {
18314        self.show_selection_menu = self
18315            .show_selection_menu
18316            .map(|show_selections_menu| !show_selections_menu)
18317            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18318
18319        cx.notify();
18320    }
18321
18322    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18323        self.show_selection_menu
18324            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18325    }
18326
18327    fn start_git_blame(
18328        &mut self,
18329        user_triggered: bool,
18330        window: &mut Window,
18331        cx: &mut Context<Self>,
18332    ) {
18333        if let Some(project) = self.project.as_ref() {
18334            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18335                return;
18336            };
18337
18338            if buffer.read(cx).file().is_none() {
18339                return;
18340            }
18341
18342            let focused = self.focus_handle(cx).contains_focused(window, cx);
18343
18344            let project = project.clone();
18345            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18346            self.blame_subscription =
18347                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18348            self.blame = Some(blame);
18349        }
18350    }
18351
18352    fn toggle_git_blame_inline_internal(
18353        &mut self,
18354        user_triggered: bool,
18355        window: &mut Window,
18356        cx: &mut Context<Self>,
18357    ) {
18358        if self.git_blame_inline_enabled {
18359            self.git_blame_inline_enabled = false;
18360            self.show_git_blame_inline = false;
18361            self.show_git_blame_inline_delay_task.take();
18362        } else {
18363            self.git_blame_inline_enabled = true;
18364            self.start_git_blame_inline(user_triggered, window, cx);
18365        }
18366
18367        cx.notify();
18368    }
18369
18370    fn start_git_blame_inline(
18371        &mut self,
18372        user_triggered: bool,
18373        window: &mut Window,
18374        cx: &mut Context<Self>,
18375    ) {
18376        self.start_git_blame(user_triggered, window, cx);
18377
18378        if ProjectSettings::get_global(cx)
18379            .git
18380            .inline_blame_delay()
18381            .is_some()
18382        {
18383            self.start_inline_blame_timer(window, cx);
18384        } else {
18385            self.show_git_blame_inline = true
18386        }
18387    }
18388
18389    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18390        self.blame.as_ref()
18391    }
18392
18393    pub fn show_git_blame_gutter(&self) -> bool {
18394        self.show_git_blame_gutter
18395    }
18396
18397    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18398        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18399    }
18400
18401    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18402        self.show_git_blame_inline
18403            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18404            && !self.newest_selection_head_on_empty_line(cx)
18405            && self.has_blame_entries(cx)
18406    }
18407
18408    fn has_blame_entries(&self, cx: &App) -> bool {
18409        self.blame()
18410            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18411    }
18412
18413    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18414        let cursor_anchor = self.selections.newest_anchor().head();
18415
18416        let snapshot = self.buffer.read(cx).snapshot(cx);
18417        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18418
18419        snapshot.line_len(buffer_row) == 0
18420    }
18421
18422    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18423        let buffer_and_selection = maybe!({
18424            let selection = self.selections.newest::<Point>(cx);
18425            let selection_range = selection.range();
18426
18427            let multi_buffer = self.buffer().read(cx);
18428            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18429            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18430
18431            let (buffer, range, _) = if selection.reversed {
18432                buffer_ranges.first()
18433            } else {
18434                buffer_ranges.last()
18435            }?;
18436
18437            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18438                ..text::ToPoint::to_point(&range.end, &buffer).row;
18439            Some((
18440                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18441                selection,
18442            ))
18443        });
18444
18445        let Some((buffer, selection)) = buffer_and_selection else {
18446            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18447        };
18448
18449        let Some(project) = self.project.as_ref() else {
18450            return Task::ready(Err(anyhow!("editor does not have project")));
18451        };
18452
18453        project.update(cx, |project, cx| {
18454            project.get_permalink_to_line(&buffer, selection, cx)
18455        })
18456    }
18457
18458    pub fn copy_permalink_to_line(
18459        &mut self,
18460        _: &CopyPermalinkToLine,
18461        window: &mut Window,
18462        cx: &mut Context<Self>,
18463    ) {
18464        let permalink_task = self.get_permalink_to_line(cx);
18465        let workspace = self.workspace();
18466
18467        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18468            Ok(permalink) => {
18469                cx.update(|_, cx| {
18470                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18471                })
18472                .ok();
18473            }
18474            Err(err) => {
18475                let message = format!("Failed to copy permalink: {err}");
18476
18477                anyhow::Result::<()>::Err(err).log_err();
18478
18479                if let Some(workspace) = workspace {
18480                    workspace
18481                        .update_in(cx, |workspace, _, cx| {
18482                            struct CopyPermalinkToLine;
18483
18484                            workspace.show_toast(
18485                                Toast::new(
18486                                    NotificationId::unique::<CopyPermalinkToLine>(),
18487                                    message,
18488                                ),
18489                                cx,
18490                            )
18491                        })
18492                        .ok();
18493                }
18494            }
18495        })
18496        .detach();
18497    }
18498
18499    pub fn copy_file_location(
18500        &mut self,
18501        _: &CopyFileLocation,
18502        _: &mut Window,
18503        cx: &mut Context<Self>,
18504    ) {
18505        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18506        if let Some(file) = self.target_file(cx) {
18507            if let Some(path) = file.path().to_str() {
18508                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18509            }
18510        }
18511    }
18512
18513    pub fn open_permalink_to_line(
18514        &mut self,
18515        _: &OpenPermalinkToLine,
18516        window: &mut Window,
18517        cx: &mut Context<Self>,
18518    ) {
18519        let permalink_task = self.get_permalink_to_line(cx);
18520        let workspace = self.workspace();
18521
18522        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18523            Ok(permalink) => {
18524                cx.update(|_, cx| {
18525                    cx.open_url(permalink.as_ref());
18526                })
18527                .ok();
18528            }
18529            Err(err) => {
18530                let message = format!("Failed to open permalink: {err}");
18531
18532                anyhow::Result::<()>::Err(err).log_err();
18533
18534                if let Some(workspace) = workspace {
18535                    workspace
18536                        .update(cx, |workspace, cx| {
18537                            struct OpenPermalinkToLine;
18538
18539                            workspace.show_toast(
18540                                Toast::new(
18541                                    NotificationId::unique::<OpenPermalinkToLine>(),
18542                                    message,
18543                                ),
18544                                cx,
18545                            )
18546                        })
18547                        .ok();
18548                }
18549            }
18550        })
18551        .detach();
18552    }
18553
18554    pub fn insert_uuid_v4(
18555        &mut self,
18556        _: &InsertUuidV4,
18557        window: &mut Window,
18558        cx: &mut Context<Self>,
18559    ) {
18560        self.insert_uuid(UuidVersion::V4, window, cx);
18561    }
18562
18563    pub fn insert_uuid_v7(
18564        &mut self,
18565        _: &InsertUuidV7,
18566        window: &mut Window,
18567        cx: &mut Context<Self>,
18568    ) {
18569        self.insert_uuid(UuidVersion::V7, window, cx);
18570    }
18571
18572    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18574        self.transact(window, cx, |this, window, cx| {
18575            let edits = this
18576                .selections
18577                .all::<Point>(cx)
18578                .into_iter()
18579                .map(|selection| {
18580                    let uuid = match version {
18581                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18582                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18583                    };
18584
18585                    (selection.range(), uuid.to_string())
18586                });
18587            this.edit(edits, cx);
18588            this.refresh_inline_completion(true, false, window, cx);
18589        });
18590    }
18591
18592    pub fn open_selections_in_multibuffer(
18593        &mut self,
18594        _: &OpenSelectionsInMultibuffer,
18595        window: &mut Window,
18596        cx: &mut Context<Self>,
18597    ) {
18598        let multibuffer = self.buffer.read(cx);
18599
18600        let Some(buffer) = multibuffer.as_singleton() else {
18601            return;
18602        };
18603
18604        let Some(workspace) = self.workspace() else {
18605            return;
18606        };
18607
18608        let title = multibuffer.title(cx).to_string();
18609
18610        let locations = self
18611            .selections
18612            .all_anchors(cx)
18613            .into_iter()
18614            .map(|selection| Location {
18615                buffer: buffer.clone(),
18616                range: selection.start.text_anchor..selection.end.text_anchor,
18617            })
18618            .collect::<Vec<_>>();
18619
18620        cx.spawn_in(window, async move |_, cx| {
18621            workspace.update_in(cx, |workspace, window, cx| {
18622                Self::open_locations_in_multibuffer(
18623                    workspace,
18624                    locations,
18625                    format!("Selections for '{title}'"),
18626                    false,
18627                    MultibufferSelectionMode::All,
18628                    window,
18629                    cx,
18630                );
18631            })
18632        })
18633        .detach();
18634    }
18635
18636    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18637    /// last highlight added will be used.
18638    ///
18639    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18640    pub fn highlight_rows<T: 'static>(
18641        &mut self,
18642        range: Range<Anchor>,
18643        color: Hsla,
18644        options: RowHighlightOptions,
18645        cx: &mut Context<Self>,
18646    ) {
18647        let snapshot = self.buffer().read(cx).snapshot(cx);
18648        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18649        let ix = row_highlights.binary_search_by(|highlight| {
18650            Ordering::Equal
18651                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18652                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18653        });
18654
18655        if let Err(mut ix) = ix {
18656            let index = post_inc(&mut self.highlight_order);
18657
18658            // If this range intersects with the preceding highlight, then merge it with
18659            // the preceding highlight. Otherwise insert a new highlight.
18660            let mut merged = false;
18661            if ix > 0 {
18662                let prev_highlight = &mut row_highlights[ix - 1];
18663                if prev_highlight
18664                    .range
18665                    .end
18666                    .cmp(&range.start, &snapshot)
18667                    .is_ge()
18668                {
18669                    ix -= 1;
18670                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18671                        prev_highlight.range.end = range.end;
18672                    }
18673                    merged = true;
18674                    prev_highlight.index = index;
18675                    prev_highlight.color = color;
18676                    prev_highlight.options = options;
18677                }
18678            }
18679
18680            if !merged {
18681                row_highlights.insert(
18682                    ix,
18683                    RowHighlight {
18684                        range: range.clone(),
18685                        index,
18686                        color,
18687                        options,
18688                        type_id: TypeId::of::<T>(),
18689                    },
18690                );
18691            }
18692
18693            // If any of the following highlights intersect with this one, merge them.
18694            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18695                let highlight = &row_highlights[ix];
18696                if next_highlight
18697                    .range
18698                    .start
18699                    .cmp(&highlight.range.end, &snapshot)
18700                    .is_le()
18701                {
18702                    if next_highlight
18703                        .range
18704                        .end
18705                        .cmp(&highlight.range.end, &snapshot)
18706                        .is_gt()
18707                    {
18708                        row_highlights[ix].range.end = next_highlight.range.end;
18709                    }
18710                    row_highlights.remove(ix + 1);
18711                } else {
18712                    break;
18713                }
18714            }
18715        }
18716    }
18717
18718    /// Remove any highlighted row ranges of the given type that intersect the
18719    /// given ranges.
18720    pub fn remove_highlighted_rows<T: 'static>(
18721        &mut self,
18722        ranges_to_remove: Vec<Range<Anchor>>,
18723        cx: &mut Context<Self>,
18724    ) {
18725        let snapshot = self.buffer().read(cx).snapshot(cx);
18726        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18727        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18728        row_highlights.retain(|highlight| {
18729            while let Some(range_to_remove) = ranges_to_remove.peek() {
18730                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18731                    Ordering::Less | Ordering::Equal => {
18732                        ranges_to_remove.next();
18733                    }
18734                    Ordering::Greater => {
18735                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18736                            Ordering::Less | Ordering::Equal => {
18737                                return false;
18738                            }
18739                            Ordering::Greater => break,
18740                        }
18741                    }
18742                }
18743            }
18744
18745            true
18746        })
18747    }
18748
18749    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18750    pub fn clear_row_highlights<T: 'static>(&mut self) {
18751        self.highlighted_rows.remove(&TypeId::of::<T>());
18752    }
18753
18754    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18755    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18756        self.highlighted_rows
18757            .get(&TypeId::of::<T>())
18758            .map_or(&[] as &[_], |vec| vec.as_slice())
18759            .iter()
18760            .map(|highlight| (highlight.range.clone(), highlight.color))
18761    }
18762
18763    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18764    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18765    /// Allows to ignore certain kinds of highlights.
18766    pub fn highlighted_display_rows(
18767        &self,
18768        window: &mut Window,
18769        cx: &mut App,
18770    ) -> BTreeMap<DisplayRow, LineHighlight> {
18771        let snapshot = self.snapshot(window, cx);
18772        let mut used_highlight_orders = HashMap::default();
18773        self.highlighted_rows
18774            .iter()
18775            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18776            .fold(
18777                BTreeMap::<DisplayRow, LineHighlight>::new(),
18778                |mut unique_rows, highlight| {
18779                    let start = highlight.range.start.to_display_point(&snapshot);
18780                    let end = highlight.range.end.to_display_point(&snapshot);
18781                    let start_row = start.row().0;
18782                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18783                        && end.column() == 0
18784                    {
18785                        end.row().0.saturating_sub(1)
18786                    } else {
18787                        end.row().0
18788                    };
18789                    for row in start_row..=end_row {
18790                        let used_index =
18791                            used_highlight_orders.entry(row).or_insert(highlight.index);
18792                        if highlight.index >= *used_index {
18793                            *used_index = highlight.index;
18794                            unique_rows.insert(
18795                                DisplayRow(row),
18796                                LineHighlight {
18797                                    include_gutter: highlight.options.include_gutter,
18798                                    border: None,
18799                                    background: highlight.color.into(),
18800                                    type_id: Some(highlight.type_id),
18801                                },
18802                            );
18803                        }
18804                    }
18805                    unique_rows
18806                },
18807            )
18808    }
18809
18810    pub fn highlighted_display_row_for_autoscroll(
18811        &self,
18812        snapshot: &DisplaySnapshot,
18813    ) -> Option<DisplayRow> {
18814        self.highlighted_rows
18815            .values()
18816            .flat_map(|highlighted_rows| highlighted_rows.iter())
18817            .filter_map(|highlight| {
18818                if highlight.options.autoscroll {
18819                    Some(highlight.range.start.to_display_point(snapshot).row())
18820                } else {
18821                    None
18822                }
18823            })
18824            .min()
18825    }
18826
18827    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18828        self.highlight_background::<SearchWithinRange>(
18829            ranges,
18830            |colors| colors.colors().editor_document_highlight_read_background,
18831            cx,
18832        )
18833    }
18834
18835    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18836        self.breadcrumb_header = Some(new_header);
18837    }
18838
18839    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18840        self.clear_background_highlights::<SearchWithinRange>(cx);
18841    }
18842
18843    pub fn highlight_background<T: 'static>(
18844        &mut self,
18845        ranges: &[Range<Anchor>],
18846        color_fetcher: fn(&Theme) -> Hsla,
18847        cx: &mut Context<Self>,
18848    ) {
18849        self.background_highlights.insert(
18850            HighlightKey::Type(TypeId::of::<T>()),
18851            (color_fetcher, Arc::from(ranges)),
18852        );
18853        self.scrollbar_marker_state.dirty = true;
18854        cx.notify();
18855    }
18856
18857    pub fn highlight_background_key<T: 'static>(
18858        &mut self,
18859        key: usize,
18860        ranges: &[Range<Anchor>],
18861        color_fetcher: fn(&Theme) -> Hsla,
18862        cx: &mut Context<Self>,
18863    ) {
18864        self.background_highlights.insert(
18865            HighlightKey::TypePlus(TypeId::of::<T>(), key),
18866            (color_fetcher, Arc::from(ranges)),
18867        );
18868        self.scrollbar_marker_state.dirty = true;
18869        cx.notify();
18870    }
18871
18872    pub fn clear_background_highlights<T: 'static>(
18873        &mut self,
18874        cx: &mut Context<Self>,
18875    ) -> Option<BackgroundHighlight> {
18876        let text_highlights = self
18877            .background_highlights
18878            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
18879        if !text_highlights.1.is_empty() {
18880            self.scrollbar_marker_state.dirty = true;
18881            cx.notify();
18882        }
18883        Some(text_highlights)
18884    }
18885
18886    pub fn highlight_gutter<T: 'static>(
18887        &mut self,
18888        ranges: impl Into<Vec<Range<Anchor>>>,
18889        color_fetcher: fn(&App) -> Hsla,
18890        cx: &mut Context<Self>,
18891    ) {
18892        self.gutter_highlights
18893            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18894        cx.notify();
18895    }
18896
18897    pub fn clear_gutter_highlights<T: 'static>(
18898        &mut self,
18899        cx: &mut Context<Self>,
18900    ) -> Option<GutterHighlight> {
18901        cx.notify();
18902        self.gutter_highlights.remove(&TypeId::of::<T>())
18903    }
18904
18905    pub fn insert_gutter_highlight<T: 'static>(
18906        &mut self,
18907        range: Range<Anchor>,
18908        color_fetcher: fn(&App) -> Hsla,
18909        cx: &mut Context<Self>,
18910    ) {
18911        let snapshot = self.buffer().read(cx).snapshot(cx);
18912        let mut highlights = self
18913            .gutter_highlights
18914            .remove(&TypeId::of::<T>())
18915            .map(|(_, highlights)| highlights)
18916            .unwrap_or_default();
18917        let ix = highlights.binary_search_by(|highlight| {
18918            Ordering::Equal
18919                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18920                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18921        });
18922        if let Err(ix) = ix {
18923            highlights.insert(ix, range);
18924        }
18925        self.gutter_highlights
18926            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18927    }
18928
18929    pub fn remove_gutter_highlights<T: 'static>(
18930        &mut self,
18931        ranges_to_remove: Vec<Range<Anchor>>,
18932        cx: &mut Context<Self>,
18933    ) {
18934        let snapshot = self.buffer().read(cx).snapshot(cx);
18935        let Some((color_fetcher, mut gutter_highlights)) =
18936            self.gutter_highlights.remove(&TypeId::of::<T>())
18937        else {
18938            return;
18939        };
18940        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18941        gutter_highlights.retain(|highlight| {
18942            while let Some(range_to_remove) = ranges_to_remove.peek() {
18943                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18944                    Ordering::Less | Ordering::Equal => {
18945                        ranges_to_remove.next();
18946                    }
18947                    Ordering::Greater => {
18948                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18949                            Ordering::Less | Ordering::Equal => {
18950                                return false;
18951                            }
18952                            Ordering::Greater => break,
18953                        }
18954                    }
18955                }
18956            }
18957
18958            true
18959        });
18960        self.gutter_highlights
18961            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18962    }
18963
18964    #[cfg(feature = "test-support")]
18965    pub fn all_text_highlights(
18966        &self,
18967        window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
18970        let snapshot = self.snapshot(window, cx);
18971        self.display_map.update(cx, |display_map, _| {
18972            display_map
18973                .all_text_highlights()
18974                .map(|highlight| {
18975                    let (style, ranges) = highlight.as_ref();
18976                    (
18977                        *style,
18978                        ranges
18979                            .iter()
18980                            .map(|range| range.clone().to_display_points(&snapshot))
18981                            .collect(),
18982                    )
18983                })
18984                .collect()
18985        })
18986    }
18987
18988    #[cfg(feature = "test-support")]
18989    pub fn all_text_background_highlights(
18990        &self,
18991        window: &mut Window,
18992        cx: &mut Context<Self>,
18993    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18994        let snapshot = self.snapshot(window, cx);
18995        let buffer = &snapshot.buffer_snapshot;
18996        let start = buffer.anchor_before(0);
18997        let end = buffer.anchor_after(buffer.len());
18998        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
18999    }
19000
19001    #[cfg(feature = "test-support")]
19002    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19003        let snapshot = self.buffer().read(cx).snapshot(cx);
19004
19005        let highlights = self
19006            .background_highlights
19007            .get(&HighlightKey::Type(TypeId::of::<
19008                items::BufferSearchHighlights,
19009            >()));
19010
19011        if let Some((_color, ranges)) = highlights {
19012            ranges
19013                .iter()
19014                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19015                .collect_vec()
19016        } else {
19017            vec![]
19018        }
19019    }
19020
19021    fn document_highlights_for_position<'a>(
19022        &'a self,
19023        position: Anchor,
19024        buffer: &'a MultiBufferSnapshot,
19025    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19026        let read_highlights = self
19027            .background_highlights
19028            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19029            .map(|h| &h.1);
19030        let write_highlights = self
19031            .background_highlights
19032            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19033            .map(|h| &h.1);
19034        let left_position = position.bias_left(buffer);
19035        let right_position = position.bias_right(buffer);
19036        read_highlights
19037            .into_iter()
19038            .chain(write_highlights)
19039            .flat_map(move |ranges| {
19040                let start_ix = match ranges.binary_search_by(|probe| {
19041                    let cmp = probe.end.cmp(&left_position, buffer);
19042                    if cmp.is_ge() {
19043                        Ordering::Greater
19044                    } else {
19045                        Ordering::Less
19046                    }
19047                }) {
19048                    Ok(i) | Err(i) => i,
19049                };
19050
19051                ranges[start_ix..]
19052                    .iter()
19053                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19054            })
19055    }
19056
19057    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19058        self.background_highlights
19059            .get(&HighlightKey::Type(TypeId::of::<T>()))
19060            .map_or(false, |(_, highlights)| !highlights.is_empty())
19061    }
19062
19063    pub fn background_highlights_in_range(
19064        &self,
19065        search_range: Range<Anchor>,
19066        display_snapshot: &DisplaySnapshot,
19067        theme: &Theme,
19068    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19069        let mut results = Vec::new();
19070        for (color_fetcher, ranges) in self.background_highlights.values() {
19071            let color = color_fetcher(theme);
19072            let start_ix = match ranges.binary_search_by(|probe| {
19073                let cmp = probe
19074                    .end
19075                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19076                if cmp.is_gt() {
19077                    Ordering::Greater
19078                } else {
19079                    Ordering::Less
19080                }
19081            }) {
19082                Ok(i) | Err(i) => i,
19083            };
19084            for range in &ranges[start_ix..] {
19085                if range
19086                    .start
19087                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19088                    .is_ge()
19089                {
19090                    break;
19091                }
19092
19093                let start = range.start.to_display_point(display_snapshot);
19094                let end = range.end.to_display_point(display_snapshot);
19095                results.push((start..end, color))
19096            }
19097        }
19098        results
19099    }
19100
19101    pub fn background_highlight_row_ranges<T: 'static>(
19102        &self,
19103        search_range: Range<Anchor>,
19104        display_snapshot: &DisplaySnapshot,
19105        count: usize,
19106    ) -> Vec<RangeInclusive<DisplayPoint>> {
19107        let mut results = Vec::new();
19108        let Some((_, ranges)) = self
19109            .background_highlights
19110            .get(&HighlightKey::Type(TypeId::of::<T>()))
19111        else {
19112            return vec![];
19113        };
19114
19115        let start_ix = match ranges.binary_search_by(|probe| {
19116            let cmp = probe
19117                .end
19118                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19119            if cmp.is_gt() {
19120                Ordering::Greater
19121            } else {
19122                Ordering::Less
19123            }
19124        }) {
19125            Ok(i) | Err(i) => i,
19126        };
19127        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19128            if let (Some(start_display), Some(end_display)) = (start, end) {
19129                results.push(
19130                    start_display.to_display_point(display_snapshot)
19131                        ..=end_display.to_display_point(display_snapshot),
19132                );
19133            }
19134        };
19135        let mut start_row: Option<Point> = None;
19136        let mut end_row: Option<Point> = None;
19137        if ranges.len() > count {
19138            return Vec::new();
19139        }
19140        for range in &ranges[start_ix..] {
19141            if range
19142                .start
19143                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19144                .is_ge()
19145            {
19146                break;
19147            }
19148            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19149            if let Some(current_row) = &end_row {
19150                if end.row == current_row.row {
19151                    continue;
19152                }
19153            }
19154            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19155            if start_row.is_none() {
19156                assert_eq!(end_row, None);
19157                start_row = Some(start);
19158                end_row = Some(end);
19159                continue;
19160            }
19161            if let Some(current_end) = end_row.as_mut() {
19162                if start.row > current_end.row + 1 {
19163                    push_region(start_row, end_row);
19164                    start_row = Some(start);
19165                    end_row = Some(end);
19166                } else {
19167                    // Merge two hunks.
19168                    *current_end = end;
19169                }
19170            } else {
19171                unreachable!();
19172            }
19173        }
19174        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19175        push_region(start_row, end_row);
19176        results
19177    }
19178
19179    pub fn gutter_highlights_in_range(
19180        &self,
19181        search_range: Range<Anchor>,
19182        display_snapshot: &DisplaySnapshot,
19183        cx: &App,
19184    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19185        let mut results = Vec::new();
19186        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19187            let color = color_fetcher(cx);
19188            let start_ix = match ranges.binary_search_by(|probe| {
19189                let cmp = probe
19190                    .end
19191                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19192                if cmp.is_gt() {
19193                    Ordering::Greater
19194                } else {
19195                    Ordering::Less
19196                }
19197            }) {
19198                Ok(i) | Err(i) => i,
19199            };
19200            for range in &ranges[start_ix..] {
19201                if range
19202                    .start
19203                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19204                    .is_ge()
19205                {
19206                    break;
19207                }
19208
19209                let start = range.start.to_display_point(display_snapshot);
19210                let end = range.end.to_display_point(display_snapshot);
19211                results.push((start..end, color))
19212            }
19213        }
19214        results
19215    }
19216
19217    /// Get the text ranges corresponding to the redaction query
19218    pub fn redacted_ranges(
19219        &self,
19220        search_range: Range<Anchor>,
19221        display_snapshot: &DisplaySnapshot,
19222        cx: &App,
19223    ) -> Vec<Range<DisplayPoint>> {
19224        display_snapshot
19225            .buffer_snapshot
19226            .redacted_ranges(search_range, |file| {
19227                if let Some(file) = file {
19228                    file.is_private()
19229                        && EditorSettings::get(
19230                            Some(SettingsLocation {
19231                                worktree_id: file.worktree_id(cx),
19232                                path: file.path().as_ref(),
19233                            }),
19234                            cx,
19235                        )
19236                        .redact_private_values
19237                } else {
19238                    false
19239                }
19240            })
19241            .map(|range| {
19242                range.start.to_display_point(display_snapshot)
19243                    ..range.end.to_display_point(display_snapshot)
19244            })
19245            .collect()
19246    }
19247
19248    pub fn highlight_text_key<T: 'static>(
19249        &mut self,
19250        key: usize,
19251        ranges: Vec<Range<Anchor>>,
19252        style: HighlightStyle,
19253        cx: &mut Context<Self>,
19254    ) {
19255        self.display_map.update(cx, |map, _| {
19256            map.highlight_text(
19257                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19258                ranges,
19259                style,
19260            );
19261        });
19262        cx.notify();
19263    }
19264
19265    pub fn highlight_text<T: 'static>(
19266        &mut self,
19267        ranges: Vec<Range<Anchor>>,
19268        style: HighlightStyle,
19269        cx: &mut Context<Self>,
19270    ) {
19271        self.display_map.update(cx, |map, _| {
19272            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19273        });
19274        cx.notify();
19275    }
19276
19277    pub(crate) fn highlight_inlays<T: 'static>(
19278        &mut self,
19279        highlights: Vec<InlayHighlight>,
19280        style: HighlightStyle,
19281        cx: &mut Context<Self>,
19282    ) {
19283        self.display_map.update(cx, |map, _| {
19284            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19285        });
19286        cx.notify();
19287    }
19288
19289    pub fn text_highlights<'a, T: 'static>(
19290        &'a self,
19291        cx: &'a App,
19292    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19293        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19294    }
19295
19296    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19297        let cleared = self
19298            .display_map
19299            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19300        if cleared {
19301            cx.notify();
19302        }
19303    }
19304
19305    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19306        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19307            && self.focus_handle.is_focused(window)
19308    }
19309
19310    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19311        self.show_cursor_when_unfocused = is_enabled;
19312        cx.notify();
19313    }
19314
19315    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19316        cx.notify();
19317    }
19318
19319    fn on_debug_session_event(
19320        &mut self,
19321        _session: Entity<Session>,
19322        event: &SessionEvent,
19323        cx: &mut Context<Self>,
19324    ) {
19325        match event {
19326            SessionEvent::InvalidateInlineValue => {
19327                self.refresh_inline_values(cx);
19328            }
19329            _ => {}
19330        }
19331    }
19332
19333    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19334        let Some(project) = self.project.clone() else {
19335            return;
19336        };
19337
19338        if !self.inline_value_cache.enabled {
19339            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19340            self.splice_inlays(&inlays, Vec::new(), cx);
19341            return;
19342        }
19343
19344        let current_execution_position = self
19345            .highlighted_rows
19346            .get(&TypeId::of::<ActiveDebugLine>())
19347            .and_then(|lines| lines.last().map(|line| line.range.end));
19348
19349        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19350            let inline_values = editor
19351                .update(cx, |editor, cx| {
19352                    let Some(current_execution_position) = current_execution_position else {
19353                        return Some(Task::ready(Ok(Vec::new())));
19354                    };
19355
19356                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19357                        let snapshot = buffer.snapshot(cx);
19358
19359                        let excerpt = snapshot.excerpt_containing(
19360                            current_execution_position..current_execution_position,
19361                        )?;
19362
19363                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19364                    })?;
19365
19366                    let range =
19367                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19368
19369                    project.inline_values(buffer, range, cx)
19370                })
19371                .ok()
19372                .flatten()?
19373                .await
19374                .context("refreshing debugger inlays")
19375                .log_err()?;
19376
19377            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19378
19379            for (buffer_id, inline_value) in inline_values
19380                .into_iter()
19381                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19382            {
19383                buffer_inline_values
19384                    .entry(buffer_id)
19385                    .or_default()
19386                    .push(inline_value);
19387            }
19388
19389            editor
19390                .update(cx, |editor, cx| {
19391                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19392                    let mut new_inlays = Vec::default();
19393
19394                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19395                        let buffer_id = buffer_snapshot.remote_id();
19396                        buffer_inline_values
19397                            .get(&buffer_id)
19398                            .into_iter()
19399                            .flatten()
19400                            .for_each(|hint| {
19401                                let inlay = Inlay::debugger(
19402                                    post_inc(&mut editor.next_inlay_id),
19403                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19404                                    hint.text(),
19405                                );
19406
19407                                new_inlays.push(inlay);
19408                            });
19409                    }
19410
19411                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19412                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19413
19414                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19415                })
19416                .ok()?;
19417            Some(())
19418        });
19419    }
19420
19421    fn on_buffer_event(
19422        &mut self,
19423        multibuffer: &Entity<MultiBuffer>,
19424        event: &multi_buffer::Event,
19425        window: &mut Window,
19426        cx: &mut Context<Self>,
19427    ) {
19428        match event {
19429            multi_buffer::Event::Edited {
19430                singleton_buffer_edited,
19431                edited_buffer,
19432            } => {
19433                self.scrollbar_marker_state.dirty = true;
19434                self.active_indent_guides_state.dirty = true;
19435                self.refresh_active_diagnostics(cx);
19436                self.refresh_code_actions(window, cx);
19437                self.refresh_selected_text_highlights(true, window, cx);
19438                refresh_matching_bracket_highlights(self, window, cx);
19439                if self.has_active_inline_completion() {
19440                    self.update_visible_inline_completion(window, cx);
19441                }
19442                if let Some(project) = self.project.as_ref() {
19443                    if let Some(edited_buffer) = edited_buffer {
19444                        project.update(cx, |project, cx| {
19445                            self.registered_buffers
19446                                .entry(edited_buffer.read(cx).remote_id())
19447                                .or_insert_with(|| {
19448                                    project
19449                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19450                                });
19451                        });
19452                    }
19453                }
19454                cx.emit(EditorEvent::BufferEdited);
19455                cx.emit(SearchEvent::MatchesInvalidated);
19456
19457                if let Some(buffer) = edited_buffer {
19458                    self.update_lsp_data(None, Some(buffer.read(cx).remote_id()), window, cx);
19459                }
19460
19461                if *singleton_buffer_edited {
19462                    if let Some(buffer) = edited_buffer {
19463                        if buffer.read(cx).file().is_none() {
19464                            cx.emit(EditorEvent::TitleChanged);
19465                        }
19466                    }
19467                    if let Some(project) = &self.project {
19468                        #[allow(clippy::mutable_key_type)]
19469                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19470                            multibuffer
19471                                .all_buffers()
19472                                .into_iter()
19473                                .filter_map(|buffer| {
19474                                    buffer.update(cx, |buffer, cx| {
19475                                        let language = buffer.language()?;
19476                                        let should_discard = project.update(cx, |project, cx| {
19477                                            project.is_local()
19478                                                && !project.has_language_servers_for(buffer, cx)
19479                                        });
19480                                        should_discard.not().then_some(language.clone())
19481                                    })
19482                                })
19483                                .collect::<HashSet<_>>()
19484                        });
19485                        if !languages_affected.is_empty() {
19486                            self.refresh_inlay_hints(
19487                                InlayHintRefreshReason::BufferEdited(languages_affected),
19488                                cx,
19489                            );
19490                        }
19491                    }
19492                }
19493
19494                let Some(project) = &self.project else { return };
19495                let (telemetry, is_via_ssh) = {
19496                    let project = project.read(cx);
19497                    let telemetry = project.client().telemetry().clone();
19498                    let is_via_ssh = project.is_via_ssh();
19499                    (telemetry, is_via_ssh)
19500                };
19501                refresh_linked_ranges(self, window, cx);
19502                telemetry.log_edit_event("editor", is_via_ssh);
19503            }
19504            multi_buffer::Event::ExcerptsAdded {
19505                buffer,
19506                predecessor,
19507                excerpts,
19508            } => {
19509                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19510                let buffer_id = buffer.read(cx).remote_id();
19511                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19512                    if let Some(project) = &self.project {
19513                        update_uncommitted_diff_for_buffer(
19514                            cx.entity(),
19515                            project,
19516                            [buffer.clone()],
19517                            self.buffer.clone(),
19518                            cx,
19519                        )
19520                        .detach();
19521                    }
19522                }
19523                self.update_lsp_data(None, Some(buffer_id), window, cx);
19524                cx.emit(EditorEvent::ExcerptsAdded {
19525                    buffer: buffer.clone(),
19526                    predecessor: *predecessor,
19527                    excerpts: excerpts.clone(),
19528                });
19529                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19530            }
19531            multi_buffer::Event::ExcerptsRemoved {
19532                ids,
19533                removed_buffer_ids,
19534            } => {
19535                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19536                let buffer = self.buffer.read(cx);
19537                self.registered_buffers
19538                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19539                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19540                cx.emit(EditorEvent::ExcerptsRemoved {
19541                    ids: ids.clone(),
19542                    removed_buffer_ids: removed_buffer_ids.clone(),
19543                });
19544            }
19545            multi_buffer::Event::ExcerptsEdited {
19546                excerpt_ids,
19547                buffer_ids,
19548            } => {
19549                self.display_map.update(cx, |map, cx| {
19550                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19551                });
19552                cx.emit(EditorEvent::ExcerptsEdited {
19553                    ids: excerpt_ids.clone(),
19554                });
19555            }
19556            multi_buffer::Event::ExcerptsExpanded { ids } => {
19557                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19558                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19559            }
19560            multi_buffer::Event::Reparsed(buffer_id) => {
19561                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19562                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19563
19564                cx.emit(EditorEvent::Reparsed(*buffer_id));
19565            }
19566            multi_buffer::Event::DiffHunksToggled => {
19567                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19568            }
19569            multi_buffer::Event::LanguageChanged(buffer_id) => {
19570                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19571                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19572                cx.emit(EditorEvent::Reparsed(*buffer_id));
19573                cx.notify();
19574            }
19575            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19576            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19577            multi_buffer::Event::FileHandleChanged
19578            | multi_buffer::Event::Reloaded
19579            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19580            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19581            multi_buffer::Event::DiagnosticsUpdated => {
19582                self.update_diagnostics_state(window, cx);
19583            }
19584            _ => {}
19585        };
19586    }
19587
19588    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19589        if !self.diagnostics_enabled() {
19590            return;
19591        }
19592        self.refresh_active_diagnostics(cx);
19593        self.refresh_inline_diagnostics(true, window, cx);
19594        self.scrollbar_marker_state.dirty = true;
19595        cx.notify();
19596    }
19597
19598    pub fn start_temporary_diff_override(&mut self) {
19599        self.load_diff_task.take();
19600        self.temporary_diff_override = true;
19601    }
19602
19603    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19604        self.temporary_diff_override = false;
19605        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19606        self.buffer.update(cx, |buffer, cx| {
19607            buffer.set_all_diff_hunks_collapsed(cx);
19608        });
19609
19610        if let Some(project) = self.project.clone() {
19611            self.load_diff_task = Some(
19612                update_uncommitted_diff_for_buffer(
19613                    cx.entity(),
19614                    &project,
19615                    self.buffer.read(cx).all_buffers(),
19616                    self.buffer.clone(),
19617                    cx,
19618                )
19619                .shared(),
19620            );
19621        }
19622    }
19623
19624    fn on_display_map_changed(
19625        &mut self,
19626        _: Entity<DisplayMap>,
19627        _: &mut Window,
19628        cx: &mut Context<Self>,
19629    ) {
19630        cx.notify();
19631    }
19632
19633    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19634        let new_severity = if self.diagnostics_enabled() {
19635            EditorSettings::get_global(cx)
19636                .diagnostics_max_severity
19637                .unwrap_or(DiagnosticSeverity::Hint)
19638        } else {
19639            DiagnosticSeverity::Off
19640        };
19641        self.set_max_diagnostics_severity(new_severity, cx);
19642        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19643        self.update_edit_prediction_settings(cx);
19644        self.refresh_inline_completion(true, false, window, cx);
19645        self.refresh_inlay_hints(
19646            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19647                self.selections.newest_anchor().head(),
19648                &self.buffer.read(cx).snapshot(cx),
19649                cx,
19650            )),
19651            cx,
19652        );
19653
19654        let old_cursor_shape = self.cursor_shape;
19655
19656        {
19657            let editor_settings = EditorSettings::get_global(cx);
19658            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19659            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19660            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19661            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19662            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19663        }
19664
19665        if old_cursor_shape != self.cursor_shape {
19666            cx.emit(EditorEvent::CursorShapeChanged);
19667        }
19668
19669        let project_settings = ProjectSettings::get_global(cx);
19670        self.serialize_dirty_buffers =
19671            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19672
19673        if self.mode.is_full() {
19674            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19675            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19676            if self.show_inline_diagnostics != show_inline_diagnostics {
19677                self.show_inline_diagnostics = show_inline_diagnostics;
19678                self.refresh_inline_diagnostics(false, window, cx);
19679            }
19680
19681            if self.git_blame_inline_enabled != inline_blame_enabled {
19682                self.toggle_git_blame_inline_internal(false, window, cx);
19683            }
19684
19685            let minimap_settings = EditorSettings::get_global(cx).minimap;
19686            if self.minimap_visibility != MinimapVisibility::Disabled {
19687                if self.minimap_visibility.settings_visibility()
19688                    != minimap_settings.minimap_enabled()
19689                {
19690                    self.set_minimap_visibility(
19691                        MinimapVisibility::for_mode(self.mode(), cx),
19692                        window,
19693                        cx,
19694                    );
19695                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19696                    minimap_entity.update(cx, |minimap_editor, cx| {
19697                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19698                    })
19699                }
19700            }
19701        }
19702
19703        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19704            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19705        }) {
19706            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19707                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19708            }
19709            self.refresh_colors(None, None, window, cx);
19710        }
19711
19712        cx.notify();
19713    }
19714
19715    pub fn set_searchable(&mut self, searchable: bool) {
19716        self.searchable = searchable;
19717    }
19718
19719    pub fn searchable(&self) -> bool {
19720        self.searchable
19721    }
19722
19723    fn open_proposed_changes_editor(
19724        &mut self,
19725        _: &OpenProposedChangesEditor,
19726        window: &mut Window,
19727        cx: &mut Context<Self>,
19728    ) {
19729        let Some(workspace) = self.workspace() else {
19730            cx.propagate();
19731            return;
19732        };
19733
19734        let selections = self.selections.all::<usize>(cx);
19735        let multi_buffer = self.buffer.read(cx);
19736        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19737        let mut new_selections_by_buffer = HashMap::default();
19738        for selection in selections {
19739            for (buffer, range, _) in
19740                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19741            {
19742                let mut range = range.to_point(buffer);
19743                range.start.column = 0;
19744                range.end.column = buffer.line_len(range.end.row);
19745                new_selections_by_buffer
19746                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19747                    .or_insert(Vec::new())
19748                    .push(range)
19749            }
19750        }
19751
19752        let proposed_changes_buffers = new_selections_by_buffer
19753            .into_iter()
19754            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19755            .collect::<Vec<_>>();
19756        let proposed_changes_editor = cx.new(|cx| {
19757            ProposedChangesEditor::new(
19758                "Proposed changes",
19759                proposed_changes_buffers,
19760                self.project.clone(),
19761                window,
19762                cx,
19763            )
19764        });
19765
19766        window.defer(cx, move |window, cx| {
19767            workspace.update(cx, |workspace, cx| {
19768                workspace.active_pane().update(cx, |pane, cx| {
19769                    pane.add_item(
19770                        Box::new(proposed_changes_editor),
19771                        true,
19772                        true,
19773                        None,
19774                        window,
19775                        cx,
19776                    );
19777                });
19778            });
19779        });
19780    }
19781
19782    pub fn open_excerpts_in_split(
19783        &mut self,
19784        _: &OpenExcerptsSplit,
19785        window: &mut Window,
19786        cx: &mut Context<Self>,
19787    ) {
19788        self.open_excerpts_common(None, true, window, cx)
19789    }
19790
19791    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19792        self.open_excerpts_common(None, false, window, cx)
19793    }
19794
19795    fn open_excerpts_common(
19796        &mut self,
19797        jump_data: Option<JumpData>,
19798        split: bool,
19799        window: &mut Window,
19800        cx: &mut Context<Self>,
19801    ) {
19802        let Some(workspace) = self.workspace() else {
19803            cx.propagate();
19804            return;
19805        };
19806
19807        if self.buffer.read(cx).is_singleton() {
19808            cx.propagate();
19809            return;
19810        }
19811
19812        let mut new_selections_by_buffer = HashMap::default();
19813        match &jump_data {
19814            Some(JumpData::MultiBufferPoint {
19815                excerpt_id,
19816                position,
19817                anchor,
19818                line_offset_from_top,
19819            }) => {
19820                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19821                if let Some(buffer) = multi_buffer_snapshot
19822                    .buffer_id_for_excerpt(*excerpt_id)
19823                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19824                {
19825                    let buffer_snapshot = buffer.read(cx).snapshot();
19826                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19827                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19828                    } else {
19829                        buffer_snapshot.clip_point(*position, Bias::Left)
19830                    };
19831                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19832                    new_selections_by_buffer.insert(
19833                        buffer,
19834                        (
19835                            vec![jump_to_offset..jump_to_offset],
19836                            Some(*line_offset_from_top),
19837                        ),
19838                    );
19839                }
19840            }
19841            Some(JumpData::MultiBufferRow {
19842                row,
19843                line_offset_from_top,
19844            }) => {
19845                let point = MultiBufferPoint::new(row.0, 0);
19846                if let Some((buffer, buffer_point, _)) =
19847                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19848                {
19849                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19850                    new_selections_by_buffer
19851                        .entry(buffer)
19852                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19853                        .0
19854                        .push(buffer_offset..buffer_offset)
19855                }
19856            }
19857            None => {
19858                let selections = self.selections.all::<usize>(cx);
19859                let multi_buffer = self.buffer.read(cx);
19860                for selection in selections {
19861                    for (snapshot, range, _, anchor) in multi_buffer
19862                        .snapshot(cx)
19863                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19864                    {
19865                        if let Some(anchor) = anchor {
19866                            // selection is in a deleted hunk
19867                            let Some(buffer_id) = anchor.buffer_id else {
19868                                continue;
19869                            };
19870                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19871                                continue;
19872                            };
19873                            let offset = text::ToOffset::to_offset(
19874                                &anchor.text_anchor,
19875                                &buffer_handle.read(cx).snapshot(),
19876                            );
19877                            let range = offset..offset;
19878                            new_selections_by_buffer
19879                                .entry(buffer_handle)
19880                                .or_insert((Vec::new(), None))
19881                                .0
19882                                .push(range)
19883                        } else {
19884                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19885                            else {
19886                                continue;
19887                            };
19888                            new_selections_by_buffer
19889                                .entry(buffer_handle)
19890                                .or_insert((Vec::new(), None))
19891                                .0
19892                                .push(range)
19893                        }
19894                    }
19895                }
19896            }
19897        }
19898
19899        new_selections_by_buffer
19900            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19901
19902        if new_selections_by_buffer.is_empty() {
19903            return;
19904        }
19905
19906        // We defer the pane interaction because we ourselves are a workspace item
19907        // and activating a new item causes the pane to call a method on us reentrantly,
19908        // which panics if we're on the stack.
19909        window.defer(cx, move |window, cx| {
19910            workspace.update(cx, |workspace, cx| {
19911                let pane = if split {
19912                    workspace.adjacent_pane(window, cx)
19913                } else {
19914                    workspace.active_pane().clone()
19915                };
19916
19917                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19918                    let editor = buffer
19919                        .read(cx)
19920                        .file()
19921                        .is_none()
19922                        .then(|| {
19923                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19924                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19925                            // Instead, we try to activate the existing editor in the pane first.
19926                            let (editor, pane_item_index) =
19927                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19928                                    let editor = item.downcast::<Editor>()?;
19929                                    let singleton_buffer =
19930                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19931                                    if singleton_buffer == buffer {
19932                                        Some((editor, i))
19933                                    } else {
19934                                        None
19935                                    }
19936                                })?;
19937                            pane.update(cx, |pane, cx| {
19938                                pane.activate_item(pane_item_index, true, true, window, cx)
19939                            });
19940                            Some(editor)
19941                        })
19942                        .flatten()
19943                        .unwrap_or_else(|| {
19944                            workspace.open_project_item::<Self>(
19945                                pane.clone(),
19946                                buffer,
19947                                true,
19948                                true,
19949                                window,
19950                                cx,
19951                            )
19952                        });
19953
19954                    editor.update(cx, |editor, cx| {
19955                        let autoscroll = match scroll_offset {
19956                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19957                            None => Autoscroll::newest(),
19958                        };
19959                        let nav_history = editor.nav_history.take();
19960                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19961                            s.select_ranges(ranges);
19962                        });
19963                        editor.nav_history = nav_history;
19964                    });
19965                }
19966            })
19967        });
19968    }
19969
19970    // For now, don't allow opening excerpts in buffers that aren't backed by
19971    // regular project files.
19972    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19973        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19974    }
19975
19976    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19977        let snapshot = self.buffer.read(cx).read(cx);
19978        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19979        Some(
19980            ranges
19981                .iter()
19982                .map(move |range| {
19983                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19984                })
19985                .collect(),
19986        )
19987    }
19988
19989    fn selection_replacement_ranges(
19990        &self,
19991        range: Range<OffsetUtf16>,
19992        cx: &mut App,
19993    ) -> Vec<Range<OffsetUtf16>> {
19994        let selections = self.selections.all::<OffsetUtf16>(cx);
19995        let newest_selection = selections
19996            .iter()
19997            .max_by_key(|selection| selection.id)
19998            .unwrap();
19999        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20000        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20001        let snapshot = self.buffer.read(cx).read(cx);
20002        selections
20003            .into_iter()
20004            .map(|mut selection| {
20005                selection.start.0 =
20006                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20007                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20008                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20009                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20010            })
20011            .collect()
20012    }
20013
20014    fn report_editor_event(
20015        &self,
20016        event_type: &'static str,
20017        file_extension: Option<String>,
20018        cx: &App,
20019    ) {
20020        if cfg!(any(test, feature = "test-support")) {
20021            return;
20022        }
20023
20024        let Some(project) = &self.project else { return };
20025
20026        // If None, we are in a file without an extension
20027        let file = self
20028            .buffer
20029            .read(cx)
20030            .as_singleton()
20031            .and_then(|b| b.read(cx).file());
20032        let file_extension = file_extension.or(file
20033            .as_ref()
20034            .and_then(|file| Path::new(file.file_name(cx)).extension())
20035            .and_then(|e| e.to_str())
20036            .map(|a| a.to_string()));
20037
20038        let vim_mode = vim_enabled(cx);
20039
20040        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20041        let copilot_enabled = edit_predictions_provider
20042            == language::language_settings::EditPredictionProvider::Copilot;
20043        let copilot_enabled_for_language = self
20044            .buffer
20045            .read(cx)
20046            .language_settings(cx)
20047            .show_edit_predictions;
20048
20049        let project = project.read(cx);
20050        telemetry::event!(
20051            event_type,
20052            file_extension,
20053            vim_mode,
20054            copilot_enabled,
20055            copilot_enabled_for_language,
20056            edit_predictions_provider,
20057            is_via_ssh = project.is_via_ssh(),
20058        );
20059    }
20060
20061    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20062    /// with each line being an array of {text, highlight} objects.
20063    fn copy_highlight_json(
20064        &mut self,
20065        _: &CopyHighlightJson,
20066        window: &mut Window,
20067        cx: &mut Context<Self>,
20068    ) {
20069        #[derive(Serialize)]
20070        struct Chunk<'a> {
20071            text: String,
20072            highlight: Option<&'a str>,
20073        }
20074
20075        let snapshot = self.buffer.read(cx).snapshot(cx);
20076        let range = self
20077            .selected_text_range(false, window, cx)
20078            .and_then(|selection| {
20079                if selection.range.is_empty() {
20080                    None
20081                } else {
20082                    Some(selection.range)
20083                }
20084            })
20085            .unwrap_or_else(|| 0..snapshot.len());
20086
20087        let chunks = snapshot.chunks(range, true);
20088        let mut lines = Vec::new();
20089        let mut line: VecDeque<Chunk> = VecDeque::new();
20090
20091        let Some(style) = self.style.as_ref() else {
20092            return;
20093        };
20094
20095        for chunk in chunks {
20096            let highlight = chunk
20097                .syntax_highlight_id
20098                .and_then(|id| id.name(&style.syntax));
20099            let mut chunk_lines = chunk.text.split('\n').peekable();
20100            while let Some(text) = chunk_lines.next() {
20101                let mut merged_with_last_token = false;
20102                if let Some(last_token) = line.back_mut() {
20103                    if last_token.highlight == highlight {
20104                        last_token.text.push_str(text);
20105                        merged_with_last_token = true;
20106                    }
20107                }
20108
20109                if !merged_with_last_token {
20110                    line.push_back(Chunk {
20111                        text: text.into(),
20112                        highlight,
20113                    });
20114                }
20115
20116                if chunk_lines.peek().is_some() {
20117                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20118                        line.pop_front();
20119                    }
20120                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20121                        line.pop_back();
20122                    }
20123
20124                    lines.push(mem::take(&mut line));
20125                }
20126            }
20127        }
20128
20129        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20130            return;
20131        };
20132        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20133    }
20134
20135    pub fn open_context_menu(
20136        &mut self,
20137        _: &OpenContextMenu,
20138        window: &mut Window,
20139        cx: &mut Context<Self>,
20140    ) {
20141        self.request_autoscroll(Autoscroll::newest(), cx);
20142        let position = self.selections.newest_display(cx).start;
20143        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20144    }
20145
20146    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20147        &self.inlay_hint_cache
20148    }
20149
20150    pub fn replay_insert_event(
20151        &mut self,
20152        text: &str,
20153        relative_utf16_range: Option<Range<isize>>,
20154        window: &mut Window,
20155        cx: &mut Context<Self>,
20156    ) {
20157        if !self.input_enabled {
20158            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20159            return;
20160        }
20161        if let Some(relative_utf16_range) = relative_utf16_range {
20162            let selections = self.selections.all::<OffsetUtf16>(cx);
20163            self.change_selections(None, window, cx, |s| {
20164                let new_ranges = selections.into_iter().map(|range| {
20165                    let start = OffsetUtf16(
20166                        range
20167                            .head()
20168                            .0
20169                            .saturating_add_signed(relative_utf16_range.start),
20170                    );
20171                    let end = OffsetUtf16(
20172                        range
20173                            .head()
20174                            .0
20175                            .saturating_add_signed(relative_utf16_range.end),
20176                    );
20177                    start..end
20178                });
20179                s.select_ranges(new_ranges);
20180            });
20181        }
20182
20183        self.handle_input(text, window, cx);
20184    }
20185
20186    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20187        let Some(provider) = self.semantics_provider.as_ref() else {
20188            return false;
20189        };
20190
20191        let mut supports = false;
20192        self.buffer().update(cx, |this, cx| {
20193            this.for_each_buffer(|buffer| {
20194                supports |= provider.supports_inlay_hints(buffer, cx);
20195            });
20196        });
20197
20198        supports
20199    }
20200
20201    pub fn is_focused(&self, window: &Window) -> bool {
20202        self.focus_handle.is_focused(window)
20203    }
20204
20205    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20206        cx.emit(EditorEvent::Focused);
20207
20208        if let Some(descendant) = self
20209            .last_focused_descendant
20210            .take()
20211            .and_then(|descendant| descendant.upgrade())
20212        {
20213            window.focus(&descendant);
20214        } else {
20215            if let Some(blame) = self.blame.as_ref() {
20216                blame.update(cx, GitBlame::focus)
20217            }
20218
20219            self.blink_manager.update(cx, BlinkManager::enable);
20220            self.show_cursor_names(window, cx);
20221            self.buffer.update(cx, |buffer, cx| {
20222                buffer.finalize_last_transaction(cx);
20223                if self.leader_id.is_none() {
20224                    buffer.set_active_selections(
20225                        &self.selections.disjoint_anchors(),
20226                        self.selections.line_mode,
20227                        self.cursor_shape,
20228                        cx,
20229                    );
20230                }
20231            });
20232        }
20233    }
20234
20235    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20236        cx.emit(EditorEvent::FocusedIn)
20237    }
20238
20239    fn handle_focus_out(
20240        &mut self,
20241        event: FocusOutEvent,
20242        _window: &mut Window,
20243        cx: &mut Context<Self>,
20244    ) {
20245        if event.blurred != self.focus_handle {
20246            self.last_focused_descendant = Some(event.blurred);
20247        }
20248        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20249    }
20250
20251    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20252        self.blink_manager.update(cx, BlinkManager::disable);
20253        self.buffer
20254            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20255
20256        if let Some(blame) = self.blame.as_ref() {
20257            blame.update(cx, GitBlame::blur)
20258        }
20259        if !self.hover_state.focused(window, cx) {
20260            hide_hover(self, cx);
20261        }
20262        if !self
20263            .context_menu
20264            .borrow()
20265            .as_ref()
20266            .is_some_and(|context_menu| context_menu.focused(window, cx))
20267        {
20268            self.hide_context_menu(window, cx);
20269        }
20270        self.discard_inline_completion(false, cx);
20271        cx.emit(EditorEvent::Blurred);
20272        cx.notify();
20273    }
20274
20275    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20276        let mut pending: String = window
20277            .pending_input_keystrokes()
20278            .into_iter()
20279            .flatten()
20280            .filter_map(|keystroke| {
20281                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20282                    keystroke.key_char.clone()
20283                } else {
20284                    None
20285                }
20286            })
20287            .collect();
20288
20289        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20290            pending = "".to_string();
20291        }
20292
20293        let existing_pending = self
20294            .text_highlights::<PendingInput>(cx)
20295            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20296        if existing_pending.is_none() && pending.is_empty() {
20297            return;
20298        }
20299        let transaction =
20300            self.transact(window, cx, |this, window, cx| {
20301                let selections = this.selections.all::<usize>(cx);
20302                let edits = selections
20303                    .iter()
20304                    .map(|selection| (selection.end..selection.end, pending.clone()));
20305                this.edit(edits, cx);
20306                this.change_selections(None, window, cx, |s| {
20307                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20308                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20309                    }));
20310                });
20311                if let Some(existing_ranges) = existing_pending {
20312                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20313                    this.edit(edits, cx);
20314                }
20315            });
20316
20317        let snapshot = self.snapshot(window, cx);
20318        let ranges = self
20319            .selections
20320            .all::<usize>(cx)
20321            .into_iter()
20322            .map(|selection| {
20323                snapshot.buffer_snapshot.anchor_after(selection.end)
20324                    ..snapshot
20325                        .buffer_snapshot
20326                        .anchor_before(selection.end + pending.len())
20327            })
20328            .collect();
20329
20330        if pending.is_empty() {
20331            self.clear_highlights::<PendingInput>(cx);
20332        } else {
20333            self.highlight_text::<PendingInput>(
20334                ranges,
20335                HighlightStyle {
20336                    underline: Some(UnderlineStyle {
20337                        thickness: px(1.),
20338                        color: None,
20339                        wavy: false,
20340                    }),
20341                    ..Default::default()
20342                },
20343                cx,
20344            );
20345        }
20346
20347        self.ime_transaction = self.ime_transaction.or(transaction);
20348        if let Some(transaction) = self.ime_transaction {
20349            self.buffer.update(cx, |buffer, cx| {
20350                buffer.group_until_transaction(transaction, cx);
20351            });
20352        }
20353
20354        if self.text_highlights::<PendingInput>(cx).is_none() {
20355            self.ime_transaction.take();
20356        }
20357    }
20358
20359    pub fn register_action_renderer(
20360        &mut self,
20361        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20362    ) -> Subscription {
20363        let id = self.next_editor_action_id.post_inc();
20364        self.editor_actions
20365            .borrow_mut()
20366            .insert(id, Box::new(listener));
20367
20368        let editor_actions = self.editor_actions.clone();
20369        Subscription::new(move || {
20370            editor_actions.borrow_mut().remove(&id);
20371        })
20372    }
20373
20374    pub fn register_action<A: Action>(
20375        &mut self,
20376        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20377    ) -> Subscription {
20378        let id = self.next_editor_action_id.post_inc();
20379        let listener = Arc::new(listener);
20380        self.editor_actions.borrow_mut().insert(
20381            id,
20382            Box::new(move |_, window, _| {
20383                let listener = listener.clone();
20384                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20385                    let action = action.downcast_ref().unwrap();
20386                    if phase == DispatchPhase::Bubble {
20387                        listener(action, window, cx)
20388                    }
20389                })
20390            }),
20391        );
20392
20393        let editor_actions = self.editor_actions.clone();
20394        Subscription::new(move || {
20395            editor_actions.borrow_mut().remove(&id);
20396        })
20397    }
20398
20399    pub fn file_header_size(&self) -> u32 {
20400        FILE_HEADER_HEIGHT
20401    }
20402
20403    pub fn restore(
20404        &mut self,
20405        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20406        window: &mut Window,
20407        cx: &mut Context<Self>,
20408    ) {
20409        let workspace = self.workspace();
20410        let project = self.project.as_ref();
20411        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20412            let mut tasks = Vec::new();
20413            for (buffer_id, changes) in revert_changes {
20414                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20415                    buffer.update(cx, |buffer, cx| {
20416                        buffer.edit(
20417                            changes
20418                                .into_iter()
20419                                .map(|(range, text)| (range, text.to_string())),
20420                            None,
20421                            cx,
20422                        );
20423                    });
20424
20425                    if let Some(project) =
20426                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20427                    {
20428                        project.update(cx, |project, cx| {
20429                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20430                        })
20431                    }
20432                }
20433            }
20434            tasks
20435        });
20436        cx.spawn_in(window, async move |_, cx| {
20437            for (buffer, task) in save_tasks {
20438                let result = task.await;
20439                if result.is_err() {
20440                    let Some(path) = buffer
20441                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20442                        .ok()
20443                    else {
20444                        continue;
20445                    };
20446                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20447                        let Some(task) = cx
20448                            .update_window_entity(&workspace, |workspace, window, cx| {
20449                                workspace
20450                                    .open_path_preview(path, None, false, false, false, window, cx)
20451                            })
20452                            .ok()
20453                        else {
20454                            continue;
20455                        };
20456                        task.await.log_err();
20457                    }
20458                }
20459            }
20460        })
20461        .detach();
20462        self.change_selections(None, window, cx, |selections| selections.refresh());
20463    }
20464
20465    pub fn to_pixel_point(
20466        &self,
20467        source: multi_buffer::Anchor,
20468        editor_snapshot: &EditorSnapshot,
20469        window: &mut Window,
20470    ) -> Option<gpui::Point<Pixels>> {
20471        let source_point = source.to_display_point(editor_snapshot);
20472        self.display_to_pixel_point(source_point, editor_snapshot, window)
20473    }
20474
20475    pub fn display_to_pixel_point(
20476        &self,
20477        source: DisplayPoint,
20478        editor_snapshot: &EditorSnapshot,
20479        window: &mut Window,
20480    ) -> Option<gpui::Point<Pixels>> {
20481        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20482        let text_layout_details = self.text_layout_details(window);
20483        let scroll_top = text_layout_details
20484            .scroll_anchor
20485            .scroll_position(editor_snapshot)
20486            .y;
20487
20488        if source.row().as_f32() < scroll_top.floor() {
20489            return None;
20490        }
20491        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20492        let source_y = line_height * (source.row().as_f32() - scroll_top);
20493        Some(gpui::Point::new(source_x, source_y))
20494    }
20495
20496    pub fn has_visible_completions_menu(&self) -> bool {
20497        !self.edit_prediction_preview_is_active()
20498            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20499                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20500            })
20501    }
20502
20503    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20504        if self.mode.is_minimap() {
20505            return;
20506        }
20507        self.addons
20508            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20509    }
20510
20511    pub fn unregister_addon<T: Addon>(&mut self) {
20512        self.addons.remove(&std::any::TypeId::of::<T>());
20513    }
20514
20515    pub fn addon<T: Addon>(&self) -> Option<&T> {
20516        let type_id = std::any::TypeId::of::<T>();
20517        self.addons
20518            .get(&type_id)
20519            .and_then(|item| item.to_any().downcast_ref::<T>())
20520    }
20521
20522    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20523        let type_id = std::any::TypeId::of::<T>();
20524        self.addons
20525            .get_mut(&type_id)
20526            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20527    }
20528
20529    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20530        let text_layout_details = self.text_layout_details(window);
20531        let style = &text_layout_details.editor_style;
20532        let font_id = window.text_system().resolve_font(&style.text.font());
20533        let font_size = style.text.font_size.to_pixels(window.rem_size());
20534        let line_height = style.text.line_height_in_pixels(window.rem_size());
20535        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20536        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20537
20538        CharacterDimensions {
20539            em_width,
20540            em_advance,
20541            line_height,
20542        }
20543    }
20544
20545    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20546        self.load_diff_task.clone()
20547    }
20548
20549    fn read_metadata_from_db(
20550        &mut self,
20551        item_id: u64,
20552        workspace_id: WorkspaceId,
20553        window: &mut Window,
20554        cx: &mut Context<Editor>,
20555    ) {
20556        if self.is_singleton(cx)
20557            && !self.mode.is_minimap()
20558            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20559        {
20560            let buffer_snapshot = OnceCell::new();
20561
20562            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20563                if !folds.is_empty() {
20564                    let snapshot =
20565                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20566                    self.fold_ranges(
20567                        folds
20568                            .into_iter()
20569                            .map(|(start, end)| {
20570                                snapshot.clip_offset(start, Bias::Left)
20571                                    ..snapshot.clip_offset(end, Bias::Right)
20572                            })
20573                            .collect(),
20574                        false,
20575                        window,
20576                        cx,
20577                    );
20578                }
20579            }
20580
20581            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20582                if !selections.is_empty() {
20583                    let snapshot =
20584                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20585                    // skip adding the initial selection to selection history
20586                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20587                    self.change_selections(None, window, cx, |s| {
20588                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20589                            snapshot.clip_offset(start, Bias::Left)
20590                                ..snapshot.clip_offset(end, Bias::Right)
20591                        }));
20592                    });
20593                    self.selection_history.mode = SelectionHistoryMode::Normal;
20594                }
20595            };
20596        }
20597
20598        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20599    }
20600
20601    fn update_lsp_data(
20602        &mut self,
20603        for_server_id: Option<LanguageServerId>,
20604        for_buffer: Option<BufferId>,
20605        window: &mut Window,
20606        cx: &mut Context<'_, Self>,
20607    ) {
20608        self.pull_diagnostics(for_buffer, window, cx);
20609        self.refresh_colors(for_server_id, for_buffer, window, cx);
20610    }
20611}
20612
20613fn vim_enabled(cx: &App) -> bool {
20614    cx.global::<SettingsStore>()
20615        .raw_user_settings()
20616        .get("vim_mode")
20617        == Some(&serde_json::Value::Bool(true))
20618}
20619
20620fn process_completion_for_edit(
20621    completion: &Completion,
20622    intent: CompletionIntent,
20623    buffer: &Entity<Buffer>,
20624    cursor_position: &text::Anchor,
20625    cx: &mut Context<Editor>,
20626) -> CompletionEdit {
20627    let buffer = buffer.read(cx);
20628    let buffer_snapshot = buffer.snapshot();
20629    let (snippet, new_text) = if completion.is_snippet() {
20630        // Workaround for typescript language server issues so that methods don't expand within
20631        // strings and functions with type expressions. The previous point is used because the query
20632        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20633        let mut snippet_source = completion.new_text.clone();
20634        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20635        previous_point.column = previous_point.column.saturating_sub(1);
20636        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20637            if scope.prefers_label_for_snippet_in_completion() {
20638                if let Some(label) = completion.label() {
20639                    if matches!(
20640                        completion.kind(),
20641                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20642                    ) {
20643                        snippet_source = label;
20644                    }
20645                }
20646            }
20647        }
20648        match Snippet::parse(&snippet_source).log_err() {
20649            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20650            None => (None, completion.new_text.clone()),
20651        }
20652    } else {
20653        (None, completion.new_text.clone())
20654    };
20655
20656    let mut range_to_replace = {
20657        let replace_range = &completion.replace_range;
20658        if let CompletionSource::Lsp {
20659            insert_range: Some(insert_range),
20660            ..
20661        } = &completion.source
20662        {
20663            debug_assert_eq!(
20664                insert_range.start, replace_range.start,
20665                "insert_range and replace_range should start at the same position"
20666            );
20667            debug_assert!(
20668                insert_range
20669                    .start
20670                    .cmp(&cursor_position, &buffer_snapshot)
20671                    .is_le(),
20672                "insert_range should start before or at cursor position"
20673            );
20674            debug_assert!(
20675                replace_range
20676                    .start
20677                    .cmp(&cursor_position, &buffer_snapshot)
20678                    .is_le(),
20679                "replace_range should start before or at cursor position"
20680            );
20681            debug_assert!(
20682                insert_range
20683                    .end
20684                    .cmp(&cursor_position, &buffer_snapshot)
20685                    .is_le(),
20686                "insert_range should end before or at cursor position"
20687            );
20688
20689            let should_replace = match intent {
20690                CompletionIntent::CompleteWithInsert => false,
20691                CompletionIntent::CompleteWithReplace => true,
20692                CompletionIntent::Complete | CompletionIntent::Compose => {
20693                    let insert_mode =
20694                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20695                            .completions
20696                            .lsp_insert_mode;
20697                    match insert_mode {
20698                        LspInsertMode::Insert => false,
20699                        LspInsertMode::Replace => true,
20700                        LspInsertMode::ReplaceSubsequence => {
20701                            let mut text_to_replace = buffer.chars_for_range(
20702                                buffer.anchor_before(replace_range.start)
20703                                    ..buffer.anchor_after(replace_range.end),
20704                            );
20705                            let mut current_needle = text_to_replace.next();
20706                            for haystack_ch in completion.label.text.chars() {
20707                                if let Some(needle_ch) = current_needle {
20708                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20709                                        current_needle = text_to_replace.next();
20710                                    }
20711                                }
20712                            }
20713                            current_needle.is_none()
20714                        }
20715                        LspInsertMode::ReplaceSuffix => {
20716                            if replace_range
20717                                .end
20718                                .cmp(&cursor_position, &buffer_snapshot)
20719                                .is_gt()
20720                            {
20721                                let range_after_cursor = *cursor_position..replace_range.end;
20722                                let text_after_cursor = buffer
20723                                    .text_for_range(
20724                                        buffer.anchor_before(range_after_cursor.start)
20725                                            ..buffer.anchor_after(range_after_cursor.end),
20726                                    )
20727                                    .collect::<String>()
20728                                    .to_ascii_lowercase();
20729                                completion
20730                                    .label
20731                                    .text
20732                                    .to_ascii_lowercase()
20733                                    .ends_with(&text_after_cursor)
20734                            } else {
20735                                true
20736                            }
20737                        }
20738                    }
20739                }
20740            };
20741
20742            if should_replace {
20743                replace_range.clone()
20744            } else {
20745                insert_range.clone()
20746            }
20747        } else {
20748            replace_range.clone()
20749        }
20750    };
20751
20752    if range_to_replace
20753        .end
20754        .cmp(&cursor_position, &buffer_snapshot)
20755        .is_lt()
20756    {
20757        range_to_replace.end = *cursor_position;
20758    }
20759
20760    CompletionEdit {
20761        new_text,
20762        replace_range: range_to_replace.to_offset(&buffer),
20763        snippet,
20764    }
20765}
20766
20767struct CompletionEdit {
20768    new_text: String,
20769    replace_range: Range<usize>,
20770    snippet: Option<Snippet>,
20771}
20772
20773fn insert_extra_newline_brackets(
20774    buffer: &MultiBufferSnapshot,
20775    range: Range<usize>,
20776    language: &language::LanguageScope,
20777) -> bool {
20778    let leading_whitespace_len = buffer
20779        .reversed_chars_at(range.start)
20780        .take_while(|c| c.is_whitespace() && *c != '\n')
20781        .map(|c| c.len_utf8())
20782        .sum::<usize>();
20783    let trailing_whitespace_len = buffer
20784        .chars_at(range.end)
20785        .take_while(|c| c.is_whitespace() && *c != '\n')
20786        .map(|c| c.len_utf8())
20787        .sum::<usize>();
20788    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20789
20790    language.brackets().any(|(pair, enabled)| {
20791        let pair_start = pair.start.trim_end();
20792        let pair_end = pair.end.trim_start();
20793
20794        enabled
20795            && pair.newline
20796            && buffer.contains_str_at(range.end, pair_end)
20797            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20798    })
20799}
20800
20801fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20802    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20803        [(buffer, range, _)] => (*buffer, range.clone()),
20804        _ => return false,
20805    };
20806    let pair = {
20807        let mut result: Option<BracketMatch> = None;
20808
20809        for pair in buffer
20810            .all_bracket_ranges(range.clone())
20811            .filter(move |pair| {
20812                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20813            })
20814        {
20815            let len = pair.close_range.end - pair.open_range.start;
20816
20817            if let Some(existing) = &result {
20818                let existing_len = existing.close_range.end - existing.open_range.start;
20819                if len > existing_len {
20820                    continue;
20821                }
20822            }
20823
20824            result = Some(pair);
20825        }
20826
20827        result
20828    };
20829    let Some(pair) = pair else {
20830        return false;
20831    };
20832    pair.newline_only
20833        && buffer
20834            .chars_for_range(pair.open_range.end..range.start)
20835            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20836            .all(|c| c.is_whitespace() && c != '\n')
20837}
20838
20839fn update_uncommitted_diff_for_buffer(
20840    editor: Entity<Editor>,
20841    project: &Entity<Project>,
20842    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20843    buffer: Entity<MultiBuffer>,
20844    cx: &mut App,
20845) -> Task<()> {
20846    let mut tasks = Vec::new();
20847    project.update(cx, |project, cx| {
20848        for buffer in buffers {
20849            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20850                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20851            }
20852        }
20853    });
20854    cx.spawn(async move |cx| {
20855        let diffs = future::join_all(tasks).await;
20856        if editor
20857            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20858            .unwrap_or(false)
20859        {
20860            return;
20861        }
20862
20863        buffer
20864            .update(cx, |buffer, cx| {
20865                for diff in diffs.into_iter().flatten() {
20866                    buffer.add_diff(diff, cx);
20867                }
20868            })
20869            .ok();
20870    })
20871}
20872
20873fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20874    let tab_size = tab_size.get() as usize;
20875    let mut width = offset;
20876
20877    for ch in text.chars() {
20878        width += if ch == '\t' {
20879            tab_size - (width % tab_size)
20880        } else {
20881            1
20882        };
20883    }
20884
20885    width - offset
20886}
20887
20888#[cfg(test)]
20889mod tests {
20890    use super::*;
20891
20892    #[test]
20893    fn test_string_size_with_expanded_tabs() {
20894        let nz = |val| NonZeroU32::new(val).unwrap();
20895        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20896        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20897        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20898        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20899        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20900        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20901        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20902        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20903    }
20904}
20905
20906/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20907struct WordBreakingTokenizer<'a> {
20908    input: &'a str,
20909}
20910
20911impl<'a> WordBreakingTokenizer<'a> {
20912    fn new(input: &'a str) -> Self {
20913        Self { input }
20914    }
20915}
20916
20917fn is_char_ideographic(ch: char) -> bool {
20918    use unicode_script::Script::*;
20919    use unicode_script::UnicodeScript;
20920    matches!(ch.script(), Han | Tangut | Yi)
20921}
20922
20923fn is_grapheme_ideographic(text: &str) -> bool {
20924    text.chars().any(is_char_ideographic)
20925}
20926
20927fn is_grapheme_whitespace(text: &str) -> bool {
20928    text.chars().any(|x| x.is_whitespace())
20929}
20930
20931fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20932    text.chars().next().map_or(false, |ch| {
20933        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20934    })
20935}
20936
20937#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20938enum WordBreakToken<'a> {
20939    Word { token: &'a str, grapheme_len: usize },
20940    InlineWhitespace { token: &'a str, grapheme_len: usize },
20941    Newline,
20942}
20943
20944impl<'a> Iterator for WordBreakingTokenizer<'a> {
20945    /// Yields a span, the count of graphemes in the token, and whether it was
20946    /// whitespace. Note that it also breaks at word boundaries.
20947    type Item = WordBreakToken<'a>;
20948
20949    fn next(&mut self) -> Option<Self::Item> {
20950        use unicode_segmentation::UnicodeSegmentation;
20951        if self.input.is_empty() {
20952            return None;
20953        }
20954
20955        let mut iter = self.input.graphemes(true).peekable();
20956        let mut offset = 0;
20957        let mut grapheme_len = 0;
20958        if let Some(first_grapheme) = iter.next() {
20959            let is_newline = first_grapheme == "\n";
20960            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20961            offset += first_grapheme.len();
20962            grapheme_len += 1;
20963            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20964                if let Some(grapheme) = iter.peek().copied() {
20965                    if should_stay_with_preceding_ideograph(grapheme) {
20966                        offset += grapheme.len();
20967                        grapheme_len += 1;
20968                    }
20969                }
20970            } else {
20971                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20972                let mut next_word_bound = words.peek().copied();
20973                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20974                    next_word_bound = words.next();
20975                }
20976                while let Some(grapheme) = iter.peek().copied() {
20977                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20978                        break;
20979                    };
20980                    if is_grapheme_whitespace(grapheme) != is_whitespace
20981                        || (grapheme == "\n") != is_newline
20982                    {
20983                        break;
20984                    };
20985                    offset += grapheme.len();
20986                    grapheme_len += 1;
20987                    iter.next();
20988                }
20989            }
20990            let token = &self.input[..offset];
20991            self.input = &self.input[offset..];
20992            if token == "\n" {
20993                Some(WordBreakToken::Newline)
20994            } else if is_whitespace {
20995                Some(WordBreakToken::InlineWhitespace {
20996                    token,
20997                    grapheme_len,
20998                })
20999            } else {
21000                Some(WordBreakToken::Word {
21001                    token,
21002                    grapheme_len,
21003                })
21004            }
21005        } else {
21006            None
21007        }
21008    }
21009}
21010
21011#[test]
21012fn test_word_breaking_tokenizer() {
21013    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21014        ("", &[]),
21015        ("  ", &[whitespace("  ", 2)]),
21016        ("Ʒ", &[word("Ʒ", 1)]),
21017        ("Ǽ", &[word("Ǽ", 1)]),
21018        ("", &[word("", 1)]),
21019        ("⋑⋑", &[word("⋑⋑", 2)]),
21020        (
21021            "原理,进而",
21022            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21023        ),
21024        (
21025            "hello world",
21026            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21027        ),
21028        (
21029            "hello, world",
21030            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21031        ),
21032        (
21033            "  hello world",
21034            &[
21035                whitespace("  ", 2),
21036                word("hello", 5),
21037                whitespace(" ", 1),
21038                word("world", 5),
21039            ],
21040        ),
21041        (
21042            "这是什么 \n 钢笔",
21043            &[
21044                word("", 1),
21045                word("", 1),
21046                word("", 1),
21047                word("", 1),
21048                whitespace(" ", 1),
21049                newline(),
21050                whitespace(" ", 1),
21051                word("", 1),
21052                word("", 1),
21053            ],
21054        ),
21055        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21056    ];
21057
21058    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21059        WordBreakToken::Word {
21060            token,
21061            grapheme_len,
21062        }
21063    }
21064
21065    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21066        WordBreakToken::InlineWhitespace {
21067            token,
21068            grapheme_len,
21069        }
21070    }
21071
21072    fn newline() -> WordBreakToken<'static> {
21073        WordBreakToken::Newline
21074    }
21075
21076    for (input, result) in tests {
21077        assert_eq!(
21078            WordBreakingTokenizer::new(input)
21079                .collect::<Vec<_>>()
21080                .as_slice(),
21081            *result,
21082        );
21083    }
21084}
21085
21086fn wrap_with_prefix(
21087    line_prefix: String,
21088    unwrapped_text: String,
21089    wrap_column: usize,
21090    tab_size: NonZeroU32,
21091    preserve_existing_whitespace: bool,
21092) -> String {
21093    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
21094    let mut wrapped_text = String::new();
21095    let mut current_line = line_prefix.clone();
21096
21097    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21098    let mut current_line_len = line_prefix_len;
21099    let mut in_whitespace = false;
21100    for token in tokenizer {
21101        let have_preceding_whitespace = in_whitespace;
21102        match token {
21103            WordBreakToken::Word {
21104                token,
21105                grapheme_len,
21106            } => {
21107                in_whitespace = false;
21108                if current_line_len + grapheme_len > wrap_column
21109                    && current_line_len != line_prefix_len
21110                {
21111                    wrapped_text.push_str(current_line.trim_end());
21112                    wrapped_text.push('\n');
21113                    current_line.truncate(line_prefix.len());
21114                    current_line_len = line_prefix_len;
21115                }
21116                current_line.push_str(token);
21117                current_line_len += grapheme_len;
21118            }
21119            WordBreakToken::InlineWhitespace {
21120                mut token,
21121                mut grapheme_len,
21122            } => {
21123                in_whitespace = true;
21124                if have_preceding_whitespace && !preserve_existing_whitespace {
21125                    continue;
21126                }
21127                if !preserve_existing_whitespace {
21128                    token = " ";
21129                    grapheme_len = 1;
21130                }
21131                if current_line_len + grapheme_len > wrap_column {
21132                    wrapped_text.push_str(current_line.trim_end());
21133                    wrapped_text.push('\n');
21134                    current_line.truncate(line_prefix.len());
21135                    current_line_len = line_prefix_len;
21136                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
21137                    current_line.push_str(token);
21138                    current_line_len += grapheme_len;
21139                }
21140            }
21141            WordBreakToken::Newline => {
21142                in_whitespace = true;
21143                if preserve_existing_whitespace {
21144                    wrapped_text.push_str(current_line.trim_end());
21145                    wrapped_text.push('\n');
21146                    current_line.truncate(line_prefix.len());
21147                    current_line_len = line_prefix_len;
21148                } else if have_preceding_whitespace {
21149                    continue;
21150                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
21151                {
21152                    wrapped_text.push_str(current_line.trim_end());
21153                    wrapped_text.push('\n');
21154                    current_line.truncate(line_prefix.len());
21155                    current_line_len = line_prefix_len;
21156                } else if current_line_len != line_prefix_len {
21157                    current_line.push(' ');
21158                    current_line_len += 1;
21159                }
21160            }
21161        }
21162    }
21163
21164    if !current_line.is_empty() {
21165        wrapped_text.push_str(&current_line);
21166    }
21167    wrapped_text
21168}
21169
21170#[test]
21171fn test_wrap_with_prefix() {
21172    assert_eq!(
21173        wrap_with_prefix(
21174            "# ".to_string(),
21175            "abcdefg".to_string(),
21176            4,
21177            NonZeroU32::new(4).unwrap(),
21178            false,
21179        ),
21180        "# abcdefg"
21181    );
21182    assert_eq!(
21183        wrap_with_prefix(
21184            "".to_string(),
21185            "\thello world".to_string(),
21186            8,
21187            NonZeroU32::new(4).unwrap(),
21188            false,
21189        ),
21190        "hello\nworld"
21191    );
21192    assert_eq!(
21193        wrap_with_prefix(
21194            "// ".to_string(),
21195            "xx \nyy zz aa bb cc".to_string(),
21196            12,
21197            NonZeroU32::new(4).unwrap(),
21198            false,
21199        ),
21200        "// xx yy zz\n// aa bb cc"
21201    );
21202    assert_eq!(
21203        wrap_with_prefix(
21204            String::new(),
21205            "这是什么 \n 钢笔".to_string(),
21206            3,
21207            NonZeroU32::new(4).unwrap(),
21208            false,
21209        ),
21210        "这是什\n么 钢\n"
21211    );
21212}
21213
21214pub trait CollaborationHub {
21215    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21216    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21217    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21218}
21219
21220impl CollaborationHub for Entity<Project> {
21221    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21222        self.read(cx).collaborators()
21223    }
21224
21225    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21226        self.read(cx).user_store().read(cx).participant_indices()
21227    }
21228
21229    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21230        let this = self.read(cx);
21231        let user_ids = this.collaborators().values().map(|c| c.user_id);
21232        this.user_store().read(cx).participant_names(user_ids, cx)
21233    }
21234}
21235
21236pub trait SemanticsProvider {
21237    fn hover(
21238        &self,
21239        buffer: &Entity<Buffer>,
21240        position: text::Anchor,
21241        cx: &mut App,
21242    ) -> Option<Task<Vec<project::Hover>>>;
21243
21244    fn inline_values(
21245        &self,
21246        buffer_handle: Entity<Buffer>,
21247        range: Range<text::Anchor>,
21248        cx: &mut App,
21249    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21250
21251    fn inlay_hints(
21252        &self,
21253        buffer_handle: Entity<Buffer>,
21254        range: Range<text::Anchor>,
21255        cx: &mut App,
21256    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21257
21258    fn resolve_inlay_hint(
21259        &self,
21260        hint: InlayHint,
21261        buffer_handle: Entity<Buffer>,
21262        server_id: LanguageServerId,
21263        cx: &mut App,
21264    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21265
21266    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21267
21268    fn document_highlights(
21269        &self,
21270        buffer: &Entity<Buffer>,
21271        position: text::Anchor,
21272        cx: &mut App,
21273    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21274
21275    fn definitions(
21276        &self,
21277        buffer: &Entity<Buffer>,
21278        position: text::Anchor,
21279        kind: GotoDefinitionKind,
21280        cx: &mut App,
21281    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21282
21283    fn range_for_rename(
21284        &self,
21285        buffer: &Entity<Buffer>,
21286        position: text::Anchor,
21287        cx: &mut App,
21288    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21289
21290    fn perform_rename(
21291        &self,
21292        buffer: &Entity<Buffer>,
21293        position: text::Anchor,
21294        new_name: String,
21295        cx: &mut App,
21296    ) -> Option<Task<Result<ProjectTransaction>>>;
21297}
21298
21299pub trait CompletionProvider {
21300    fn completions(
21301        &self,
21302        excerpt_id: ExcerptId,
21303        buffer: &Entity<Buffer>,
21304        buffer_position: text::Anchor,
21305        trigger: CompletionContext,
21306        window: &mut Window,
21307        cx: &mut Context<Editor>,
21308    ) -> Task<Result<Vec<CompletionResponse>>>;
21309
21310    fn resolve_completions(
21311        &self,
21312        _buffer: Entity<Buffer>,
21313        _completion_indices: Vec<usize>,
21314        _completions: Rc<RefCell<Box<[Completion]>>>,
21315        _cx: &mut Context<Editor>,
21316    ) -> Task<Result<bool>> {
21317        Task::ready(Ok(false))
21318    }
21319
21320    fn apply_additional_edits_for_completion(
21321        &self,
21322        _buffer: Entity<Buffer>,
21323        _completions: Rc<RefCell<Box<[Completion]>>>,
21324        _completion_index: usize,
21325        _push_to_history: bool,
21326        _cx: &mut Context<Editor>,
21327    ) -> Task<Result<Option<language::Transaction>>> {
21328        Task::ready(Ok(None))
21329    }
21330
21331    fn is_completion_trigger(
21332        &self,
21333        buffer: &Entity<Buffer>,
21334        position: language::Anchor,
21335        text: &str,
21336        trigger_in_words: bool,
21337        menu_is_open: bool,
21338        cx: &mut Context<Editor>,
21339    ) -> bool;
21340
21341    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21342
21343    fn sort_completions(&self) -> bool {
21344        true
21345    }
21346
21347    fn filter_completions(&self) -> bool {
21348        true
21349    }
21350}
21351
21352pub trait CodeActionProvider {
21353    fn id(&self) -> Arc<str>;
21354
21355    fn code_actions(
21356        &self,
21357        buffer: &Entity<Buffer>,
21358        range: Range<text::Anchor>,
21359        window: &mut Window,
21360        cx: &mut App,
21361    ) -> Task<Result<Vec<CodeAction>>>;
21362
21363    fn apply_code_action(
21364        &self,
21365        buffer_handle: Entity<Buffer>,
21366        action: CodeAction,
21367        excerpt_id: ExcerptId,
21368        push_to_history: bool,
21369        window: &mut Window,
21370        cx: &mut App,
21371    ) -> Task<Result<ProjectTransaction>>;
21372}
21373
21374impl CodeActionProvider for Entity<Project> {
21375    fn id(&self) -> Arc<str> {
21376        "project".into()
21377    }
21378
21379    fn code_actions(
21380        &self,
21381        buffer: &Entity<Buffer>,
21382        range: Range<text::Anchor>,
21383        _window: &mut Window,
21384        cx: &mut App,
21385    ) -> Task<Result<Vec<CodeAction>>> {
21386        self.update(cx, |project, cx| {
21387            let code_lens = project.code_lens(buffer, range.clone(), cx);
21388            let code_actions = project.code_actions(buffer, range, None, cx);
21389            cx.background_spawn(async move {
21390                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21391                Ok(code_lens
21392                    .context("code lens fetch")?
21393                    .into_iter()
21394                    .chain(code_actions.context("code action fetch")?)
21395                    .collect())
21396            })
21397        })
21398    }
21399
21400    fn apply_code_action(
21401        &self,
21402        buffer_handle: Entity<Buffer>,
21403        action: CodeAction,
21404        _excerpt_id: ExcerptId,
21405        push_to_history: bool,
21406        _window: &mut Window,
21407        cx: &mut App,
21408    ) -> Task<Result<ProjectTransaction>> {
21409        self.update(cx, |project, cx| {
21410            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21411        })
21412    }
21413}
21414
21415fn snippet_completions(
21416    project: &Project,
21417    buffer: &Entity<Buffer>,
21418    buffer_position: text::Anchor,
21419    cx: &mut App,
21420) -> Task<Result<CompletionResponse>> {
21421    let languages = buffer.read(cx).languages_at(buffer_position);
21422    let snippet_store = project.snippets().read(cx);
21423
21424    let scopes: Vec<_> = languages
21425        .iter()
21426        .filter_map(|language| {
21427            let language_name = language.lsp_id();
21428            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21429
21430            if snippets.is_empty() {
21431                None
21432            } else {
21433                Some((language.default_scope(), snippets))
21434            }
21435        })
21436        .collect();
21437
21438    if scopes.is_empty() {
21439        return Task::ready(Ok(CompletionResponse {
21440            completions: vec![],
21441            is_incomplete: false,
21442        }));
21443    }
21444
21445    let snapshot = buffer.read(cx).text_snapshot();
21446    let chars: String = snapshot
21447        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21448        .collect();
21449    let executor = cx.background_executor().clone();
21450
21451    cx.background_spawn(async move {
21452        let mut is_incomplete = false;
21453        let mut completions: Vec<Completion> = Vec::new();
21454        for (scope, snippets) in scopes.into_iter() {
21455            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21456            let mut last_word = chars
21457                .chars()
21458                .take_while(|c| classifier.is_word(*c))
21459                .collect::<String>();
21460            last_word = last_word.chars().rev().collect();
21461
21462            if last_word.is_empty() {
21463                return Ok(CompletionResponse {
21464                    completions: vec![],
21465                    is_incomplete: true,
21466                });
21467            }
21468
21469            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21470            let to_lsp = |point: &text::Anchor| {
21471                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21472                point_to_lsp(end)
21473            };
21474            let lsp_end = to_lsp(&buffer_position);
21475
21476            let candidates = snippets
21477                .iter()
21478                .enumerate()
21479                .flat_map(|(ix, snippet)| {
21480                    snippet
21481                        .prefix
21482                        .iter()
21483                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21484                })
21485                .collect::<Vec<StringMatchCandidate>>();
21486
21487            const MAX_RESULTS: usize = 100;
21488            let mut matches = fuzzy::match_strings(
21489                &candidates,
21490                &last_word,
21491                last_word.chars().any(|c| c.is_uppercase()),
21492                true,
21493                MAX_RESULTS,
21494                &Default::default(),
21495                executor.clone(),
21496            )
21497            .await;
21498
21499            if matches.len() >= MAX_RESULTS {
21500                is_incomplete = true;
21501            }
21502
21503            // Remove all candidates where the query's start does not match the start of any word in the candidate
21504            if let Some(query_start) = last_word.chars().next() {
21505                matches.retain(|string_match| {
21506                    split_words(&string_match.string).any(|word| {
21507                        // Check that the first codepoint of the word as lowercase matches the first
21508                        // codepoint of the query as lowercase
21509                        word.chars()
21510                            .flat_map(|codepoint| codepoint.to_lowercase())
21511                            .zip(query_start.to_lowercase())
21512                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21513                    })
21514                });
21515            }
21516
21517            let matched_strings = matches
21518                .into_iter()
21519                .map(|m| m.string)
21520                .collect::<HashSet<_>>();
21521
21522            completions.extend(snippets.iter().filter_map(|snippet| {
21523                let matching_prefix = snippet
21524                    .prefix
21525                    .iter()
21526                    .find(|prefix| matched_strings.contains(*prefix))?;
21527                let start = as_offset - last_word.len();
21528                let start = snapshot.anchor_before(start);
21529                let range = start..buffer_position;
21530                let lsp_start = to_lsp(&start);
21531                let lsp_range = lsp::Range {
21532                    start: lsp_start,
21533                    end: lsp_end,
21534                };
21535                Some(Completion {
21536                    replace_range: range,
21537                    new_text: snippet.body.clone(),
21538                    source: CompletionSource::Lsp {
21539                        insert_range: None,
21540                        server_id: LanguageServerId(usize::MAX),
21541                        resolved: true,
21542                        lsp_completion: Box::new(lsp::CompletionItem {
21543                            label: snippet.prefix.first().unwrap().clone(),
21544                            kind: Some(CompletionItemKind::SNIPPET),
21545                            label_details: snippet.description.as_ref().map(|description| {
21546                                lsp::CompletionItemLabelDetails {
21547                                    detail: Some(description.clone()),
21548                                    description: None,
21549                                }
21550                            }),
21551                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21552                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21553                                lsp::InsertReplaceEdit {
21554                                    new_text: snippet.body.clone(),
21555                                    insert: lsp_range,
21556                                    replace: lsp_range,
21557                                },
21558                            )),
21559                            filter_text: Some(snippet.body.clone()),
21560                            sort_text: Some(char::MAX.to_string()),
21561                            ..lsp::CompletionItem::default()
21562                        }),
21563                        lsp_defaults: None,
21564                    },
21565                    label: CodeLabel {
21566                        text: matching_prefix.clone(),
21567                        runs: Vec::new(),
21568                        filter_range: 0..matching_prefix.len(),
21569                    },
21570                    icon_path: None,
21571                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21572                        single_line: snippet.name.clone().into(),
21573                        plain_text: snippet
21574                            .description
21575                            .clone()
21576                            .map(|description| description.into()),
21577                    }),
21578                    insert_text_mode: None,
21579                    confirm: None,
21580                })
21581            }))
21582        }
21583
21584        Ok(CompletionResponse {
21585            completions,
21586            is_incomplete,
21587        })
21588    })
21589}
21590
21591impl CompletionProvider for Entity<Project> {
21592    fn completions(
21593        &self,
21594        _excerpt_id: ExcerptId,
21595        buffer: &Entity<Buffer>,
21596        buffer_position: text::Anchor,
21597        options: CompletionContext,
21598        _window: &mut Window,
21599        cx: &mut Context<Editor>,
21600    ) -> Task<Result<Vec<CompletionResponse>>> {
21601        self.update(cx, |project, cx| {
21602            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21603            let project_completions = project.completions(buffer, buffer_position, options, cx);
21604            cx.background_spawn(async move {
21605                let mut responses = project_completions.await?;
21606                let snippets = snippets.await?;
21607                if !snippets.completions.is_empty() {
21608                    responses.push(snippets);
21609                }
21610                Ok(responses)
21611            })
21612        })
21613    }
21614
21615    fn resolve_completions(
21616        &self,
21617        buffer: Entity<Buffer>,
21618        completion_indices: Vec<usize>,
21619        completions: Rc<RefCell<Box<[Completion]>>>,
21620        cx: &mut Context<Editor>,
21621    ) -> Task<Result<bool>> {
21622        self.update(cx, |project, cx| {
21623            project.lsp_store().update(cx, |lsp_store, cx| {
21624                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21625            })
21626        })
21627    }
21628
21629    fn apply_additional_edits_for_completion(
21630        &self,
21631        buffer: Entity<Buffer>,
21632        completions: Rc<RefCell<Box<[Completion]>>>,
21633        completion_index: usize,
21634        push_to_history: bool,
21635        cx: &mut Context<Editor>,
21636    ) -> Task<Result<Option<language::Transaction>>> {
21637        self.update(cx, |project, cx| {
21638            project.lsp_store().update(cx, |lsp_store, cx| {
21639                lsp_store.apply_additional_edits_for_completion(
21640                    buffer,
21641                    completions,
21642                    completion_index,
21643                    push_to_history,
21644                    cx,
21645                )
21646            })
21647        })
21648    }
21649
21650    fn is_completion_trigger(
21651        &self,
21652        buffer: &Entity<Buffer>,
21653        position: language::Anchor,
21654        text: &str,
21655        trigger_in_words: bool,
21656        menu_is_open: bool,
21657        cx: &mut Context<Editor>,
21658    ) -> bool {
21659        let mut chars = text.chars();
21660        let char = if let Some(char) = chars.next() {
21661            char
21662        } else {
21663            return false;
21664        };
21665        if chars.next().is_some() {
21666            return false;
21667        }
21668
21669        let buffer = buffer.read(cx);
21670        let snapshot = buffer.snapshot();
21671        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21672            return false;
21673        }
21674        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21675        if trigger_in_words && classifier.is_word(char) {
21676            return true;
21677        }
21678
21679        buffer.completion_triggers().contains(text)
21680    }
21681}
21682
21683impl SemanticsProvider for Entity<Project> {
21684    fn hover(
21685        &self,
21686        buffer: &Entity<Buffer>,
21687        position: text::Anchor,
21688        cx: &mut App,
21689    ) -> Option<Task<Vec<project::Hover>>> {
21690        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21691    }
21692
21693    fn document_highlights(
21694        &self,
21695        buffer: &Entity<Buffer>,
21696        position: text::Anchor,
21697        cx: &mut App,
21698    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21699        Some(self.update(cx, |project, cx| {
21700            project.document_highlights(buffer, position, cx)
21701        }))
21702    }
21703
21704    fn definitions(
21705        &self,
21706        buffer: &Entity<Buffer>,
21707        position: text::Anchor,
21708        kind: GotoDefinitionKind,
21709        cx: &mut App,
21710    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21711        Some(self.update(cx, |project, cx| match kind {
21712            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21713            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21714            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21715            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21716        }))
21717    }
21718
21719    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21720        // TODO: make this work for remote projects
21721        self.update(cx, |project, cx| {
21722            if project
21723                .active_debug_session(cx)
21724                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21725            {
21726                return true;
21727            }
21728
21729            buffer.update(cx, |buffer, cx| {
21730                project.any_language_server_supports_inlay_hints(buffer, cx)
21731            })
21732        })
21733    }
21734
21735    fn inline_values(
21736        &self,
21737        buffer_handle: Entity<Buffer>,
21738        range: Range<text::Anchor>,
21739        cx: &mut App,
21740    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21741        self.update(cx, |project, cx| {
21742            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21743
21744            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21745        })
21746    }
21747
21748    fn inlay_hints(
21749        &self,
21750        buffer_handle: Entity<Buffer>,
21751        range: Range<text::Anchor>,
21752        cx: &mut App,
21753    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21754        Some(self.update(cx, |project, cx| {
21755            project.inlay_hints(buffer_handle, range, cx)
21756        }))
21757    }
21758
21759    fn resolve_inlay_hint(
21760        &self,
21761        hint: InlayHint,
21762        buffer_handle: Entity<Buffer>,
21763        server_id: LanguageServerId,
21764        cx: &mut App,
21765    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21766        Some(self.update(cx, |project, cx| {
21767            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21768        }))
21769    }
21770
21771    fn range_for_rename(
21772        &self,
21773        buffer: &Entity<Buffer>,
21774        position: text::Anchor,
21775        cx: &mut App,
21776    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21777        Some(self.update(cx, |project, cx| {
21778            let buffer = buffer.clone();
21779            let task = project.prepare_rename(buffer.clone(), position, cx);
21780            cx.spawn(async move |_, cx| {
21781                Ok(match task.await? {
21782                    PrepareRenameResponse::Success(range) => Some(range),
21783                    PrepareRenameResponse::InvalidPosition => None,
21784                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21785                        // Fallback on using TreeSitter info to determine identifier range
21786                        buffer.read_with(cx, |buffer, _| {
21787                            let snapshot = buffer.snapshot();
21788                            let (range, kind) = snapshot.surrounding_word(position);
21789                            if kind != Some(CharKind::Word) {
21790                                return None;
21791                            }
21792                            Some(
21793                                snapshot.anchor_before(range.start)
21794                                    ..snapshot.anchor_after(range.end),
21795                            )
21796                        })?
21797                    }
21798                })
21799            })
21800        }))
21801    }
21802
21803    fn perform_rename(
21804        &self,
21805        buffer: &Entity<Buffer>,
21806        position: text::Anchor,
21807        new_name: String,
21808        cx: &mut App,
21809    ) -> Option<Task<Result<ProjectTransaction>>> {
21810        Some(self.update(cx, |project, cx| {
21811            project.perform_rename(buffer.clone(), position, new_name, cx)
21812        }))
21813    }
21814}
21815
21816fn inlay_hint_settings(
21817    location: Anchor,
21818    snapshot: &MultiBufferSnapshot,
21819    cx: &mut Context<Editor>,
21820) -> InlayHintSettings {
21821    let file = snapshot.file_at(location);
21822    let language = snapshot.language_at(location).map(|l| l.name());
21823    language_settings(language, file, cx).inlay_hints
21824}
21825
21826fn consume_contiguous_rows(
21827    contiguous_row_selections: &mut Vec<Selection<Point>>,
21828    selection: &Selection<Point>,
21829    display_map: &DisplaySnapshot,
21830    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21831) -> (MultiBufferRow, MultiBufferRow) {
21832    contiguous_row_selections.push(selection.clone());
21833    let start_row = MultiBufferRow(selection.start.row);
21834    let mut end_row = ending_row(selection, display_map);
21835
21836    while let Some(next_selection) = selections.peek() {
21837        if next_selection.start.row <= end_row.0 {
21838            end_row = ending_row(next_selection, display_map);
21839            contiguous_row_selections.push(selections.next().unwrap().clone());
21840        } else {
21841            break;
21842        }
21843    }
21844    (start_row, end_row)
21845}
21846
21847fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21848    if next_selection.end.column > 0 || next_selection.is_empty() {
21849        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21850    } else {
21851        MultiBufferRow(next_selection.end.row)
21852    }
21853}
21854
21855impl EditorSnapshot {
21856    pub fn remote_selections_in_range<'a>(
21857        &'a self,
21858        range: &'a Range<Anchor>,
21859        collaboration_hub: &dyn CollaborationHub,
21860        cx: &'a App,
21861    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21862        let participant_names = collaboration_hub.user_names(cx);
21863        let participant_indices = collaboration_hub.user_participant_indices(cx);
21864        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21865        let collaborators_by_replica_id = collaborators_by_peer_id
21866            .values()
21867            .map(|collaborator| (collaborator.replica_id, collaborator))
21868            .collect::<HashMap<_, _>>();
21869        self.buffer_snapshot
21870            .selections_in_range(range, false)
21871            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21872                if replica_id == AGENT_REPLICA_ID {
21873                    Some(RemoteSelection {
21874                        replica_id,
21875                        selection,
21876                        cursor_shape,
21877                        line_mode,
21878                        collaborator_id: CollaboratorId::Agent,
21879                        user_name: Some("Agent".into()),
21880                        color: cx.theme().players().agent(),
21881                    })
21882                } else {
21883                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21884                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21885                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21886                    Some(RemoteSelection {
21887                        replica_id,
21888                        selection,
21889                        cursor_shape,
21890                        line_mode,
21891                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21892                        user_name,
21893                        color: if let Some(index) = participant_index {
21894                            cx.theme().players().color_for_participant(index.0)
21895                        } else {
21896                            cx.theme().players().absent()
21897                        },
21898                    })
21899                }
21900            })
21901    }
21902
21903    pub fn hunks_for_ranges(
21904        &self,
21905        ranges: impl IntoIterator<Item = Range<Point>>,
21906    ) -> Vec<MultiBufferDiffHunk> {
21907        let mut hunks = Vec::new();
21908        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21909            HashMap::default();
21910        for query_range in ranges {
21911            let query_rows =
21912                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21913            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21914                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21915            ) {
21916                // Include deleted hunks that are adjacent to the query range, because
21917                // otherwise they would be missed.
21918                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21919                if hunk.status().is_deleted() {
21920                    intersects_range |= hunk.row_range.start == query_rows.end;
21921                    intersects_range |= hunk.row_range.end == query_rows.start;
21922                }
21923                if intersects_range {
21924                    if !processed_buffer_rows
21925                        .entry(hunk.buffer_id)
21926                        .or_default()
21927                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21928                    {
21929                        continue;
21930                    }
21931                    hunks.push(hunk);
21932                }
21933            }
21934        }
21935
21936        hunks
21937    }
21938
21939    fn display_diff_hunks_for_rows<'a>(
21940        &'a self,
21941        display_rows: Range<DisplayRow>,
21942        folded_buffers: &'a HashSet<BufferId>,
21943    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21944        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21945        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21946
21947        self.buffer_snapshot
21948            .diff_hunks_in_range(buffer_start..buffer_end)
21949            .filter_map(|hunk| {
21950                if folded_buffers.contains(&hunk.buffer_id) {
21951                    return None;
21952                }
21953
21954                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21955                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21956
21957                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21958                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21959
21960                let display_hunk = if hunk_display_start.column() != 0 {
21961                    DisplayDiffHunk::Folded {
21962                        display_row: hunk_display_start.row(),
21963                    }
21964                } else {
21965                    let mut end_row = hunk_display_end.row();
21966                    if hunk_display_end.column() > 0 {
21967                        end_row.0 += 1;
21968                    }
21969                    let is_created_file = hunk.is_created_file();
21970                    DisplayDiffHunk::Unfolded {
21971                        status: hunk.status(),
21972                        diff_base_byte_range: hunk.diff_base_byte_range,
21973                        display_row_range: hunk_display_start.row()..end_row,
21974                        multi_buffer_range: Anchor::range_in_buffer(
21975                            hunk.excerpt_id,
21976                            hunk.buffer_id,
21977                            hunk.buffer_range,
21978                        ),
21979                        is_created_file,
21980                    }
21981                };
21982
21983                Some(display_hunk)
21984            })
21985    }
21986
21987    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21988        self.display_snapshot.buffer_snapshot.language_at(position)
21989    }
21990
21991    pub fn is_focused(&self) -> bool {
21992        self.is_focused
21993    }
21994
21995    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21996        self.placeholder_text.as_ref()
21997    }
21998
21999    pub fn scroll_position(&self) -> gpui::Point<f32> {
22000        self.scroll_anchor.scroll_position(&self.display_snapshot)
22001    }
22002
22003    fn gutter_dimensions(
22004        &self,
22005        font_id: FontId,
22006        font_size: Pixels,
22007        max_line_number_width: Pixels,
22008        cx: &App,
22009    ) -> Option<GutterDimensions> {
22010        if !self.show_gutter {
22011            return None;
22012        }
22013
22014        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22015        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22016
22017        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22018            matches!(
22019                ProjectSettings::get_global(cx).git.git_gutter,
22020                Some(GitGutterSetting::TrackedFiles)
22021            )
22022        });
22023        let gutter_settings = EditorSettings::get_global(cx).gutter;
22024        let show_line_numbers = self
22025            .show_line_numbers
22026            .unwrap_or(gutter_settings.line_numbers);
22027        let line_gutter_width = if show_line_numbers {
22028            // Avoid flicker-like gutter resizes when the line number gains another digit by
22029            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22030            let min_width_for_number_on_gutter =
22031                ch_advance * gutter_settings.min_line_number_digits as f32;
22032            max_line_number_width.max(min_width_for_number_on_gutter)
22033        } else {
22034            0.0.into()
22035        };
22036
22037        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22038        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22039
22040        let git_blame_entries_width =
22041            self.git_blame_gutter_max_author_length
22042                .map(|max_author_length| {
22043                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22044                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22045
22046                    /// The number of characters to dedicate to gaps and margins.
22047                    const SPACING_WIDTH: usize = 4;
22048
22049                    let max_char_count = max_author_length.min(renderer.max_author_length())
22050                        + ::git::SHORT_SHA_LENGTH
22051                        + MAX_RELATIVE_TIMESTAMP.len()
22052                        + SPACING_WIDTH;
22053
22054                    ch_advance * max_char_count
22055                });
22056
22057        let is_singleton = self.buffer_snapshot.is_singleton();
22058
22059        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22060        left_padding += if !is_singleton {
22061            ch_width * 4.0
22062        } else if show_runnables || show_breakpoints {
22063            ch_width * 3.0
22064        } else if show_git_gutter && show_line_numbers {
22065            ch_width * 2.0
22066        } else if show_git_gutter || show_line_numbers {
22067            ch_width
22068        } else {
22069            px(0.)
22070        };
22071
22072        let shows_folds = is_singleton && gutter_settings.folds;
22073
22074        let right_padding = if shows_folds && show_line_numbers {
22075            ch_width * 4.0
22076        } else if shows_folds || (!is_singleton && show_line_numbers) {
22077            ch_width * 3.0
22078        } else if show_line_numbers {
22079            ch_width
22080        } else {
22081            px(0.)
22082        };
22083
22084        Some(GutterDimensions {
22085            left_padding,
22086            right_padding,
22087            width: line_gutter_width + left_padding + right_padding,
22088            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22089            git_blame_entries_width,
22090        })
22091    }
22092
22093    pub fn render_crease_toggle(
22094        &self,
22095        buffer_row: MultiBufferRow,
22096        row_contains_cursor: bool,
22097        editor: Entity<Editor>,
22098        window: &mut Window,
22099        cx: &mut App,
22100    ) -> Option<AnyElement> {
22101        let folded = self.is_line_folded(buffer_row);
22102        let mut is_foldable = false;
22103
22104        if let Some(crease) = self
22105            .crease_snapshot
22106            .query_row(buffer_row, &self.buffer_snapshot)
22107        {
22108            is_foldable = true;
22109            match crease {
22110                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22111                    if let Some(render_toggle) = render_toggle {
22112                        let toggle_callback =
22113                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22114                                if folded {
22115                                    editor.update(cx, |editor, cx| {
22116                                        editor.fold_at(buffer_row, window, cx)
22117                                    });
22118                                } else {
22119                                    editor.update(cx, |editor, cx| {
22120                                        editor.unfold_at(buffer_row, window, cx)
22121                                    });
22122                                }
22123                            });
22124                        return Some((render_toggle)(
22125                            buffer_row,
22126                            folded,
22127                            toggle_callback,
22128                            window,
22129                            cx,
22130                        ));
22131                    }
22132                }
22133            }
22134        }
22135
22136        is_foldable |= self.starts_indent(buffer_row);
22137
22138        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22139            Some(
22140                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22141                    .toggle_state(folded)
22142                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22143                        if folded {
22144                            this.unfold_at(buffer_row, window, cx);
22145                        } else {
22146                            this.fold_at(buffer_row, window, cx);
22147                        }
22148                    }))
22149                    .into_any_element(),
22150            )
22151        } else {
22152            None
22153        }
22154    }
22155
22156    pub fn render_crease_trailer(
22157        &self,
22158        buffer_row: MultiBufferRow,
22159        window: &mut Window,
22160        cx: &mut App,
22161    ) -> Option<AnyElement> {
22162        let folded = self.is_line_folded(buffer_row);
22163        if let Crease::Inline { render_trailer, .. } = self
22164            .crease_snapshot
22165            .query_row(buffer_row, &self.buffer_snapshot)?
22166        {
22167            let render_trailer = render_trailer.as_ref()?;
22168            Some(render_trailer(buffer_row, folded, window, cx))
22169        } else {
22170            None
22171        }
22172    }
22173}
22174
22175impl Deref for EditorSnapshot {
22176    type Target = DisplaySnapshot;
22177
22178    fn deref(&self) -> &Self::Target {
22179        &self.display_snapshot
22180    }
22181}
22182
22183#[derive(Clone, Debug, PartialEq, Eq)]
22184pub enum EditorEvent {
22185    InputIgnored {
22186        text: Arc<str>,
22187    },
22188    InputHandled {
22189        utf16_range_to_replace: Option<Range<isize>>,
22190        text: Arc<str>,
22191    },
22192    ExcerptsAdded {
22193        buffer: Entity<Buffer>,
22194        predecessor: ExcerptId,
22195        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22196    },
22197    ExcerptsRemoved {
22198        ids: Vec<ExcerptId>,
22199        removed_buffer_ids: Vec<BufferId>,
22200    },
22201    BufferFoldToggled {
22202        ids: Vec<ExcerptId>,
22203        folded: bool,
22204    },
22205    ExcerptsEdited {
22206        ids: Vec<ExcerptId>,
22207    },
22208    ExcerptsExpanded {
22209        ids: Vec<ExcerptId>,
22210    },
22211    BufferEdited,
22212    Edited {
22213        transaction_id: clock::Lamport,
22214    },
22215    Reparsed(BufferId),
22216    Focused,
22217    FocusedIn,
22218    Blurred,
22219    DirtyChanged,
22220    Saved,
22221    TitleChanged,
22222    DiffBaseChanged,
22223    SelectionsChanged {
22224        local: bool,
22225    },
22226    ScrollPositionChanged {
22227        local: bool,
22228        autoscroll: bool,
22229    },
22230    Closed,
22231    TransactionUndone {
22232        transaction_id: clock::Lamport,
22233    },
22234    TransactionBegun {
22235        transaction_id: clock::Lamport,
22236    },
22237    Reloaded,
22238    CursorShapeChanged,
22239    PushedToNavHistory {
22240        anchor: Anchor,
22241        is_deactivate: bool,
22242    },
22243}
22244
22245impl EventEmitter<EditorEvent> for Editor {}
22246
22247impl Focusable for Editor {
22248    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22249        self.focus_handle.clone()
22250    }
22251}
22252
22253impl Render for Editor {
22254    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22255        let settings = ThemeSettings::get_global(cx);
22256
22257        let mut text_style = match self.mode {
22258            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22259                color: cx.theme().colors().editor_foreground,
22260                font_family: settings.ui_font.family.clone(),
22261                font_features: settings.ui_font.features.clone(),
22262                font_fallbacks: settings.ui_font.fallbacks.clone(),
22263                font_size: rems(0.875).into(),
22264                font_weight: settings.ui_font.weight,
22265                line_height: relative(settings.buffer_line_height.value()),
22266                ..Default::default()
22267            },
22268            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22269                color: cx.theme().colors().editor_foreground,
22270                font_family: settings.buffer_font.family.clone(),
22271                font_features: settings.buffer_font.features.clone(),
22272                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22273                font_size: settings.buffer_font_size(cx).into(),
22274                font_weight: settings.buffer_font.weight,
22275                line_height: relative(settings.buffer_line_height.value()),
22276                ..Default::default()
22277            },
22278        };
22279        if let Some(text_style_refinement) = &self.text_style_refinement {
22280            text_style.refine(text_style_refinement)
22281        }
22282
22283        let background = match self.mode {
22284            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22285            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22286            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22287            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22288        };
22289
22290        EditorElement::new(
22291            &cx.entity(),
22292            EditorStyle {
22293                background,
22294                local_player: cx.theme().players().local(),
22295                text: text_style,
22296                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22297                syntax: cx.theme().syntax().clone(),
22298                status: cx.theme().status().clone(),
22299                inlay_hints_style: make_inlay_hints_style(cx),
22300                inline_completion_styles: make_suggestion_styles(cx),
22301                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22302                show_underlines: self.diagnostics_enabled(),
22303            },
22304        )
22305    }
22306}
22307
22308impl EntityInputHandler for Editor {
22309    fn text_for_range(
22310        &mut self,
22311        range_utf16: Range<usize>,
22312        adjusted_range: &mut Option<Range<usize>>,
22313        _: &mut Window,
22314        cx: &mut Context<Self>,
22315    ) -> Option<String> {
22316        let snapshot = self.buffer.read(cx).read(cx);
22317        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22318        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22319        if (start.0..end.0) != range_utf16 {
22320            adjusted_range.replace(start.0..end.0);
22321        }
22322        Some(snapshot.text_for_range(start..end).collect())
22323    }
22324
22325    fn selected_text_range(
22326        &mut self,
22327        ignore_disabled_input: bool,
22328        _: &mut Window,
22329        cx: &mut Context<Self>,
22330    ) -> Option<UTF16Selection> {
22331        // Prevent the IME menu from appearing when holding down an alphabetic key
22332        // while input is disabled.
22333        if !ignore_disabled_input && !self.input_enabled {
22334            return None;
22335        }
22336
22337        let selection = self.selections.newest::<OffsetUtf16>(cx);
22338        let range = selection.range();
22339
22340        Some(UTF16Selection {
22341            range: range.start.0..range.end.0,
22342            reversed: selection.reversed,
22343        })
22344    }
22345
22346    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22347        let snapshot = self.buffer.read(cx).read(cx);
22348        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22349        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22350    }
22351
22352    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22353        self.clear_highlights::<InputComposition>(cx);
22354        self.ime_transaction.take();
22355    }
22356
22357    fn replace_text_in_range(
22358        &mut self,
22359        range_utf16: Option<Range<usize>>,
22360        text: &str,
22361        window: &mut Window,
22362        cx: &mut Context<Self>,
22363    ) {
22364        if !self.input_enabled {
22365            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22366            return;
22367        }
22368
22369        self.transact(window, cx, |this, window, cx| {
22370            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22371                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22372                Some(this.selection_replacement_ranges(range_utf16, cx))
22373            } else {
22374                this.marked_text_ranges(cx)
22375            };
22376
22377            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22378                let newest_selection_id = this.selections.newest_anchor().id;
22379                this.selections
22380                    .all::<OffsetUtf16>(cx)
22381                    .iter()
22382                    .zip(ranges_to_replace.iter())
22383                    .find_map(|(selection, range)| {
22384                        if selection.id == newest_selection_id {
22385                            Some(
22386                                (range.start.0 as isize - selection.head().0 as isize)
22387                                    ..(range.end.0 as isize - selection.head().0 as isize),
22388                            )
22389                        } else {
22390                            None
22391                        }
22392                    })
22393            });
22394
22395            cx.emit(EditorEvent::InputHandled {
22396                utf16_range_to_replace: range_to_replace,
22397                text: text.into(),
22398            });
22399
22400            if let Some(new_selected_ranges) = new_selected_ranges {
22401                this.change_selections(None, window, cx, |selections| {
22402                    selections.select_ranges(new_selected_ranges)
22403                });
22404                this.backspace(&Default::default(), window, cx);
22405            }
22406
22407            this.handle_input(text, window, cx);
22408        });
22409
22410        if let Some(transaction) = self.ime_transaction {
22411            self.buffer.update(cx, |buffer, cx| {
22412                buffer.group_until_transaction(transaction, cx);
22413            });
22414        }
22415
22416        self.unmark_text(window, cx);
22417    }
22418
22419    fn replace_and_mark_text_in_range(
22420        &mut self,
22421        range_utf16: Option<Range<usize>>,
22422        text: &str,
22423        new_selected_range_utf16: Option<Range<usize>>,
22424        window: &mut Window,
22425        cx: &mut Context<Self>,
22426    ) {
22427        if !self.input_enabled {
22428            return;
22429        }
22430
22431        let transaction = self.transact(window, cx, |this, window, cx| {
22432            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22433                let snapshot = this.buffer.read(cx).read(cx);
22434                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22435                    for marked_range in &mut marked_ranges {
22436                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22437                        marked_range.start.0 += relative_range_utf16.start;
22438                        marked_range.start =
22439                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22440                        marked_range.end =
22441                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22442                    }
22443                }
22444                Some(marked_ranges)
22445            } else if let Some(range_utf16) = range_utf16 {
22446                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22447                Some(this.selection_replacement_ranges(range_utf16, cx))
22448            } else {
22449                None
22450            };
22451
22452            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22453                let newest_selection_id = this.selections.newest_anchor().id;
22454                this.selections
22455                    .all::<OffsetUtf16>(cx)
22456                    .iter()
22457                    .zip(ranges_to_replace.iter())
22458                    .find_map(|(selection, range)| {
22459                        if selection.id == newest_selection_id {
22460                            Some(
22461                                (range.start.0 as isize - selection.head().0 as isize)
22462                                    ..(range.end.0 as isize - selection.head().0 as isize),
22463                            )
22464                        } else {
22465                            None
22466                        }
22467                    })
22468            });
22469
22470            cx.emit(EditorEvent::InputHandled {
22471                utf16_range_to_replace: range_to_replace,
22472                text: text.into(),
22473            });
22474
22475            if let Some(ranges) = ranges_to_replace {
22476                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22477            }
22478
22479            let marked_ranges = {
22480                let snapshot = this.buffer.read(cx).read(cx);
22481                this.selections
22482                    .disjoint_anchors()
22483                    .iter()
22484                    .map(|selection| {
22485                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22486                    })
22487                    .collect::<Vec<_>>()
22488            };
22489
22490            if text.is_empty() {
22491                this.unmark_text(window, cx);
22492            } else {
22493                this.highlight_text::<InputComposition>(
22494                    marked_ranges.clone(),
22495                    HighlightStyle {
22496                        underline: Some(UnderlineStyle {
22497                            thickness: px(1.),
22498                            color: None,
22499                            wavy: false,
22500                        }),
22501                        ..Default::default()
22502                    },
22503                    cx,
22504                );
22505            }
22506
22507            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22508            let use_autoclose = this.use_autoclose;
22509            let use_auto_surround = this.use_auto_surround;
22510            this.set_use_autoclose(false);
22511            this.set_use_auto_surround(false);
22512            this.handle_input(text, window, cx);
22513            this.set_use_autoclose(use_autoclose);
22514            this.set_use_auto_surround(use_auto_surround);
22515
22516            if let Some(new_selected_range) = new_selected_range_utf16 {
22517                let snapshot = this.buffer.read(cx).read(cx);
22518                let new_selected_ranges = marked_ranges
22519                    .into_iter()
22520                    .map(|marked_range| {
22521                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22522                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22523                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22524                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22525                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22526                    })
22527                    .collect::<Vec<_>>();
22528
22529                drop(snapshot);
22530                this.change_selections(None, window, cx, |selections| {
22531                    selections.select_ranges(new_selected_ranges)
22532                });
22533            }
22534        });
22535
22536        self.ime_transaction = self.ime_transaction.or(transaction);
22537        if let Some(transaction) = self.ime_transaction {
22538            self.buffer.update(cx, |buffer, cx| {
22539                buffer.group_until_transaction(transaction, cx);
22540            });
22541        }
22542
22543        if self.text_highlights::<InputComposition>(cx).is_none() {
22544            self.ime_transaction.take();
22545        }
22546    }
22547
22548    fn bounds_for_range(
22549        &mut self,
22550        range_utf16: Range<usize>,
22551        element_bounds: gpui::Bounds<Pixels>,
22552        window: &mut Window,
22553        cx: &mut Context<Self>,
22554    ) -> Option<gpui::Bounds<Pixels>> {
22555        let text_layout_details = self.text_layout_details(window);
22556        let CharacterDimensions {
22557            em_width,
22558            em_advance,
22559            line_height,
22560        } = self.character_dimensions(window);
22561
22562        let snapshot = self.snapshot(window, cx);
22563        let scroll_position = snapshot.scroll_position();
22564        let scroll_left = scroll_position.x * em_advance;
22565
22566        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22567        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22568            + self.gutter_dimensions.full_width();
22569        let y = line_height * (start.row().as_f32() - scroll_position.y);
22570
22571        Some(Bounds {
22572            origin: element_bounds.origin + point(x, y),
22573            size: size(em_width, line_height),
22574        })
22575    }
22576
22577    fn character_index_for_point(
22578        &mut self,
22579        point: gpui::Point<Pixels>,
22580        _window: &mut Window,
22581        _cx: &mut Context<Self>,
22582    ) -> Option<usize> {
22583        let position_map = self.last_position_map.as_ref()?;
22584        if !position_map.text_hitbox.contains(&point) {
22585            return None;
22586        }
22587        let display_point = position_map.point_for_position(point).previous_valid;
22588        let anchor = position_map
22589            .snapshot
22590            .display_point_to_anchor(display_point, Bias::Left);
22591        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22592        Some(utf16_offset.0)
22593    }
22594}
22595
22596trait SelectionExt {
22597    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22598    fn spanned_rows(
22599        &self,
22600        include_end_if_at_line_start: bool,
22601        map: &DisplaySnapshot,
22602    ) -> Range<MultiBufferRow>;
22603}
22604
22605impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22606    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22607        let start = self
22608            .start
22609            .to_point(&map.buffer_snapshot)
22610            .to_display_point(map);
22611        let end = self
22612            .end
22613            .to_point(&map.buffer_snapshot)
22614            .to_display_point(map);
22615        if self.reversed {
22616            end..start
22617        } else {
22618            start..end
22619        }
22620    }
22621
22622    fn spanned_rows(
22623        &self,
22624        include_end_if_at_line_start: bool,
22625        map: &DisplaySnapshot,
22626    ) -> Range<MultiBufferRow> {
22627        let start = self.start.to_point(&map.buffer_snapshot);
22628        let mut end = self.end.to_point(&map.buffer_snapshot);
22629        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22630            end.row -= 1;
22631        }
22632
22633        let buffer_start = map.prev_line_boundary(start).0;
22634        let buffer_end = map.next_line_boundary(end).0;
22635        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22636    }
22637}
22638
22639impl<T: InvalidationRegion> InvalidationStack<T> {
22640    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22641    where
22642        S: Clone + ToOffset,
22643    {
22644        while let Some(region) = self.last() {
22645            let all_selections_inside_invalidation_ranges =
22646                if selections.len() == region.ranges().len() {
22647                    selections
22648                        .iter()
22649                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22650                        .all(|(selection, invalidation_range)| {
22651                            let head = selection.head().to_offset(buffer);
22652                            invalidation_range.start <= head && invalidation_range.end >= head
22653                        })
22654                } else {
22655                    false
22656                };
22657
22658            if all_selections_inside_invalidation_ranges {
22659                break;
22660            } else {
22661                self.pop();
22662            }
22663        }
22664    }
22665}
22666
22667impl<T> Default for InvalidationStack<T> {
22668    fn default() -> Self {
22669        Self(Default::default())
22670    }
22671}
22672
22673impl<T> Deref for InvalidationStack<T> {
22674    type Target = Vec<T>;
22675
22676    fn deref(&self) -> &Self::Target {
22677        &self.0
22678    }
22679}
22680
22681impl<T> DerefMut for InvalidationStack<T> {
22682    fn deref_mut(&mut self) -> &mut Self::Target {
22683        &mut self.0
22684    }
22685}
22686
22687impl InvalidationRegion for SnippetState {
22688    fn ranges(&self) -> &[Range<Anchor>] {
22689        &self.ranges[self.active_index]
22690    }
22691}
22692
22693fn inline_completion_edit_text(
22694    current_snapshot: &BufferSnapshot,
22695    edits: &[(Range<Anchor>, String)],
22696    edit_preview: &EditPreview,
22697    include_deletions: bool,
22698    cx: &App,
22699) -> HighlightedText {
22700    let edits = edits
22701        .iter()
22702        .map(|(anchor, text)| {
22703            (
22704                anchor.start.text_anchor..anchor.end.text_anchor,
22705                text.clone(),
22706            )
22707        })
22708        .collect::<Vec<_>>();
22709
22710    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22711}
22712
22713pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22714    match severity {
22715        lsp::DiagnosticSeverity::ERROR => colors.error,
22716        lsp::DiagnosticSeverity::WARNING => colors.warning,
22717        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22718        lsp::DiagnosticSeverity::HINT => colors.info,
22719        _ => colors.ignored,
22720    }
22721}
22722
22723pub fn styled_runs_for_code_label<'a>(
22724    label: &'a CodeLabel,
22725    syntax_theme: &'a theme::SyntaxTheme,
22726) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22727    let fade_out = HighlightStyle {
22728        fade_out: Some(0.35),
22729        ..Default::default()
22730    };
22731
22732    let mut prev_end = label.filter_range.end;
22733    label
22734        .runs
22735        .iter()
22736        .enumerate()
22737        .flat_map(move |(ix, (range, highlight_id))| {
22738            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22739                style
22740            } else {
22741                return Default::default();
22742            };
22743            let mut muted_style = style;
22744            muted_style.highlight(fade_out);
22745
22746            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22747            if range.start >= label.filter_range.end {
22748                if range.start > prev_end {
22749                    runs.push((prev_end..range.start, fade_out));
22750                }
22751                runs.push((range.clone(), muted_style));
22752            } else if range.end <= label.filter_range.end {
22753                runs.push((range.clone(), style));
22754            } else {
22755                runs.push((range.start..label.filter_range.end, style));
22756                runs.push((label.filter_range.end..range.end, muted_style));
22757            }
22758            prev_end = cmp::max(prev_end, range.end);
22759
22760            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22761                runs.push((prev_end..label.text.len(), fade_out));
22762            }
22763
22764            runs
22765        })
22766}
22767
22768pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22769    let mut prev_index = 0;
22770    let mut prev_codepoint: Option<char> = None;
22771    text.char_indices()
22772        .chain([(text.len(), '\0')])
22773        .filter_map(move |(index, codepoint)| {
22774            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22775            let is_boundary = index == text.len()
22776                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22777                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22778            if is_boundary {
22779                let chunk = &text[prev_index..index];
22780                prev_index = index;
22781                Some(chunk)
22782            } else {
22783                None
22784            }
22785        })
22786}
22787
22788pub trait RangeToAnchorExt: Sized {
22789    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22790
22791    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22792        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22793        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22794    }
22795}
22796
22797impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22798    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22799        let start_offset = self.start.to_offset(snapshot);
22800        let end_offset = self.end.to_offset(snapshot);
22801        if start_offset == end_offset {
22802            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22803        } else {
22804            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22805        }
22806    }
22807}
22808
22809pub trait RowExt {
22810    fn as_f32(&self) -> f32;
22811
22812    fn next_row(&self) -> Self;
22813
22814    fn previous_row(&self) -> Self;
22815
22816    fn minus(&self, other: Self) -> u32;
22817}
22818
22819impl RowExt for DisplayRow {
22820    fn as_f32(&self) -> f32 {
22821        self.0 as f32
22822    }
22823
22824    fn next_row(&self) -> Self {
22825        Self(self.0 + 1)
22826    }
22827
22828    fn previous_row(&self) -> Self {
22829        Self(self.0.saturating_sub(1))
22830    }
22831
22832    fn minus(&self, other: Self) -> u32 {
22833        self.0 - other.0
22834    }
22835}
22836
22837impl RowExt for MultiBufferRow {
22838    fn as_f32(&self) -> f32 {
22839        self.0 as f32
22840    }
22841
22842    fn next_row(&self) -> Self {
22843        Self(self.0 + 1)
22844    }
22845
22846    fn previous_row(&self) -> Self {
22847        Self(self.0.saturating_sub(1))
22848    }
22849
22850    fn minus(&self, other: Self) -> u32 {
22851        self.0 - other.0
22852    }
22853}
22854
22855trait RowRangeExt {
22856    type Row;
22857
22858    fn len(&self) -> usize;
22859
22860    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22861}
22862
22863impl RowRangeExt for Range<MultiBufferRow> {
22864    type Row = MultiBufferRow;
22865
22866    fn len(&self) -> usize {
22867        (self.end.0 - self.start.0) as usize
22868    }
22869
22870    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22871        (self.start.0..self.end.0).map(MultiBufferRow)
22872    }
22873}
22874
22875impl RowRangeExt for Range<DisplayRow> {
22876    type Row = DisplayRow;
22877
22878    fn len(&self) -> usize {
22879        (self.end.0 - self.start.0) as usize
22880    }
22881
22882    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22883        (self.start.0..self.end.0).map(DisplayRow)
22884    }
22885}
22886
22887/// If select range has more than one line, we
22888/// just point the cursor to range.start.
22889fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22890    if range.start.row == range.end.row {
22891        range
22892    } else {
22893        range.start..range.start
22894    }
22895}
22896pub struct KillRing(ClipboardItem);
22897impl Global for KillRing {}
22898
22899const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22900
22901enum BreakpointPromptEditAction {
22902    Log,
22903    Condition,
22904    HitCondition,
22905}
22906
22907struct BreakpointPromptEditor {
22908    pub(crate) prompt: Entity<Editor>,
22909    editor: WeakEntity<Editor>,
22910    breakpoint_anchor: Anchor,
22911    breakpoint: Breakpoint,
22912    edit_action: BreakpointPromptEditAction,
22913    block_ids: HashSet<CustomBlockId>,
22914    editor_margins: Arc<Mutex<EditorMargins>>,
22915    _subscriptions: Vec<Subscription>,
22916}
22917
22918impl BreakpointPromptEditor {
22919    const MAX_LINES: u8 = 4;
22920
22921    fn new(
22922        editor: WeakEntity<Editor>,
22923        breakpoint_anchor: Anchor,
22924        breakpoint: Breakpoint,
22925        edit_action: BreakpointPromptEditAction,
22926        window: &mut Window,
22927        cx: &mut Context<Self>,
22928    ) -> Self {
22929        let base_text = match edit_action {
22930            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22931            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22932            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22933        }
22934        .map(|msg| msg.to_string())
22935        .unwrap_or_default();
22936
22937        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22938        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22939
22940        let prompt = cx.new(|cx| {
22941            let mut prompt = Editor::new(
22942                EditorMode::AutoHeight {
22943                    min_lines: 1,
22944                    max_lines: Some(Self::MAX_LINES as usize),
22945                },
22946                buffer,
22947                None,
22948                window,
22949                cx,
22950            );
22951            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22952            prompt.set_show_cursor_when_unfocused(false, cx);
22953            prompt.set_placeholder_text(
22954                match edit_action {
22955                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22956                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22957                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22958                },
22959                cx,
22960            );
22961
22962            prompt
22963        });
22964
22965        Self {
22966            prompt,
22967            editor,
22968            breakpoint_anchor,
22969            breakpoint,
22970            edit_action,
22971            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22972            block_ids: Default::default(),
22973            _subscriptions: vec![],
22974        }
22975    }
22976
22977    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22978        self.block_ids.extend(block_ids)
22979    }
22980
22981    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22982        if let Some(editor) = self.editor.upgrade() {
22983            let message = self
22984                .prompt
22985                .read(cx)
22986                .buffer
22987                .read(cx)
22988                .as_singleton()
22989                .expect("A multi buffer in breakpoint prompt isn't possible")
22990                .read(cx)
22991                .as_rope()
22992                .to_string();
22993
22994            editor.update(cx, |editor, cx| {
22995                editor.edit_breakpoint_at_anchor(
22996                    self.breakpoint_anchor,
22997                    self.breakpoint.clone(),
22998                    match self.edit_action {
22999                        BreakpointPromptEditAction::Log => {
23000                            BreakpointEditAction::EditLogMessage(message.into())
23001                        }
23002                        BreakpointPromptEditAction::Condition => {
23003                            BreakpointEditAction::EditCondition(message.into())
23004                        }
23005                        BreakpointPromptEditAction::HitCondition => {
23006                            BreakpointEditAction::EditHitCondition(message.into())
23007                        }
23008                    },
23009                    cx,
23010                );
23011
23012                editor.remove_blocks(self.block_ids.clone(), None, cx);
23013                cx.focus_self(window);
23014            });
23015        }
23016    }
23017
23018    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23019        self.editor
23020            .update(cx, |editor, cx| {
23021                editor.remove_blocks(self.block_ids.clone(), None, cx);
23022                window.focus(&editor.focus_handle);
23023            })
23024            .log_err();
23025    }
23026
23027    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23028        let settings = ThemeSettings::get_global(cx);
23029        let text_style = TextStyle {
23030            color: if self.prompt.read(cx).read_only(cx) {
23031                cx.theme().colors().text_disabled
23032            } else {
23033                cx.theme().colors().text
23034            },
23035            font_family: settings.buffer_font.family.clone(),
23036            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23037            font_size: settings.buffer_font_size(cx).into(),
23038            font_weight: settings.buffer_font.weight,
23039            line_height: relative(settings.buffer_line_height.value()),
23040            ..Default::default()
23041        };
23042        EditorElement::new(
23043            &self.prompt,
23044            EditorStyle {
23045                background: cx.theme().colors().editor_background,
23046                local_player: cx.theme().players().local(),
23047                text: text_style,
23048                ..Default::default()
23049            },
23050        )
23051    }
23052}
23053
23054impl Render for BreakpointPromptEditor {
23055    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23056        let editor_margins = *self.editor_margins.lock();
23057        let gutter_dimensions = editor_margins.gutter;
23058        h_flex()
23059            .key_context("Editor")
23060            .bg(cx.theme().colors().editor_background)
23061            .border_y_1()
23062            .border_color(cx.theme().status().info_border)
23063            .size_full()
23064            .py(window.line_height() / 2.5)
23065            .on_action(cx.listener(Self::confirm))
23066            .on_action(cx.listener(Self::cancel))
23067            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23068            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23069    }
23070}
23071
23072impl Focusable for BreakpointPromptEditor {
23073    fn focus_handle(&self, cx: &App) -> FocusHandle {
23074        self.prompt.focus_handle(cx)
23075    }
23076}
23077
23078fn all_edits_insertions_or_deletions(
23079    edits: &Vec<(Range<Anchor>, String)>,
23080    snapshot: &MultiBufferSnapshot,
23081) -> bool {
23082    let mut all_insertions = true;
23083    let mut all_deletions = true;
23084
23085    for (range, new_text) in edits.iter() {
23086        let range_is_empty = range.to_offset(&snapshot).is_empty();
23087        let text_is_empty = new_text.is_empty();
23088
23089        if range_is_empty != text_is_empty {
23090            if range_is_empty {
23091                all_deletions = false;
23092            } else {
23093                all_insertions = false;
23094            }
23095        } else {
23096            return false;
23097        }
23098
23099        if !all_insertions && !all_deletions {
23100            return false;
23101        }
23102    }
23103    all_insertions || all_deletions
23104}
23105
23106struct MissingEditPredictionKeybindingTooltip;
23107
23108impl Render for MissingEditPredictionKeybindingTooltip {
23109    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23110        ui::tooltip_container(window, cx, |container, _, cx| {
23111            container
23112                .flex_shrink_0()
23113                .max_w_80()
23114                .min_h(rems_from_px(124.))
23115                .justify_between()
23116                .child(
23117                    v_flex()
23118                        .flex_1()
23119                        .text_ui_sm(cx)
23120                        .child(Label::new("Conflict with Accept Keybinding"))
23121                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23122                )
23123                .child(
23124                    h_flex()
23125                        .pb_1()
23126                        .gap_1()
23127                        .items_end()
23128                        .w_full()
23129                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23130                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23131                        }))
23132                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23133                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23134                        })),
23135                )
23136        })
23137    }
23138}
23139
23140#[derive(Debug, Clone, Copy, PartialEq)]
23141pub struct LineHighlight {
23142    pub background: Background,
23143    pub border: Option<gpui::Hsla>,
23144    pub include_gutter: bool,
23145    pub type_id: Option<TypeId>,
23146}
23147
23148struct LineManipulationResult {
23149    pub new_text: String,
23150    pub line_count_before: usize,
23151    pub line_count_after: usize,
23152}
23153
23154fn render_diff_hunk_controls(
23155    row: u32,
23156    status: &DiffHunkStatus,
23157    hunk_range: Range<Anchor>,
23158    is_created_file: bool,
23159    line_height: Pixels,
23160    editor: &Entity<Editor>,
23161    _window: &mut Window,
23162    cx: &mut App,
23163) -> AnyElement {
23164    h_flex()
23165        .h(line_height)
23166        .mr_1()
23167        .gap_1()
23168        .px_0p5()
23169        .pb_1()
23170        .border_x_1()
23171        .border_b_1()
23172        .border_color(cx.theme().colors().border_variant)
23173        .rounded_b_lg()
23174        .bg(cx.theme().colors().editor_background)
23175        .gap_1()
23176        .block_mouse_except_scroll()
23177        .shadow_md()
23178        .child(if status.has_secondary_hunk() {
23179            Button::new(("stage", row as u64), "Stage")
23180                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23181                .tooltip({
23182                    let focus_handle = editor.focus_handle(cx);
23183                    move |window, cx| {
23184                        Tooltip::for_action_in(
23185                            "Stage Hunk",
23186                            &::git::ToggleStaged,
23187                            &focus_handle,
23188                            window,
23189                            cx,
23190                        )
23191                    }
23192                })
23193                .on_click({
23194                    let editor = editor.clone();
23195                    move |_event, _window, cx| {
23196                        editor.update(cx, |editor, cx| {
23197                            editor.stage_or_unstage_diff_hunks(
23198                                true,
23199                                vec![hunk_range.start..hunk_range.start],
23200                                cx,
23201                            );
23202                        });
23203                    }
23204                })
23205        } else {
23206            Button::new(("unstage", row as u64), "Unstage")
23207                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23208                .tooltip({
23209                    let focus_handle = editor.focus_handle(cx);
23210                    move |window, cx| {
23211                        Tooltip::for_action_in(
23212                            "Unstage Hunk",
23213                            &::git::ToggleStaged,
23214                            &focus_handle,
23215                            window,
23216                            cx,
23217                        )
23218                    }
23219                })
23220                .on_click({
23221                    let editor = editor.clone();
23222                    move |_event, _window, cx| {
23223                        editor.update(cx, |editor, cx| {
23224                            editor.stage_or_unstage_diff_hunks(
23225                                false,
23226                                vec![hunk_range.start..hunk_range.start],
23227                                cx,
23228                            );
23229                        });
23230                    }
23231                })
23232        })
23233        .child(
23234            Button::new(("restore", row as u64), "Restore")
23235                .tooltip({
23236                    let focus_handle = editor.focus_handle(cx);
23237                    move |window, cx| {
23238                        Tooltip::for_action_in(
23239                            "Restore Hunk",
23240                            &::git::Restore,
23241                            &focus_handle,
23242                            window,
23243                            cx,
23244                        )
23245                    }
23246                })
23247                .on_click({
23248                    let editor = editor.clone();
23249                    move |_event, window, cx| {
23250                        editor.update(cx, |editor, cx| {
23251                            let snapshot = editor.snapshot(window, cx);
23252                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23253                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23254                        });
23255                    }
23256                })
23257                .disabled(is_created_file),
23258        )
23259        .when(
23260            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23261            |el| {
23262                el.child(
23263                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23264                        .shape(IconButtonShape::Square)
23265                        .icon_size(IconSize::Small)
23266                        // .disabled(!has_multiple_hunks)
23267                        .tooltip({
23268                            let focus_handle = editor.focus_handle(cx);
23269                            move |window, cx| {
23270                                Tooltip::for_action_in(
23271                                    "Next Hunk",
23272                                    &GoToHunk,
23273                                    &focus_handle,
23274                                    window,
23275                                    cx,
23276                                )
23277                            }
23278                        })
23279                        .on_click({
23280                            let editor = editor.clone();
23281                            move |_event, window, cx| {
23282                                editor.update(cx, |editor, cx| {
23283                                    let snapshot = editor.snapshot(window, cx);
23284                                    let position =
23285                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23286                                    editor.go_to_hunk_before_or_after_position(
23287                                        &snapshot,
23288                                        position,
23289                                        Direction::Next,
23290                                        window,
23291                                        cx,
23292                                    );
23293                                    editor.expand_selected_diff_hunks(cx);
23294                                });
23295                            }
23296                        }),
23297                )
23298                .child(
23299                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23300                        .shape(IconButtonShape::Square)
23301                        .icon_size(IconSize::Small)
23302                        // .disabled(!has_multiple_hunks)
23303                        .tooltip({
23304                            let focus_handle = editor.focus_handle(cx);
23305                            move |window, cx| {
23306                                Tooltip::for_action_in(
23307                                    "Previous Hunk",
23308                                    &GoToPreviousHunk,
23309                                    &focus_handle,
23310                                    window,
23311                                    cx,
23312                                )
23313                            }
23314                        })
23315                        .on_click({
23316                            let editor = editor.clone();
23317                            move |_event, window, cx| {
23318                                editor.update(cx, |editor, cx| {
23319                                    let snapshot = editor.snapshot(window, cx);
23320                                    let point =
23321                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23322                                    editor.go_to_hunk_before_or_after_position(
23323                                        &snapshot,
23324                                        point,
23325                                        Direction::Prev,
23326                                        window,
23327                                        cx,
23328                                    );
23329                                    editor.expand_selected_diff_hunks(cx);
23330                                });
23331                            }
23332                        }),
23333                )
23334            },
23335        )
23336        .into_any_element()
23337}