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_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82
   83use ::git::blame::BlameEntry;
   84use ::git::{Restore, blame::ParsedCommitMessage};
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use git::blame::{GitBlame, GlobalBlameRenderer};
   90use gpui::{
   91    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   92    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   93    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   94    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   95    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   96    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   97    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   98    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   99};
  100use highlight_matching_bracket::refresh_matching_bracket_highlights;
  101use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  102pub use hover_popover::hover_markdown_style;
  103use hover_popover::{HoverState, hide_hover};
  104use indent_guides::ActiveIndentGuidesState;
  105use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  106pub use inline_completion::Direction;
  107use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  108pub use items::MAX_TAB_TITLE_LEN;
  109use itertools::Itertools;
  110use language::{
  111    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  112    CursorShape, DiagnosticEntry, DiagnosticSourceKind, DiffOptions, DocumentationConfig,
  113    EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language,
  114    OffsetRangeExt, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  115    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, LspPullDiagnostics, ProjectPath, PulledDiagnostics,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    project_settings::DiagnosticSeverity,
  137};
  138
  139pub use git::blame::BlameRenderer;
  140pub use proposed_changes_editor::{
  141    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  142};
  143use std::{cell::OnceCell, iter::Peekable, ops::Not};
  144use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  145
  146pub use lsp::CompletionContext;
  147use lsp::{
  148    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  149    LanguageServerId, LanguageServerName,
  150};
  151
  152use language::BufferSnapshot;
  153pub use lsp_ext::lsp_tasks;
  154use movement::TextLayoutDetails;
  155pub use multi_buffer::{
  156    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  157    RowInfo, ToOffset, ToPoint,
  158};
  159use multi_buffer::{
  160    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  161    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  162};
  163use parking_lot::Mutex;
  164use project::{
  165    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  166    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  167    TaskSourceKind,
  168    debugger::breakpoint_store::Breakpoint,
  169    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  170    project_settings::{GitGutterSetting, ProjectSettings},
  171};
  172use rand::prelude::*;
  173use rpc::{ErrorExt, proto::*};
  174use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  175use selections_collection::{
  176    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  177};
  178use serde::{Deserialize, Serialize};
  179use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  180use smallvec::{SmallVec, smallvec};
  181use snippet::Snippet;
  182use std::sync::Arc;
  183use std::{
  184    any::TypeId,
  185    borrow::Cow,
  186    cell::RefCell,
  187    cmp::{self, Ordering, Reverse},
  188    mem,
  189    num::NonZeroU32,
  190    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  191    path::{Path, PathBuf},
  192    rc::Rc,
  193    time::{Duration, Instant},
  194};
  195pub use sum_tree::Bias;
  196use sum_tree::TreeMap;
  197use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  198use theme::{
  199    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  200    observe_buffer_font_size_adjustment,
  201};
  202use ui::{
  203    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  204    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  205};
  206use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  207use workspace::{
  208    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  209    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  210    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  211    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  212    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  213    searchable::SearchEvent,
  214};
  215
  216use crate::{
  217    code_context_menus::CompletionsMenuSource,
  218    hover_links::{find_url, find_url_from_range},
  219};
  220use crate::{
  221    editor_settings::MultiCursorModifier,
  222    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  223};
  224
  225pub const FILE_HEADER_HEIGHT: u32 = 2;
  226pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  227pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  228const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  229const MAX_LINE_LEN: usize = 1024;
  230const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  231const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  232pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  233#[doc(hidden)]
  234pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  235const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  236
  237pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  240
  241pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  242pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  243pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  244
  245pub type RenderDiffHunkControlsFn = Arc<
  246    dyn Fn(
  247        u32,
  248        &DiffHunkStatus,
  249        Range<Anchor>,
  250        bool,
  251        Pixels,
  252        &Entity<Editor>,
  253        &mut Window,
  254        &mut App,
  255    ) -> AnyElement,
  256>;
  257
  258struct InlineValueCache {
  259    enabled: bool,
  260    inlays: Vec<InlayId>,
  261    refresh_task: Task<Option<()>>,
  262}
  263
  264impl InlineValueCache {
  265    fn new(enabled: bool) -> Self {
  266        Self {
  267            enabled,
  268            inlays: Vec::new(),
  269            refresh_task: Task::ready(None),
  270        }
  271    }
  272}
  273
  274#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  275pub enum InlayId {
  276    InlineCompletion(usize),
  277    Hint(usize),
  278    DebuggerValue(usize),
  279}
  280
  281impl InlayId {
  282    fn id(&self) -> usize {
  283        match self {
  284            Self::InlineCompletion(id) => *id,
  285            Self::Hint(id) => *id,
  286            Self::DebuggerValue(id) => *id,
  287        }
  288    }
  289}
  290
  291pub enum ActiveDebugLine {}
  292pub enum DebugStackFrameLine {}
  293enum DocumentHighlightRead {}
  294enum DocumentHighlightWrite {}
  295enum InputComposition {}
  296pub enum PendingInput {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        mode: ColumnarMode,
  451        goal_column: u32,
  452    },
  453    Extend {
  454        position: DisplayPoint,
  455        click_count: usize,
  456    },
  457    Update {
  458        position: DisplayPoint,
  459        goal_column: u32,
  460        scroll_delta: gpui::Point<f32>,
  461    },
  462    End,
  463}
  464
  465#[derive(Clone, Debug, PartialEq)]
  466pub enum ColumnarMode {
  467    FromMouse,
  468    FromSelection,
  469}
  470
  471#[derive(Clone, Debug)]
  472pub enum SelectMode {
  473    Character,
  474    Word(Range<Anchor>),
  475    Line(Range<Anchor>),
  476    All,
  477}
  478
  479#[derive(Clone, PartialEq, Eq, Debug)]
  480pub enum EditorMode {
  481    SingleLine {
  482        auto_width: bool,
  483    },
  484    AutoHeight {
  485        min_lines: usize,
  486        max_lines: usize,
  487    },
  488    Full {
  489        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  490        scale_ui_elements_with_buffer_font_size: bool,
  491        /// When set to `true`, the editor will render a background for the active line.
  492        show_active_line_background: bool,
  493        /// When set to `true`, the editor's height will be determined by its content.
  494        sized_by_content: bool,
  495    },
  496    Minimap {
  497        parent: WeakEntity<Editor>,
  498    },
  499}
  500
  501impl EditorMode {
  502    pub fn full() -> Self {
  503        Self::Full {
  504            scale_ui_elements_with_buffer_font_size: true,
  505            show_active_line_background: true,
  506            sized_by_content: false,
  507        }
  508    }
  509
  510    pub fn is_full(&self) -> bool {
  511        matches!(self, Self::Full { .. })
  512    }
  513
  514    fn is_minimap(&self) -> bool {
  515        matches!(self, Self::Minimap { .. })
  516    }
  517}
  518
  519#[derive(Copy, Clone, Debug)]
  520pub enum SoftWrap {
  521    /// Prefer not to wrap at all.
  522    ///
  523    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  524    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  525    GitDiff,
  526    /// Prefer a single line generally, unless an overly long line is encountered.
  527    None,
  528    /// Soft wrap lines that exceed the editor width.
  529    EditorWidth,
  530    /// Soft wrap lines at the preferred line length.
  531    Column(u32),
  532    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  533    Bounded(u32),
  534}
  535
  536#[derive(Clone)]
  537pub struct EditorStyle {
  538    pub background: Hsla,
  539    pub local_player: PlayerColor,
  540    pub text: TextStyle,
  541    pub scrollbar_width: Pixels,
  542    pub syntax: Arc<SyntaxTheme>,
  543    pub status: StatusColors,
  544    pub inlay_hints_style: HighlightStyle,
  545    pub inline_completion_styles: InlineCompletionStyles,
  546    pub unnecessary_code_fade: f32,
  547    pub show_underlines: bool,
  548}
  549
  550impl Default for EditorStyle {
  551    fn default() -> Self {
  552        Self {
  553            background: Hsla::default(),
  554            local_player: PlayerColor::default(),
  555            text: TextStyle::default(),
  556            scrollbar_width: Pixels::default(),
  557            syntax: Default::default(),
  558            // HACK: Status colors don't have a real default.
  559            // We should look into removing the status colors from the editor
  560            // style and retrieve them directly from the theme.
  561            status: StatusColors::dark(),
  562            inlay_hints_style: HighlightStyle::default(),
  563            inline_completion_styles: InlineCompletionStyles {
  564                insertion: HighlightStyle::default(),
  565                whitespace: HighlightStyle::default(),
  566            },
  567            unnecessary_code_fade: Default::default(),
  568            show_underlines: true,
  569        }
  570    }
  571}
  572
  573pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  574    let show_background = language_settings::language_settings(None, None, cx)
  575        .inlay_hints
  576        .show_background;
  577
  578    HighlightStyle {
  579        color: Some(cx.theme().status().hint),
  580        background_color: show_background.then(|| cx.theme().status().hint_background),
  581        ..HighlightStyle::default()
  582    }
  583}
  584
  585pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  586    InlineCompletionStyles {
  587        insertion: HighlightStyle {
  588            color: Some(cx.theme().status().predictive),
  589            ..HighlightStyle::default()
  590        },
  591        whitespace: HighlightStyle {
  592            background_color: Some(cx.theme().status().created_background),
  593            ..HighlightStyle::default()
  594        },
  595    }
  596}
  597
  598type CompletionId = usize;
  599
  600pub(crate) enum EditDisplayMode {
  601    TabAccept,
  602    DiffPopover,
  603    Inline,
  604}
  605
  606enum InlineCompletion {
  607    Edit {
  608        edits: Vec<(Range<Anchor>, String)>,
  609        edit_preview: Option<EditPreview>,
  610        display_mode: EditDisplayMode,
  611        snapshot: BufferSnapshot,
  612    },
  613    Move {
  614        target: Anchor,
  615        snapshot: BufferSnapshot,
  616    },
  617}
  618
  619struct InlineCompletionState {
  620    inlay_ids: Vec<InlayId>,
  621    completion: InlineCompletion,
  622    completion_id: Option<SharedString>,
  623    invalidation_range: Range<Anchor>,
  624}
  625
  626enum EditPredictionSettings {
  627    Disabled,
  628    Enabled {
  629        show_in_menu: bool,
  630        preview_requires_modifier: bool,
  631    },
  632}
  633
  634enum InlineCompletionHighlight {}
  635
  636#[derive(Debug, Clone)]
  637struct InlineDiagnostic {
  638    message: SharedString,
  639    group_id: usize,
  640    is_primary: bool,
  641    start: Point,
  642    severity: lsp::DiagnosticSeverity,
  643}
  644
  645pub enum MenuInlineCompletionsPolicy {
  646    Never,
  647    ByProvider,
  648}
  649
  650pub enum EditPredictionPreview {
  651    /// Modifier is not pressed
  652    Inactive { released_too_fast: bool },
  653    /// Modifier pressed
  654    Active {
  655        since: Instant,
  656        previous_scroll_position: Option<ScrollAnchor>,
  657    },
  658}
  659
  660impl EditPredictionPreview {
  661    pub fn released_too_fast(&self) -> bool {
  662        match self {
  663            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  664            EditPredictionPreview::Active { .. } => false,
  665        }
  666    }
  667
  668    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  669        if let EditPredictionPreview::Active {
  670            previous_scroll_position,
  671            ..
  672        } = self
  673        {
  674            *previous_scroll_position = scroll_position;
  675        }
  676    }
  677}
  678
  679pub struct ContextMenuOptions {
  680    pub min_entries_visible: usize,
  681    pub max_entries_visible: usize,
  682    pub placement: Option<ContextMenuPlacement>,
  683}
  684
  685#[derive(Debug, Clone, PartialEq, Eq)]
  686pub enum ContextMenuPlacement {
  687    Above,
  688    Below,
  689}
  690
  691#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  692struct EditorActionId(usize);
  693
  694impl EditorActionId {
  695    pub fn post_inc(&mut self) -> Self {
  696        let answer = self.0;
  697
  698        *self = Self(answer + 1);
  699
  700        Self(answer)
  701    }
  702}
  703
  704// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  705// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  706
  707type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  708type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  709
  710#[derive(Default)]
  711struct ScrollbarMarkerState {
  712    scrollbar_size: Size<Pixels>,
  713    dirty: bool,
  714    markers: Arc<[PaintQuad]>,
  715    pending_refresh: Option<Task<Result<()>>>,
  716}
  717
  718impl ScrollbarMarkerState {
  719    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  720        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  721    }
  722}
  723
  724#[derive(Clone, Copy, PartialEq, Eq)]
  725pub enum MinimapVisibility {
  726    Disabled,
  727    Enabled {
  728        /// The configuration currently present in the users settings.
  729        setting_configuration: bool,
  730        /// Whether to override the currently set visibility from the users setting.
  731        toggle_override: bool,
  732    },
  733}
  734
  735impl MinimapVisibility {
  736    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  737        if mode.is_full() {
  738            Self::Enabled {
  739                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  740                toggle_override: false,
  741            }
  742        } else {
  743            Self::Disabled
  744        }
  745    }
  746
  747    fn hidden(&self) -> Self {
  748        match *self {
  749            Self::Enabled {
  750                setting_configuration,
  751                ..
  752            } => Self::Enabled {
  753                setting_configuration,
  754                toggle_override: setting_configuration,
  755            },
  756            Self::Disabled => Self::Disabled,
  757        }
  758    }
  759
  760    fn disabled(&self) -> bool {
  761        match *self {
  762            Self::Disabled => true,
  763            _ => false,
  764        }
  765    }
  766
  767    fn settings_visibility(&self) -> bool {
  768        match *self {
  769            Self::Enabled {
  770                setting_configuration,
  771                ..
  772            } => setting_configuration,
  773            _ => false,
  774        }
  775    }
  776
  777    fn visible(&self) -> bool {
  778        match *self {
  779            Self::Enabled {
  780                setting_configuration,
  781                toggle_override,
  782            } => setting_configuration ^ toggle_override,
  783            _ => false,
  784        }
  785    }
  786
  787    fn toggle_visibility(&self) -> Self {
  788        match *self {
  789            Self::Enabled {
  790                toggle_override,
  791                setting_configuration,
  792            } => Self::Enabled {
  793                setting_configuration,
  794                toggle_override: !toggle_override,
  795            },
  796            Self::Disabled => Self::Disabled,
  797        }
  798    }
  799}
  800
  801#[derive(Clone, Debug)]
  802struct RunnableTasks {
  803    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  804    offset: multi_buffer::Anchor,
  805    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  806    column: u32,
  807    // Values of all named captures, including those starting with '_'
  808    extra_variables: HashMap<String, String>,
  809    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  810    context_range: Range<BufferOffset>,
  811}
  812
  813impl RunnableTasks {
  814    fn resolve<'a>(
  815        &'a self,
  816        cx: &'a task::TaskContext,
  817    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  818        self.templates.iter().filter_map(|(kind, template)| {
  819            template
  820                .resolve_task(&kind.to_id_base(), cx)
  821                .map(|task| (kind.clone(), task))
  822        })
  823    }
  824}
  825
  826#[derive(Clone)]
  827pub struct ResolvedTasks {
  828    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  829    position: Anchor,
  830}
  831
  832#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  833struct BufferOffset(usize);
  834
  835// Addons allow storing per-editor state in other crates (e.g. Vim)
  836pub trait Addon: 'static {
  837    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  838
  839    fn render_buffer_header_controls(
  840        &self,
  841        _: &ExcerptInfo,
  842        _: &Window,
  843        _: &App,
  844    ) -> Option<AnyElement> {
  845        None
  846    }
  847
  848    fn to_any(&self) -> &dyn std::any::Any;
  849
  850    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  851        None
  852    }
  853}
  854
  855/// A set of caret positions, registered when the editor was edited.
  856pub struct ChangeList {
  857    changes: Vec<Vec<Anchor>>,
  858    /// Currently "selected" change.
  859    position: Option<usize>,
  860}
  861
  862impl ChangeList {
  863    pub fn new() -> Self {
  864        Self {
  865            changes: Vec::new(),
  866            position: None,
  867        }
  868    }
  869
  870    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  871    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  872    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  873        if self.changes.is_empty() {
  874            return None;
  875        }
  876
  877        let prev = self.position.unwrap_or(self.changes.len());
  878        let next = if direction == Direction::Prev {
  879            prev.saturating_sub(count)
  880        } else {
  881            (prev + count).min(self.changes.len() - 1)
  882        };
  883        self.position = Some(next);
  884        self.changes.get(next).map(|anchors| anchors.as_slice())
  885    }
  886
  887    /// Adds a new change to the list, resetting the change list position.
  888    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  889        self.position.take();
  890        if pop_state {
  891            self.changes.pop();
  892        }
  893        self.changes.push(new_positions.clone());
  894    }
  895
  896    pub fn last(&self) -> Option<&[Anchor]> {
  897        self.changes.last().map(|anchors| anchors.as_slice())
  898    }
  899}
  900
  901#[derive(Clone)]
  902struct InlineBlamePopoverState {
  903    scroll_handle: ScrollHandle,
  904    commit_message: Option<ParsedCommitMessage>,
  905    markdown: Entity<Markdown>,
  906}
  907
  908struct InlineBlamePopover {
  909    position: gpui::Point<Pixels>,
  910    hide_task: Option<Task<()>>,
  911    popover_bounds: Option<Bounds<Pixels>>,
  912    popover_state: InlineBlamePopoverState,
  913}
  914
  915enum SelectionDragState {
  916    /// State when no drag related activity is detected.
  917    None,
  918    /// State when the mouse is down on a selection that is about to be dragged.
  919    ReadyToDrag {
  920        selection: Selection<Anchor>,
  921        click_position: gpui::Point<Pixels>,
  922        mouse_down_time: Instant,
  923    },
  924    /// State when the mouse is dragging the selection in the editor.
  925    Dragging {
  926        selection: Selection<Anchor>,
  927        drop_cursor: Selection<Anchor>,
  928        hide_drop_cursor: bool,
  929    },
  930}
  931
  932enum ColumnarSelectionState {
  933    FromMouse {
  934        selection_tail: Anchor,
  935        display_point: Option<DisplayPoint>,
  936    },
  937    FromSelection {
  938        selection_tail: Anchor,
  939    },
  940}
  941
  942/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  943/// a breakpoint on them.
  944#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  945struct PhantomBreakpointIndicator {
  946    display_row: DisplayRow,
  947    /// There's a small debounce between hovering over the line and showing the indicator.
  948    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  949    is_active: bool,
  950    collides_with_existing_breakpoint: bool,
  951}
  952
  953/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  954///
  955/// See the [module level documentation](self) for more information.
  956pub struct Editor {
  957    focus_handle: FocusHandle,
  958    last_focused_descendant: Option<WeakFocusHandle>,
  959    /// The text buffer being edited
  960    buffer: Entity<MultiBuffer>,
  961    /// Map of how text in the buffer should be displayed.
  962    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  963    pub display_map: Entity<DisplayMap>,
  964    pub selections: SelectionsCollection,
  965    pub scroll_manager: ScrollManager,
  966    /// When inline assist editors are linked, they all render cursors because
  967    /// typing enters text into each of them, even the ones that aren't focused.
  968    pub(crate) show_cursor_when_unfocused: bool,
  969    columnar_selection_state: Option<ColumnarSelectionState>,
  970    add_selections_state: Option<AddSelectionsState>,
  971    select_next_state: Option<SelectNextState>,
  972    select_prev_state: Option<SelectNextState>,
  973    selection_history: SelectionHistory,
  974    defer_selection_effects: bool,
  975    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  976    autoclose_regions: Vec<AutocloseRegion>,
  977    snippet_stack: InvalidationStack<SnippetState>,
  978    select_syntax_node_history: SelectSyntaxNodeHistory,
  979    ime_transaction: Option<TransactionId>,
  980    pub diagnostics_max_severity: DiagnosticSeverity,
  981    active_diagnostics: ActiveDiagnostic,
  982    show_inline_diagnostics: bool,
  983    inline_diagnostics_update: Task<()>,
  984    inline_diagnostics_enabled: bool,
  985    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  986    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  987    hard_wrap: Option<usize>,
  988
  989    // TODO: make this a access method
  990    pub project: Option<Entity<Project>>,
  991    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  992    completion_provider: Option<Rc<dyn CompletionProvider>>,
  993    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  994    blink_manager: Entity<BlinkManager>,
  995    show_cursor_names: bool,
  996    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  997    pub show_local_selections: bool,
  998    mode: EditorMode,
  999    show_breadcrumbs: bool,
 1000    show_gutter: bool,
 1001    show_scrollbars: ScrollbarAxes,
 1002    minimap_visibility: MinimapVisibility,
 1003    offset_content: bool,
 1004    disable_expand_excerpt_buttons: bool,
 1005    show_line_numbers: Option<bool>,
 1006    use_relative_line_numbers: Option<bool>,
 1007    show_git_diff_gutter: Option<bool>,
 1008    show_code_actions: Option<bool>,
 1009    show_runnables: Option<bool>,
 1010    show_breakpoints: Option<bool>,
 1011    show_wrap_guides: Option<bool>,
 1012    show_indent_guides: Option<bool>,
 1013    placeholder_text: Option<Arc<str>>,
 1014    highlight_order: usize,
 1015    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1016    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1017    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1018    scrollbar_marker_state: ScrollbarMarkerState,
 1019    active_indent_guides_state: ActiveIndentGuidesState,
 1020    nav_history: Option<ItemNavHistory>,
 1021    context_menu: RefCell<Option<CodeContextMenu>>,
 1022    context_menu_options: Option<ContextMenuOptions>,
 1023    mouse_context_menu: Option<MouseContextMenu>,
 1024    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1025    inline_blame_popover: Option<InlineBlamePopover>,
 1026    inline_blame_popover_show_task: Option<Task<()>>,
 1027    signature_help_state: SignatureHelpState,
 1028    auto_signature_help: Option<bool>,
 1029    find_all_references_task_sources: Vec<Anchor>,
 1030    next_completion_id: CompletionId,
 1031    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1032    code_actions_task: Option<Task<Result<()>>>,
 1033    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1034    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1035    document_highlights_task: Option<Task<()>>,
 1036    linked_editing_range_task: Option<Task<Option<()>>>,
 1037    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1038    pending_rename: Option<RenameState>,
 1039    searchable: bool,
 1040    cursor_shape: CursorShape,
 1041    current_line_highlight: Option<CurrentLineHighlight>,
 1042    collapse_matches: bool,
 1043    autoindent_mode: Option<AutoindentMode>,
 1044    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1045    input_enabled: bool,
 1046    use_modal_editing: bool,
 1047    read_only: bool,
 1048    leader_id: Option<CollaboratorId>,
 1049    remote_id: Option<ViewId>,
 1050    pub hover_state: HoverState,
 1051    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1052    gutter_hovered: bool,
 1053    hovered_link_state: Option<HoveredLinkState>,
 1054    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1055    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1056    active_inline_completion: Option<InlineCompletionState>,
 1057    /// Used to prevent flickering as the user types while the menu is open
 1058    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1059    edit_prediction_settings: EditPredictionSettings,
 1060    inline_completions_hidden_for_vim_mode: bool,
 1061    show_inline_completions_override: Option<bool>,
 1062    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1063    edit_prediction_preview: EditPredictionPreview,
 1064    edit_prediction_indent_conflict: bool,
 1065    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1066    inlay_hint_cache: InlayHintCache,
 1067    next_inlay_id: usize,
 1068    _subscriptions: Vec<Subscription>,
 1069    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1070    gutter_dimensions: GutterDimensions,
 1071    style: Option<EditorStyle>,
 1072    text_style_refinement: Option<TextStyleRefinement>,
 1073    next_editor_action_id: EditorActionId,
 1074    editor_actions: Rc<
 1075        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1076    >,
 1077    use_autoclose: bool,
 1078    use_auto_surround: bool,
 1079    auto_replace_emoji_shortcode: bool,
 1080    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1081    show_git_blame_gutter: bool,
 1082    show_git_blame_inline: bool,
 1083    show_git_blame_inline_delay_task: Option<Task<()>>,
 1084    git_blame_inline_enabled: bool,
 1085    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1086    serialize_dirty_buffers: bool,
 1087    show_selection_menu: Option<bool>,
 1088    blame: Option<Entity<GitBlame>>,
 1089    blame_subscription: Option<Subscription>,
 1090    custom_context_menu: Option<
 1091        Box<
 1092            dyn 'static
 1093                + Fn(
 1094                    &mut Self,
 1095                    DisplayPoint,
 1096                    &mut Window,
 1097                    &mut Context<Self>,
 1098                ) -> Option<Entity<ui::ContextMenu>>,
 1099        >,
 1100    >,
 1101    last_bounds: Option<Bounds<Pixels>>,
 1102    last_position_map: Option<Rc<PositionMap>>,
 1103    expect_bounds_change: Option<Bounds<Pixels>>,
 1104    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1105    tasks_update_task: Option<Task<()>>,
 1106    breakpoint_store: Option<Entity<BreakpointStore>>,
 1107    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1108    hovered_diff_hunk_row: Option<DisplayRow>,
 1109    pull_diagnostics_task: Task<()>,
 1110    in_project_search: bool,
 1111    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1112    breadcrumb_header: Option<String>,
 1113    focused_block: Option<FocusedBlock>,
 1114    next_scroll_position: NextScrollCursorCenterTopBottom,
 1115    addons: HashMap<TypeId, Box<dyn Addon>>,
 1116    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1117    load_diff_task: Option<Shared<Task<()>>>,
 1118    /// Whether we are temporarily displaying a diff other than git's
 1119    temporary_diff_override: bool,
 1120    selection_mark_mode: bool,
 1121    toggle_fold_multiple_buffers: Task<()>,
 1122    _scroll_cursor_center_top_bottom_task: Task<()>,
 1123    serialize_selections: Task<()>,
 1124    serialize_folds: Task<()>,
 1125    mouse_cursor_hidden: bool,
 1126    minimap: Option<Entity<Self>>,
 1127    hide_mouse_mode: HideMouseMode,
 1128    pub change_list: ChangeList,
 1129    inline_value_cache: InlineValueCache,
 1130    selection_drag_state: SelectionDragState,
 1131    drag_and_drop_selection_enabled: bool,
 1132}
 1133
 1134#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1135enum NextScrollCursorCenterTopBottom {
 1136    #[default]
 1137    Center,
 1138    Top,
 1139    Bottom,
 1140}
 1141
 1142impl NextScrollCursorCenterTopBottom {
 1143    fn next(&self) -> Self {
 1144        match self {
 1145            Self::Center => Self::Top,
 1146            Self::Top => Self::Bottom,
 1147            Self::Bottom => Self::Center,
 1148        }
 1149    }
 1150}
 1151
 1152#[derive(Clone)]
 1153pub struct EditorSnapshot {
 1154    pub mode: EditorMode,
 1155    show_gutter: bool,
 1156    show_line_numbers: Option<bool>,
 1157    show_git_diff_gutter: Option<bool>,
 1158    show_code_actions: Option<bool>,
 1159    show_runnables: Option<bool>,
 1160    show_breakpoints: Option<bool>,
 1161    git_blame_gutter_max_author_length: Option<usize>,
 1162    pub display_snapshot: DisplaySnapshot,
 1163    pub placeholder_text: Option<Arc<str>>,
 1164    is_focused: bool,
 1165    scroll_anchor: ScrollAnchor,
 1166    ongoing_scroll: OngoingScroll,
 1167    current_line_highlight: CurrentLineHighlight,
 1168    gutter_hovered: bool,
 1169}
 1170
 1171#[derive(Default, Debug, Clone, Copy)]
 1172pub struct GutterDimensions {
 1173    pub left_padding: Pixels,
 1174    pub right_padding: Pixels,
 1175    pub width: Pixels,
 1176    pub margin: Pixels,
 1177    pub git_blame_entries_width: Option<Pixels>,
 1178}
 1179
 1180impl GutterDimensions {
 1181    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1182        Self {
 1183            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1184            ..Default::default()
 1185        }
 1186    }
 1187
 1188    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1189        -cx.text_system().descent(font_id, font_size)
 1190    }
 1191    /// The full width of the space taken up by the gutter.
 1192    pub fn full_width(&self) -> Pixels {
 1193        self.margin + self.width
 1194    }
 1195
 1196    /// The width of the space reserved for the fold indicators,
 1197    /// use alongside 'justify_end' and `gutter_width` to
 1198    /// right align content with the line numbers
 1199    pub fn fold_area_width(&self) -> Pixels {
 1200        self.margin + self.right_padding
 1201    }
 1202}
 1203
 1204#[derive(Debug)]
 1205pub struct RemoteSelection {
 1206    pub replica_id: ReplicaId,
 1207    pub selection: Selection<Anchor>,
 1208    pub cursor_shape: CursorShape,
 1209    pub collaborator_id: CollaboratorId,
 1210    pub line_mode: bool,
 1211    pub user_name: Option<SharedString>,
 1212    pub color: PlayerColor,
 1213}
 1214
 1215#[derive(Clone, Debug)]
 1216struct SelectionHistoryEntry {
 1217    selections: Arc<[Selection<Anchor>]>,
 1218    select_next_state: Option<SelectNextState>,
 1219    select_prev_state: Option<SelectNextState>,
 1220    add_selections_state: Option<AddSelectionsState>,
 1221}
 1222
 1223#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1224enum SelectionHistoryMode {
 1225    Normal,
 1226    Undoing,
 1227    Redoing,
 1228    Skipping,
 1229}
 1230
 1231#[derive(Clone, PartialEq, Eq, Hash)]
 1232struct HoveredCursor {
 1233    replica_id: u16,
 1234    selection_id: usize,
 1235}
 1236
 1237impl Default for SelectionHistoryMode {
 1238    fn default() -> Self {
 1239        Self::Normal
 1240    }
 1241}
 1242
 1243#[derive(Debug)]
 1244pub struct SelectionEffects {
 1245    nav_history: bool,
 1246    completions: bool,
 1247    scroll: Option<Autoscroll>,
 1248}
 1249
 1250impl Default for SelectionEffects {
 1251    fn default() -> Self {
 1252        Self {
 1253            nav_history: true,
 1254            completions: true,
 1255            scroll: Some(Autoscroll::fit()),
 1256        }
 1257    }
 1258}
 1259impl SelectionEffects {
 1260    pub fn scroll(scroll: Autoscroll) -> Self {
 1261        Self {
 1262            scroll: Some(scroll),
 1263            ..Default::default()
 1264        }
 1265    }
 1266
 1267    pub fn no_scroll() -> Self {
 1268        Self {
 1269            scroll: None,
 1270            ..Default::default()
 1271        }
 1272    }
 1273
 1274    pub fn completions(self, completions: bool) -> Self {
 1275        Self {
 1276            completions,
 1277            ..self
 1278        }
 1279    }
 1280
 1281    pub fn nav_history(self, nav_history: bool) -> Self {
 1282        Self {
 1283            nav_history,
 1284            ..self
 1285        }
 1286    }
 1287}
 1288
 1289struct DeferredSelectionEffectsState {
 1290    changed: bool,
 1291    effects: SelectionEffects,
 1292    old_cursor_position: Anchor,
 1293    history_entry: SelectionHistoryEntry,
 1294}
 1295
 1296#[derive(Default)]
 1297struct SelectionHistory {
 1298    #[allow(clippy::type_complexity)]
 1299    selections_by_transaction:
 1300        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1301    mode: SelectionHistoryMode,
 1302    undo_stack: VecDeque<SelectionHistoryEntry>,
 1303    redo_stack: VecDeque<SelectionHistoryEntry>,
 1304}
 1305
 1306impl SelectionHistory {
 1307    #[track_caller]
 1308    fn insert_transaction(
 1309        &mut self,
 1310        transaction_id: TransactionId,
 1311        selections: Arc<[Selection<Anchor>]>,
 1312    ) {
 1313        if selections.is_empty() {
 1314            log::error!(
 1315                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1316                std::panic::Location::caller()
 1317            );
 1318            return;
 1319        }
 1320        self.selections_by_transaction
 1321            .insert(transaction_id, (selections, None));
 1322    }
 1323
 1324    #[allow(clippy::type_complexity)]
 1325    fn transaction(
 1326        &self,
 1327        transaction_id: TransactionId,
 1328    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1329        self.selections_by_transaction.get(&transaction_id)
 1330    }
 1331
 1332    #[allow(clippy::type_complexity)]
 1333    fn transaction_mut(
 1334        &mut self,
 1335        transaction_id: TransactionId,
 1336    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1337        self.selections_by_transaction.get_mut(&transaction_id)
 1338    }
 1339
 1340    fn push(&mut self, entry: SelectionHistoryEntry) {
 1341        if !entry.selections.is_empty() {
 1342            match self.mode {
 1343                SelectionHistoryMode::Normal => {
 1344                    self.push_undo(entry);
 1345                    self.redo_stack.clear();
 1346                }
 1347                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1348                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1349                SelectionHistoryMode::Skipping => {}
 1350            }
 1351        }
 1352    }
 1353
 1354    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1355        if self
 1356            .undo_stack
 1357            .back()
 1358            .map_or(true, |e| e.selections != entry.selections)
 1359        {
 1360            self.undo_stack.push_back(entry);
 1361            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1362                self.undo_stack.pop_front();
 1363            }
 1364        }
 1365    }
 1366
 1367    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1368        if self
 1369            .redo_stack
 1370            .back()
 1371            .map_or(true, |e| e.selections != entry.selections)
 1372        {
 1373            self.redo_stack.push_back(entry);
 1374            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1375                self.redo_stack.pop_front();
 1376            }
 1377        }
 1378    }
 1379}
 1380
 1381#[derive(Clone, Copy)]
 1382pub struct RowHighlightOptions {
 1383    pub autoscroll: bool,
 1384    pub include_gutter: bool,
 1385}
 1386
 1387impl Default for RowHighlightOptions {
 1388    fn default() -> Self {
 1389        Self {
 1390            autoscroll: Default::default(),
 1391            include_gutter: true,
 1392        }
 1393    }
 1394}
 1395
 1396struct RowHighlight {
 1397    index: usize,
 1398    range: Range<Anchor>,
 1399    color: Hsla,
 1400    options: RowHighlightOptions,
 1401    type_id: TypeId,
 1402}
 1403
 1404#[derive(Clone, Debug)]
 1405struct AddSelectionsState {
 1406    groups: Vec<AddSelectionsGroup>,
 1407}
 1408
 1409#[derive(Clone, Debug)]
 1410struct AddSelectionsGroup {
 1411    above: bool,
 1412    stack: Vec<usize>,
 1413}
 1414
 1415#[derive(Clone)]
 1416struct SelectNextState {
 1417    query: AhoCorasick,
 1418    wordwise: bool,
 1419    done: bool,
 1420}
 1421
 1422impl std::fmt::Debug for SelectNextState {
 1423    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1424        f.debug_struct(std::any::type_name::<Self>())
 1425            .field("wordwise", &self.wordwise)
 1426            .field("done", &self.done)
 1427            .finish()
 1428    }
 1429}
 1430
 1431#[derive(Debug)]
 1432struct AutocloseRegion {
 1433    selection_id: usize,
 1434    range: Range<Anchor>,
 1435    pair: BracketPair,
 1436}
 1437
 1438#[derive(Debug)]
 1439struct SnippetState {
 1440    ranges: Vec<Vec<Range<Anchor>>>,
 1441    active_index: usize,
 1442    choices: Vec<Option<Vec<String>>>,
 1443}
 1444
 1445#[doc(hidden)]
 1446pub struct RenameState {
 1447    pub range: Range<Anchor>,
 1448    pub old_name: Arc<str>,
 1449    pub editor: Entity<Editor>,
 1450    block_id: CustomBlockId,
 1451}
 1452
 1453struct InvalidationStack<T>(Vec<T>);
 1454
 1455struct RegisteredInlineCompletionProvider {
 1456    provider: Arc<dyn InlineCompletionProviderHandle>,
 1457    _subscription: Subscription,
 1458}
 1459
 1460#[derive(Debug, PartialEq, Eq)]
 1461pub struct ActiveDiagnosticGroup {
 1462    pub active_range: Range<Anchor>,
 1463    pub active_message: String,
 1464    pub group_id: usize,
 1465    pub blocks: HashSet<CustomBlockId>,
 1466}
 1467
 1468#[derive(Debug, PartialEq, Eq)]
 1469
 1470pub(crate) enum ActiveDiagnostic {
 1471    None,
 1472    All,
 1473    Group(ActiveDiagnosticGroup),
 1474}
 1475
 1476#[derive(Serialize, Deserialize, Clone, Debug)]
 1477pub struct ClipboardSelection {
 1478    /// The number of bytes in this selection.
 1479    pub len: usize,
 1480    /// Whether this was a full-line selection.
 1481    pub is_entire_line: bool,
 1482    /// The indentation of the first line when this content was originally copied.
 1483    pub first_line_indent: u32,
 1484}
 1485
 1486// selections, scroll behavior, was newest selection reversed
 1487type SelectSyntaxNodeHistoryState = (
 1488    Box<[Selection<usize>]>,
 1489    SelectSyntaxNodeScrollBehavior,
 1490    bool,
 1491);
 1492
 1493#[derive(Default)]
 1494struct SelectSyntaxNodeHistory {
 1495    stack: Vec<SelectSyntaxNodeHistoryState>,
 1496    // disable temporarily to allow changing selections without losing the stack
 1497    pub disable_clearing: bool,
 1498}
 1499
 1500impl SelectSyntaxNodeHistory {
 1501    pub fn try_clear(&mut self) {
 1502        if !self.disable_clearing {
 1503            self.stack.clear();
 1504        }
 1505    }
 1506
 1507    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1508        self.stack.push(selection);
 1509    }
 1510
 1511    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1512        self.stack.pop()
 1513    }
 1514}
 1515
 1516enum SelectSyntaxNodeScrollBehavior {
 1517    CursorTop,
 1518    FitSelection,
 1519    CursorBottom,
 1520}
 1521
 1522#[derive(Debug)]
 1523pub(crate) struct NavigationData {
 1524    cursor_anchor: Anchor,
 1525    cursor_position: Point,
 1526    scroll_anchor: ScrollAnchor,
 1527    scroll_top_row: u32,
 1528}
 1529
 1530#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1531pub enum GotoDefinitionKind {
 1532    Symbol,
 1533    Declaration,
 1534    Type,
 1535    Implementation,
 1536}
 1537
 1538#[derive(Debug, Clone)]
 1539enum InlayHintRefreshReason {
 1540    ModifiersChanged(bool),
 1541    Toggle(bool),
 1542    SettingsChange(InlayHintSettings),
 1543    NewLinesShown,
 1544    BufferEdited(HashSet<Arc<Language>>),
 1545    RefreshRequested,
 1546    ExcerptsRemoved(Vec<ExcerptId>),
 1547}
 1548
 1549impl InlayHintRefreshReason {
 1550    fn description(&self) -> &'static str {
 1551        match self {
 1552            Self::ModifiersChanged(_) => "modifiers changed",
 1553            Self::Toggle(_) => "toggle",
 1554            Self::SettingsChange(_) => "settings change",
 1555            Self::NewLinesShown => "new lines shown",
 1556            Self::BufferEdited(_) => "buffer edited",
 1557            Self::RefreshRequested => "refresh requested",
 1558            Self::ExcerptsRemoved(_) => "excerpts removed",
 1559        }
 1560    }
 1561}
 1562
 1563pub enum FormatTarget {
 1564    Buffers(HashSet<Entity<Buffer>>),
 1565    Ranges(Vec<Range<MultiBufferPoint>>),
 1566}
 1567
 1568pub(crate) struct FocusedBlock {
 1569    id: BlockId,
 1570    focus_handle: WeakFocusHandle,
 1571}
 1572
 1573#[derive(Clone)]
 1574enum JumpData {
 1575    MultiBufferRow {
 1576        row: MultiBufferRow,
 1577        line_offset_from_top: u32,
 1578    },
 1579    MultiBufferPoint {
 1580        excerpt_id: ExcerptId,
 1581        position: Point,
 1582        anchor: text::Anchor,
 1583        line_offset_from_top: u32,
 1584    },
 1585}
 1586
 1587pub enum MultibufferSelectionMode {
 1588    First,
 1589    All,
 1590}
 1591
 1592#[derive(Clone, Copy, Debug, Default)]
 1593pub struct RewrapOptions {
 1594    pub override_language_settings: bool,
 1595    pub preserve_existing_whitespace: bool,
 1596}
 1597
 1598impl Editor {
 1599    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1600        let buffer = cx.new(|cx| Buffer::local("", cx));
 1601        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1602        Self::new(
 1603            EditorMode::SingleLine { auto_width: false },
 1604            buffer,
 1605            None,
 1606            window,
 1607            cx,
 1608        )
 1609    }
 1610
 1611    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1612        let buffer = cx.new(|cx| Buffer::local("", cx));
 1613        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1614        Self::new(EditorMode::full(), buffer, None, window, cx)
 1615    }
 1616
 1617    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1618        let buffer = cx.new(|cx| Buffer::local("", cx));
 1619        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1620        Self::new(
 1621            EditorMode::SingleLine { auto_width: true },
 1622            buffer,
 1623            None,
 1624            window,
 1625            cx,
 1626        )
 1627    }
 1628
 1629    pub fn auto_height(
 1630        min_lines: usize,
 1631        max_lines: usize,
 1632        window: &mut Window,
 1633        cx: &mut Context<Self>,
 1634    ) -> Self {
 1635        let buffer = cx.new(|cx| Buffer::local("", cx));
 1636        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1637        Self::new(
 1638            EditorMode::AutoHeight {
 1639                min_lines,
 1640                max_lines,
 1641            },
 1642            buffer,
 1643            None,
 1644            window,
 1645            cx,
 1646        )
 1647    }
 1648
 1649    pub fn for_buffer(
 1650        buffer: Entity<Buffer>,
 1651        project: Option<Entity<Project>>,
 1652        window: &mut Window,
 1653        cx: &mut Context<Self>,
 1654    ) -> Self {
 1655        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1656        Self::new(EditorMode::full(), buffer, project, window, cx)
 1657    }
 1658
 1659    pub fn for_multibuffer(
 1660        buffer: Entity<MultiBuffer>,
 1661        project: Option<Entity<Project>>,
 1662        window: &mut Window,
 1663        cx: &mut Context<Self>,
 1664    ) -> Self {
 1665        Self::new(EditorMode::full(), buffer, project, window, cx)
 1666    }
 1667
 1668    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1669        let mut clone = Self::new(
 1670            self.mode.clone(),
 1671            self.buffer.clone(),
 1672            self.project.clone(),
 1673            window,
 1674            cx,
 1675        );
 1676        self.display_map.update(cx, |display_map, cx| {
 1677            let snapshot = display_map.snapshot(cx);
 1678            clone.display_map.update(cx, |display_map, cx| {
 1679                display_map.set_state(&snapshot, cx);
 1680            });
 1681        });
 1682        clone.folds_did_change(cx);
 1683        clone.selections.clone_state(&self.selections);
 1684        clone.scroll_manager.clone_state(&self.scroll_manager);
 1685        clone.searchable = self.searchable;
 1686        clone.read_only = self.read_only;
 1687        clone
 1688    }
 1689
 1690    pub fn new(
 1691        mode: EditorMode,
 1692        buffer: Entity<MultiBuffer>,
 1693        project: Option<Entity<Project>>,
 1694        window: &mut Window,
 1695        cx: &mut Context<Self>,
 1696    ) -> Self {
 1697        Editor::new_internal(mode, buffer, project, None, window, cx)
 1698    }
 1699
 1700    fn new_internal(
 1701        mode: EditorMode,
 1702        buffer: Entity<MultiBuffer>,
 1703        project: Option<Entity<Project>>,
 1704        display_map: Option<Entity<DisplayMap>>,
 1705        window: &mut Window,
 1706        cx: &mut Context<Self>,
 1707    ) -> Self {
 1708        debug_assert!(
 1709            display_map.is_none() || mode.is_minimap(),
 1710            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1711        );
 1712
 1713        let full_mode = mode.is_full();
 1714        let diagnostics_max_severity = if full_mode {
 1715            EditorSettings::get_global(cx)
 1716                .diagnostics_max_severity
 1717                .unwrap_or(DiagnosticSeverity::Hint)
 1718        } else {
 1719            DiagnosticSeverity::Off
 1720        };
 1721        let style = window.text_style();
 1722        let font_size = style.font_size.to_pixels(window.rem_size());
 1723        let editor = cx.entity().downgrade();
 1724        let fold_placeholder = FoldPlaceholder {
 1725            constrain_width: true,
 1726            render: Arc::new(move |fold_id, fold_range, cx| {
 1727                let editor = editor.clone();
 1728                div()
 1729                    .id(fold_id)
 1730                    .bg(cx.theme().colors().ghost_element_background)
 1731                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1732                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1733                    .rounded_xs()
 1734                    .size_full()
 1735                    .cursor_pointer()
 1736                    .child("")
 1737                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1738                    .on_click(move |_, _window, cx| {
 1739                        editor
 1740                            .update(cx, |editor, cx| {
 1741                                editor.unfold_ranges(
 1742                                    &[fold_range.start..fold_range.end],
 1743                                    true,
 1744                                    false,
 1745                                    cx,
 1746                                );
 1747                                cx.stop_propagation();
 1748                            })
 1749                            .ok();
 1750                    })
 1751                    .into_any()
 1752            }),
 1753            merge_adjacent: true,
 1754            ..FoldPlaceholder::default()
 1755        };
 1756        let display_map = display_map.unwrap_or_else(|| {
 1757            cx.new(|cx| {
 1758                DisplayMap::new(
 1759                    buffer.clone(),
 1760                    style.font(),
 1761                    font_size,
 1762                    None,
 1763                    FILE_HEADER_HEIGHT,
 1764                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1765                    fold_placeholder,
 1766                    diagnostics_max_severity,
 1767                    cx,
 1768                )
 1769            })
 1770        });
 1771
 1772        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1773
 1774        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1775
 1776        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1777            .then(|| language_settings::SoftWrap::None);
 1778
 1779        let mut project_subscriptions = Vec::new();
 1780        if mode.is_full() {
 1781            if let Some(project) = project.as_ref() {
 1782                project_subscriptions.push(cx.subscribe_in(
 1783                    project,
 1784                    window,
 1785                    |editor, _, event, window, cx| match event {
 1786                        project::Event::RefreshCodeLens => {
 1787                            // we always query lens with actions, without storing them, always refreshing them
 1788                        }
 1789                        project::Event::RefreshInlayHints => {
 1790                            editor
 1791                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1792                        }
 1793                        project::Event::LanguageServerAdded(..)
 1794                        | project::Event::LanguageServerRemoved(..) => {
 1795                            if editor.tasks_update_task.is_none() {
 1796                                editor.tasks_update_task =
 1797                                    Some(editor.refresh_runnables(window, cx));
 1798                            }
 1799                            editor.pull_diagnostics(None, window, cx);
 1800                        }
 1801                        project::Event::SnippetEdit(id, snippet_edits) => {
 1802                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1803                                let focus_handle = editor.focus_handle(cx);
 1804                                if focus_handle.is_focused(window) {
 1805                                    let snapshot = buffer.read(cx).snapshot();
 1806                                    for (range, snippet) in snippet_edits {
 1807                                        let editor_range =
 1808                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1809                                        editor
 1810                                            .insert_snippet(
 1811                                                &[editor_range],
 1812                                                snippet.clone(),
 1813                                                window,
 1814                                                cx,
 1815                                            )
 1816                                            .ok();
 1817                                    }
 1818                                }
 1819                            }
 1820                        }
 1821                        _ => {}
 1822                    },
 1823                ));
 1824                if let Some(task_inventory) = project
 1825                    .read(cx)
 1826                    .task_store()
 1827                    .read(cx)
 1828                    .task_inventory()
 1829                    .cloned()
 1830                {
 1831                    project_subscriptions.push(cx.observe_in(
 1832                        &task_inventory,
 1833                        window,
 1834                        |editor, _, window, cx| {
 1835                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1836                        },
 1837                    ));
 1838                };
 1839
 1840                project_subscriptions.push(cx.subscribe_in(
 1841                    &project.read(cx).breakpoint_store(),
 1842                    window,
 1843                    |editor, _, event, window, cx| match event {
 1844                        BreakpointStoreEvent::ClearDebugLines => {
 1845                            editor.clear_row_highlights::<ActiveDebugLine>();
 1846                            editor.refresh_inline_values(cx);
 1847                        }
 1848                        BreakpointStoreEvent::SetDebugLine => {
 1849                            if editor.go_to_active_debug_line(window, cx) {
 1850                                cx.stop_propagation();
 1851                            }
 1852
 1853                            editor.refresh_inline_values(cx);
 1854                        }
 1855                        _ => {}
 1856                    },
 1857                ));
 1858            }
 1859        }
 1860
 1861        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1862
 1863        let inlay_hint_settings =
 1864            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1865        let focus_handle = cx.focus_handle();
 1866        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1867            .detach();
 1868        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1869            .detach();
 1870        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1871            .detach();
 1872        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1873            .detach();
 1874        cx.observe_pending_input(window, Self::observe_pending_input)
 1875            .detach();
 1876
 1877        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1878            Some(false)
 1879        } else {
 1880            None
 1881        };
 1882
 1883        let breakpoint_store = match (&mode, project.as_ref()) {
 1884            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1885            _ => None,
 1886        };
 1887
 1888        let mut code_action_providers = Vec::new();
 1889        let mut load_uncommitted_diff = None;
 1890        if let Some(project) = project.clone() {
 1891            load_uncommitted_diff = Some(
 1892                update_uncommitted_diff_for_buffer(
 1893                    cx.entity(),
 1894                    &project,
 1895                    buffer.read(cx).all_buffers(),
 1896                    buffer.clone(),
 1897                    cx,
 1898                )
 1899                .shared(),
 1900            );
 1901            code_action_providers.push(Rc::new(project) as Rc<_>);
 1902        }
 1903
 1904        let mut editor = Self {
 1905            focus_handle,
 1906            show_cursor_when_unfocused: false,
 1907            last_focused_descendant: None,
 1908            buffer: buffer.clone(),
 1909            display_map: display_map.clone(),
 1910            selections,
 1911            scroll_manager: ScrollManager::new(cx),
 1912            columnar_selection_state: None,
 1913            add_selections_state: None,
 1914            select_next_state: None,
 1915            select_prev_state: None,
 1916            selection_history: SelectionHistory::default(),
 1917            defer_selection_effects: false,
 1918            deferred_selection_effects_state: None,
 1919            autoclose_regions: Vec::new(),
 1920            snippet_stack: InvalidationStack::default(),
 1921            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1922            ime_transaction: None,
 1923            active_diagnostics: ActiveDiagnostic::None,
 1924            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1925            inline_diagnostics_update: Task::ready(()),
 1926            inline_diagnostics: Vec::new(),
 1927            soft_wrap_mode_override,
 1928            diagnostics_max_severity,
 1929            hard_wrap: None,
 1930            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1931            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1932            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1933            project,
 1934            blink_manager: blink_manager.clone(),
 1935            show_local_selections: true,
 1936            show_scrollbars: ScrollbarAxes {
 1937                horizontal: full_mode,
 1938                vertical: full_mode,
 1939            },
 1940            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1941            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1942            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1943            show_gutter: mode.is_full(),
 1944            show_line_numbers: None,
 1945            use_relative_line_numbers: None,
 1946            disable_expand_excerpt_buttons: false,
 1947            show_git_diff_gutter: None,
 1948            show_code_actions: None,
 1949            show_runnables: None,
 1950            show_breakpoints: None,
 1951            show_wrap_guides: None,
 1952            show_indent_guides,
 1953            placeholder_text: None,
 1954            highlight_order: 0,
 1955            highlighted_rows: HashMap::default(),
 1956            background_highlights: TreeMap::default(),
 1957            gutter_highlights: TreeMap::default(),
 1958            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1959            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1960            nav_history: None,
 1961            context_menu: RefCell::new(None),
 1962            context_menu_options: None,
 1963            mouse_context_menu: None,
 1964            completion_tasks: Vec::new(),
 1965            inline_blame_popover: None,
 1966            inline_blame_popover_show_task: None,
 1967            signature_help_state: SignatureHelpState::default(),
 1968            auto_signature_help: None,
 1969            find_all_references_task_sources: Vec::new(),
 1970            next_completion_id: 0,
 1971            next_inlay_id: 0,
 1972            code_action_providers,
 1973            available_code_actions: None,
 1974            code_actions_task: None,
 1975            quick_selection_highlight_task: None,
 1976            debounced_selection_highlight_task: None,
 1977            document_highlights_task: None,
 1978            linked_editing_range_task: None,
 1979            pending_rename: None,
 1980            searchable: true,
 1981            cursor_shape: EditorSettings::get_global(cx)
 1982                .cursor_shape
 1983                .unwrap_or_default(),
 1984            current_line_highlight: None,
 1985            autoindent_mode: Some(AutoindentMode::EachLine),
 1986            collapse_matches: false,
 1987            workspace: None,
 1988            input_enabled: true,
 1989            use_modal_editing: mode.is_full(),
 1990            read_only: mode.is_minimap(),
 1991            use_autoclose: true,
 1992            use_auto_surround: true,
 1993            auto_replace_emoji_shortcode: false,
 1994            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1995            leader_id: None,
 1996            remote_id: None,
 1997            hover_state: HoverState::default(),
 1998            pending_mouse_down: None,
 1999            hovered_link_state: None,
 2000            edit_prediction_provider: None,
 2001            active_inline_completion: None,
 2002            stale_inline_completion_in_menu: None,
 2003            edit_prediction_preview: EditPredictionPreview::Inactive {
 2004                released_too_fast: false,
 2005            },
 2006            inline_diagnostics_enabled: mode.is_full(),
 2007            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2008            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2009
 2010            gutter_hovered: false,
 2011            pixel_position_of_newest_cursor: None,
 2012            last_bounds: None,
 2013            last_position_map: None,
 2014            expect_bounds_change: None,
 2015            gutter_dimensions: GutterDimensions::default(),
 2016            style: None,
 2017            show_cursor_names: false,
 2018            hovered_cursors: HashMap::default(),
 2019            next_editor_action_id: EditorActionId::default(),
 2020            editor_actions: Rc::default(),
 2021            inline_completions_hidden_for_vim_mode: false,
 2022            show_inline_completions_override: None,
 2023            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2024            edit_prediction_settings: EditPredictionSettings::Disabled,
 2025            edit_prediction_indent_conflict: false,
 2026            edit_prediction_requires_modifier_in_indent_conflict: true,
 2027            custom_context_menu: None,
 2028            show_git_blame_gutter: false,
 2029            show_git_blame_inline: false,
 2030            show_selection_menu: None,
 2031            show_git_blame_inline_delay_task: None,
 2032            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2033            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2034            serialize_dirty_buffers: !mode.is_minimap()
 2035                && ProjectSettings::get_global(cx)
 2036                    .session
 2037                    .restore_unsaved_buffers,
 2038            blame: None,
 2039            blame_subscription: None,
 2040            tasks: BTreeMap::default(),
 2041
 2042            breakpoint_store,
 2043            gutter_breakpoint_indicator: (None, None),
 2044            hovered_diff_hunk_row: None,
 2045            _subscriptions: vec![
 2046                cx.observe(&buffer, Self::on_buffer_changed),
 2047                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2048                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2049                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2050                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2051                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2052                cx.observe_window_activation(window, |editor, window, cx| {
 2053                    let active = window.is_window_active();
 2054                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2055                        if active {
 2056                            blink_manager.enable(cx);
 2057                        } else {
 2058                            blink_manager.disable(cx);
 2059                        }
 2060                    });
 2061                    if active {
 2062                        editor.show_mouse_cursor(cx);
 2063                    }
 2064                }),
 2065            ],
 2066            tasks_update_task: None,
 2067            pull_diagnostics_task: Task::ready(()),
 2068            linked_edit_ranges: Default::default(),
 2069            in_project_search: false,
 2070            previous_search_ranges: None,
 2071            breadcrumb_header: None,
 2072            focused_block: None,
 2073            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2074            addons: HashMap::default(),
 2075            registered_buffers: HashMap::default(),
 2076            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2077            selection_mark_mode: false,
 2078            toggle_fold_multiple_buffers: Task::ready(()),
 2079            serialize_selections: Task::ready(()),
 2080            serialize_folds: Task::ready(()),
 2081            text_style_refinement: None,
 2082            load_diff_task: load_uncommitted_diff,
 2083            temporary_diff_override: false,
 2084            mouse_cursor_hidden: false,
 2085            minimap: None,
 2086            hide_mouse_mode: EditorSettings::get_global(cx)
 2087                .hide_mouse
 2088                .unwrap_or_default(),
 2089            change_list: ChangeList::new(),
 2090            mode,
 2091            selection_drag_state: SelectionDragState::None,
 2092            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2093        };
 2094        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2095            editor
 2096                ._subscriptions
 2097                .push(cx.observe(breakpoints, |_, _, cx| {
 2098                    cx.notify();
 2099                }));
 2100        }
 2101        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2102        editor._subscriptions.extend(project_subscriptions);
 2103
 2104        editor._subscriptions.push(cx.subscribe_in(
 2105            &cx.entity(),
 2106            window,
 2107            |editor, _, e: &EditorEvent, window, cx| match e {
 2108                EditorEvent::ScrollPositionChanged { local, .. } => {
 2109                    if *local {
 2110                        let new_anchor = editor.scroll_manager.anchor();
 2111                        let snapshot = editor.snapshot(window, cx);
 2112                        editor.update_restoration_data(cx, move |data| {
 2113                            data.scroll_position = (
 2114                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2115                                new_anchor.offset,
 2116                            );
 2117                        });
 2118                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2119                        editor.inline_blame_popover.take();
 2120                    }
 2121                }
 2122                EditorEvent::Edited { .. } => {
 2123                    if !vim_enabled(cx) {
 2124                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2125                        let pop_state = editor
 2126                            .change_list
 2127                            .last()
 2128                            .map(|previous| {
 2129                                previous.len() == selections.len()
 2130                                    && previous.iter().enumerate().all(|(ix, p)| {
 2131                                        p.to_display_point(&map).row()
 2132                                            == selections[ix].head().row()
 2133                                    })
 2134                            })
 2135                            .unwrap_or(false);
 2136                        let new_positions = selections
 2137                            .into_iter()
 2138                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2139                            .collect();
 2140                        editor
 2141                            .change_list
 2142                            .push_to_change_list(pop_state, new_positions);
 2143                    }
 2144                }
 2145                _ => (),
 2146            },
 2147        ));
 2148
 2149        if let Some(dap_store) = editor
 2150            .project
 2151            .as_ref()
 2152            .map(|project| project.read(cx).dap_store())
 2153        {
 2154            let weak_editor = cx.weak_entity();
 2155
 2156            editor
 2157                ._subscriptions
 2158                .push(
 2159                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2160                        let session_entity = cx.entity();
 2161                        weak_editor
 2162                            .update(cx, |editor, cx| {
 2163                                editor._subscriptions.push(
 2164                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2165                                );
 2166                            })
 2167                            .ok();
 2168                    }),
 2169                );
 2170
 2171            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2172                editor
 2173                    ._subscriptions
 2174                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2175            }
 2176        }
 2177
 2178        // skip adding the initial selection to selection history
 2179        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2180        editor.end_selection(window, cx);
 2181        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2182
 2183        editor.scroll_manager.show_scrollbars(window, cx);
 2184        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2185
 2186        if full_mode {
 2187            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2188            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2189
 2190            if editor.git_blame_inline_enabled {
 2191                editor.start_git_blame_inline(false, window, cx);
 2192            }
 2193
 2194            editor.go_to_active_debug_line(window, cx);
 2195
 2196            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2197                if let Some(project) = editor.project.as_ref() {
 2198                    let handle = project.update(cx, |project, cx| {
 2199                        project.register_buffer_with_language_servers(&buffer, cx)
 2200                    });
 2201                    editor
 2202                        .registered_buffers
 2203                        .insert(buffer.read(cx).remote_id(), handle);
 2204                }
 2205            }
 2206
 2207            editor.minimap =
 2208                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2209            editor.pull_diagnostics(None, window, cx);
 2210        }
 2211
 2212        editor.report_editor_event("Editor Opened", None, cx);
 2213        editor
 2214    }
 2215
 2216    pub fn deploy_mouse_context_menu(
 2217        &mut self,
 2218        position: gpui::Point<Pixels>,
 2219        context_menu: Entity<ContextMenu>,
 2220        window: &mut Window,
 2221        cx: &mut Context<Self>,
 2222    ) {
 2223        self.mouse_context_menu = Some(MouseContextMenu::new(
 2224            self,
 2225            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2226            context_menu,
 2227            window,
 2228            cx,
 2229        ));
 2230    }
 2231
 2232    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2233        self.mouse_context_menu
 2234            .as_ref()
 2235            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2236    }
 2237
 2238    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2239        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2240    }
 2241
 2242    fn key_context_internal(
 2243        &self,
 2244        has_active_edit_prediction: bool,
 2245        window: &Window,
 2246        cx: &App,
 2247    ) -> KeyContext {
 2248        let mut key_context = KeyContext::new_with_defaults();
 2249        key_context.add("Editor");
 2250        let mode = match self.mode {
 2251            EditorMode::SingleLine { .. } => "single_line",
 2252            EditorMode::AutoHeight { .. } => "auto_height",
 2253            EditorMode::Minimap { .. } => "minimap",
 2254            EditorMode::Full { .. } => "full",
 2255        };
 2256
 2257        if EditorSettings::jupyter_enabled(cx) {
 2258            key_context.add("jupyter");
 2259        }
 2260
 2261        key_context.set("mode", mode);
 2262        if self.pending_rename.is_some() {
 2263            key_context.add("renaming");
 2264        }
 2265
 2266        match self.context_menu.borrow().as_ref() {
 2267            Some(CodeContextMenu::Completions(_)) => {
 2268                key_context.add("menu");
 2269                key_context.add("showing_completions");
 2270            }
 2271            Some(CodeContextMenu::CodeActions(_)) => {
 2272                key_context.add("menu");
 2273                key_context.add("showing_code_actions")
 2274            }
 2275            None => {}
 2276        }
 2277
 2278        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2279        if !self.focus_handle(cx).contains_focused(window, cx)
 2280            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2281        {
 2282            for addon in self.addons.values() {
 2283                addon.extend_key_context(&mut key_context, cx)
 2284            }
 2285        }
 2286
 2287        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2288            if let Some(extension) = singleton_buffer
 2289                .read(cx)
 2290                .file()
 2291                .and_then(|file| file.path().extension()?.to_str())
 2292            {
 2293                key_context.set("extension", extension.to_string());
 2294            }
 2295        } else {
 2296            key_context.add("multibuffer");
 2297        }
 2298
 2299        if has_active_edit_prediction {
 2300            if self.edit_prediction_in_conflict() {
 2301                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2302            } else {
 2303                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2304                key_context.add("copilot_suggestion");
 2305            }
 2306        }
 2307
 2308        if self.selection_mark_mode {
 2309            key_context.add("selection_mode");
 2310        }
 2311
 2312        key_context
 2313    }
 2314
 2315    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2316        if self.mouse_cursor_hidden {
 2317            self.mouse_cursor_hidden = false;
 2318            cx.notify();
 2319        }
 2320    }
 2321
 2322    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2323        let hide_mouse_cursor = match origin {
 2324            HideMouseCursorOrigin::TypingAction => {
 2325                matches!(
 2326                    self.hide_mouse_mode,
 2327                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2328                )
 2329            }
 2330            HideMouseCursorOrigin::MovementAction => {
 2331                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2332            }
 2333        };
 2334        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2335            self.mouse_cursor_hidden = hide_mouse_cursor;
 2336            cx.notify();
 2337        }
 2338    }
 2339
 2340    pub fn edit_prediction_in_conflict(&self) -> bool {
 2341        if !self.show_edit_predictions_in_menu() {
 2342            return false;
 2343        }
 2344
 2345        let showing_completions = self
 2346            .context_menu
 2347            .borrow()
 2348            .as_ref()
 2349            .map_or(false, |context| {
 2350                matches!(context, CodeContextMenu::Completions(_))
 2351            });
 2352
 2353        showing_completions
 2354            || self.edit_prediction_requires_modifier()
 2355            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2356            // bindings to insert tab characters.
 2357            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2358    }
 2359
 2360    pub fn accept_edit_prediction_keybind(
 2361        &self,
 2362        accept_partial: bool,
 2363        window: &Window,
 2364        cx: &App,
 2365    ) -> AcceptEditPredictionBinding {
 2366        let key_context = self.key_context_internal(true, window, cx);
 2367        let in_conflict = self.edit_prediction_in_conflict();
 2368
 2369        let bindings = if accept_partial {
 2370            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2371        } else {
 2372            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2373        };
 2374
 2375        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2376        // just the first one.
 2377        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2378            !in_conflict
 2379                || binding
 2380                    .keystrokes()
 2381                    .first()
 2382                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2383        }))
 2384    }
 2385
 2386    pub fn new_file(
 2387        workspace: &mut Workspace,
 2388        _: &workspace::NewFile,
 2389        window: &mut Window,
 2390        cx: &mut Context<Workspace>,
 2391    ) {
 2392        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2393            "Failed to create buffer",
 2394            window,
 2395            cx,
 2396            |e, _, _| match e.error_code() {
 2397                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2398                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2399                e.error_tag("required").unwrap_or("the latest version")
 2400            )),
 2401                _ => None,
 2402            },
 2403        );
 2404    }
 2405
 2406    pub fn new_in_workspace(
 2407        workspace: &mut Workspace,
 2408        window: &mut Window,
 2409        cx: &mut Context<Workspace>,
 2410    ) -> Task<Result<Entity<Editor>>> {
 2411        let project = workspace.project().clone();
 2412        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2413
 2414        cx.spawn_in(window, async move |workspace, cx| {
 2415            let buffer = create.await?;
 2416            workspace.update_in(cx, |workspace, window, cx| {
 2417                let editor =
 2418                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2419                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2420                editor
 2421            })
 2422        })
 2423    }
 2424
 2425    fn new_file_vertical(
 2426        workspace: &mut Workspace,
 2427        _: &workspace::NewFileSplitVertical,
 2428        window: &mut Window,
 2429        cx: &mut Context<Workspace>,
 2430    ) {
 2431        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2432    }
 2433
 2434    fn new_file_horizontal(
 2435        workspace: &mut Workspace,
 2436        _: &workspace::NewFileSplitHorizontal,
 2437        window: &mut Window,
 2438        cx: &mut Context<Workspace>,
 2439    ) {
 2440        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2441    }
 2442
 2443    fn new_file_in_direction(
 2444        workspace: &mut Workspace,
 2445        direction: SplitDirection,
 2446        window: &mut Window,
 2447        cx: &mut Context<Workspace>,
 2448    ) {
 2449        let project = workspace.project().clone();
 2450        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2451
 2452        cx.spawn_in(window, async move |workspace, cx| {
 2453            let buffer = create.await?;
 2454            workspace.update_in(cx, move |workspace, window, cx| {
 2455                workspace.split_item(
 2456                    direction,
 2457                    Box::new(
 2458                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2459                    ),
 2460                    window,
 2461                    cx,
 2462                )
 2463            })?;
 2464            anyhow::Ok(())
 2465        })
 2466        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2467            match e.error_code() {
 2468                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2469                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2470                e.error_tag("required").unwrap_or("the latest version")
 2471            )),
 2472                _ => None,
 2473            }
 2474        });
 2475    }
 2476
 2477    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2478        self.leader_id
 2479    }
 2480
 2481    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2482        &self.buffer
 2483    }
 2484
 2485    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2486        self.workspace.as_ref()?.0.upgrade()
 2487    }
 2488
 2489    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2490        self.buffer().read(cx).title(cx)
 2491    }
 2492
 2493    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2494        let git_blame_gutter_max_author_length = self
 2495            .render_git_blame_gutter(cx)
 2496            .then(|| {
 2497                if let Some(blame) = self.blame.as_ref() {
 2498                    let max_author_length =
 2499                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2500                    Some(max_author_length)
 2501                } else {
 2502                    None
 2503                }
 2504            })
 2505            .flatten();
 2506
 2507        EditorSnapshot {
 2508            mode: self.mode.clone(),
 2509            show_gutter: self.show_gutter,
 2510            show_line_numbers: self.show_line_numbers,
 2511            show_git_diff_gutter: self.show_git_diff_gutter,
 2512            show_code_actions: self.show_code_actions,
 2513            show_runnables: self.show_runnables,
 2514            show_breakpoints: self.show_breakpoints,
 2515            git_blame_gutter_max_author_length,
 2516            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2517            scroll_anchor: self.scroll_manager.anchor(),
 2518            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2519            placeholder_text: self.placeholder_text.clone(),
 2520            is_focused: self.focus_handle.is_focused(window),
 2521            current_line_highlight: self
 2522                .current_line_highlight
 2523                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2524            gutter_hovered: self.gutter_hovered,
 2525        }
 2526    }
 2527
 2528    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2529        self.buffer.read(cx).language_at(point, cx)
 2530    }
 2531
 2532    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2533        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2534    }
 2535
 2536    pub fn active_excerpt(
 2537        &self,
 2538        cx: &App,
 2539    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2540        self.buffer
 2541            .read(cx)
 2542            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2543    }
 2544
 2545    pub fn mode(&self) -> &EditorMode {
 2546        &self.mode
 2547    }
 2548
 2549    pub fn set_mode(&mut self, mode: EditorMode) {
 2550        self.mode = mode;
 2551    }
 2552
 2553    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2554        self.collaboration_hub.as_deref()
 2555    }
 2556
 2557    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2558        self.collaboration_hub = Some(hub);
 2559    }
 2560
 2561    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2562        self.in_project_search = in_project_search;
 2563    }
 2564
 2565    pub fn set_custom_context_menu(
 2566        &mut self,
 2567        f: impl 'static
 2568        + Fn(
 2569            &mut Self,
 2570            DisplayPoint,
 2571            &mut Window,
 2572            &mut Context<Self>,
 2573        ) -> Option<Entity<ui::ContextMenu>>,
 2574    ) {
 2575        self.custom_context_menu = Some(Box::new(f))
 2576    }
 2577
 2578    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2579        self.completion_provider = provider;
 2580    }
 2581
 2582    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2583        self.semantics_provider.clone()
 2584    }
 2585
 2586    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2587        self.semantics_provider = provider;
 2588    }
 2589
 2590    pub fn set_edit_prediction_provider<T>(
 2591        &mut self,
 2592        provider: Option<Entity<T>>,
 2593        window: &mut Window,
 2594        cx: &mut Context<Self>,
 2595    ) where
 2596        T: EditPredictionProvider,
 2597    {
 2598        self.edit_prediction_provider =
 2599            provider.map(|provider| RegisteredInlineCompletionProvider {
 2600                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2601                    if this.focus_handle.is_focused(window) {
 2602                        this.update_visible_inline_completion(window, cx);
 2603                    }
 2604                }),
 2605                provider: Arc::new(provider),
 2606            });
 2607        self.update_edit_prediction_settings(cx);
 2608        self.refresh_inline_completion(false, false, window, cx);
 2609    }
 2610
 2611    pub fn placeholder_text(&self) -> Option<&str> {
 2612        self.placeholder_text.as_deref()
 2613    }
 2614
 2615    pub fn set_placeholder_text(
 2616        &mut self,
 2617        placeholder_text: impl Into<Arc<str>>,
 2618        cx: &mut Context<Self>,
 2619    ) {
 2620        let placeholder_text = Some(placeholder_text.into());
 2621        if self.placeholder_text != placeholder_text {
 2622            self.placeholder_text = placeholder_text;
 2623            cx.notify();
 2624        }
 2625    }
 2626
 2627    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2628        self.cursor_shape = cursor_shape;
 2629
 2630        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2631        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2632
 2633        cx.notify();
 2634    }
 2635
 2636    pub fn set_current_line_highlight(
 2637        &mut self,
 2638        current_line_highlight: Option<CurrentLineHighlight>,
 2639    ) {
 2640        self.current_line_highlight = current_line_highlight;
 2641    }
 2642
 2643    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2644        self.collapse_matches = collapse_matches;
 2645    }
 2646
 2647    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2648        let buffers = self.buffer.read(cx).all_buffers();
 2649        let Some(project) = self.project.as_ref() else {
 2650            return;
 2651        };
 2652        project.update(cx, |project, cx| {
 2653            for buffer in buffers {
 2654                self.registered_buffers
 2655                    .entry(buffer.read(cx).remote_id())
 2656                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2657            }
 2658        })
 2659    }
 2660
 2661    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2662        if self.collapse_matches {
 2663            return range.start..range.start;
 2664        }
 2665        range.clone()
 2666    }
 2667
 2668    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2669        if self.display_map.read(cx).clip_at_line_ends != clip {
 2670            self.display_map
 2671                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2672        }
 2673    }
 2674
 2675    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2676        self.input_enabled = input_enabled;
 2677    }
 2678
 2679    pub fn set_inline_completions_hidden_for_vim_mode(
 2680        &mut self,
 2681        hidden: bool,
 2682        window: &mut Window,
 2683        cx: &mut Context<Self>,
 2684    ) {
 2685        if hidden != self.inline_completions_hidden_for_vim_mode {
 2686            self.inline_completions_hidden_for_vim_mode = hidden;
 2687            if hidden {
 2688                self.update_visible_inline_completion(window, cx);
 2689            } else {
 2690                self.refresh_inline_completion(true, false, window, cx);
 2691            }
 2692        }
 2693    }
 2694
 2695    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2696        self.menu_inline_completions_policy = value;
 2697    }
 2698
 2699    pub fn set_autoindent(&mut self, autoindent: bool) {
 2700        if autoindent {
 2701            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2702        } else {
 2703            self.autoindent_mode = None;
 2704        }
 2705    }
 2706
 2707    pub fn read_only(&self, cx: &App) -> bool {
 2708        self.read_only || self.buffer.read(cx).read_only()
 2709    }
 2710
 2711    pub fn set_read_only(&mut self, read_only: bool) {
 2712        self.read_only = read_only;
 2713    }
 2714
 2715    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2716        self.use_autoclose = autoclose;
 2717    }
 2718
 2719    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2720        self.use_auto_surround = auto_surround;
 2721    }
 2722
 2723    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2724        self.auto_replace_emoji_shortcode = auto_replace;
 2725    }
 2726
 2727    pub fn toggle_edit_predictions(
 2728        &mut self,
 2729        _: &ToggleEditPrediction,
 2730        window: &mut Window,
 2731        cx: &mut Context<Self>,
 2732    ) {
 2733        if self.show_inline_completions_override.is_some() {
 2734            self.set_show_edit_predictions(None, window, cx);
 2735        } else {
 2736            let show_edit_predictions = !self.edit_predictions_enabled();
 2737            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2738        }
 2739    }
 2740
 2741    pub fn set_show_edit_predictions(
 2742        &mut self,
 2743        show_edit_predictions: Option<bool>,
 2744        window: &mut Window,
 2745        cx: &mut Context<Self>,
 2746    ) {
 2747        self.show_inline_completions_override = show_edit_predictions;
 2748        self.update_edit_prediction_settings(cx);
 2749
 2750        if let Some(false) = show_edit_predictions {
 2751            self.discard_inline_completion(false, cx);
 2752        } else {
 2753            self.refresh_inline_completion(false, true, window, cx);
 2754        }
 2755    }
 2756
 2757    fn inline_completions_disabled_in_scope(
 2758        &self,
 2759        buffer: &Entity<Buffer>,
 2760        buffer_position: language::Anchor,
 2761        cx: &App,
 2762    ) -> bool {
 2763        let snapshot = buffer.read(cx).snapshot();
 2764        let settings = snapshot.settings_at(buffer_position, cx);
 2765
 2766        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2767            return false;
 2768        };
 2769
 2770        scope.override_name().map_or(false, |scope_name| {
 2771            settings
 2772                .edit_predictions_disabled_in
 2773                .iter()
 2774                .any(|s| s == scope_name)
 2775        })
 2776    }
 2777
 2778    pub fn set_use_modal_editing(&mut self, to: bool) {
 2779        self.use_modal_editing = to;
 2780    }
 2781
 2782    pub fn use_modal_editing(&self) -> bool {
 2783        self.use_modal_editing
 2784    }
 2785
 2786    fn selections_did_change(
 2787        &mut self,
 2788        local: bool,
 2789        old_cursor_position: &Anchor,
 2790        effects: SelectionEffects,
 2791        window: &mut Window,
 2792        cx: &mut Context<Self>,
 2793    ) {
 2794        window.invalidate_character_coordinates();
 2795
 2796        // Copy selections to primary selection buffer
 2797        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2798        if local {
 2799            let selections = self.selections.all::<usize>(cx);
 2800            let buffer_handle = self.buffer.read(cx).read(cx);
 2801
 2802            let mut text = String::new();
 2803            for (index, selection) in selections.iter().enumerate() {
 2804                let text_for_selection = buffer_handle
 2805                    .text_for_range(selection.start..selection.end)
 2806                    .collect::<String>();
 2807
 2808                text.push_str(&text_for_selection);
 2809                if index != selections.len() - 1 {
 2810                    text.push('\n');
 2811                }
 2812            }
 2813
 2814            if !text.is_empty() {
 2815                cx.write_to_primary(ClipboardItem::new_string(text));
 2816            }
 2817        }
 2818
 2819        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2820            self.buffer.update(cx, |buffer, cx| {
 2821                buffer.set_active_selections(
 2822                    &self.selections.disjoint_anchors(),
 2823                    self.selections.line_mode,
 2824                    self.cursor_shape,
 2825                    cx,
 2826                )
 2827            });
 2828        }
 2829        let display_map = self
 2830            .display_map
 2831            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2832        let buffer = &display_map.buffer_snapshot;
 2833        if self.selections.count() == 1 {
 2834            self.add_selections_state = None;
 2835        }
 2836        self.select_next_state = None;
 2837        self.select_prev_state = None;
 2838        self.select_syntax_node_history.try_clear();
 2839        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2840        self.snippet_stack
 2841            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2842        self.take_rename(false, window, cx);
 2843
 2844        let newest_selection = self.selections.newest_anchor();
 2845        let new_cursor_position = newest_selection.head();
 2846        let selection_start = newest_selection.start;
 2847
 2848        if effects.nav_history {
 2849            self.push_to_nav_history(
 2850                *old_cursor_position,
 2851                Some(new_cursor_position.to_point(buffer)),
 2852                false,
 2853                cx,
 2854            );
 2855        }
 2856
 2857        if local {
 2858            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2859                if !self.registered_buffers.contains_key(&buffer_id) {
 2860                    if let Some(project) = self.project.as_ref() {
 2861                        project.update(cx, |project, cx| {
 2862                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2863                                return;
 2864                            };
 2865                            self.registered_buffers.insert(
 2866                                buffer_id,
 2867                                project.register_buffer_with_language_servers(&buffer, cx),
 2868                            );
 2869                        })
 2870                    }
 2871                }
 2872            }
 2873
 2874            let mut context_menu = self.context_menu.borrow_mut();
 2875            let completion_menu = match context_menu.as_ref() {
 2876                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2877                Some(CodeContextMenu::CodeActions(_)) => {
 2878                    *context_menu = None;
 2879                    None
 2880                }
 2881                None => None,
 2882            };
 2883            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2884            drop(context_menu);
 2885
 2886            if effects.completions {
 2887                if let Some(completion_position) = completion_position {
 2888                    let start_offset = selection_start.to_offset(buffer);
 2889                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2890                    let continue_showing = if position_matches {
 2891                        if self.snippet_stack.is_empty() {
 2892                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2893                        } else {
 2894                            // Snippet choices can be shown even when the cursor is in whitespace.
 2895                            // Dismissing the menu with actions like backspace is handled by
 2896                            // invalidation regions.
 2897                            true
 2898                        }
 2899                    } else {
 2900                        false
 2901                    };
 2902
 2903                    if continue_showing {
 2904                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2905                    } else {
 2906                        self.hide_context_menu(window, cx);
 2907                    }
 2908                }
 2909            }
 2910
 2911            hide_hover(self, cx);
 2912
 2913            if old_cursor_position.to_display_point(&display_map).row()
 2914                != new_cursor_position.to_display_point(&display_map).row()
 2915            {
 2916                self.available_code_actions.take();
 2917            }
 2918            self.refresh_code_actions(window, cx);
 2919            self.refresh_document_highlights(cx);
 2920            self.refresh_selected_text_highlights(false, window, cx);
 2921            refresh_matching_bracket_highlights(self, window, cx);
 2922            self.update_visible_inline_completion(window, cx);
 2923            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2924            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2925            self.inline_blame_popover.take();
 2926            if self.git_blame_inline_enabled {
 2927                self.start_inline_blame_timer(window, cx);
 2928            }
 2929        }
 2930
 2931        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2932        cx.emit(EditorEvent::SelectionsChanged { local });
 2933
 2934        let selections = &self.selections.disjoint;
 2935        if selections.len() == 1 {
 2936            cx.emit(SearchEvent::ActiveMatchChanged)
 2937        }
 2938        if local {
 2939            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2940                let inmemory_selections = selections
 2941                    .iter()
 2942                    .map(|s| {
 2943                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2944                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2945                    })
 2946                    .collect();
 2947                self.update_restoration_data(cx, |data| {
 2948                    data.selections = inmemory_selections;
 2949                });
 2950
 2951                if WorkspaceSettings::get(None, cx).restore_on_startup
 2952                    != RestoreOnStartupBehavior::None
 2953                {
 2954                    if let Some(workspace_id) =
 2955                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2956                    {
 2957                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2958                        let selections = selections.clone();
 2959                        let background_executor = cx.background_executor().clone();
 2960                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2961                        self.serialize_selections = cx.background_spawn(async move {
 2962                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2963                            let db_selections = selections
 2964                                .iter()
 2965                                .map(|selection| {
 2966                                    (
 2967                                        selection.start.to_offset(&snapshot),
 2968                                        selection.end.to_offset(&snapshot),
 2969                                    )
 2970                                })
 2971                                .collect();
 2972
 2973                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2974                                .await
 2975                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2976                                .log_err();
 2977                        });
 2978                    }
 2979                }
 2980            }
 2981        }
 2982
 2983        cx.notify();
 2984    }
 2985
 2986    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2987        use text::ToOffset as _;
 2988        use text::ToPoint as _;
 2989
 2990        if self.mode.is_minimap()
 2991            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2992        {
 2993            return;
 2994        }
 2995
 2996        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2997            return;
 2998        };
 2999
 3000        let snapshot = singleton.read(cx).snapshot();
 3001        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3002            let display_snapshot = display_map.snapshot(cx);
 3003
 3004            display_snapshot
 3005                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3006                .map(|fold| {
 3007                    fold.range.start.text_anchor.to_point(&snapshot)
 3008                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3009                })
 3010                .collect()
 3011        });
 3012        self.update_restoration_data(cx, |data| {
 3013            data.folds = inmemory_folds;
 3014        });
 3015
 3016        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3017            return;
 3018        };
 3019        let background_executor = cx.background_executor().clone();
 3020        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3021        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3022            display_map
 3023                .snapshot(cx)
 3024                .folds_in_range(0..snapshot.len())
 3025                .map(|fold| {
 3026                    (
 3027                        fold.range.start.text_anchor.to_offset(&snapshot),
 3028                        fold.range.end.text_anchor.to_offset(&snapshot),
 3029                    )
 3030                })
 3031                .collect()
 3032        });
 3033        self.serialize_folds = cx.background_spawn(async move {
 3034            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3035            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3036                .await
 3037                .with_context(|| {
 3038                    format!(
 3039                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3040                    )
 3041                })
 3042                .log_err();
 3043        });
 3044    }
 3045
 3046    pub fn sync_selections(
 3047        &mut self,
 3048        other: Entity<Editor>,
 3049        cx: &mut Context<Self>,
 3050    ) -> gpui::Subscription {
 3051        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3052        self.selections.change_with(cx, |selections| {
 3053            selections.select_anchors(other_selections);
 3054        });
 3055
 3056        let other_subscription =
 3057            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3058                EditorEvent::SelectionsChanged { local: true } => {
 3059                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3060                    if other_selections.is_empty() {
 3061                        return;
 3062                    }
 3063                    this.selections.change_with(cx, |selections| {
 3064                        selections.select_anchors(other_selections);
 3065                    });
 3066                }
 3067                _ => {}
 3068            });
 3069
 3070        let this_subscription =
 3071            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3072                EditorEvent::SelectionsChanged { local: true } => {
 3073                    let these_selections = this.selections.disjoint.to_vec();
 3074                    if these_selections.is_empty() {
 3075                        return;
 3076                    }
 3077                    other.update(cx, |other_editor, cx| {
 3078                        other_editor.selections.change_with(cx, |selections| {
 3079                            selections.select_anchors(these_selections);
 3080                        })
 3081                    });
 3082                }
 3083                _ => {}
 3084            });
 3085
 3086        Subscription::join(other_subscription, this_subscription)
 3087    }
 3088
 3089    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3090    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3091    /// effects of selection change occur at the end of the transaction.
 3092    pub fn change_selections<R>(
 3093        &mut self,
 3094        effects: impl Into<SelectionEffects>,
 3095        window: &mut Window,
 3096        cx: &mut Context<Self>,
 3097        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3098    ) -> R {
 3099        let effects = effects.into();
 3100        if let Some(state) = &mut self.deferred_selection_effects_state {
 3101            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3102            state.effects.completions = effects.completions;
 3103            state.effects.nav_history |= effects.nav_history;
 3104            let (changed, result) = self.selections.change_with(cx, change);
 3105            state.changed |= changed;
 3106            return result;
 3107        }
 3108        let mut state = DeferredSelectionEffectsState {
 3109            changed: false,
 3110            effects,
 3111            old_cursor_position: self.selections.newest_anchor().head(),
 3112            history_entry: SelectionHistoryEntry {
 3113                selections: self.selections.disjoint_anchors(),
 3114                select_next_state: self.select_next_state.clone(),
 3115                select_prev_state: self.select_prev_state.clone(),
 3116                add_selections_state: self.add_selections_state.clone(),
 3117            },
 3118        };
 3119        let (changed, result) = self.selections.change_with(cx, change);
 3120        state.changed = state.changed || changed;
 3121        if self.defer_selection_effects {
 3122            self.deferred_selection_effects_state = Some(state);
 3123        } else {
 3124            self.apply_selection_effects(state, window, cx);
 3125        }
 3126        result
 3127    }
 3128
 3129    /// Defers the effects of selection change, so that the effects of multiple calls to
 3130    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3131    /// to selection history and the state of popovers based on selection position aren't
 3132    /// erroneously updated.
 3133    pub fn with_selection_effects_deferred<R>(
 3134        &mut self,
 3135        window: &mut Window,
 3136        cx: &mut Context<Self>,
 3137        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3138    ) -> R {
 3139        let already_deferred = self.defer_selection_effects;
 3140        self.defer_selection_effects = true;
 3141        let result = update(self, window, cx);
 3142        if !already_deferred {
 3143            self.defer_selection_effects = false;
 3144            if let Some(state) = self.deferred_selection_effects_state.take() {
 3145                self.apply_selection_effects(state, window, cx);
 3146            }
 3147        }
 3148        result
 3149    }
 3150
 3151    fn apply_selection_effects(
 3152        &mut self,
 3153        state: DeferredSelectionEffectsState,
 3154        window: &mut Window,
 3155        cx: &mut Context<Self>,
 3156    ) {
 3157        if state.changed {
 3158            self.selection_history.push(state.history_entry);
 3159
 3160            if let Some(autoscroll) = state.effects.scroll {
 3161                self.request_autoscroll(autoscroll, cx);
 3162            }
 3163
 3164            let old_cursor_position = &state.old_cursor_position;
 3165
 3166            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3167
 3168            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3169                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3170            }
 3171        }
 3172    }
 3173
 3174    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3175    where
 3176        I: IntoIterator<Item = (Range<S>, T)>,
 3177        S: ToOffset,
 3178        T: Into<Arc<str>>,
 3179    {
 3180        if self.read_only(cx) {
 3181            return;
 3182        }
 3183
 3184        self.buffer
 3185            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3186    }
 3187
 3188    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3189    where
 3190        I: IntoIterator<Item = (Range<S>, T)>,
 3191        S: ToOffset,
 3192        T: Into<Arc<str>>,
 3193    {
 3194        if self.read_only(cx) {
 3195            return;
 3196        }
 3197
 3198        self.buffer.update(cx, |buffer, cx| {
 3199            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3200        });
 3201    }
 3202
 3203    pub fn edit_with_block_indent<I, S, T>(
 3204        &mut self,
 3205        edits: I,
 3206        original_indent_columns: Vec<Option<u32>>,
 3207        cx: &mut Context<Self>,
 3208    ) where
 3209        I: IntoIterator<Item = (Range<S>, T)>,
 3210        S: ToOffset,
 3211        T: Into<Arc<str>>,
 3212    {
 3213        if self.read_only(cx) {
 3214            return;
 3215        }
 3216
 3217        self.buffer.update(cx, |buffer, cx| {
 3218            buffer.edit(
 3219                edits,
 3220                Some(AutoindentMode::Block {
 3221                    original_indent_columns,
 3222                }),
 3223                cx,
 3224            )
 3225        });
 3226    }
 3227
 3228    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3229        self.hide_context_menu(window, cx);
 3230
 3231        match phase {
 3232            SelectPhase::Begin {
 3233                position,
 3234                add,
 3235                click_count,
 3236            } => self.begin_selection(position, add, click_count, window, cx),
 3237            SelectPhase::BeginColumnar {
 3238                position,
 3239                goal_column,
 3240                reset,
 3241                mode,
 3242            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3243            SelectPhase::Extend {
 3244                position,
 3245                click_count,
 3246            } => self.extend_selection(position, click_count, window, cx),
 3247            SelectPhase::Update {
 3248                position,
 3249                goal_column,
 3250                scroll_delta,
 3251            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3252            SelectPhase::End => self.end_selection(window, cx),
 3253        }
 3254    }
 3255
 3256    fn extend_selection(
 3257        &mut self,
 3258        position: DisplayPoint,
 3259        click_count: usize,
 3260        window: &mut Window,
 3261        cx: &mut Context<Self>,
 3262    ) {
 3263        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3264        let tail = self.selections.newest::<usize>(cx).tail();
 3265        self.begin_selection(position, false, click_count, window, cx);
 3266
 3267        let position = position.to_offset(&display_map, Bias::Left);
 3268        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3269
 3270        let mut pending_selection = self
 3271            .selections
 3272            .pending_anchor()
 3273            .expect("extend_selection not called with pending selection");
 3274        if position >= tail {
 3275            pending_selection.start = tail_anchor;
 3276        } else {
 3277            pending_selection.end = tail_anchor;
 3278            pending_selection.reversed = true;
 3279        }
 3280
 3281        let mut pending_mode = self.selections.pending_mode().unwrap();
 3282        match &mut pending_mode {
 3283            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3284            _ => {}
 3285        }
 3286
 3287        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3288            SelectionEffects::scroll(Autoscroll::fit())
 3289        } else {
 3290            SelectionEffects::no_scroll()
 3291        };
 3292
 3293        self.change_selections(effects, window, cx, |s| {
 3294            s.set_pending(pending_selection, pending_mode)
 3295        });
 3296    }
 3297
 3298    fn begin_selection(
 3299        &mut self,
 3300        position: DisplayPoint,
 3301        add: bool,
 3302        click_count: usize,
 3303        window: &mut Window,
 3304        cx: &mut Context<Self>,
 3305    ) {
 3306        if !self.focus_handle.is_focused(window) {
 3307            self.last_focused_descendant = None;
 3308            window.focus(&self.focus_handle);
 3309        }
 3310
 3311        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3312        let buffer = &display_map.buffer_snapshot;
 3313        let position = display_map.clip_point(position, Bias::Left);
 3314
 3315        let start;
 3316        let end;
 3317        let mode;
 3318        let mut auto_scroll;
 3319        match click_count {
 3320            1 => {
 3321                start = buffer.anchor_before(position.to_point(&display_map));
 3322                end = start;
 3323                mode = SelectMode::Character;
 3324                auto_scroll = true;
 3325            }
 3326            2 => {
 3327                let range = movement::surrounding_word(&display_map, position);
 3328                start = buffer.anchor_before(range.start.to_point(&display_map));
 3329                end = buffer.anchor_before(range.end.to_point(&display_map));
 3330                mode = SelectMode::Word(start..end);
 3331                auto_scroll = true;
 3332            }
 3333            3 => {
 3334                let position = display_map
 3335                    .clip_point(position, Bias::Left)
 3336                    .to_point(&display_map);
 3337                let line_start = display_map.prev_line_boundary(position).0;
 3338                let next_line_start = buffer.clip_point(
 3339                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3340                    Bias::Left,
 3341                );
 3342                start = buffer.anchor_before(line_start);
 3343                end = buffer.anchor_before(next_line_start);
 3344                mode = SelectMode::Line(start..end);
 3345                auto_scroll = true;
 3346            }
 3347            _ => {
 3348                start = buffer.anchor_before(0);
 3349                end = buffer.anchor_before(buffer.len());
 3350                mode = SelectMode::All;
 3351                auto_scroll = false;
 3352            }
 3353        }
 3354        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3355
 3356        let point_to_delete: Option<usize> = {
 3357            let selected_points: Vec<Selection<Point>> =
 3358                self.selections.disjoint_in_range(start..end, cx);
 3359
 3360            if !add || click_count > 1 {
 3361                None
 3362            } else if !selected_points.is_empty() {
 3363                Some(selected_points[0].id)
 3364            } else {
 3365                let clicked_point_already_selected =
 3366                    self.selections.disjoint.iter().find(|selection| {
 3367                        selection.start.to_point(buffer) == start.to_point(buffer)
 3368                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3369                    });
 3370
 3371                clicked_point_already_selected.map(|selection| selection.id)
 3372            }
 3373        };
 3374
 3375        let selections_count = self.selections.count();
 3376
 3377        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3378            if let Some(point_to_delete) = point_to_delete {
 3379                s.delete(point_to_delete);
 3380
 3381                if selections_count == 1 {
 3382                    s.set_pending_anchor_range(start..end, mode);
 3383                }
 3384            } else {
 3385                if !add {
 3386                    s.clear_disjoint();
 3387                }
 3388
 3389                s.set_pending_anchor_range(start..end, mode);
 3390            }
 3391        });
 3392    }
 3393
 3394    fn begin_columnar_selection(
 3395        &mut self,
 3396        position: DisplayPoint,
 3397        goal_column: u32,
 3398        reset: bool,
 3399        mode: ColumnarMode,
 3400        window: &mut Window,
 3401        cx: &mut Context<Self>,
 3402    ) {
 3403        if !self.focus_handle.is_focused(window) {
 3404            self.last_focused_descendant = None;
 3405            window.focus(&self.focus_handle);
 3406        }
 3407
 3408        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3409
 3410        if reset {
 3411            let pointer_position = display_map
 3412                .buffer_snapshot
 3413                .anchor_before(position.to_point(&display_map));
 3414
 3415            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3416                s.clear_disjoint();
 3417                s.set_pending_anchor_range(
 3418                    pointer_position..pointer_position,
 3419                    SelectMode::Character,
 3420                );
 3421            });
 3422        };
 3423
 3424        let tail = self.selections.newest::<Point>(cx).tail();
 3425        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3426        self.columnar_selection_state = match mode {
 3427            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3428                selection_tail: selection_anchor,
 3429                display_point: if reset {
 3430                    if position.column() != goal_column {
 3431                        Some(DisplayPoint::new(position.row(), goal_column))
 3432                    } else {
 3433                        None
 3434                    }
 3435                } else {
 3436                    None
 3437                },
 3438            }),
 3439            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3440                selection_tail: selection_anchor,
 3441            }),
 3442        };
 3443
 3444        if !reset {
 3445            self.select_columns(position, goal_column, &display_map, window, cx);
 3446        }
 3447    }
 3448
 3449    fn update_selection(
 3450        &mut self,
 3451        position: DisplayPoint,
 3452        goal_column: u32,
 3453        scroll_delta: gpui::Point<f32>,
 3454        window: &mut Window,
 3455        cx: &mut Context<Self>,
 3456    ) {
 3457        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3458
 3459        if self.columnar_selection_state.is_some() {
 3460            self.select_columns(position, goal_column, &display_map, window, cx);
 3461        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3462            let buffer = self.buffer.read(cx).snapshot(cx);
 3463            let head;
 3464            let tail;
 3465            let mode = self.selections.pending_mode().unwrap();
 3466            match &mode {
 3467                SelectMode::Character => {
 3468                    head = position.to_point(&display_map);
 3469                    tail = pending.tail().to_point(&buffer);
 3470                }
 3471                SelectMode::Word(original_range) => {
 3472                    let original_display_range = original_range.start.to_display_point(&display_map)
 3473                        ..original_range.end.to_display_point(&display_map);
 3474                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3475                        ..original_display_range.end.to_point(&display_map);
 3476                    if movement::is_inside_word(&display_map, position)
 3477                        || original_display_range.contains(&position)
 3478                    {
 3479                        let word_range = movement::surrounding_word(&display_map, position);
 3480                        if word_range.start < original_display_range.start {
 3481                            head = word_range.start.to_point(&display_map);
 3482                        } else {
 3483                            head = word_range.end.to_point(&display_map);
 3484                        }
 3485                    } else {
 3486                        head = position.to_point(&display_map);
 3487                    }
 3488
 3489                    if head <= original_buffer_range.start {
 3490                        tail = original_buffer_range.end;
 3491                    } else {
 3492                        tail = original_buffer_range.start;
 3493                    }
 3494                }
 3495                SelectMode::Line(original_range) => {
 3496                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3497
 3498                    let position = display_map
 3499                        .clip_point(position, Bias::Left)
 3500                        .to_point(&display_map);
 3501                    let line_start = display_map.prev_line_boundary(position).0;
 3502                    let next_line_start = buffer.clip_point(
 3503                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3504                        Bias::Left,
 3505                    );
 3506
 3507                    if line_start < original_range.start {
 3508                        head = line_start
 3509                    } else {
 3510                        head = next_line_start
 3511                    }
 3512
 3513                    if head <= original_range.start {
 3514                        tail = original_range.end;
 3515                    } else {
 3516                        tail = original_range.start;
 3517                    }
 3518                }
 3519                SelectMode::All => {
 3520                    return;
 3521                }
 3522            };
 3523
 3524            if head < tail {
 3525                pending.start = buffer.anchor_before(head);
 3526                pending.end = buffer.anchor_before(tail);
 3527                pending.reversed = true;
 3528            } else {
 3529                pending.start = buffer.anchor_before(tail);
 3530                pending.end = buffer.anchor_before(head);
 3531                pending.reversed = false;
 3532            }
 3533
 3534            self.change_selections(None, window, cx, |s| {
 3535                s.set_pending(pending, mode);
 3536            });
 3537        } else {
 3538            log::error!("update_selection dispatched with no pending selection");
 3539            return;
 3540        }
 3541
 3542        self.apply_scroll_delta(scroll_delta, window, cx);
 3543        cx.notify();
 3544    }
 3545
 3546    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3547        self.columnar_selection_state.take();
 3548        if self.selections.pending_anchor().is_some() {
 3549            let selections = self.selections.all::<usize>(cx);
 3550            self.change_selections(None, window, cx, |s| {
 3551                s.select(selections);
 3552                s.clear_pending();
 3553            });
 3554        }
 3555    }
 3556
 3557    fn select_columns(
 3558        &mut self,
 3559        head: DisplayPoint,
 3560        goal_column: u32,
 3561        display_map: &DisplaySnapshot,
 3562        window: &mut Window,
 3563        cx: &mut Context<Self>,
 3564    ) {
 3565        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3566            return;
 3567        };
 3568
 3569        let tail = match columnar_state {
 3570            ColumnarSelectionState::FromMouse {
 3571                selection_tail,
 3572                display_point,
 3573            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3574            ColumnarSelectionState::FromSelection { selection_tail } => {
 3575                selection_tail.to_display_point(&display_map)
 3576            }
 3577        };
 3578
 3579        let start_row = cmp::min(tail.row(), head.row());
 3580        let end_row = cmp::max(tail.row(), head.row());
 3581        let start_column = cmp::min(tail.column(), goal_column);
 3582        let end_column = cmp::max(tail.column(), goal_column);
 3583        let reversed = start_column < tail.column();
 3584
 3585        let selection_ranges = (start_row.0..=end_row.0)
 3586            .map(DisplayRow)
 3587            .filter_map(|row| {
 3588                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3589                    || start_column <= display_map.line_len(row))
 3590                    && !display_map.is_block_line(row)
 3591                {
 3592                    let start = display_map
 3593                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3594                        .to_point(display_map);
 3595                    let end = display_map
 3596                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3597                        .to_point(display_map);
 3598                    if reversed {
 3599                        Some(end..start)
 3600                    } else {
 3601                        Some(start..end)
 3602                    }
 3603                } else {
 3604                    None
 3605                }
 3606            })
 3607            .collect::<Vec<_>>();
 3608
 3609        let ranges = match columnar_state {
 3610            ColumnarSelectionState::FromMouse { .. } => {
 3611                let mut non_empty_ranges = selection_ranges
 3612                    .iter()
 3613                    .filter(|selection_range| selection_range.start != selection_range.end)
 3614                    .peekable();
 3615                if non_empty_ranges.peek().is_some() {
 3616                    non_empty_ranges.cloned().collect()
 3617                } else {
 3618                    selection_ranges
 3619                }
 3620            }
 3621            _ => selection_ranges,
 3622        };
 3623
 3624        self.change_selections(None, window, cx, |s| {
 3625            s.select_ranges(ranges);
 3626        });
 3627        cx.notify();
 3628    }
 3629
 3630    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3631        self.selections
 3632            .all_adjusted(cx)
 3633            .iter()
 3634            .any(|selection| !selection.is_empty())
 3635    }
 3636
 3637    pub fn has_pending_nonempty_selection(&self) -> bool {
 3638        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3639            Some(Selection { start, end, .. }) => start != end,
 3640            None => false,
 3641        };
 3642
 3643        pending_nonempty_selection
 3644            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3645    }
 3646
 3647    pub fn has_pending_selection(&self) -> bool {
 3648        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3649    }
 3650
 3651    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3652        self.selection_mark_mode = false;
 3653        self.selection_drag_state = SelectionDragState::None;
 3654
 3655        if self.clear_expanded_diff_hunks(cx) {
 3656            cx.notify();
 3657            return;
 3658        }
 3659        if self.dismiss_menus_and_popups(true, window, cx) {
 3660            return;
 3661        }
 3662
 3663        if self.mode.is_full()
 3664            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3665        {
 3666            return;
 3667        }
 3668
 3669        cx.propagate();
 3670    }
 3671
 3672    pub fn dismiss_menus_and_popups(
 3673        &mut self,
 3674        is_user_requested: bool,
 3675        window: &mut Window,
 3676        cx: &mut Context<Self>,
 3677    ) -> bool {
 3678        if self.take_rename(false, window, cx).is_some() {
 3679            return true;
 3680        }
 3681
 3682        if hide_hover(self, cx) {
 3683            return true;
 3684        }
 3685
 3686        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3687            return true;
 3688        }
 3689
 3690        if self.hide_context_menu(window, cx).is_some() {
 3691            return true;
 3692        }
 3693
 3694        if self.mouse_context_menu.take().is_some() {
 3695            return true;
 3696        }
 3697
 3698        if is_user_requested && self.discard_inline_completion(true, cx) {
 3699            return true;
 3700        }
 3701
 3702        if self.snippet_stack.pop().is_some() {
 3703            return true;
 3704        }
 3705
 3706        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3707            self.dismiss_diagnostics(cx);
 3708            return true;
 3709        }
 3710
 3711        false
 3712    }
 3713
 3714    fn linked_editing_ranges_for(
 3715        &self,
 3716        selection: Range<text::Anchor>,
 3717        cx: &App,
 3718    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3719        if self.linked_edit_ranges.is_empty() {
 3720            return None;
 3721        }
 3722        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3723            selection.end.buffer_id.and_then(|end_buffer_id| {
 3724                if selection.start.buffer_id != Some(end_buffer_id) {
 3725                    return None;
 3726                }
 3727                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3728                let snapshot = buffer.read(cx).snapshot();
 3729                self.linked_edit_ranges
 3730                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3731                    .map(|ranges| (ranges, snapshot, buffer))
 3732            })?;
 3733        use text::ToOffset as TO;
 3734        // find offset from the start of current range to current cursor position
 3735        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3736
 3737        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3738        let start_difference = start_offset - start_byte_offset;
 3739        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3740        let end_difference = end_offset - start_byte_offset;
 3741        // Current range has associated linked ranges.
 3742        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3743        for range in linked_ranges.iter() {
 3744            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3745            let end_offset = start_offset + end_difference;
 3746            let start_offset = start_offset + start_difference;
 3747            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3748                continue;
 3749            }
 3750            if self.selections.disjoint_anchor_ranges().any(|s| {
 3751                if s.start.buffer_id != selection.start.buffer_id
 3752                    || s.end.buffer_id != selection.end.buffer_id
 3753                {
 3754                    return false;
 3755                }
 3756                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3757                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3758            }) {
 3759                continue;
 3760            }
 3761            let start = buffer_snapshot.anchor_after(start_offset);
 3762            let end = buffer_snapshot.anchor_after(end_offset);
 3763            linked_edits
 3764                .entry(buffer.clone())
 3765                .or_default()
 3766                .push(start..end);
 3767        }
 3768        Some(linked_edits)
 3769    }
 3770
 3771    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3772        let text: Arc<str> = text.into();
 3773
 3774        if self.read_only(cx) {
 3775            return;
 3776        }
 3777
 3778        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3779
 3780        let selections = self.selections.all_adjusted(cx);
 3781        let mut bracket_inserted = false;
 3782        let mut edits = Vec::new();
 3783        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3784        let mut new_selections = Vec::with_capacity(selections.len());
 3785        let mut new_autoclose_regions = Vec::new();
 3786        let snapshot = self.buffer.read(cx).read(cx);
 3787        let mut clear_linked_edit_ranges = false;
 3788
 3789        for (selection, autoclose_region) in
 3790            self.selections_with_autoclose_regions(selections, &snapshot)
 3791        {
 3792            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3793                // Determine if the inserted text matches the opening or closing
 3794                // bracket of any of this language's bracket pairs.
 3795                let mut bracket_pair = None;
 3796                let mut is_bracket_pair_start = false;
 3797                let mut is_bracket_pair_end = false;
 3798                if !text.is_empty() {
 3799                    let mut bracket_pair_matching_end = None;
 3800                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3801                    //  and they are removing the character that triggered IME popup.
 3802                    for (pair, enabled) in scope.brackets() {
 3803                        if !pair.close && !pair.surround {
 3804                            continue;
 3805                        }
 3806
 3807                        if enabled && pair.start.ends_with(text.as_ref()) {
 3808                            let prefix_len = pair.start.len() - text.len();
 3809                            let preceding_text_matches_prefix = prefix_len == 0
 3810                                || (selection.start.column >= (prefix_len as u32)
 3811                                    && snapshot.contains_str_at(
 3812                                        Point::new(
 3813                                            selection.start.row,
 3814                                            selection.start.column - (prefix_len as u32),
 3815                                        ),
 3816                                        &pair.start[..prefix_len],
 3817                                    ));
 3818                            if preceding_text_matches_prefix {
 3819                                bracket_pair = Some(pair.clone());
 3820                                is_bracket_pair_start = true;
 3821                                break;
 3822                            }
 3823                        }
 3824                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3825                        {
 3826                            // take first bracket pair matching end, but don't break in case a later bracket
 3827                            // pair matches start
 3828                            bracket_pair_matching_end = Some(pair.clone());
 3829                        }
 3830                    }
 3831                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3832                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3833                        is_bracket_pair_end = true;
 3834                    }
 3835                }
 3836
 3837                if let Some(bracket_pair) = bracket_pair {
 3838                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3839                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3840                    let auto_surround =
 3841                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3842                    if selection.is_empty() {
 3843                        if is_bracket_pair_start {
 3844                            // If the inserted text is a suffix of an opening bracket and the
 3845                            // selection is preceded by the rest of the opening bracket, then
 3846                            // insert the closing bracket.
 3847                            let following_text_allows_autoclose = snapshot
 3848                                .chars_at(selection.start)
 3849                                .next()
 3850                                .map_or(true, |c| scope.should_autoclose_before(c));
 3851
 3852                            let preceding_text_allows_autoclose = selection.start.column == 0
 3853                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3854                                    true,
 3855                                    |c| {
 3856                                        bracket_pair.start != bracket_pair.end
 3857                                            || !snapshot
 3858                                                .char_classifier_at(selection.start)
 3859                                                .is_word(c)
 3860                                    },
 3861                                );
 3862
 3863                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3864                                && bracket_pair.start.len() == 1
 3865                            {
 3866                                let target = bracket_pair.start.chars().next().unwrap();
 3867                                let current_line_count = snapshot
 3868                                    .reversed_chars_at(selection.start)
 3869                                    .take_while(|&c| c != '\n')
 3870                                    .filter(|&c| c == target)
 3871                                    .count();
 3872                                current_line_count % 2 == 1
 3873                            } else {
 3874                                false
 3875                            };
 3876
 3877                            if autoclose
 3878                                && bracket_pair.close
 3879                                && following_text_allows_autoclose
 3880                                && preceding_text_allows_autoclose
 3881                                && !is_closing_quote
 3882                            {
 3883                                let anchor = snapshot.anchor_before(selection.end);
 3884                                new_selections.push((selection.map(|_| anchor), text.len()));
 3885                                new_autoclose_regions.push((
 3886                                    anchor,
 3887                                    text.len(),
 3888                                    selection.id,
 3889                                    bracket_pair.clone(),
 3890                                ));
 3891                                edits.push((
 3892                                    selection.range(),
 3893                                    format!("{}{}", text, bracket_pair.end).into(),
 3894                                ));
 3895                                bracket_inserted = true;
 3896                                continue;
 3897                            }
 3898                        }
 3899
 3900                        if let Some(region) = autoclose_region {
 3901                            // If the selection is followed by an auto-inserted closing bracket,
 3902                            // then don't insert that closing bracket again; just move the selection
 3903                            // past the closing bracket.
 3904                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3905                                && text.as_ref() == region.pair.end.as_str();
 3906                            if should_skip {
 3907                                let anchor = snapshot.anchor_after(selection.end);
 3908                                new_selections
 3909                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3910                                continue;
 3911                            }
 3912                        }
 3913
 3914                        let always_treat_brackets_as_autoclosed = snapshot
 3915                            .language_settings_at(selection.start, cx)
 3916                            .always_treat_brackets_as_autoclosed;
 3917                        if always_treat_brackets_as_autoclosed
 3918                            && is_bracket_pair_end
 3919                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3920                        {
 3921                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3922                            // and the inserted text is a closing bracket and the selection is followed
 3923                            // by the closing bracket then move the selection past the closing bracket.
 3924                            let anchor = snapshot.anchor_after(selection.end);
 3925                            new_selections.push((selection.map(|_| anchor), text.len()));
 3926                            continue;
 3927                        }
 3928                    }
 3929                    // If an opening bracket is 1 character long and is typed while
 3930                    // text is selected, then surround that text with the bracket pair.
 3931                    else if auto_surround
 3932                        && bracket_pair.surround
 3933                        && is_bracket_pair_start
 3934                        && bracket_pair.start.chars().count() == 1
 3935                    {
 3936                        edits.push((selection.start..selection.start, text.clone()));
 3937                        edits.push((
 3938                            selection.end..selection.end,
 3939                            bracket_pair.end.as_str().into(),
 3940                        ));
 3941                        bracket_inserted = true;
 3942                        new_selections.push((
 3943                            Selection {
 3944                                id: selection.id,
 3945                                start: snapshot.anchor_after(selection.start),
 3946                                end: snapshot.anchor_before(selection.end),
 3947                                reversed: selection.reversed,
 3948                                goal: selection.goal,
 3949                            },
 3950                            0,
 3951                        ));
 3952                        continue;
 3953                    }
 3954                }
 3955            }
 3956
 3957            if self.auto_replace_emoji_shortcode
 3958                && selection.is_empty()
 3959                && text.as_ref().ends_with(':')
 3960            {
 3961                if let Some(possible_emoji_short_code) =
 3962                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3963                {
 3964                    if !possible_emoji_short_code.is_empty() {
 3965                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3966                            let emoji_shortcode_start = Point::new(
 3967                                selection.start.row,
 3968                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3969                            );
 3970
 3971                            // Remove shortcode from buffer
 3972                            edits.push((
 3973                                emoji_shortcode_start..selection.start,
 3974                                "".to_string().into(),
 3975                            ));
 3976                            new_selections.push((
 3977                                Selection {
 3978                                    id: selection.id,
 3979                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3980                                    end: snapshot.anchor_before(selection.start),
 3981                                    reversed: selection.reversed,
 3982                                    goal: selection.goal,
 3983                                },
 3984                                0,
 3985                            ));
 3986
 3987                            // Insert emoji
 3988                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3989                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3990                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3991
 3992                            continue;
 3993                        }
 3994                    }
 3995                }
 3996            }
 3997
 3998            // If not handling any auto-close operation, then just replace the selected
 3999            // text with the given input and move the selection to the end of the
 4000            // newly inserted text.
 4001            let anchor = snapshot.anchor_after(selection.end);
 4002            if !self.linked_edit_ranges.is_empty() {
 4003                let start_anchor = snapshot.anchor_before(selection.start);
 4004
 4005                let is_word_char = text.chars().next().map_or(true, |char| {
 4006                    let classifier = snapshot
 4007                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4008                        .ignore_punctuation(true);
 4009                    classifier.is_word(char)
 4010                });
 4011
 4012                if is_word_char {
 4013                    if let Some(ranges) = self
 4014                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4015                    {
 4016                        for (buffer, edits) in ranges {
 4017                            linked_edits
 4018                                .entry(buffer.clone())
 4019                                .or_default()
 4020                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4021                        }
 4022                    }
 4023                } else {
 4024                    clear_linked_edit_ranges = true;
 4025                }
 4026            }
 4027
 4028            new_selections.push((selection.map(|_| anchor), 0));
 4029            edits.push((selection.start..selection.end, text.clone()));
 4030        }
 4031
 4032        drop(snapshot);
 4033
 4034        self.transact(window, cx, |this, window, cx| {
 4035            if clear_linked_edit_ranges {
 4036                this.linked_edit_ranges.clear();
 4037            }
 4038            let initial_buffer_versions =
 4039                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4040
 4041            this.buffer.update(cx, |buffer, cx| {
 4042                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4043            });
 4044            for (buffer, edits) in linked_edits {
 4045                buffer.update(cx, |buffer, cx| {
 4046                    let snapshot = buffer.snapshot();
 4047                    let edits = edits
 4048                        .into_iter()
 4049                        .map(|(range, text)| {
 4050                            use text::ToPoint as TP;
 4051                            let end_point = TP::to_point(&range.end, &snapshot);
 4052                            let start_point = TP::to_point(&range.start, &snapshot);
 4053                            (start_point..end_point, text)
 4054                        })
 4055                        .sorted_by_key(|(range, _)| range.start);
 4056                    buffer.edit(edits, None, cx);
 4057                })
 4058            }
 4059            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4060            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4061            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4062            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4063                .zip(new_selection_deltas)
 4064                .map(|(selection, delta)| Selection {
 4065                    id: selection.id,
 4066                    start: selection.start + delta,
 4067                    end: selection.end + delta,
 4068                    reversed: selection.reversed,
 4069                    goal: SelectionGoal::None,
 4070                })
 4071                .collect::<Vec<_>>();
 4072
 4073            let mut i = 0;
 4074            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4075                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4076                let start = map.buffer_snapshot.anchor_before(position);
 4077                let end = map.buffer_snapshot.anchor_after(position);
 4078                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4079                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4080                        Ordering::Less => i += 1,
 4081                        Ordering::Greater => break,
 4082                        Ordering::Equal => {
 4083                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4084                                Ordering::Less => i += 1,
 4085                                Ordering::Equal => break,
 4086                                Ordering::Greater => break,
 4087                            }
 4088                        }
 4089                    }
 4090                }
 4091                this.autoclose_regions.insert(
 4092                    i,
 4093                    AutocloseRegion {
 4094                        selection_id,
 4095                        range: start..end,
 4096                        pair,
 4097                    },
 4098                );
 4099            }
 4100
 4101            let had_active_inline_completion = this.has_active_inline_completion();
 4102            this.change_selections(
 4103                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4104                window,
 4105                cx,
 4106                |s| s.select(new_selections),
 4107            );
 4108
 4109            if !bracket_inserted {
 4110                if let Some(on_type_format_task) =
 4111                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4112                {
 4113                    on_type_format_task.detach_and_log_err(cx);
 4114                }
 4115            }
 4116
 4117            let editor_settings = EditorSettings::get_global(cx);
 4118            if bracket_inserted
 4119                && (editor_settings.auto_signature_help
 4120                    || editor_settings.show_signature_help_after_edits)
 4121            {
 4122                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4123            }
 4124
 4125            let trigger_in_words =
 4126                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4127            if this.hard_wrap.is_some() {
 4128                let latest: Range<Point> = this.selections.newest(cx).range();
 4129                if latest.is_empty()
 4130                    && this
 4131                        .buffer()
 4132                        .read(cx)
 4133                        .snapshot(cx)
 4134                        .line_len(MultiBufferRow(latest.start.row))
 4135                        == latest.start.column
 4136                {
 4137                    this.rewrap_impl(
 4138                        RewrapOptions {
 4139                            override_language_settings: true,
 4140                            preserve_existing_whitespace: true,
 4141                        },
 4142                        cx,
 4143                    )
 4144                }
 4145            }
 4146            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4147            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4148            this.refresh_inline_completion(true, false, window, cx);
 4149            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4150        });
 4151    }
 4152
 4153    fn find_possible_emoji_shortcode_at_position(
 4154        snapshot: &MultiBufferSnapshot,
 4155        position: Point,
 4156    ) -> Option<String> {
 4157        let mut chars = Vec::new();
 4158        let mut found_colon = false;
 4159        for char in snapshot.reversed_chars_at(position).take(100) {
 4160            // Found a possible emoji shortcode in the middle of the buffer
 4161            if found_colon {
 4162                if char.is_whitespace() {
 4163                    chars.reverse();
 4164                    return Some(chars.iter().collect());
 4165                }
 4166                // If the previous character is not a whitespace, we are in the middle of a word
 4167                // and we only want to complete the shortcode if the word is made up of other emojis
 4168                let mut containing_word = String::new();
 4169                for ch in snapshot
 4170                    .reversed_chars_at(position)
 4171                    .skip(chars.len() + 1)
 4172                    .take(100)
 4173                {
 4174                    if ch.is_whitespace() {
 4175                        break;
 4176                    }
 4177                    containing_word.push(ch);
 4178                }
 4179                let containing_word = containing_word.chars().rev().collect::<String>();
 4180                if util::word_consists_of_emojis(containing_word.as_str()) {
 4181                    chars.reverse();
 4182                    return Some(chars.iter().collect());
 4183                }
 4184            }
 4185
 4186            if char.is_whitespace() || !char.is_ascii() {
 4187                return None;
 4188            }
 4189            if char == ':' {
 4190                found_colon = true;
 4191            } else {
 4192                chars.push(char);
 4193            }
 4194        }
 4195        // Found a possible emoji shortcode at the beginning of the buffer
 4196        chars.reverse();
 4197        Some(chars.iter().collect())
 4198    }
 4199
 4200    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4201        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4202        self.transact(window, cx, |this, window, cx| {
 4203            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4204                let selections = this.selections.all::<usize>(cx);
 4205                let multi_buffer = this.buffer.read(cx);
 4206                let buffer = multi_buffer.snapshot(cx);
 4207                selections
 4208                    .iter()
 4209                    .map(|selection| {
 4210                        let start_point = selection.start.to_point(&buffer);
 4211                        let mut existing_indent =
 4212                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4213                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4214                        let start = selection.start;
 4215                        let end = selection.end;
 4216                        let selection_is_empty = start == end;
 4217                        let language_scope = buffer.language_scope_at(start);
 4218                        let (
 4219                            comment_delimiter,
 4220                            doc_delimiter,
 4221                            insert_extra_newline,
 4222                            indent_on_newline,
 4223                            indent_on_extra_newline,
 4224                        ) = if let Some(language) = &language_scope {
 4225                            let mut insert_extra_newline =
 4226                                insert_extra_newline_brackets(&buffer, start..end, language)
 4227                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4228
 4229                            // Comment extension on newline is allowed only for cursor selections
 4230                            let comment_delimiter = maybe!({
 4231                                if !selection_is_empty {
 4232                                    return None;
 4233                                }
 4234
 4235                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4236                                    return None;
 4237                                }
 4238
 4239                                let delimiters = language.line_comment_prefixes();
 4240                                let max_len_of_delimiter =
 4241                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4242                                let (snapshot, range) =
 4243                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4244
 4245                                let num_of_whitespaces = snapshot
 4246                                    .chars_for_range(range.clone())
 4247                                    .take_while(|c| c.is_whitespace())
 4248                                    .count();
 4249                                let comment_candidate = snapshot
 4250                                    .chars_for_range(range)
 4251                                    .skip(num_of_whitespaces)
 4252                                    .take(max_len_of_delimiter)
 4253                                    .collect::<String>();
 4254                                let (delimiter, trimmed_len) = delimiters
 4255                                    .iter()
 4256                                    .filter_map(|delimiter| {
 4257                                        let prefix = delimiter.trim_end();
 4258                                        if comment_candidate.starts_with(prefix) {
 4259                                            Some((delimiter, prefix.len()))
 4260                                        } else {
 4261                                            None
 4262                                        }
 4263                                    })
 4264                                    .max_by_key(|(_, len)| *len)?;
 4265
 4266                                let cursor_is_placed_after_comment_marker =
 4267                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4268                                if cursor_is_placed_after_comment_marker {
 4269                                    Some(delimiter.clone())
 4270                                } else {
 4271                                    None
 4272                                }
 4273                            });
 4274
 4275                            let mut indent_on_newline = IndentSize::spaces(0);
 4276                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4277
 4278                            let doc_delimiter = maybe!({
 4279                                if !selection_is_empty {
 4280                                    return None;
 4281                                }
 4282
 4283                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4284                                    return None;
 4285                                }
 4286
 4287                                let DocumentationConfig {
 4288                                    start: start_tag,
 4289                                    end: end_tag,
 4290                                    prefix: delimiter,
 4291                                    tab_size: len,
 4292                                } = language.documentation()?;
 4293
 4294                                let is_within_block_comment = buffer
 4295                                    .language_scope_at(start_point)
 4296                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4297                                if !is_within_block_comment {
 4298                                    return None;
 4299                                }
 4300
 4301                                let (snapshot, range) =
 4302                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4303
 4304                                let num_of_whitespaces = snapshot
 4305                                    .chars_for_range(range.clone())
 4306                                    .take_while(|c| c.is_whitespace())
 4307                                    .count();
 4308
 4309                                // 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.
 4310                                let column = start_point.column;
 4311                                let cursor_is_after_start_tag = {
 4312                                    let start_tag_len = start_tag.len();
 4313                                    let start_tag_line = snapshot
 4314                                        .chars_for_range(range.clone())
 4315                                        .skip(num_of_whitespaces)
 4316                                        .take(start_tag_len)
 4317                                        .collect::<String>();
 4318                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4319                                        num_of_whitespaces + start_tag_len <= column as usize
 4320                                    } else {
 4321                                        false
 4322                                    }
 4323                                };
 4324
 4325                                let cursor_is_after_delimiter = {
 4326                                    let delimiter_trim = delimiter.trim_end();
 4327                                    let delimiter_line = snapshot
 4328                                        .chars_for_range(range.clone())
 4329                                        .skip(num_of_whitespaces)
 4330                                        .take(delimiter_trim.len())
 4331                                        .collect::<String>();
 4332                                    if delimiter_line.starts_with(delimiter_trim) {
 4333                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4334                                    } else {
 4335                                        false
 4336                                    }
 4337                                };
 4338
 4339                                let cursor_is_before_end_tag_if_exists = {
 4340                                    let mut char_position = 0u32;
 4341                                    let mut end_tag_offset = None;
 4342
 4343                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4344                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4345                                            let chars_before_match =
 4346                                                chunk[..byte_pos].chars().count() as u32;
 4347                                            end_tag_offset =
 4348                                                Some(char_position + chars_before_match);
 4349                                            break 'outer;
 4350                                        }
 4351                                        char_position += chunk.chars().count() as u32;
 4352                                    }
 4353
 4354                                    if let Some(end_tag_offset) = end_tag_offset {
 4355                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4356                                        if cursor_is_after_start_tag {
 4357                                            if cursor_is_before_end_tag {
 4358                                                insert_extra_newline = true;
 4359                                            }
 4360                                            let cursor_is_at_start_of_end_tag =
 4361                                                column == end_tag_offset;
 4362                                            if cursor_is_at_start_of_end_tag {
 4363                                                indent_on_extra_newline.len = (*len).into();
 4364                                            }
 4365                                        }
 4366                                        cursor_is_before_end_tag
 4367                                    } else {
 4368                                        true
 4369                                    }
 4370                                };
 4371
 4372                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4373                                    && cursor_is_before_end_tag_if_exists
 4374                                {
 4375                                    if cursor_is_after_start_tag {
 4376                                        indent_on_newline.len = (*len).into();
 4377                                    }
 4378                                    Some(delimiter.clone())
 4379                                } else {
 4380                                    None
 4381                                }
 4382                            });
 4383
 4384                            (
 4385                                comment_delimiter,
 4386                                doc_delimiter,
 4387                                insert_extra_newline,
 4388                                indent_on_newline,
 4389                                indent_on_extra_newline,
 4390                            )
 4391                        } else {
 4392                            (
 4393                                None,
 4394                                None,
 4395                                false,
 4396                                IndentSize::default(),
 4397                                IndentSize::default(),
 4398                            )
 4399                        };
 4400
 4401                        let prevent_auto_indent = doc_delimiter.is_some();
 4402                        let delimiter = comment_delimiter.or(doc_delimiter);
 4403
 4404                        let capacity_for_delimiter =
 4405                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4406                        let mut new_text = String::with_capacity(
 4407                            1 + capacity_for_delimiter
 4408                                + existing_indent.len as usize
 4409                                + indent_on_newline.len as usize
 4410                                + indent_on_extra_newline.len as usize,
 4411                        );
 4412                        new_text.push('\n');
 4413                        new_text.extend(existing_indent.chars());
 4414                        new_text.extend(indent_on_newline.chars());
 4415
 4416                        if let Some(delimiter) = &delimiter {
 4417                            new_text.push_str(delimiter);
 4418                        }
 4419
 4420                        if insert_extra_newline {
 4421                            new_text.push('\n');
 4422                            new_text.extend(existing_indent.chars());
 4423                            new_text.extend(indent_on_extra_newline.chars());
 4424                        }
 4425
 4426                        let anchor = buffer.anchor_after(end);
 4427                        let new_selection = selection.map(|_| anchor);
 4428                        (
 4429                            ((start..end, new_text), prevent_auto_indent),
 4430                            (insert_extra_newline, new_selection),
 4431                        )
 4432                    })
 4433                    .unzip()
 4434            };
 4435
 4436            let mut auto_indent_edits = Vec::new();
 4437            let mut edits = Vec::new();
 4438            for (edit, prevent_auto_indent) in edits_with_flags {
 4439                if prevent_auto_indent {
 4440                    edits.push(edit);
 4441                } else {
 4442                    auto_indent_edits.push(edit);
 4443                }
 4444            }
 4445            if !edits.is_empty() {
 4446                this.edit(edits, cx);
 4447            }
 4448            if !auto_indent_edits.is_empty() {
 4449                this.edit_with_autoindent(auto_indent_edits, cx);
 4450            }
 4451
 4452            let buffer = this.buffer.read(cx).snapshot(cx);
 4453            let new_selections = selection_info
 4454                .into_iter()
 4455                .map(|(extra_newline_inserted, new_selection)| {
 4456                    let mut cursor = new_selection.end.to_point(&buffer);
 4457                    if extra_newline_inserted {
 4458                        cursor.row -= 1;
 4459                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4460                    }
 4461                    new_selection.map(|_| cursor)
 4462                })
 4463                .collect();
 4464
 4465            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4466                s.select(new_selections)
 4467            });
 4468            this.refresh_inline_completion(true, false, window, cx);
 4469        });
 4470    }
 4471
 4472    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4473        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4474
 4475        let buffer = self.buffer.read(cx);
 4476        let snapshot = buffer.snapshot(cx);
 4477
 4478        let mut edits = Vec::new();
 4479        let mut rows = Vec::new();
 4480
 4481        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4482            let cursor = selection.head();
 4483            let row = cursor.row;
 4484
 4485            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4486
 4487            let newline = "\n".to_string();
 4488            edits.push((start_of_line..start_of_line, newline));
 4489
 4490            rows.push(row + rows_inserted as u32);
 4491        }
 4492
 4493        self.transact(window, cx, |editor, window, cx| {
 4494            editor.edit(edits, cx);
 4495
 4496            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4497                let mut index = 0;
 4498                s.move_cursors_with(|map, _, _| {
 4499                    let row = rows[index];
 4500                    index += 1;
 4501
 4502                    let point = Point::new(row, 0);
 4503                    let boundary = map.next_line_boundary(point).1;
 4504                    let clipped = map.clip_point(boundary, Bias::Left);
 4505
 4506                    (clipped, SelectionGoal::None)
 4507                });
 4508            });
 4509
 4510            let mut indent_edits = Vec::new();
 4511            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4512            for row in rows {
 4513                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4514                for (row, indent) in indents {
 4515                    if indent.len == 0 {
 4516                        continue;
 4517                    }
 4518
 4519                    let text = match indent.kind {
 4520                        IndentKind::Space => " ".repeat(indent.len as usize),
 4521                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4522                    };
 4523                    let point = Point::new(row.0, 0);
 4524                    indent_edits.push((point..point, text));
 4525                }
 4526            }
 4527            editor.edit(indent_edits, cx);
 4528        });
 4529    }
 4530
 4531    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4532        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4533
 4534        let buffer = self.buffer.read(cx);
 4535        let snapshot = buffer.snapshot(cx);
 4536
 4537        let mut edits = Vec::new();
 4538        let mut rows = Vec::new();
 4539        let mut rows_inserted = 0;
 4540
 4541        for selection in self.selections.all_adjusted(cx) {
 4542            let cursor = selection.head();
 4543            let row = cursor.row;
 4544
 4545            let point = Point::new(row + 1, 0);
 4546            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4547
 4548            let newline = "\n".to_string();
 4549            edits.push((start_of_line..start_of_line, newline));
 4550
 4551            rows_inserted += 1;
 4552            rows.push(row + rows_inserted);
 4553        }
 4554
 4555        self.transact(window, cx, |editor, window, cx| {
 4556            editor.edit(edits, cx);
 4557
 4558            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4559                let mut index = 0;
 4560                s.move_cursors_with(|map, _, _| {
 4561                    let row = rows[index];
 4562                    index += 1;
 4563
 4564                    let point = Point::new(row, 0);
 4565                    let boundary = map.next_line_boundary(point).1;
 4566                    let clipped = map.clip_point(boundary, Bias::Left);
 4567
 4568                    (clipped, SelectionGoal::None)
 4569                });
 4570            });
 4571
 4572            let mut indent_edits = Vec::new();
 4573            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4574            for row in rows {
 4575                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4576                for (row, indent) in indents {
 4577                    if indent.len == 0 {
 4578                        continue;
 4579                    }
 4580
 4581                    let text = match indent.kind {
 4582                        IndentKind::Space => " ".repeat(indent.len as usize),
 4583                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4584                    };
 4585                    let point = Point::new(row.0, 0);
 4586                    indent_edits.push((point..point, text));
 4587                }
 4588            }
 4589            editor.edit(indent_edits, cx);
 4590        });
 4591    }
 4592
 4593    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4594        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4595            original_indent_columns: Vec::new(),
 4596        });
 4597        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4598    }
 4599
 4600    fn insert_with_autoindent_mode(
 4601        &mut self,
 4602        text: &str,
 4603        autoindent_mode: Option<AutoindentMode>,
 4604        window: &mut Window,
 4605        cx: &mut Context<Self>,
 4606    ) {
 4607        if self.read_only(cx) {
 4608            return;
 4609        }
 4610
 4611        let text: Arc<str> = text.into();
 4612        self.transact(window, cx, |this, window, cx| {
 4613            let old_selections = this.selections.all_adjusted(cx);
 4614            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4615                let anchors = {
 4616                    let snapshot = buffer.read(cx);
 4617                    old_selections
 4618                        .iter()
 4619                        .map(|s| {
 4620                            let anchor = snapshot.anchor_after(s.head());
 4621                            s.map(|_| anchor)
 4622                        })
 4623                        .collect::<Vec<_>>()
 4624                };
 4625                buffer.edit(
 4626                    old_selections
 4627                        .iter()
 4628                        .map(|s| (s.start..s.end, text.clone())),
 4629                    autoindent_mode,
 4630                    cx,
 4631                );
 4632                anchors
 4633            });
 4634
 4635            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4636                s.select_anchors(selection_anchors);
 4637            });
 4638
 4639            cx.notify();
 4640        });
 4641    }
 4642
 4643    fn trigger_completion_on_input(
 4644        &mut self,
 4645        text: &str,
 4646        trigger_in_words: bool,
 4647        window: &mut Window,
 4648        cx: &mut Context<Self>,
 4649    ) {
 4650        let completions_source = self
 4651            .context_menu
 4652            .borrow()
 4653            .as_ref()
 4654            .and_then(|menu| match menu {
 4655                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4656                CodeContextMenu::CodeActions(_) => None,
 4657            });
 4658
 4659        match completions_source {
 4660            Some(CompletionsMenuSource::Words) => {
 4661                self.show_word_completions(&ShowWordCompletions, window, cx)
 4662            }
 4663            Some(CompletionsMenuSource::Normal)
 4664            | Some(CompletionsMenuSource::SnippetChoices)
 4665            | None
 4666                if self.is_completion_trigger(
 4667                    text,
 4668                    trigger_in_words,
 4669                    completions_source.is_some(),
 4670                    cx,
 4671                ) =>
 4672            {
 4673                self.show_completions(
 4674                    &ShowCompletions {
 4675                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4676                    },
 4677                    window,
 4678                    cx,
 4679                )
 4680            }
 4681            _ => {
 4682                self.hide_context_menu(window, cx);
 4683            }
 4684        }
 4685    }
 4686
 4687    fn is_completion_trigger(
 4688        &self,
 4689        text: &str,
 4690        trigger_in_words: bool,
 4691        menu_is_open: bool,
 4692        cx: &mut Context<Self>,
 4693    ) -> bool {
 4694        let position = self.selections.newest_anchor().head();
 4695        let multibuffer = self.buffer.read(cx);
 4696        let Some(buffer) = position
 4697            .buffer_id
 4698            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4699        else {
 4700            return false;
 4701        };
 4702
 4703        if let Some(completion_provider) = &self.completion_provider {
 4704            completion_provider.is_completion_trigger(
 4705                &buffer,
 4706                position.text_anchor,
 4707                text,
 4708                trigger_in_words,
 4709                menu_is_open,
 4710                cx,
 4711            )
 4712        } else {
 4713            false
 4714        }
 4715    }
 4716
 4717    /// If any empty selections is touching the start of its innermost containing autoclose
 4718    /// region, expand it to select the brackets.
 4719    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4720        let selections = self.selections.all::<usize>(cx);
 4721        let buffer = self.buffer.read(cx).read(cx);
 4722        let new_selections = self
 4723            .selections_with_autoclose_regions(selections, &buffer)
 4724            .map(|(mut selection, region)| {
 4725                if !selection.is_empty() {
 4726                    return selection;
 4727                }
 4728
 4729                if let Some(region) = region {
 4730                    let mut range = region.range.to_offset(&buffer);
 4731                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4732                        range.start -= region.pair.start.len();
 4733                        if buffer.contains_str_at(range.start, &region.pair.start)
 4734                            && buffer.contains_str_at(range.end, &region.pair.end)
 4735                        {
 4736                            range.end += region.pair.end.len();
 4737                            selection.start = range.start;
 4738                            selection.end = range.end;
 4739
 4740                            return selection;
 4741                        }
 4742                    }
 4743                }
 4744
 4745                let always_treat_brackets_as_autoclosed = buffer
 4746                    .language_settings_at(selection.start, cx)
 4747                    .always_treat_brackets_as_autoclosed;
 4748
 4749                if !always_treat_brackets_as_autoclosed {
 4750                    return selection;
 4751                }
 4752
 4753                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4754                    for (pair, enabled) in scope.brackets() {
 4755                        if !enabled || !pair.close {
 4756                            continue;
 4757                        }
 4758
 4759                        if buffer.contains_str_at(selection.start, &pair.end) {
 4760                            let pair_start_len = pair.start.len();
 4761                            if buffer.contains_str_at(
 4762                                selection.start.saturating_sub(pair_start_len),
 4763                                &pair.start,
 4764                            ) {
 4765                                selection.start -= pair_start_len;
 4766                                selection.end += pair.end.len();
 4767
 4768                                return selection;
 4769                            }
 4770                        }
 4771                    }
 4772                }
 4773
 4774                selection
 4775            })
 4776            .collect();
 4777
 4778        drop(buffer);
 4779        self.change_selections(None, window, cx, |selections| {
 4780            selections.select(new_selections)
 4781        });
 4782    }
 4783
 4784    /// Iterate the given selections, and for each one, find the smallest surrounding
 4785    /// autoclose region. This uses the ordering of the selections and the autoclose
 4786    /// regions to avoid repeated comparisons.
 4787    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4788        &'a self,
 4789        selections: impl IntoIterator<Item = Selection<D>>,
 4790        buffer: &'a MultiBufferSnapshot,
 4791    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4792        let mut i = 0;
 4793        let mut regions = self.autoclose_regions.as_slice();
 4794        selections.into_iter().map(move |selection| {
 4795            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4796
 4797            let mut enclosing = None;
 4798            while let Some(pair_state) = regions.get(i) {
 4799                if pair_state.range.end.to_offset(buffer) < range.start {
 4800                    regions = &regions[i + 1..];
 4801                    i = 0;
 4802                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4803                    break;
 4804                } else {
 4805                    if pair_state.selection_id == selection.id {
 4806                        enclosing = Some(pair_state);
 4807                    }
 4808                    i += 1;
 4809                }
 4810            }
 4811
 4812            (selection, enclosing)
 4813        })
 4814    }
 4815
 4816    /// Remove any autoclose regions that no longer contain their selection.
 4817    fn invalidate_autoclose_regions(
 4818        &mut self,
 4819        mut selections: &[Selection<Anchor>],
 4820        buffer: &MultiBufferSnapshot,
 4821    ) {
 4822        self.autoclose_regions.retain(|state| {
 4823            let mut i = 0;
 4824            while let Some(selection) = selections.get(i) {
 4825                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4826                    selections = &selections[1..];
 4827                    continue;
 4828                }
 4829                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4830                    break;
 4831                }
 4832                if selection.id == state.selection_id {
 4833                    return true;
 4834                } else {
 4835                    i += 1;
 4836                }
 4837            }
 4838            false
 4839        });
 4840    }
 4841
 4842    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4843        let offset = position.to_offset(buffer);
 4844        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4845        if offset > word_range.start && kind == Some(CharKind::Word) {
 4846            Some(
 4847                buffer
 4848                    .text_for_range(word_range.start..offset)
 4849                    .collect::<String>(),
 4850            )
 4851        } else {
 4852            None
 4853        }
 4854    }
 4855
 4856    pub fn toggle_inline_values(
 4857        &mut self,
 4858        _: &ToggleInlineValues,
 4859        _: &mut Window,
 4860        cx: &mut Context<Self>,
 4861    ) {
 4862        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4863
 4864        self.refresh_inline_values(cx);
 4865    }
 4866
 4867    pub fn toggle_inlay_hints(
 4868        &mut self,
 4869        _: &ToggleInlayHints,
 4870        _: &mut Window,
 4871        cx: &mut Context<Self>,
 4872    ) {
 4873        self.refresh_inlay_hints(
 4874            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4875            cx,
 4876        );
 4877    }
 4878
 4879    pub fn inlay_hints_enabled(&self) -> bool {
 4880        self.inlay_hint_cache.enabled
 4881    }
 4882
 4883    pub fn inline_values_enabled(&self) -> bool {
 4884        self.inline_value_cache.enabled
 4885    }
 4886
 4887    #[cfg(any(test, feature = "test-support"))]
 4888    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4889        self.display_map
 4890            .read(cx)
 4891            .current_inlays()
 4892            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4893            .cloned()
 4894            .collect()
 4895    }
 4896
 4897    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4898        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4899            return;
 4900        }
 4901
 4902        let reason_description = reason.description();
 4903        let ignore_debounce = matches!(
 4904            reason,
 4905            InlayHintRefreshReason::SettingsChange(_)
 4906                | InlayHintRefreshReason::Toggle(_)
 4907                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4908                | InlayHintRefreshReason::ModifiersChanged(_)
 4909        );
 4910        let (invalidate_cache, required_languages) = match reason {
 4911            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4912                match self.inlay_hint_cache.modifiers_override(enabled) {
 4913                    Some(enabled) => {
 4914                        if enabled {
 4915                            (InvalidationStrategy::RefreshRequested, None)
 4916                        } else {
 4917                            self.splice_inlays(
 4918                                &self
 4919                                    .visible_inlay_hints(cx)
 4920                                    .iter()
 4921                                    .map(|inlay| inlay.id)
 4922                                    .collect::<Vec<InlayId>>(),
 4923                                Vec::new(),
 4924                                cx,
 4925                            );
 4926                            return;
 4927                        }
 4928                    }
 4929                    None => return,
 4930                }
 4931            }
 4932            InlayHintRefreshReason::Toggle(enabled) => {
 4933                if self.inlay_hint_cache.toggle(enabled) {
 4934                    if enabled {
 4935                        (InvalidationStrategy::RefreshRequested, None)
 4936                    } else {
 4937                        self.splice_inlays(
 4938                            &self
 4939                                .visible_inlay_hints(cx)
 4940                                .iter()
 4941                                .map(|inlay| inlay.id)
 4942                                .collect::<Vec<InlayId>>(),
 4943                            Vec::new(),
 4944                            cx,
 4945                        );
 4946                        return;
 4947                    }
 4948                } else {
 4949                    return;
 4950                }
 4951            }
 4952            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4953                match self.inlay_hint_cache.update_settings(
 4954                    &self.buffer,
 4955                    new_settings,
 4956                    self.visible_inlay_hints(cx),
 4957                    cx,
 4958                ) {
 4959                    ControlFlow::Break(Some(InlaySplice {
 4960                        to_remove,
 4961                        to_insert,
 4962                    })) => {
 4963                        self.splice_inlays(&to_remove, to_insert, cx);
 4964                        return;
 4965                    }
 4966                    ControlFlow::Break(None) => return,
 4967                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4968                }
 4969            }
 4970            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4971                if let Some(InlaySplice {
 4972                    to_remove,
 4973                    to_insert,
 4974                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4975                {
 4976                    self.splice_inlays(&to_remove, to_insert, cx);
 4977                }
 4978                self.display_map.update(cx, |display_map, _| {
 4979                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4980                });
 4981                return;
 4982            }
 4983            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4984            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4985                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4986            }
 4987            InlayHintRefreshReason::RefreshRequested => {
 4988                (InvalidationStrategy::RefreshRequested, None)
 4989            }
 4990        };
 4991
 4992        if let Some(InlaySplice {
 4993            to_remove,
 4994            to_insert,
 4995        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4996            reason_description,
 4997            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4998            invalidate_cache,
 4999            ignore_debounce,
 5000            cx,
 5001        ) {
 5002            self.splice_inlays(&to_remove, to_insert, cx);
 5003        }
 5004    }
 5005
 5006    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5007        self.display_map
 5008            .read(cx)
 5009            .current_inlays()
 5010            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5011            .cloned()
 5012            .collect()
 5013    }
 5014
 5015    pub fn excerpts_for_inlay_hints_query(
 5016        &self,
 5017        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5018        cx: &mut Context<Editor>,
 5019    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5020        let Some(project) = self.project.as_ref() else {
 5021            return HashMap::default();
 5022        };
 5023        let project = project.read(cx);
 5024        let multi_buffer = self.buffer().read(cx);
 5025        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5026        let multi_buffer_visible_start = self
 5027            .scroll_manager
 5028            .anchor()
 5029            .anchor
 5030            .to_point(&multi_buffer_snapshot);
 5031        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5032            multi_buffer_visible_start
 5033                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5034            Bias::Left,
 5035        );
 5036        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5037        multi_buffer_snapshot
 5038            .range_to_buffer_ranges(multi_buffer_visible_range)
 5039            .into_iter()
 5040            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5041            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5042                let buffer_file = project::File::from_dyn(buffer.file())?;
 5043                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5044                let worktree_entry = buffer_worktree
 5045                    .read(cx)
 5046                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5047                if worktree_entry.is_ignored {
 5048                    return None;
 5049                }
 5050
 5051                let language = buffer.language()?;
 5052                if let Some(restrict_to_languages) = restrict_to_languages {
 5053                    if !restrict_to_languages.contains(language) {
 5054                        return None;
 5055                    }
 5056                }
 5057                Some((
 5058                    excerpt_id,
 5059                    (
 5060                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5061                        buffer.version().clone(),
 5062                        excerpt_visible_range,
 5063                    ),
 5064                ))
 5065            })
 5066            .collect()
 5067    }
 5068
 5069    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5070        TextLayoutDetails {
 5071            text_system: window.text_system().clone(),
 5072            editor_style: self.style.clone().unwrap(),
 5073            rem_size: window.rem_size(),
 5074            scroll_anchor: self.scroll_manager.anchor(),
 5075            visible_rows: self.visible_line_count(),
 5076            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5077        }
 5078    }
 5079
 5080    pub fn splice_inlays(
 5081        &self,
 5082        to_remove: &[InlayId],
 5083        to_insert: Vec<Inlay>,
 5084        cx: &mut Context<Self>,
 5085    ) {
 5086        self.display_map.update(cx, |display_map, cx| {
 5087            display_map.splice_inlays(to_remove, to_insert, cx)
 5088        });
 5089        cx.notify();
 5090    }
 5091
 5092    fn trigger_on_type_formatting(
 5093        &self,
 5094        input: String,
 5095        window: &mut Window,
 5096        cx: &mut Context<Self>,
 5097    ) -> Option<Task<Result<()>>> {
 5098        if input.len() != 1 {
 5099            return None;
 5100        }
 5101
 5102        let project = self.project.as_ref()?;
 5103        let position = self.selections.newest_anchor().head();
 5104        let (buffer, buffer_position) = self
 5105            .buffer
 5106            .read(cx)
 5107            .text_anchor_for_position(position, cx)?;
 5108
 5109        let settings = language_settings::language_settings(
 5110            buffer
 5111                .read(cx)
 5112                .language_at(buffer_position)
 5113                .map(|l| l.name()),
 5114            buffer.read(cx).file(),
 5115            cx,
 5116        );
 5117        if !settings.use_on_type_format {
 5118            return None;
 5119        }
 5120
 5121        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5122        // hence we do LSP request & edit on host side only — add formats to host's history.
 5123        let push_to_lsp_host_history = true;
 5124        // If this is not the host, append its history with new edits.
 5125        let push_to_client_history = project.read(cx).is_via_collab();
 5126
 5127        let on_type_formatting = project.update(cx, |project, cx| {
 5128            project.on_type_format(
 5129                buffer.clone(),
 5130                buffer_position,
 5131                input,
 5132                push_to_lsp_host_history,
 5133                cx,
 5134            )
 5135        });
 5136        Some(cx.spawn_in(window, async move |editor, cx| {
 5137            if let Some(transaction) = on_type_formatting.await? {
 5138                if push_to_client_history {
 5139                    buffer
 5140                        .update(cx, |buffer, _| {
 5141                            buffer.push_transaction(transaction, Instant::now());
 5142                            buffer.finalize_last_transaction();
 5143                        })
 5144                        .ok();
 5145                }
 5146                editor.update(cx, |editor, cx| {
 5147                    editor.refresh_document_highlights(cx);
 5148                })?;
 5149            }
 5150            Ok(())
 5151        }))
 5152    }
 5153
 5154    pub fn show_word_completions(
 5155        &mut self,
 5156        _: &ShowWordCompletions,
 5157        window: &mut Window,
 5158        cx: &mut Context<Self>,
 5159    ) {
 5160        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5161    }
 5162
 5163    pub fn show_completions(
 5164        &mut self,
 5165        options: &ShowCompletions,
 5166        window: &mut Window,
 5167        cx: &mut Context<Self>,
 5168    ) {
 5169        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5170    }
 5171
 5172    fn open_or_update_completions_menu(
 5173        &mut self,
 5174        requested_source: Option<CompletionsMenuSource>,
 5175        trigger: Option<&str>,
 5176        window: &mut Window,
 5177        cx: &mut Context<Self>,
 5178    ) {
 5179        if self.pending_rename.is_some() {
 5180            return;
 5181        }
 5182
 5183        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5184
 5185        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5186        // inserted and selected. To handle that case, the start of the selection is used so that
 5187        // the menu starts with all choices.
 5188        let position = self
 5189            .selections
 5190            .newest_anchor()
 5191            .start
 5192            .bias_right(&multibuffer_snapshot);
 5193        if position.diff_base_anchor.is_some() {
 5194            return;
 5195        }
 5196        let (buffer, buffer_position) =
 5197            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5198                output
 5199            } else {
 5200                return;
 5201            };
 5202        let buffer_snapshot = buffer.read(cx).snapshot();
 5203
 5204        let query: Option<Arc<String>> =
 5205            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5206
 5207        drop(multibuffer_snapshot);
 5208
 5209        let provider = match requested_source {
 5210            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5211            Some(CompletionsMenuSource::Words) => None,
 5212            Some(CompletionsMenuSource::SnippetChoices) => {
 5213                log::error!("bug: SnippetChoices requested_source is not handled");
 5214                None
 5215            }
 5216        };
 5217
 5218        let sort_completions = provider
 5219            .as_ref()
 5220            .map_or(false, |provider| provider.sort_completions());
 5221
 5222        let filter_completions = provider
 5223            .as_ref()
 5224            .map_or(true, |provider| provider.filter_completions());
 5225
 5226        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5227            if filter_completions {
 5228                menu.filter(query.clone(), provider.clone(), window, cx);
 5229            }
 5230            // When `is_incomplete` is false, no need to re-query completions when the current query
 5231            // is a suffix of the initial query.
 5232            if !menu.is_incomplete {
 5233                // If the new query is a suffix of the old query (typing more characters) and
 5234                // the previous result was complete, the existing completions can be filtered.
 5235                //
 5236                // Note that this is always true for snippet completions.
 5237                let query_matches = match (&menu.initial_query, &query) {
 5238                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5239                    (None, _) => true,
 5240                    _ => false,
 5241                };
 5242                if query_matches {
 5243                    let position_matches = if menu.initial_position == position {
 5244                        true
 5245                    } else {
 5246                        let snapshot = self.buffer.read(cx).read(cx);
 5247                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5248                    };
 5249                    if position_matches {
 5250                        return;
 5251                    }
 5252                }
 5253            }
 5254        };
 5255
 5256        let trigger_kind = match trigger {
 5257            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5258                CompletionTriggerKind::TRIGGER_CHARACTER
 5259            }
 5260            _ => CompletionTriggerKind::INVOKED,
 5261        };
 5262        let completion_context = CompletionContext {
 5263            trigger_character: trigger.and_then(|trigger| {
 5264                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5265                    Some(String::from(trigger))
 5266                } else {
 5267                    None
 5268                }
 5269            }),
 5270            trigger_kind,
 5271        };
 5272
 5273        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5274            buffer_snapshot.surrounding_word(buffer_position)
 5275        {
 5276            let word_to_exclude = buffer_snapshot
 5277                .text_for_range(word_range.clone())
 5278                .collect::<String>();
 5279            (
 5280                buffer_snapshot.anchor_before(word_range.start)
 5281                    ..buffer_snapshot.anchor_after(buffer_position),
 5282                Some(word_to_exclude),
 5283            )
 5284        } else {
 5285            (buffer_position..buffer_position, None)
 5286        };
 5287
 5288        let language = buffer_snapshot
 5289            .language_at(buffer_position)
 5290            .map(|language| language.name());
 5291
 5292        let completion_settings =
 5293            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5294
 5295        let show_completion_documentation = buffer_snapshot
 5296            .settings_at(buffer_position, cx)
 5297            .show_completion_documentation;
 5298
 5299        // The document can be large, so stay in reasonable bounds when searching for words,
 5300        // otherwise completion pop-up might be slow to appear.
 5301        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5302        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5303        let min_word_search = buffer_snapshot.clip_point(
 5304            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5305            Bias::Left,
 5306        );
 5307        let max_word_search = buffer_snapshot.clip_point(
 5308            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5309            Bias::Right,
 5310        );
 5311        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5312            ..buffer_snapshot.point_to_offset(max_word_search);
 5313
 5314        let skip_digits = query
 5315            .as_ref()
 5316            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5317
 5318        let (mut words, provider_responses) = match &provider {
 5319            Some(provider) => {
 5320                let provider_responses = provider.completions(
 5321                    position.excerpt_id,
 5322                    &buffer,
 5323                    buffer_position,
 5324                    completion_context,
 5325                    window,
 5326                    cx,
 5327                );
 5328
 5329                let words = match completion_settings.words {
 5330                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5331                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5332                        .background_spawn(async move {
 5333                            buffer_snapshot.words_in_range(WordsQuery {
 5334                                fuzzy_contents: None,
 5335                                range: word_search_range,
 5336                                skip_digits,
 5337                            })
 5338                        }),
 5339                };
 5340
 5341                (words, provider_responses)
 5342            }
 5343            None => (
 5344                cx.background_spawn(async move {
 5345                    buffer_snapshot.words_in_range(WordsQuery {
 5346                        fuzzy_contents: None,
 5347                        range: word_search_range,
 5348                        skip_digits,
 5349                    })
 5350                }),
 5351                Task::ready(Ok(Vec::new())),
 5352            ),
 5353        };
 5354
 5355        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5356
 5357        let id = post_inc(&mut self.next_completion_id);
 5358        let task = cx.spawn_in(window, async move |editor, cx| {
 5359            let Ok(()) = editor.update(cx, |this, _| {
 5360                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5361            }) else {
 5362                return;
 5363            };
 5364
 5365            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5366            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5367            let mut completions = Vec::new();
 5368            let mut is_incomplete = false;
 5369            if let Some(provider_responses) = provider_responses.await.log_err() {
 5370                if !provider_responses.is_empty() {
 5371                    for response in provider_responses {
 5372                        completions.extend(response.completions);
 5373                        is_incomplete = is_incomplete || response.is_incomplete;
 5374                    }
 5375                    if completion_settings.words == WordsCompletionMode::Fallback {
 5376                        words = Task::ready(BTreeMap::default());
 5377                    }
 5378                }
 5379            }
 5380
 5381            let mut words = words.await;
 5382            if let Some(word_to_exclude) = &word_to_exclude {
 5383                words.remove(word_to_exclude);
 5384            }
 5385            for lsp_completion in &completions {
 5386                words.remove(&lsp_completion.new_text);
 5387            }
 5388            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5389                replace_range: word_replace_range.clone(),
 5390                new_text: word.clone(),
 5391                label: CodeLabel::plain(word, None),
 5392                icon_path: None,
 5393                documentation: None,
 5394                source: CompletionSource::BufferWord {
 5395                    word_range,
 5396                    resolved: false,
 5397                },
 5398                insert_text_mode: Some(InsertTextMode::AS_IS),
 5399                confirm: None,
 5400            }));
 5401
 5402            let menu = if completions.is_empty() {
 5403                None
 5404            } else {
 5405                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5406                    let languages = editor
 5407                        .workspace
 5408                        .as_ref()
 5409                        .and_then(|(workspace, _)| workspace.upgrade())
 5410                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5411                    let menu = CompletionsMenu::new(
 5412                        id,
 5413                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5414                        sort_completions,
 5415                        show_completion_documentation,
 5416                        position,
 5417                        query.clone(),
 5418                        is_incomplete,
 5419                        buffer.clone(),
 5420                        completions.into(),
 5421                        snippet_sort_order,
 5422                        languages,
 5423                        language,
 5424                        cx,
 5425                    );
 5426
 5427                    let query = if filter_completions { query } else { None };
 5428                    let matches_task = if let Some(query) = query {
 5429                        menu.do_async_filtering(query, cx)
 5430                    } else {
 5431                        Task::ready(menu.unfiltered_matches())
 5432                    };
 5433                    (menu, matches_task)
 5434                }) else {
 5435                    return;
 5436                };
 5437
 5438                let matches = matches_task.await;
 5439
 5440                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5441                    // Newer menu already set, so exit.
 5442                    match editor.context_menu.borrow().as_ref() {
 5443                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5444                            if prev_menu.id > id {
 5445                                return;
 5446                            }
 5447                        }
 5448                        _ => {}
 5449                    };
 5450
 5451                    // Only valid to take prev_menu because it the new menu is immediately set
 5452                    // below, or the menu is hidden.
 5453                    match editor.context_menu.borrow_mut().take() {
 5454                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5455                            let position_matches =
 5456                                if prev_menu.initial_position == menu.initial_position {
 5457                                    true
 5458                                } else {
 5459                                    let snapshot = editor.buffer.read(cx).read(cx);
 5460                                    prev_menu.initial_position.to_offset(&snapshot)
 5461                                        == menu.initial_position.to_offset(&snapshot)
 5462                                };
 5463                            if position_matches {
 5464                                // Preserve markdown cache before `set_filter_results` because it will
 5465                                // try to populate the documentation cache.
 5466                                menu.preserve_markdown_cache(prev_menu);
 5467                            }
 5468                        }
 5469                        _ => {}
 5470                    };
 5471
 5472                    menu.set_filter_results(matches, provider, window, cx);
 5473                }) else {
 5474                    return;
 5475                };
 5476
 5477                menu.visible().then_some(menu)
 5478            };
 5479
 5480            editor
 5481                .update_in(cx, |editor, window, cx| {
 5482                    if editor.focus_handle.is_focused(window) {
 5483                        if let Some(menu) = menu {
 5484                            *editor.context_menu.borrow_mut() =
 5485                                Some(CodeContextMenu::Completions(menu));
 5486
 5487                            crate::hover_popover::hide_hover(editor, cx);
 5488                            if editor.show_edit_predictions_in_menu() {
 5489                                editor.update_visible_inline_completion(window, cx);
 5490                            } else {
 5491                                editor.discard_inline_completion(false, cx);
 5492                            }
 5493
 5494                            cx.notify();
 5495                            return;
 5496                        }
 5497                    }
 5498
 5499                    if editor.completion_tasks.len() <= 1 {
 5500                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5501                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5502                        // If it was already hidden and we don't show inline completions in the menu, we should
 5503                        // also show the inline-completion when available.
 5504                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5505                            editor.update_visible_inline_completion(window, cx);
 5506                        }
 5507                    }
 5508                })
 5509                .ok();
 5510        });
 5511
 5512        self.completion_tasks.push((id, task));
 5513    }
 5514
 5515    #[cfg(feature = "test-support")]
 5516    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5517        let menu = self.context_menu.borrow();
 5518        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5519            let completions = menu.completions.borrow();
 5520            Some(completions.to_vec())
 5521        } else {
 5522            None
 5523        }
 5524    }
 5525
 5526    pub fn with_completions_menu_matching_id<R>(
 5527        &self,
 5528        id: CompletionId,
 5529        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5530    ) -> R {
 5531        let mut context_menu = self.context_menu.borrow_mut();
 5532        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5533            return f(None);
 5534        };
 5535        if completions_menu.id != id {
 5536            return f(None);
 5537        }
 5538        f(Some(completions_menu))
 5539    }
 5540
 5541    pub fn confirm_completion(
 5542        &mut self,
 5543        action: &ConfirmCompletion,
 5544        window: &mut Window,
 5545        cx: &mut Context<Self>,
 5546    ) -> Option<Task<Result<()>>> {
 5547        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5548        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5549    }
 5550
 5551    pub fn confirm_completion_insert(
 5552        &mut self,
 5553        _: &ConfirmCompletionInsert,
 5554        window: &mut Window,
 5555        cx: &mut Context<Self>,
 5556    ) -> Option<Task<Result<()>>> {
 5557        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5558        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5559    }
 5560
 5561    pub fn confirm_completion_replace(
 5562        &mut self,
 5563        _: &ConfirmCompletionReplace,
 5564        window: &mut Window,
 5565        cx: &mut Context<Self>,
 5566    ) -> Option<Task<Result<()>>> {
 5567        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5568        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5569    }
 5570
 5571    pub fn compose_completion(
 5572        &mut self,
 5573        action: &ComposeCompletion,
 5574        window: &mut Window,
 5575        cx: &mut Context<Self>,
 5576    ) -> Option<Task<Result<()>>> {
 5577        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5578        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5579    }
 5580
 5581    fn do_completion(
 5582        &mut self,
 5583        item_ix: Option<usize>,
 5584        intent: CompletionIntent,
 5585        window: &mut Window,
 5586        cx: &mut Context<Editor>,
 5587    ) -> Option<Task<Result<()>>> {
 5588        use language::ToOffset as _;
 5589
 5590        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5591        else {
 5592            return None;
 5593        };
 5594
 5595        let candidate_id = {
 5596            let entries = completions_menu.entries.borrow();
 5597            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5598            if self.show_edit_predictions_in_menu() {
 5599                self.discard_inline_completion(true, cx);
 5600            }
 5601            mat.candidate_id
 5602        };
 5603
 5604        let completion = completions_menu
 5605            .completions
 5606            .borrow()
 5607            .get(candidate_id)?
 5608            .clone();
 5609        cx.stop_propagation();
 5610
 5611        let buffer_handle = completions_menu.buffer.clone();
 5612
 5613        let CompletionEdit {
 5614            new_text,
 5615            snippet,
 5616            replace_range,
 5617        } = process_completion_for_edit(
 5618            &completion,
 5619            intent,
 5620            &buffer_handle,
 5621            &completions_menu.initial_position.text_anchor,
 5622            cx,
 5623        );
 5624
 5625        let buffer = buffer_handle.read(cx);
 5626        let snapshot = self.buffer.read(cx).snapshot(cx);
 5627        let newest_anchor = self.selections.newest_anchor();
 5628        let replace_range_multibuffer = {
 5629            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5630            let multibuffer_anchor = snapshot
 5631                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5632                .unwrap()
 5633                ..snapshot
 5634                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5635                    .unwrap();
 5636            multibuffer_anchor.start.to_offset(&snapshot)
 5637                ..multibuffer_anchor.end.to_offset(&snapshot)
 5638        };
 5639        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5640            return None;
 5641        }
 5642
 5643        let old_text = buffer
 5644            .text_for_range(replace_range.clone())
 5645            .collect::<String>();
 5646        let lookbehind = newest_anchor
 5647            .start
 5648            .text_anchor
 5649            .to_offset(buffer)
 5650            .saturating_sub(replace_range.start);
 5651        let lookahead = replace_range
 5652            .end
 5653            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5654        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5655        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5656
 5657        let selections = self.selections.all::<usize>(cx);
 5658        let mut ranges = Vec::new();
 5659        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5660
 5661        for selection in &selections {
 5662            let range = if selection.id == newest_anchor.id {
 5663                replace_range_multibuffer.clone()
 5664            } else {
 5665                let mut range = selection.range();
 5666
 5667                // if prefix is present, don't duplicate it
 5668                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5669                    range.start = range.start.saturating_sub(lookbehind);
 5670
 5671                    // if suffix is also present, mimic the newest cursor and replace it
 5672                    if selection.id != newest_anchor.id
 5673                        && snapshot.contains_str_at(range.end, suffix)
 5674                    {
 5675                        range.end += lookahead;
 5676                    }
 5677                }
 5678                range
 5679            };
 5680
 5681            ranges.push(range.clone());
 5682
 5683            if !self.linked_edit_ranges.is_empty() {
 5684                let start_anchor = snapshot.anchor_before(range.start);
 5685                let end_anchor = snapshot.anchor_after(range.end);
 5686                if let Some(ranges) = self
 5687                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5688                {
 5689                    for (buffer, edits) in ranges {
 5690                        linked_edits
 5691                            .entry(buffer.clone())
 5692                            .or_default()
 5693                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5694                    }
 5695                }
 5696            }
 5697        }
 5698
 5699        let common_prefix_len = old_text
 5700            .chars()
 5701            .zip(new_text.chars())
 5702            .take_while(|(a, b)| a == b)
 5703            .map(|(a, _)| a.len_utf8())
 5704            .sum::<usize>();
 5705
 5706        cx.emit(EditorEvent::InputHandled {
 5707            utf16_range_to_replace: None,
 5708            text: new_text[common_prefix_len..].into(),
 5709        });
 5710
 5711        self.transact(window, cx, |this, window, cx| {
 5712            if let Some(mut snippet) = snippet {
 5713                snippet.text = new_text.to_string();
 5714                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5715            } else {
 5716                this.buffer.update(cx, |buffer, cx| {
 5717                    let auto_indent = match completion.insert_text_mode {
 5718                        Some(InsertTextMode::AS_IS) => None,
 5719                        _ => this.autoindent_mode.clone(),
 5720                    };
 5721                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5722                    buffer.edit(edits, auto_indent, cx);
 5723                });
 5724            }
 5725            for (buffer, edits) in linked_edits {
 5726                buffer.update(cx, |buffer, cx| {
 5727                    let snapshot = buffer.snapshot();
 5728                    let edits = edits
 5729                        .into_iter()
 5730                        .map(|(range, text)| {
 5731                            use text::ToPoint as TP;
 5732                            let end_point = TP::to_point(&range.end, &snapshot);
 5733                            let start_point = TP::to_point(&range.start, &snapshot);
 5734                            (start_point..end_point, text)
 5735                        })
 5736                        .sorted_by_key(|(range, _)| range.start);
 5737                    buffer.edit(edits, None, cx);
 5738                })
 5739            }
 5740
 5741            this.refresh_inline_completion(true, false, window, cx);
 5742        });
 5743
 5744        let show_new_completions_on_confirm = completion
 5745            .confirm
 5746            .as_ref()
 5747            .map_or(false, |confirm| confirm(intent, window, cx));
 5748        if show_new_completions_on_confirm {
 5749            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5750        }
 5751
 5752        let provider = self.completion_provider.as_ref()?;
 5753        drop(completion);
 5754        let apply_edits = provider.apply_additional_edits_for_completion(
 5755            buffer_handle,
 5756            completions_menu.completions.clone(),
 5757            candidate_id,
 5758            true,
 5759            cx,
 5760        );
 5761
 5762        let editor_settings = EditorSettings::get_global(cx);
 5763        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5764            // After the code completion is finished, users often want to know what signatures are needed.
 5765            // so we should automatically call signature_help
 5766            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5767        }
 5768
 5769        Some(cx.foreground_executor().spawn(async move {
 5770            apply_edits.await?;
 5771            Ok(())
 5772        }))
 5773    }
 5774
 5775    pub fn toggle_code_actions(
 5776        &mut self,
 5777        action: &ToggleCodeActions,
 5778        window: &mut Window,
 5779        cx: &mut Context<Self>,
 5780    ) {
 5781        let quick_launch = action.quick_launch;
 5782        let mut context_menu = self.context_menu.borrow_mut();
 5783        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5784            if code_actions.deployed_from == action.deployed_from {
 5785                // Toggle if we're selecting the same one
 5786                *context_menu = None;
 5787                cx.notify();
 5788                return;
 5789            } else {
 5790                // Otherwise, clear it and start a new one
 5791                *context_menu = None;
 5792                cx.notify();
 5793            }
 5794        }
 5795        drop(context_menu);
 5796        let snapshot = self.snapshot(window, cx);
 5797        let deployed_from = action.deployed_from.clone();
 5798        let action = action.clone();
 5799        self.completion_tasks.clear();
 5800        self.discard_inline_completion(false, cx);
 5801
 5802        let multibuffer_point = match &action.deployed_from {
 5803            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5804                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5805            }
 5806            _ => self.selections.newest::<Point>(cx).head(),
 5807        };
 5808        let Some((buffer, buffer_row)) = snapshot
 5809            .buffer_snapshot
 5810            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5811            .and_then(|(buffer_snapshot, range)| {
 5812                self.buffer()
 5813                    .read(cx)
 5814                    .buffer(buffer_snapshot.remote_id())
 5815                    .map(|buffer| (buffer, range.start.row))
 5816            })
 5817        else {
 5818            return;
 5819        };
 5820        let buffer_id = buffer.read(cx).remote_id();
 5821        let tasks = self
 5822            .tasks
 5823            .get(&(buffer_id, buffer_row))
 5824            .map(|t| Arc::new(t.to_owned()));
 5825
 5826        if !self.focus_handle.is_focused(window) {
 5827            return;
 5828        }
 5829        let project = self.project.clone();
 5830
 5831        let code_actions_task = match deployed_from {
 5832            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5833            _ => self.code_actions(buffer_row, window, cx),
 5834        };
 5835
 5836        let runnable_task = match deployed_from {
 5837            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5838            _ => {
 5839                let mut task_context_task = Task::ready(None);
 5840                if let Some(tasks) = &tasks {
 5841                    if let Some(project) = project {
 5842                        task_context_task =
 5843                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5844                    }
 5845                }
 5846
 5847                cx.spawn_in(window, {
 5848                    let buffer = buffer.clone();
 5849                    async move |editor, cx| {
 5850                        let task_context = task_context_task.await;
 5851
 5852                        let resolved_tasks =
 5853                            tasks
 5854                                .zip(task_context.clone())
 5855                                .map(|(tasks, task_context)| ResolvedTasks {
 5856                                    templates: tasks.resolve(&task_context).collect(),
 5857                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5858                                        multibuffer_point.row,
 5859                                        tasks.column,
 5860                                    )),
 5861                                });
 5862                        let debug_scenarios = editor
 5863                            .update(cx, |editor, cx| {
 5864                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5865                            })?
 5866                            .await;
 5867                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5868                    }
 5869                })
 5870            }
 5871        };
 5872
 5873        cx.spawn_in(window, async move |editor, cx| {
 5874            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5875            let code_actions = code_actions_task.await;
 5876            let spawn_straight_away = quick_launch
 5877                && resolved_tasks
 5878                    .as_ref()
 5879                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5880                && code_actions
 5881                    .as_ref()
 5882                    .map_or(true, |actions| actions.is_empty())
 5883                && debug_scenarios.is_empty();
 5884
 5885            editor.update_in(cx, |editor, window, cx| {
 5886                crate::hover_popover::hide_hover(editor, cx);
 5887                *editor.context_menu.borrow_mut() =
 5888                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5889                        buffer,
 5890                        actions: CodeActionContents::new(
 5891                            resolved_tasks,
 5892                            code_actions,
 5893                            debug_scenarios,
 5894                            task_context.unwrap_or_default(),
 5895                        ),
 5896                        selected_item: Default::default(),
 5897                        scroll_handle: UniformListScrollHandle::default(),
 5898                        deployed_from,
 5899                    }));
 5900                cx.notify();
 5901                if spawn_straight_away {
 5902                    if let Some(task) = editor.confirm_code_action(
 5903                        &ConfirmCodeAction { item_ix: Some(0) },
 5904                        window,
 5905                        cx,
 5906                    ) {
 5907                        return task;
 5908                    }
 5909                }
 5910
 5911                Task::ready(Ok(()))
 5912            })
 5913        })
 5914        .detach_and_log_err(cx);
 5915    }
 5916
 5917    fn debug_scenarios(
 5918        &mut self,
 5919        resolved_tasks: &Option<ResolvedTasks>,
 5920        buffer: &Entity<Buffer>,
 5921        cx: &mut App,
 5922    ) -> Task<Vec<task::DebugScenario>> {
 5923        if cx.has_flag::<DebuggerFeatureFlag>() {
 5924            maybe!({
 5925                let project = self.project.as_ref()?;
 5926                let dap_store = project.read(cx).dap_store();
 5927                let mut scenarios = vec![];
 5928                let resolved_tasks = resolved_tasks.as_ref()?;
 5929                let buffer = buffer.read(cx);
 5930                let language = buffer.language()?;
 5931                let file = buffer.file();
 5932                let debug_adapter = language_settings(language.name().into(), file, cx)
 5933                    .debuggers
 5934                    .first()
 5935                    .map(SharedString::from)
 5936                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5937
 5938                dap_store.update(cx, |dap_store, cx| {
 5939                    for (_, task) in &resolved_tasks.templates {
 5940                        let maybe_scenario = dap_store.debug_scenario_for_build_task(
 5941                            task.original_task().clone(),
 5942                            debug_adapter.clone().into(),
 5943                            task.display_label().to_owned().into(),
 5944                            cx,
 5945                        );
 5946                        scenarios.push(maybe_scenario);
 5947                    }
 5948                });
 5949                Some(cx.background_spawn(async move {
 5950                    let scenarios = futures::future::join_all(scenarios)
 5951                        .await
 5952                        .into_iter()
 5953                        .flatten()
 5954                        .collect::<Vec<_>>();
 5955                    scenarios
 5956                }))
 5957            })
 5958            .unwrap_or_else(|| Task::ready(vec![]))
 5959        } else {
 5960            Task::ready(vec![])
 5961        }
 5962    }
 5963
 5964    fn code_actions(
 5965        &mut self,
 5966        buffer_row: u32,
 5967        window: &mut Window,
 5968        cx: &mut Context<Self>,
 5969    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5970        let mut task = self.code_actions_task.take();
 5971        cx.spawn_in(window, async move |editor, cx| {
 5972            while let Some(prev_task) = task {
 5973                prev_task.await.log_err();
 5974                task = editor
 5975                    .update(cx, |this, _| this.code_actions_task.take())
 5976                    .ok()?;
 5977            }
 5978
 5979            editor
 5980                .update(cx, |editor, cx| {
 5981                    editor
 5982                        .available_code_actions
 5983                        .clone()
 5984                        .and_then(|(location, code_actions)| {
 5985                            let snapshot = location.buffer.read(cx).snapshot();
 5986                            let point_range = location.range.to_point(&snapshot);
 5987                            let point_range = point_range.start.row..=point_range.end.row;
 5988                            if point_range.contains(&buffer_row) {
 5989                                Some(code_actions)
 5990                            } else {
 5991                                None
 5992                            }
 5993                        })
 5994                })
 5995                .ok()
 5996                .flatten()
 5997        })
 5998    }
 5999
 6000    pub fn confirm_code_action(
 6001        &mut self,
 6002        action: &ConfirmCodeAction,
 6003        window: &mut Window,
 6004        cx: &mut Context<Self>,
 6005    ) -> Option<Task<Result<()>>> {
 6006        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6007
 6008        let actions_menu =
 6009            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6010                menu
 6011            } else {
 6012                return None;
 6013            };
 6014
 6015        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6016        let action = actions_menu.actions.get(action_ix)?;
 6017        let title = action.label();
 6018        let buffer = actions_menu.buffer;
 6019        let workspace = self.workspace()?;
 6020
 6021        match action {
 6022            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6023                workspace.update(cx, |workspace, cx| {
 6024                    workspace.schedule_resolved_task(
 6025                        task_source_kind,
 6026                        resolved_task,
 6027                        false,
 6028                        window,
 6029                        cx,
 6030                    );
 6031
 6032                    Some(Task::ready(Ok(())))
 6033                })
 6034            }
 6035            CodeActionsItem::CodeAction {
 6036                excerpt_id,
 6037                action,
 6038                provider,
 6039            } => {
 6040                let apply_code_action =
 6041                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6042                let workspace = workspace.downgrade();
 6043                Some(cx.spawn_in(window, async move |editor, cx| {
 6044                    let project_transaction = apply_code_action.await?;
 6045                    Self::open_project_transaction(
 6046                        &editor,
 6047                        workspace,
 6048                        project_transaction,
 6049                        title,
 6050                        cx,
 6051                    )
 6052                    .await
 6053                }))
 6054            }
 6055            CodeActionsItem::DebugScenario(scenario) => {
 6056                let context = actions_menu.actions.context.clone();
 6057
 6058                workspace.update(cx, |workspace, cx| {
 6059                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6060                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6061                });
 6062                Some(Task::ready(Ok(())))
 6063            }
 6064        }
 6065    }
 6066
 6067    pub async fn open_project_transaction(
 6068        this: &WeakEntity<Editor>,
 6069        workspace: WeakEntity<Workspace>,
 6070        transaction: ProjectTransaction,
 6071        title: String,
 6072        cx: &mut AsyncWindowContext,
 6073    ) -> Result<()> {
 6074        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6075        cx.update(|_, cx| {
 6076            entries.sort_unstable_by_key(|(buffer, _)| {
 6077                buffer.read(cx).file().map(|f| f.path().clone())
 6078            });
 6079        })?;
 6080
 6081        // If the project transaction's edits are all contained within this editor, then
 6082        // avoid opening a new editor to display them.
 6083
 6084        if let Some((buffer, transaction)) = entries.first() {
 6085            if entries.len() == 1 {
 6086                let excerpt = this.update(cx, |editor, cx| {
 6087                    editor
 6088                        .buffer()
 6089                        .read(cx)
 6090                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6091                })?;
 6092                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6093                    if excerpted_buffer == *buffer {
 6094                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6095                            let excerpt_range = excerpt_range.to_offset(buffer);
 6096                            buffer
 6097                                .edited_ranges_for_transaction::<usize>(transaction)
 6098                                .all(|range| {
 6099                                    excerpt_range.start <= range.start
 6100                                        && excerpt_range.end >= range.end
 6101                                })
 6102                        })?;
 6103
 6104                        if all_edits_within_excerpt {
 6105                            return Ok(());
 6106                        }
 6107                    }
 6108                }
 6109            }
 6110        } else {
 6111            return Ok(());
 6112        }
 6113
 6114        let mut ranges_to_highlight = Vec::new();
 6115        let excerpt_buffer = cx.new(|cx| {
 6116            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6117            for (buffer_handle, transaction) in &entries {
 6118                let edited_ranges = buffer_handle
 6119                    .read(cx)
 6120                    .edited_ranges_for_transaction::<Point>(transaction)
 6121                    .collect::<Vec<_>>();
 6122                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6123                    PathKey::for_buffer(buffer_handle, cx),
 6124                    buffer_handle.clone(),
 6125                    edited_ranges,
 6126                    DEFAULT_MULTIBUFFER_CONTEXT,
 6127                    cx,
 6128                );
 6129
 6130                ranges_to_highlight.extend(ranges);
 6131            }
 6132            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6133            multibuffer
 6134        })?;
 6135
 6136        workspace.update_in(cx, |workspace, window, cx| {
 6137            let project = workspace.project().clone();
 6138            let editor =
 6139                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6140            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6141            editor.update(cx, |editor, cx| {
 6142                editor.highlight_background::<Self>(
 6143                    &ranges_to_highlight,
 6144                    |theme| theme.editor_highlighted_line_background,
 6145                    cx,
 6146                );
 6147            });
 6148        })?;
 6149
 6150        Ok(())
 6151    }
 6152
 6153    pub fn clear_code_action_providers(&mut self) {
 6154        self.code_action_providers.clear();
 6155        self.available_code_actions.take();
 6156    }
 6157
 6158    pub fn add_code_action_provider(
 6159        &mut self,
 6160        provider: Rc<dyn CodeActionProvider>,
 6161        window: &mut Window,
 6162        cx: &mut Context<Self>,
 6163    ) {
 6164        if self
 6165            .code_action_providers
 6166            .iter()
 6167            .any(|existing_provider| existing_provider.id() == provider.id())
 6168        {
 6169            return;
 6170        }
 6171
 6172        self.code_action_providers.push(provider);
 6173        self.refresh_code_actions(window, cx);
 6174    }
 6175
 6176    pub fn remove_code_action_provider(
 6177        &mut self,
 6178        id: Arc<str>,
 6179        window: &mut Window,
 6180        cx: &mut Context<Self>,
 6181    ) {
 6182        self.code_action_providers
 6183            .retain(|provider| provider.id() != id);
 6184        self.refresh_code_actions(window, cx);
 6185    }
 6186
 6187    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6188        !self.code_action_providers.is_empty()
 6189            && EditorSettings::get_global(cx).toolbar.code_actions
 6190    }
 6191
 6192    pub fn has_available_code_actions(&self) -> bool {
 6193        self.available_code_actions
 6194            .as_ref()
 6195            .is_some_and(|(_, actions)| !actions.is_empty())
 6196    }
 6197
 6198    fn render_inline_code_actions(
 6199        &self,
 6200        icon_size: ui::IconSize,
 6201        display_row: DisplayRow,
 6202        is_active: bool,
 6203        cx: &mut Context<Self>,
 6204    ) -> AnyElement {
 6205        let show_tooltip = !self.context_menu_visible();
 6206        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6207            .icon_size(icon_size)
 6208            .shape(ui::IconButtonShape::Square)
 6209            .style(ButtonStyle::Transparent)
 6210            .icon_color(ui::Color::Hidden)
 6211            .toggle_state(is_active)
 6212            .when(show_tooltip, |this| {
 6213                this.tooltip({
 6214                    let focus_handle = self.focus_handle.clone();
 6215                    move |window, cx| {
 6216                        Tooltip::for_action_in(
 6217                            "Toggle Code Actions",
 6218                            &ToggleCodeActions {
 6219                                deployed_from: None,
 6220                                quick_launch: false,
 6221                            },
 6222                            &focus_handle,
 6223                            window,
 6224                            cx,
 6225                        )
 6226                    }
 6227                })
 6228            })
 6229            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6230                window.focus(&editor.focus_handle(cx));
 6231                editor.toggle_code_actions(
 6232                    &crate::actions::ToggleCodeActions {
 6233                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6234                            display_row,
 6235                        )),
 6236                        quick_launch: false,
 6237                    },
 6238                    window,
 6239                    cx,
 6240                );
 6241            }))
 6242            .into_any_element()
 6243    }
 6244
 6245    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6246        &self.context_menu
 6247    }
 6248
 6249    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6250        let newest_selection = self.selections.newest_anchor().clone();
 6251        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6252        let buffer = self.buffer.read(cx);
 6253        if newest_selection.head().diff_base_anchor.is_some() {
 6254            return None;
 6255        }
 6256        let (start_buffer, start) =
 6257            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6258        let (end_buffer, end) =
 6259            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6260        if start_buffer != end_buffer {
 6261            return None;
 6262        }
 6263
 6264        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6265            cx.background_executor()
 6266                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6267                .await;
 6268
 6269            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6270                let providers = this.code_action_providers.clone();
 6271                let tasks = this
 6272                    .code_action_providers
 6273                    .iter()
 6274                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6275                    .collect::<Vec<_>>();
 6276                (providers, tasks)
 6277            })?;
 6278
 6279            let mut actions = Vec::new();
 6280            for (provider, provider_actions) in
 6281                providers.into_iter().zip(future::join_all(tasks).await)
 6282            {
 6283                if let Some(provider_actions) = provider_actions.log_err() {
 6284                    actions.extend(provider_actions.into_iter().map(|action| {
 6285                        AvailableCodeAction {
 6286                            excerpt_id: newest_selection.start.excerpt_id,
 6287                            action,
 6288                            provider: provider.clone(),
 6289                        }
 6290                    }));
 6291                }
 6292            }
 6293
 6294            this.update(cx, |this, cx| {
 6295                this.available_code_actions = if actions.is_empty() {
 6296                    None
 6297                } else {
 6298                    Some((
 6299                        Location {
 6300                            buffer: start_buffer,
 6301                            range: start..end,
 6302                        },
 6303                        actions.into(),
 6304                    ))
 6305                };
 6306                cx.notify();
 6307            })
 6308        }));
 6309        None
 6310    }
 6311
 6312    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6313        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6314            self.show_git_blame_inline = false;
 6315
 6316            self.show_git_blame_inline_delay_task =
 6317                Some(cx.spawn_in(window, async move |this, cx| {
 6318                    cx.background_executor().timer(delay).await;
 6319
 6320                    this.update(cx, |this, cx| {
 6321                        this.show_git_blame_inline = true;
 6322                        cx.notify();
 6323                    })
 6324                    .log_err();
 6325                }));
 6326        }
 6327    }
 6328
 6329    fn show_blame_popover(
 6330        &mut self,
 6331        blame_entry: &BlameEntry,
 6332        position: gpui::Point<Pixels>,
 6333        cx: &mut Context<Self>,
 6334    ) {
 6335        if let Some(state) = &mut self.inline_blame_popover {
 6336            state.hide_task.take();
 6337        } else {
 6338            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6339            let blame_entry = blame_entry.clone();
 6340            let show_task = cx.spawn(async move |editor, cx| {
 6341                cx.background_executor()
 6342                    .timer(std::time::Duration::from_millis(delay))
 6343                    .await;
 6344                editor
 6345                    .update(cx, |editor, cx| {
 6346                        editor.inline_blame_popover_show_task.take();
 6347                        let Some(blame) = editor.blame.as_ref() else {
 6348                            return;
 6349                        };
 6350                        let blame = blame.read(cx);
 6351                        let details = blame.details_for_entry(&blame_entry);
 6352                        let markdown = cx.new(|cx| {
 6353                            Markdown::new(
 6354                                details
 6355                                    .as_ref()
 6356                                    .map(|message| message.message.clone())
 6357                                    .unwrap_or_default(),
 6358                                None,
 6359                                None,
 6360                                cx,
 6361                            )
 6362                        });
 6363                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6364                            position,
 6365                            hide_task: None,
 6366                            popover_bounds: None,
 6367                            popover_state: InlineBlamePopoverState {
 6368                                scroll_handle: ScrollHandle::new(),
 6369                                commit_message: details,
 6370                                markdown,
 6371                            },
 6372                        });
 6373                        cx.notify();
 6374                    })
 6375                    .ok();
 6376            });
 6377            self.inline_blame_popover_show_task = Some(show_task);
 6378        }
 6379    }
 6380
 6381    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6382        self.inline_blame_popover_show_task.take();
 6383        if let Some(state) = &mut self.inline_blame_popover {
 6384            let hide_task = cx.spawn(async move |editor, cx| {
 6385                cx.background_executor()
 6386                    .timer(std::time::Duration::from_millis(100))
 6387                    .await;
 6388                editor
 6389                    .update(cx, |editor, cx| {
 6390                        editor.inline_blame_popover.take();
 6391                        cx.notify();
 6392                    })
 6393                    .ok();
 6394            });
 6395            state.hide_task = Some(hide_task);
 6396        }
 6397    }
 6398
 6399    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6400        if self.pending_rename.is_some() {
 6401            return None;
 6402        }
 6403
 6404        let provider = self.semantics_provider.clone()?;
 6405        let buffer = self.buffer.read(cx);
 6406        let newest_selection = self.selections.newest_anchor().clone();
 6407        let cursor_position = newest_selection.head();
 6408        let (cursor_buffer, cursor_buffer_position) =
 6409            buffer.text_anchor_for_position(cursor_position, cx)?;
 6410        let (tail_buffer, tail_buffer_position) =
 6411            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6412        if cursor_buffer != tail_buffer {
 6413            return None;
 6414        }
 6415
 6416        let snapshot = cursor_buffer.read(cx).snapshot();
 6417        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6418        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6419        if start_word_range != end_word_range {
 6420            self.document_highlights_task.take();
 6421            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6422            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6423            return None;
 6424        }
 6425
 6426        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6427        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6428            cx.background_executor()
 6429                .timer(Duration::from_millis(debounce))
 6430                .await;
 6431
 6432            let highlights = if let Some(highlights) = cx
 6433                .update(|cx| {
 6434                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6435                })
 6436                .ok()
 6437                .flatten()
 6438            {
 6439                highlights.await.log_err()
 6440            } else {
 6441                None
 6442            };
 6443
 6444            if let Some(highlights) = highlights {
 6445                this.update(cx, |this, cx| {
 6446                    if this.pending_rename.is_some() {
 6447                        return;
 6448                    }
 6449
 6450                    let buffer_id = cursor_position.buffer_id;
 6451                    let buffer = this.buffer.read(cx);
 6452                    if !buffer
 6453                        .text_anchor_for_position(cursor_position, cx)
 6454                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6455                    {
 6456                        return;
 6457                    }
 6458
 6459                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6460                    let mut write_ranges = Vec::new();
 6461                    let mut read_ranges = Vec::new();
 6462                    for highlight in highlights {
 6463                        for (excerpt_id, excerpt_range) in
 6464                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6465                        {
 6466                            let start = highlight
 6467                                .range
 6468                                .start
 6469                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6470                            let end = highlight
 6471                                .range
 6472                                .end
 6473                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6474                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6475                                continue;
 6476                            }
 6477
 6478                            let range = Anchor {
 6479                                buffer_id,
 6480                                excerpt_id,
 6481                                text_anchor: start,
 6482                                diff_base_anchor: None,
 6483                            }..Anchor {
 6484                                buffer_id,
 6485                                excerpt_id,
 6486                                text_anchor: end,
 6487                                diff_base_anchor: None,
 6488                            };
 6489                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6490                                write_ranges.push(range);
 6491                            } else {
 6492                                read_ranges.push(range);
 6493                            }
 6494                        }
 6495                    }
 6496
 6497                    this.highlight_background::<DocumentHighlightRead>(
 6498                        &read_ranges,
 6499                        |theme| theme.editor_document_highlight_read_background,
 6500                        cx,
 6501                    );
 6502                    this.highlight_background::<DocumentHighlightWrite>(
 6503                        &write_ranges,
 6504                        |theme| theme.editor_document_highlight_write_background,
 6505                        cx,
 6506                    );
 6507                    cx.notify();
 6508                })
 6509                .log_err();
 6510            }
 6511        }));
 6512        None
 6513    }
 6514
 6515    fn prepare_highlight_query_from_selection(
 6516        &mut self,
 6517        cx: &mut Context<Editor>,
 6518    ) -> Option<(String, Range<Anchor>)> {
 6519        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6520            return None;
 6521        }
 6522        if !EditorSettings::get_global(cx).selection_highlight {
 6523            return None;
 6524        }
 6525        if self.selections.count() != 1 || self.selections.line_mode {
 6526            return None;
 6527        }
 6528        let selection = self.selections.newest::<Point>(cx);
 6529        if selection.is_empty() || selection.start.row != selection.end.row {
 6530            return None;
 6531        }
 6532        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6533        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6534        let query = multi_buffer_snapshot
 6535            .text_for_range(selection_anchor_range.clone())
 6536            .collect::<String>();
 6537        if query.trim().is_empty() {
 6538            return None;
 6539        }
 6540        Some((query, selection_anchor_range))
 6541    }
 6542
 6543    fn update_selection_occurrence_highlights(
 6544        &mut self,
 6545        query_text: String,
 6546        query_range: Range<Anchor>,
 6547        multi_buffer_range_to_query: Range<Point>,
 6548        use_debounce: bool,
 6549        window: &mut Window,
 6550        cx: &mut Context<Editor>,
 6551    ) -> Task<()> {
 6552        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6553        cx.spawn_in(window, async move |editor, cx| {
 6554            if use_debounce {
 6555                cx.background_executor()
 6556                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6557                    .await;
 6558            }
 6559            let match_task = cx.background_spawn(async move {
 6560                let buffer_ranges = multi_buffer_snapshot
 6561                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6562                    .into_iter()
 6563                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6564                let mut match_ranges = Vec::new();
 6565                let Ok(regex) = project::search::SearchQuery::text(
 6566                    query_text.clone(),
 6567                    false,
 6568                    false,
 6569                    false,
 6570                    Default::default(),
 6571                    Default::default(),
 6572                    false,
 6573                    None,
 6574                ) else {
 6575                    return Vec::default();
 6576                };
 6577                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6578                    match_ranges.extend(
 6579                        regex
 6580                            .search(&buffer_snapshot, Some(search_range.clone()))
 6581                            .await
 6582                            .into_iter()
 6583                            .filter_map(|match_range| {
 6584                                let match_start = buffer_snapshot
 6585                                    .anchor_after(search_range.start + match_range.start);
 6586                                let match_end = buffer_snapshot
 6587                                    .anchor_before(search_range.start + match_range.end);
 6588                                let match_anchor_range = Anchor::range_in_buffer(
 6589                                    excerpt_id,
 6590                                    buffer_snapshot.remote_id(),
 6591                                    match_start..match_end,
 6592                                );
 6593                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6594                            }),
 6595                    );
 6596                }
 6597                match_ranges
 6598            });
 6599            let match_ranges = match_task.await;
 6600            editor
 6601                .update_in(cx, |editor, _, cx| {
 6602                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6603                    if !match_ranges.is_empty() {
 6604                        editor.highlight_background::<SelectedTextHighlight>(
 6605                            &match_ranges,
 6606                            |theme| theme.editor_document_highlight_bracket_background,
 6607                            cx,
 6608                        )
 6609                    }
 6610                })
 6611                .log_err();
 6612        })
 6613    }
 6614
 6615    fn refresh_selected_text_highlights(
 6616        &mut self,
 6617        on_buffer_edit: bool,
 6618        window: &mut Window,
 6619        cx: &mut Context<Editor>,
 6620    ) {
 6621        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6622        else {
 6623            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6624            self.quick_selection_highlight_task.take();
 6625            self.debounced_selection_highlight_task.take();
 6626            return;
 6627        };
 6628        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6629        if on_buffer_edit
 6630            || self
 6631                .quick_selection_highlight_task
 6632                .as_ref()
 6633                .map_or(true, |(prev_anchor_range, _)| {
 6634                    prev_anchor_range != &query_range
 6635                })
 6636        {
 6637            let multi_buffer_visible_start = self
 6638                .scroll_manager
 6639                .anchor()
 6640                .anchor
 6641                .to_point(&multi_buffer_snapshot);
 6642            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6643                multi_buffer_visible_start
 6644                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6645                Bias::Left,
 6646            );
 6647            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6648            self.quick_selection_highlight_task = Some((
 6649                query_range.clone(),
 6650                self.update_selection_occurrence_highlights(
 6651                    query_text.clone(),
 6652                    query_range.clone(),
 6653                    multi_buffer_visible_range,
 6654                    false,
 6655                    window,
 6656                    cx,
 6657                ),
 6658            ));
 6659        }
 6660        if on_buffer_edit
 6661            || self
 6662                .debounced_selection_highlight_task
 6663                .as_ref()
 6664                .map_or(true, |(prev_anchor_range, _)| {
 6665                    prev_anchor_range != &query_range
 6666                })
 6667        {
 6668            let multi_buffer_start = multi_buffer_snapshot
 6669                .anchor_before(0)
 6670                .to_point(&multi_buffer_snapshot);
 6671            let multi_buffer_end = multi_buffer_snapshot
 6672                .anchor_after(multi_buffer_snapshot.len())
 6673                .to_point(&multi_buffer_snapshot);
 6674            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6675            self.debounced_selection_highlight_task = Some((
 6676                query_range.clone(),
 6677                self.update_selection_occurrence_highlights(
 6678                    query_text,
 6679                    query_range,
 6680                    multi_buffer_full_range,
 6681                    true,
 6682                    window,
 6683                    cx,
 6684                ),
 6685            ));
 6686        }
 6687    }
 6688
 6689    pub fn refresh_inline_completion(
 6690        &mut self,
 6691        debounce: bool,
 6692        user_requested: bool,
 6693        window: &mut Window,
 6694        cx: &mut Context<Self>,
 6695    ) -> Option<()> {
 6696        let provider = self.edit_prediction_provider()?;
 6697        let cursor = self.selections.newest_anchor().head();
 6698        let (buffer, cursor_buffer_position) =
 6699            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6700
 6701        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6702            self.discard_inline_completion(false, cx);
 6703            return None;
 6704        }
 6705
 6706        if !user_requested
 6707            && (!self.should_show_edit_predictions()
 6708                || !self.is_focused(window)
 6709                || buffer.read(cx).is_empty())
 6710        {
 6711            self.discard_inline_completion(false, cx);
 6712            return None;
 6713        }
 6714
 6715        self.update_visible_inline_completion(window, cx);
 6716        provider.refresh(
 6717            self.project.clone(),
 6718            buffer,
 6719            cursor_buffer_position,
 6720            debounce,
 6721            cx,
 6722        );
 6723        Some(())
 6724    }
 6725
 6726    fn show_edit_predictions_in_menu(&self) -> bool {
 6727        match self.edit_prediction_settings {
 6728            EditPredictionSettings::Disabled => false,
 6729            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6730        }
 6731    }
 6732
 6733    pub fn edit_predictions_enabled(&self) -> bool {
 6734        match self.edit_prediction_settings {
 6735            EditPredictionSettings::Disabled => false,
 6736            EditPredictionSettings::Enabled { .. } => true,
 6737        }
 6738    }
 6739
 6740    fn edit_prediction_requires_modifier(&self) -> bool {
 6741        match self.edit_prediction_settings {
 6742            EditPredictionSettings::Disabled => false,
 6743            EditPredictionSettings::Enabled {
 6744                preview_requires_modifier,
 6745                ..
 6746            } => preview_requires_modifier,
 6747        }
 6748    }
 6749
 6750    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6751        if self.edit_prediction_provider.is_none() {
 6752            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6753        } else {
 6754            let selection = self.selections.newest_anchor();
 6755            let cursor = selection.head();
 6756
 6757            if let Some((buffer, cursor_buffer_position)) =
 6758                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6759            {
 6760                self.edit_prediction_settings =
 6761                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6762            }
 6763        }
 6764    }
 6765
 6766    fn edit_prediction_settings_at_position(
 6767        &self,
 6768        buffer: &Entity<Buffer>,
 6769        buffer_position: language::Anchor,
 6770        cx: &App,
 6771    ) -> EditPredictionSettings {
 6772        if !self.mode.is_full()
 6773            || !self.show_inline_completions_override.unwrap_or(true)
 6774            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6775        {
 6776            return EditPredictionSettings::Disabled;
 6777        }
 6778
 6779        let buffer = buffer.read(cx);
 6780
 6781        let file = buffer.file();
 6782
 6783        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6784            return EditPredictionSettings::Disabled;
 6785        };
 6786
 6787        let by_provider = matches!(
 6788            self.menu_inline_completions_policy,
 6789            MenuInlineCompletionsPolicy::ByProvider
 6790        );
 6791
 6792        let show_in_menu = by_provider
 6793            && self
 6794                .edit_prediction_provider
 6795                .as_ref()
 6796                .map_or(false, |provider| {
 6797                    provider.provider.show_completions_in_menu()
 6798                });
 6799
 6800        let preview_requires_modifier =
 6801            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6802
 6803        EditPredictionSettings::Enabled {
 6804            show_in_menu,
 6805            preview_requires_modifier,
 6806        }
 6807    }
 6808
 6809    fn should_show_edit_predictions(&self) -> bool {
 6810        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6811    }
 6812
 6813    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6814        matches!(
 6815            self.edit_prediction_preview,
 6816            EditPredictionPreview::Active { .. }
 6817        )
 6818    }
 6819
 6820    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6821        let cursor = self.selections.newest_anchor().head();
 6822        if let Some((buffer, cursor_position)) =
 6823            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6824        {
 6825            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6826        } else {
 6827            false
 6828        }
 6829    }
 6830
 6831    pub fn supports_minimap(&self, cx: &App) -> bool {
 6832        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6833    }
 6834
 6835    fn edit_predictions_enabled_in_buffer(
 6836        &self,
 6837        buffer: &Entity<Buffer>,
 6838        buffer_position: language::Anchor,
 6839        cx: &App,
 6840    ) -> bool {
 6841        maybe!({
 6842            if self.read_only(cx) {
 6843                return Some(false);
 6844            }
 6845            let provider = self.edit_prediction_provider()?;
 6846            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6847                return Some(false);
 6848            }
 6849            let buffer = buffer.read(cx);
 6850            let Some(file) = buffer.file() else {
 6851                return Some(true);
 6852            };
 6853            let settings = all_language_settings(Some(file), cx);
 6854            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6855        })
 6856        .unwrap_or(false)
 6857    }
 6858
 6859    fn cycle_inline_completion(
 6860        &mut self,
 6861        direction: Direction,
 6862        window: &mut Window,
 6863        cx: &mut Context<Self>,
 6864    ) -> Option<()> {
 6865        let provider = self.edit_prediction_provider()?;
 6866        let cursor = self.selections.newest_anchor().head();
 6867        let (buffer, cursor_buffer_position) =
 6868            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6869        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6870            return None;
 6871        }
 6872
 6873        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6874        self.update_visible_inline_completion(window, cx);
 6875
 6876        Some(())
 6877    }
 6878
 6879    pub fn show_inline_completion(
 6880        &mut self,
 6881        _: &ShowEditPrediction,
 6882        window: &mut Window,
 6883        cx: &mut Context<Self>,
 6884    ) {
 6885        if !self.has_active_inline_completion() {
 6886            self.refresh_inline_completion(false, true, window, cx);
 6887            return;
 6888        }
 6889
 6890        self.update_visible_inline_completion(window, cx);
 6891    }
 6892
 6893    pub fn display_cursor_names(
 6894        &mut self,
 6895        _: &DisplayCursorNames,
 6896        window: &mut Window,
 6897        cx: &mut Context<Self>,
 6898    ) {
 6899        self.show_cursor_names(window, cx);
 6900    }
 6901
 6902    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6903        self.show_cursor_names = true;
 6904        cx.notify();
 6905        cx.spawn_in(window, async move |this, cx| {
 6906            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6907            this.update(cx, |this, cx| {
 6908                this.show_cursor_names = false;
 6909                cx.notify()
 6910            })
 6911            .ok()
 6912        })
 6913        .detach();
 6914    }
 6915
 6916    pub fn next_edit_prediction(
 6917        &mut self,
 6918        _: &NextEditPrediction,
 6919        window: &mut Window,
 6920        cx: &mut Context<Self>,
 6921    ) {
 6922        if self.has_active_inline_completion() {
 6923            self.cycle_inline_completion(Direction::Next, window, cx);
 6924        } else {
 6925            let is_copilot_disabled = self
 6926                .refresh_inline_completion(false, true, window, cx)
 6927                .is_none();
 6928            if is_copilot_disabled {
 6929                cx.propagate();
 6930            }
 6931        }
 6932    }
 6933
 6934    pub fn previous_edit_prediction(
 6935        &mut self,
 6936        _: &PreviousEditPrediction,
 6937        window: &mut Window,
 6938        cx: &mut Context<Self>,
 6939    ) {
 6940        if self.has_active_inline_completion() {
 6941            self.cycle_inline_completion(Direction::Prev, window, cx);
 6942        } else {
 6943            let is_copilot_disabled = self
 6944                .refresh_inline_completion(false, true, window, cx)
 6945                .is_none();
 6946            if is_copilot_disabled {
 6947                cx.propagate();
 6948            }
 6949        }
 6950    }
 6951
 6952    pub fn accept_edit_prediction(
 6953        &mut self,
 6954        _: &AcceptEditPrediction,
 6955        window: &mut Window,
 6956        cx: &mut Context<Self>,
 6957    ) {
 6958        if self.show_edit_predictions_in_menu() {
 6959            self.hide_context_menu(window, cx);
 6960        }
 6961
 6962        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6963            return;
 6964        };
 6965
 6966        self.report_inline_completion_event(
 6967            active_inline_completion.completion_id.clone(),
 6968            true,
 6969            cx,
 6970        );
 6971
 6972        match &active_inline_completion.completion {
 6973            InlineCompletion::Move { target, .. } => {
 6974                let target = *target;
 6975
 6976                if let Some(position_map) = &self.last_position_map {
 6977                    if position_map
 6978                        .visible_row_range
 6979                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6980                        || !self.edit_prediction_requires_modifier()
 6981                    {
 6982                        self.unfold_ranges(&[target..target], true, false, cx);
 6983                        // Note that this is also done in vim's handler of the Tab action.
 6984                        self.change_selections(
 6985                            Some(Autoscroll::newest()),
 6986                            window,
 6987                            cx,
 6988                            |selections| {
 6989                                selections.select_anchor_ranges([target..target]);
 6990                            },
 6991                        );
 6992                        self.clear_row_highlights::<EditPredictionPreview>();
 6993
 6994                        self.edit_prediction_preview
 6995                            .set_previous_scroll_position(None);
 6996                    } else {
 6997                        self.edit_prediction_preview
 6998                            .set_previous_scroll_position(Some(
 6999                                position_map.snapshot.scroll_anchor,
 7000                            ));
 7001
 7002                        self.highlight_rows::<EditPredictionPreview>(
 7003                            target..target,
 7004                            cx.theme().colors().editor_highlighted_line_background,
 7005                            RowHighlightOptions {
 7006                                autoscroll: true,
 7007                                ..Default::default()
 7008                            },
 7009                            cx,
 7010                        );
 7011                        self.request_autoscroll(Autoscroll::fit(), cx);
 7012                    }
 7013                }
 7014            }
 7015            InlineCompletion::Edit { edits, .. } => {
 7016                if let Some(provider) = self.edit_prediction_provider() {
 7017                    provider.accept(cx);
 7018                }
 7019
 7020                // Store the transaction ID and selections before applying the edit
 7021                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7022
 7023                let snapshot = self.buffer.read(cx).snapshot(cx);
 7024                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7025
 7026                self.buffer.update(cx, |buffer, cx| {
 7027                    buffer.edit(edits.iter().cloned(), None, cx)
 7028                });
 7029
 7030                self.change_selections(None, window, cx, |s| {
 7031                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7032                });
 7033
 7034                let selections = self.selections.disjoint_anchors();
 7035                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7036                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7037                    if has_new_transaction {
 7038                        self.selection_history
 7039                            .insert_transaction(transaction_id_now, selections);
 7040                    }
 7041                }
 7042
 7043                self.update_visible_inline_completion(window, cx);
 7044                if self.active_inline_completion.is_none() {
 7045                    self.refresh_inline_completion(true, true, window, cx);
 7046                }
 7047
 7048                cx.notify();
 7049            }
 7050        }
 7051
 7052        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7053    }
 7054
 7055    pub fn accept_partial_inline_completion(
 7056        &mut self,
 7057        _: &AcceptPartialEditPrediction,
 7058        window: &mut Window,
 7059        cx: &mut Context<Self>,
 7060    ) {
 7061        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7062            return;
 7063        };
 7064        if self.selections.count() != 1 {
 7065            return;
 7066        }
 7067
 7068        self.report_inline_completion_event(
 7069            active_inline_completion.completion_id.clone(),
 7070            true,
 7071            cx,
 7072        );
 7073
 7074        match &active_inline_completion.completion {
 7075            InlineCompletion::Move { target, .. } => {
 7076                let target = *target;
 7077                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7078                    selections.select_anchor_ranges([target..target]);
 7079                });
 7080            }
 7081            InlineCompletion::Edit { edits, .. } => {
 7082                // Find an insertion that starts at the cursor position.
 7083                let snapshot = self.buffer.read(cx).snapshot(cx);
 7084                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7085                let insertion = edits.iter().find_map(|(range, text)| {
 7086                    let range = range.to_offset(&snapshot);
 7087                    if range.is_empty() && range.start == cursor_offset {
 7088                        Some(text)
 7089                    } else {
 7090                        None
 7091                    }
 7092                });
 7093
 7094                if let Some(text) = insertion {
 7095                    let mut partial_completion = text
 7096                        .chars()
 7097                        .by_ref()
 7098                        .take_while(|c| c.is_alphabetic())
 7099                        .collect::<String>();
 7100                    if partial_completion.is_empty() {
 7101                        partial_completion = text
 7102                            .chars()
 7103                            .by_ref()
 7104                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7105                            .collect::<String>();
 7106                    }
 7107
 7108                    cx.emit(EditorEvent::InputHandled {
 7109                        utf16_range_to_replace: None,
 7110                        text: partial_completion.clone().into(),
 7111                    });
 7112
 7113                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7114
 7115                    self.refresh_inline_completion(true, true, window, cx);
 7116                    cx.notify();
 7117                } else {
 7118                    self.accept_edit_prediction(&Default::default(), window, cx);
 7119                }
 7120            }
 7121        }
 7122    }
 7123
 7124    fn discard_inline_completion(
 7125        &mut self,
 7126        should_report_inline_completion_event: bool,
 7127        cx: &mut Context<Self>,
 7128    ) -> bool {
 7129        if should_report_inline_completion_event {
 7130            let completion_id = self
 7131                .active_inline_completion
 7132                .as_ref()
 7133                .and_then(|active_completion| active_completion.completion_id.clone());
 7134
 7135            self.report_inline_completion_event(completion_id, false, cx);
 7136        }
 7137
 7138        if let Some(provider) = self.edit_prediction_provider() {
 7139            provider.discard(cx);
 7140        }
 7141
 7142        self.take_active_inline_completion(cx)
 7143    }
 7144
 7145    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7146        let Some(provider) = self.edit_prediction_provider() else {
 7147            return;
 7148        };
 7149
 7150        let Some((_, buffer, _)) = self
 7151            .buffer
 7152            .read(cx)
 7153            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7154        else {
 7155            return;
 7156        };
 7157
 7158        let extension = buffer
 7159            .read(cx)
 7160            .file()
 7161            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7162
 7163        let event_type = match accepted {
 7164            true => "Edit Prediction Accepted",
 7165            false => "Edit Prediction Discarded",
 7166        };
 7167        telemetry::event!(
 7168            event_type,
 7169            provider = provider.name(),
 7170            prediction_id = id,
 7171            suggestion_accepted = accepted,
 7172            file_extension = extension,
 7173        );
 7174    }
 7175
 7176    pub fn has_active_inline_completion(&self) -> bool {
 7177        self.active_inline_completion.is_some()
 7178    }
 7179
 7180    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7181        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7182            return false;
 7183        };
 7184
 7185        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7186        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7187        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7188        true
 7189    }
 7190
 7191    /// Returns true when we're displaying the edit prediction popover below the cursor
 7192    /// like we are not previewing and the LSP autocomplete menu is visible
 7193    /// or we are in `when_holding_modifier` mode.
 7194    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7195        if self.edit_prediction_preview_is_active()
 7196            || !self.show_edit_predictions_in_menu()
 7197            || !self.edit_predictions_enabled()
 7198        {
 7199            return false;
 7200        }
 7201
 7202        if self.has_visible_completions_menu() {
 7203            return true;
 7204        }
 7205
 7206        has_completion && self.edit_prediction_requires_modifier()
 7207    }
 7208
 7209    fn handle_modifiers_changed(
 7210        &mut self,
 7211        modifiers: Modifiers,
 7212        position_map: &PositionMap,
 7213        window: &mut Window,
 7214        cx: &mut Context<Self>,
 7215    ) {
 7216        if self.show_edit_predictions_in_menu() {
 7217            self.update_edit_prediction_preview(&modifiers, window, cx);
 7218        }
 7219
 7220        self.update_selection_mode(&modifiers, position_map, window, cx);
 7221
 7222        let mouse_position = window.mouse_position();
 7223        if !position_map.text_hitbox.is_hovered(window) {
 7224            return;
 7225        }
 7226
 7227        self.update_hovered_link(
 7228            position_map.point_for_position(mouse_position),
 7229            &position_map.snapshot,
 7230            modifiers,
 7231            window,
 7232            cx,
 7233        )
 7234    }
 7235
 7236    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7237        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7238        if invert {
 7239            match multi_cursor_setting {
 7240                MultiCursorModifier::Alt => modifiers.alt,
 7241                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7242            }
 7243        } else {
 7244            match multi_cursor_setting {
 7245                MultiCursorModifier::Alt => modifiers.secondary(),
 7246                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7247            }
 7248        }
 7249    }
 7250
 7251    fn columnar_selection_mode(
 7252        modifiers: &Modifiers,
 7253        cx: &mut Context<Self>,
 7254    ) -> Option<ColumnarMode> {
 7255        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7256            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7257                Some(ColumnarMode::FromMouse)
 7258            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7259                Some(ColumnarMode::FromSelection)
 7260            } else {
 7261                None
 7262            }
 7263        } else {
 7264            None
 7265        }
 7266    }
 7267
 7268    fn update_selection_mode(
 7269        &mut self,
 7270        modifiers: &Modifiers,
 7271        position_map: &PositionMap,
 7272        window: &mut Window,
 7273        cx: &mut Context<Self>,
 7274    ) {
 7275        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7276            return;
 7277        };
 7278        if self.selections.pending.is_none() {
 7279            return;
 7280        }
 7281
 7282        let mouse_position = window.mouse_position();
 7283        let point_for_position = position_map.point_for_position(mouse_position);
 7284        let position = point_for_position.previous_valid;
 7285
 7286        self.select(
 7287            SelectPhase::BeginColumnar {
 7288                position,
 7289                reset: false,
 7290                mode,
 7291                goal_column: point_for_position.exact_unclipped.column(),
 7292            },
 7293            window,
 7294            cx,
 7295        );
 7296    }
 7297
 7298    fn update_edit_prediction_preview(
 7299        &mut self,
 7300        modifiers: &Modifiers,
 7301        window: &mut Window,
 7302        cx: &mut Context<Self>,
 7303    ) {
 7304        let mut modifiers_held = false;
 7305        if let Some(accept_keystroke) = self
 7306            .accept_edit_prediction_keybind(false, window, cx)
 7307            .keystroke()
 7308        {
 7309            modifiers_held = modifiers_held
 7310                || (&accept_keystroke.modifiers == modifiers
 7311                    && accept_keystroke.modifiers.modified());
 7312        };
 7313        if let Some(accept_partial_keystroke) = self
 7314            .accept_edit_prediction_keybind(true, window, cx)
 7315            .keystroke()
 7316        {
 7317            modifiers_held = modifiers_held
 7318                || (&accept_partial_keystroke.modifiers == modifiers
 7319                    && accept_partial_keystroke.modifiers.modified());
 7320        }
 7321
 7322        if modifiers_held {
 7323            if matches!(
 7324                self.edit_prediction_preview,
 7325                EditPredictionPreview::Inactive { .. }
 7326            ) {
 7327                self.edit_prediction_preview = EditPredictionPreview::Active {
 7328                    previous_scroll_position: None,
 7329                    since: Instant::now(),
 7330                };
 7331
 7332                self.update_visible_inline_completion(window, cx);
 7333                cx.notify();
 7334            }
 7335        } else if let EditPredictionPreview::Active {
 7336            previous_scroll_position,
 7337            since,
 7338        } = self.edit_prediction_preview
 7339        {
 7340            if let (Some(previous_scroll_position), Some(position_map)) =
 7341                (previous_scroll_position, self.last_position_map.as_ref())
 7342            {
 7343                self.set_scroll_position(
 7344                    previous_scroll_position
 7345                        .scroll_position(&position_map.snapshot.display_snapshot),
 7346                    window,
 7347                    cx,
 7348                );
 7349            }
 7350
 7351            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7352                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7353            };
 7354            self.clear_row_highlights::<EditPredictionPreview>();
 7355            self.update_visible_inline_completion(window, cx);
 7356            cx.notify();
 7357        }
 7358    }
 7359
 7360    fn update_visible_inline_completion(
 7361        &mut self,
 7362        _window: &mut Window,
 7363        cx: &mut Context<Self>,
 7364    ) -> Option<()> {
 7365        let selection = self.selections.newest_anchor();
 7366        let cursor = selection.head();
 7367        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7368        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7369        let excerpt_id = cursor.excerpt_id;
 7370
 7371        let show_in_menu = self.show_edit_predictions_in_menu();
 7372        let completions_menu_has_precedence = !show_in_menu
 7373            && (self.context_menu.borrow().is_some()
 7374                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7375
 7376        if completions_menu_has_precedence
 7377            || !offset_selection.is_empty()
 7378            || self
 7379                .active_inline_completion
 7380                .as_ref()
 7381                .map_or(false, |completion| {
 7382                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7383                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7384                    !invalidation_range.contains(&offset_selection.head())
 7385                })
 7386        {
 7387            self.discard_inline_completion(false, cx);
 7388            return None;
 7389        }
 7390
 7391        self.take_active_inline_completion(cx);
 7392        let Some(provider) = self.edit_prediction_provider() else {
 7393            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7394            return None;
 7395        };
 7396
 7397        let (buffer, cursor_buffer_position) =
 7398            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7399
 7400        self.edit_prediction_settings =
 7401            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7402
 7403        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7404
 7405        if self.edit_prediction_indent_conflict {
 7406            let cursor_point = cursor.to_point(&multibuffer);
 7407
 7408            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7409
 7410            if let Some((_, indent)) = indents.iter().next() {
 7411                if indent.len == cursor_point.column {
 7412                    self.edit_prediction_indent_conflict = false;
 7413                }
 7414            }
 7415        }
 7416
 7417        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7418        let edits = inline_completion
 7419            .edits
 7420            .into_iter()
 7421            .flat_map(|(range, new_text)| {
 7422                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7423                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7424                Some((start..end, new_text))
 7425            })
 7426            .collect::<Vec<_>>();
 7427        if edits.is_empty() {
 7428            return None;
 7429        }
 7430
 7431        let first_edit_start = edits.first().unwrap().0.start;
 7432        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7433        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7434
 7435        let last_edit_end = edits.last().unwrap().0.end;
 7436        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7437        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7438
 7439        let cursor_row = cursor.to_point(&multibuffer).row;
 7440
 7441        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7442
 7443        let mut inlay_ids = Vec::new();
 7444        let invalidation_row_range;
 7445        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7446            Some(cursor_row..edit_end_row)
 7447        } else if cursor_row > edit_end_row {
 7448            Some(edit_start_row..cursor_row)
 7449        } else {
 7450            None
 7451        };
 7452        let is_move =
 7453            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7454        let completion = if is_move {
 7455            invalidation_row_range =
 7456                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7457            let target = first_edit_start;
 7458            InlineCompletion::Move { target, snapshot }
 7459        } else {
 7460            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7461                && !self.inline_completions_hidden_for_vim_mode;
 7462
 7463            if show_completions_in_buffer {
 7464                if edits
 7465                    .iter()
 7466                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7467                {
 7468                    let mut inlays = Vec::new();
 7469                    for (range, new_text) in &edits {
 7470                        let inlay = Inlay::inline_completion(
 7471                            post_inc(&mut self.next_inlay_id),
 7472                            range.start,
 7473                            new_text.as_str(),
 7474                        );
 7475                        inlay_ids.push(inlay.id);
 7476                        inlays.push(inlay);
 7477                    }
 7478
 7479                    self.splice_inlays(&[], inlays, cx);
 7480                } else {
 7481                    let background_color = cx.theme().status().deleted_background;
 7482                    self.highlight_text::<InlineCompletionHighlight>(
 7483                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7484                        HighlightStyle {
 7485                            background_color: Some(background_color),
 7486                            ..Default::default()
 7487                        },
 7488                        cx,
 7489                    );
 7490                }
 7491            }
 7492
 7493            invalidation_row_range = edit_start_row..edit_end_row;
 7494
 7495            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7496                if provider.show_tab_accept_marker() {
 7497                    EditDisplayMode::TabAccept
 7498                } else {
 7499                    EditDisplayMode::Inline
 7500                }
 7501            } else {
 7502                EditDisplayMode::DiffPopover
 7503            };
 7504
 7505            InlineCompletion::Edit {
 7506                edits,
 7507                edit_preview: inline_completion.edit_preview,
 7508                display_mode,
 7509                snapshot,
 7510            }
 7511        };
 7512
 7513        let invalidation_range = multibuffer
 7514            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7515            ..multibuffer.anchor_after(Point::new(
 7516                invalidation_row_range.end,
 7517                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7518            ));
 7519
 7520        self.stale_inline_completion_in_menu = None;
 7521        self.active_inline_completion = Some(InlineCompletionState {
 7522            inlay_ids,
 7523            completion,
 7524            completion_id: inline_completion.id,
 7525            invalidation_range,
 7526        });
 7527
 7528        cx.notify();
 7529
 7530        Some(())
 7531    }
 7532
 7533    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7534        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7535    }
 7536
 7537    fn clear_tasks(&mut self) {
 7538        self.tasks.clear()
 7539    }
 7540
 7541    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7542        if self.tasks.insert(key, value).is_some() {
 7543            // This case should hopefully be rare, but just in case...
 7544            log::error!(
 7545                "multiple different run targets found on a single line, only the last target will be rendered"
 7546            )
 7547        }
 7548    }
 7549
 7550    /// Get all display points of breakpoints that will be rendered within editor
 7551    ///
 7552    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7553    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7554    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7555    fn active_breakpoints(
 7556        &self,
 7557        range: Range<DisplayRow>,
 7558        window: &mut Window,
 7559        cx: &mut Context<Self>,
 7560    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7561        let mut breakpoint_display_points = HashMap::default();
 7562
 7563        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7564            return breakpoint_display_points;
 7565        };
 7566
 7567        let snapshot = self.snapshot(window, cx);
 7568
 7569        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7570        let Some(project) = self.project.as_ref() else {
 7571            return breakpoint_display_points;
 7572        };
 7573
 7574        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7575            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7576
 7577        for (buffer_snapshot, range, excerpt_id) in
 7578            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7579        {
 7580            let Some(buffer) = project
 7581                .read(cx)
 7582                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7583            else {
 7584                continue;
 7585            };
 7586            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7587                &buffer,
 7588                Some(
 7589                    buffer_snapshot.anchor_before(range.start)
 7590                        ..buffer_snapshot.anchor_after(range.end),
 7591                ),
 7592                buffer_snapshot,
 7593                cx,
 7594            );
 7595            for (breakpoint, state) in breakpoints {
 7596                let multi_buffer_anchor =
 7597                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7598                let position = multi_buffer_anchor
 7599                    .to_point(&multi_buffer_snapshot)
 7600                    .to_display_point(&snapshot);
 7601
 7602                breakpoint_display_points.insert(
 7603                    position.row(),
 7604                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7605                );
 7606            }
 7607        }
 7608
 7609        breakpoint_display_points
 7610    }
 7611
 7612    fn breakpoint_context_menu(
 7613        &self,
 7614        anchor: Anchor,
 7615        window: &mut Window,
 7616        cx: &mut Context<Self>,
 7617    ) -> Entity<ui::ContextMenu> {
 7618        let weak_editor = cx.weak_entity();
 7619        let focus_handle = self.focus_handle(cx);
 7620
 7621        let row = self
 7622            .buffer
 7623            .read(cx)
 7624            .snapshot(cx)
 7625            .summary_for_anchor::<Point>(&anchor)
 7626            .row;
 7627
 7628        let breakpoint = self
 7629            .breakpoint_at_row(row, window, cx)
 7630            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7631
 7632        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7633            "Edit Log Breakpoint"
 7634        } else {
 7635            "Set Log Breakpoint"
 7636        };
 7637
 7638        let condition_breakpoint_msg = if breakpoint
 7639            .as_ref()
 7640            .is_some_and(|bp| bp.1.condition.is_some())
 7641        {
 7642            "Edit Condition Breakpoint"
 7643        } else {
 7644            "Set Condition Breakpoint"
 7645        };
 7646
 7647        let hit_condition_breakpoint_msg = if breakpoint
 7648            .as_ref()
 7649            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7650        {
 7651            "Edit Hit Condition Breakpoint"
 7652        } else {
 7653            "Set Hit Condition Breakpoint"
 7654        };
 7655
 7656        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7657            "Unset Breakpoint"
 7658        } else {
 7659            "Set Breakpoint"
 7660        };
 7661
 7662        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7663
 7664        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7665            BreakpointState::Enabled => Some("Disable"),
 7666            BreakpointState::Disabled => Some("Enable"),
 7667        });
 7668
 7669        let (anchor, breakpoint) =
 7670            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7671
 7672        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7673            menu.on_blur_subscription(Subscription::new(|| {}))
 7674                .context(focus_handle)
 7675                .when(run_to_cursor, |this| {
 7676                    let weak_editor = weak_editor.clone();
 7677                    this.entry("Run to cursor", None, move |window, cx| {
 7678                        weak_editor
 7679                            .update(cx, |editor, cx| {
 7680                                editor.change_selections(None, window, cx, |s| {
 7681                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7682                                });
 7683                            })
 7684                            .ok();
 7685
 7686                        window.dispatch_action(Box::new(RunToCursor), cx);
 7687                    })
 7688                    .separator()
 7689                })
 7690                .when_some(toggle_state_msg, |this, msg| {
 7691                    this.entry(msg, None, {
 7692                        let weak_editor = weak_editor.clone();
 7693                        let breakpoint = breakpoint.clone();
 7694                        move |_window, cx| {
 7695                            weak_editor
 7696                                .update(cx, |this, cx| {
 7697                                    this.edit_breakpoint_at_anchor(
 7698                                        anchor,
 7699                                        breakpoint.as_ref().clone(),
 7700                                        BreakpointEditAction::InvertState,
 7701                                        cx,
 7702                                    );
 7703                                })
 7704                                .log_err();
 7705                        }
 7706                    })
 7707                })
 7708                .entry(set_breakpoint_msg, None, {
 7709                    let weak_editor = weak_editor.clone();
 7710                    let breakpoint = breakpoint.clone();
 7711                    move |_window, cx| {
 7712                        weak_editor
 7713                            .update(cx, |this, cx| {
 7714                                this.edit_breakpoint_at_anchor(
 7715                                    anchor,
 7716                                    breakpoint.as_ref().clone(),
 7717                                    BreakpointEditAction::Toggle,
 7718                                    cx,
 7719                                );
 7720                            })
 7721                            .log_err();
 7722                    }
 7723                })
 7724                .entry(log_breakpoint_msg, None, {
 7725                    let breakpoint = breakpoint.clone();
 7726                    let weak_editor = weak_editor.clone();
 7727                    move |window, cx| {
 7728                        weak_editor
 7729                            .update(cx, |this, cx| {
 7730                                this.add_edit_breakpoint_block(
 7731                                    anchor,
 7732                                    breakpoint.as_ref(),
 7733                                    BreakpointPromptEditAction::Log,
 7734                                    window,
 7735                                    cx,
 7736                                );
 7737                            })
 7738                            .log_err();
 7739                    }
 7740                })
 7741                .entry(condition_breakpoint_msg, None, {
 7742                    let breakpoint = breakpoint.clone();
 7743                    let weak_editor = weak_editor.clone();
 7744                    move |window, cx| {
 7745                        weak_editor
 7746                            .update(cx, |this, cx| {
 7747                                this.add_edit_breakpoint_block(
 7748                                    anchor,
 7749                                    breakpoint.as_ref(),
 7750                                    BreakpointPromptEditAction::Condition,
 7751                                    window,
 7752                                    cx,
 7753                                );
 7754                            })
 7755                            .log_err();
 7756                    }
 7757                })
 7758                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7759                    weak_editor
 7760                        .update(cx, |this, cx| {
 7761                            this.add_edit_breakpoint_block(
 7762                                anchor,
 7763                                breakpoint.as_ref(),
 7764                                BreakpointPromptEditAction::HitCondition,
 7765                                window,
 7766                                cx,
 7767                            );
 7768                        })
 7769                        .log_err();
 7770                })
 7771        })
 7772    }
 7773
 7774    fn render_breakpoint(
 7775        &self,
 7776        position: Anchor,
 7777        row: DisplayRow,
 7778        breakpoint: &Breakpoint,
 7779        state: Option<BreakpointSessionState>,
 7780        cx: &mut Context<Self>,
 7781    ) -> IconButton {
 7782        let is_rejected = state.is_some_and(|s| !s.verified);
 7783        // Is it a breakpoint that shows up when hovering over gutter?
 7784        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7785            (false, false),
 7786            |PhantomBreakpointIndicator {
 7787                 is_active,
 7788                 display_row,
 7789                 collides_with_existing_breakpoint,
 7790             }| {
 7791                (
 7792                    is_active && display_row == row,
 7793                    collides_with_existing_breakpoint,
 7794                )
 7795            },
 7796        );
 7797
 7798        let (color, icon) = {
 7799            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7800                (false, false) => ui::IconName::DebugBreakpoint,
 7801                (true, false) => ui::IconName::DebugLogBreakpoint,
 7802                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7803                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7804            };
 7805
 7806            let color = if is_phantom {
 7807                Color::Hint
 7808            } else if is_rejected {
 7809                Color::Disabled
 7810            } else {
 7811                Color::Debugger
 7812            };
 7813
 7814            (color, icon)
 7815        };
 7816
 7817        let breakpoint = Arc::from(breakpoint.clone());
 7818
 7819        let alt_as_text = gpui::Keystroke {
 7820            modifiers: Modifiers::secondary_key(),
 7821            ..Default::default()
 7822        };
 7823        let primary_action_text = if breakpoint.is_disabled() {
 7824            "Enable breakpoint"
 7825        } else if is_phantom && !collides_with_existing {
 7826            "Set breakpoint"
 7827        } else {
 7828            "Unset breakpoint"
 7829        };
 7830        let focus_handle = self.focus_handle.clone();
 7831
 7832        let meta = if is_rejected {
 7833            SharedString::from("No executable code is associated with this line.")
 7834        } else if collides_with_existing && !breakpoint.is_disabled() {
 7835            SharedString::from(format!(
 7836                "{alt_as_text}-click to disable,\nright-click for more options."
 7837            ))
 7838        } else {
 7839            SharedString::from("Right-click for more options.")
 7840        };
 7841        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7842            .icon_size(IconSize::XSmall)
 7843            .size(ui::ButtonSize::None)
 7844            .when(is_rejected, |this| {
 7845                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7846            })
 7847            .icon_color(color)
 7848            .style(ButtonStyle::Transparent)
 7849            .on_click(cx.listener({
 7850                let breakpoint = breakpoint.clone();
 7851
 7852                move |editor, event: &ClickEvent, window, cx| {
 7853                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7854                        BreakpointEditAction::InvertState
 7855                    } else {
 7856                        BreakpointEditAction::Toggle
 7857                    };
 7858
 7859                    window.focus(&editor.focus_handle(cx));
 7860                    editor.edit_breakpoint_at_anchor(
 7861                        position,
 7862                        breakpoint.as_ref().clone(),
 7863                        edit_action,
 7864                        cx,
 7865                    );
 7866                }
 7867            }))
 7868            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7869                editor.set_breakpoint_context_menu(
 7870                    row,
 7871                    Some(position),
 7872                    event.down.position,
 7873                    window,
 7874                    cx,
 7875                );
 7876            }))
 7877            .tooltip(move |window, cx| {
 7878                Tooltip::with_meta_in(
 7879                    primary_action_text,
 7880                    Some(&ToggleBreakpoint),
 7881                    meta.clone(),
 7882                    &focus_handle,
 7883                    window,
 7884                    cx,
 7885                )
 7886            })
 7887    }
 7888
 7889    fn build_tasks_context(
 7890        project: &Entity<Project>,
 7891        buffer: &Entity<Buffer>,
 7892        buffer_row: u32,
 7893        tasks: &Arc<RunnableTasks>,
 7894        cx: &mut Context<Self>,
 7895    ) -> Task<Option<task::TaskContext>> {
 7896        let position = Point::new(buffer_row, tasks.column);
 7897        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7898        let location = Location {
 7899            buffer: buffer.clone(),
 7900            range: range_start..range_start,
 7901        };
 7902        // Fill in the environmental variables from the tree-sitter captures
 7903        let mut captured_task_variables = TaskVariables::default();
 7904        for (capture_name, value) in tasks.extra_variables.clone() {
 7905            captured_task_variables.insert(
 7906                task::VariableName::Custom(capture_name.into()),
 7907                value.clone(),
 7908            );
 7909        }
 7910        project.update(cx, |project, cx| {
 7911            project.task_store().update(cx, |task_store, cx| {
 7912                task_store.task_context_for_location(captured_task_variables, location, cx)
 7913            })
 7914        })
 7915    }
 7916
 7917    pub fn spawn_nearest_task(
 7918        &mut self,
 7919        action: &SpawnNearestTask,
 7920        window: &mut Window,
 7921        cx: &mut Context<Self>,
 7922    ) {
 7923        let Some((workspace, _)) = self.workspace.clone() else {
 7924            return;
 7925        };
 7926        let Some(project) = self.project.clone() else {
 7927            return;
 7928        };
 7929
 7930        // Try to find a closest, enclosing node using tree-sitter that has a
 7931        // task
 7932        let Some((buffer, buffer_row, tasks)) = self
 7933            .find_enclosing_node_task(cx)
 7934            // Or find the task that's closest in row-distance.
 7935            .or_else(|| self.find_closest_task(cx))
 7936        else {
 7937            return;
 7938        };
 7939
 7940        let reveal_strategy = action.reveal;
 7941        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7942        cx.spawn_in(window, async move |_, cx| {
 7943            let context = task_context.await?;
 7944            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7945
 7946            let resolved = &mut resolved_task.resolved;
 7947            resolved.reveal = reveal_strategy;
 7948
 7949            workspace
 7950                .update_in(cx, |workspace, window, cx| {
 7951                    workspace.schedule_resolved_task(
 7952                        task_source_kind,
 7953                        resolved_task,
 7954                        false,
 7955                        window,
 7956                        cx,
 7957                    );
 7958                })
 7959                .ok()
 7960        })
 7961        .detach();
 7962    }
 7963
 7964    fn find_closest_task(
 7965        &mut self,
 7966        cx: &mut Context<Self>,
 7967    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7968        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7969
 7970        let ((buffer_id, row), tasks) = self
 7971            .tasks
 7972            .iter()
 7973            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7974
 7975        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7976        let tasks = Arc::new(tasks.to_owned());
 7977        Some((buffer, *row, tasks))
 7978    }
 7979
 7980    fn find_enclosing_node_task(
 7981        &mut self,
 7982        cx: &mut Context<Self>,
 7983    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7984        let snapshot = self.buffer.read(cx).snapshot(cx);
 7985        let offset = self.selections.newest::<usize>(cx).head();
 7986        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7987        let buffer_id = excerpt.buffer().remote_id();
 7988
 7989        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7990        let mut cursor = layer.node().walk();
 7991
 7992        while cursor.goto_first_child_for_byte(offset).is_some() {
 7993            if cursor.node().end_byte() == offset {
 7994                cursor.goto_next_sibling();
 7995            }
 7996        }
 7997
 7998        // Ascend to the smallest ancestor that contains the range and has a task.
 7999        loop {
 8000            let node = cursor.node();
 8001            let node_range = node.byte_range();
 8002            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8003
 8004            // Check if this node contains our offset
 8005            if node_range.start <= offset && node_range.end >= offset {
 8006                // If it contains offset, check for task
 8007                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8008                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8009                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8010                }
 8011            }
 8012
 8013            if !cursor.goto_parent() {
 8014                break;
 8015            }
 8016        }
 8017        None
 8018    }
 8019
 8020    fn render_run_indicator(
 8021        &self,
 8022        _style: &EditorStyle,
 8023        is_active: bool,
 8024        row: DisplayRow,
 8025        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8026        cx: &mut Context<Self>,
 8027    ) -> IconButton {
 8028        let color = Color::Muted;
 8029        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8030
 8031        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8032            .shape(ui::IconButtonShape::Square)
 8033            .icon_size(IconSize::XSmall)
 8034            .icon_color(color)
 8035            .toggle_state(is_active)
 8036            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8037                let quick_launch = e.down.button == MouseButton::Left;
 8038                window.focus(&editor.focus_handle(cx));
 8039                editor.toggle_code_actions(
 8040                    &ToggleCodeActions {
 8041                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8042                        quick_launch,
 8043                    },
 8044                    window,
 8045                    cx,
 8046                );
 8047            }))
 8048            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8049                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8050            }))
 8051    }
 8052
 8053    pub fn context_menu_visible(&self) -> bool {
 8054        !self.edit_prediction_preview_is_active()
 8055            && self
 8056                .context_menu
 8057                .borrow()
 8058                .as_ref()
 8059                .map_or(false, |menu| menu.visible())
 8060    }
 8061
 8062    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8063        self.context_menu
 8064            .borrow()
 8065            .as_ref()
 8066            .map(|menu| menu.origin())
 8067    }
 8068
 8069    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8070        self.context_menu_options = Some(options);
 8071    }
 8072
 8073    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8074    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8075
 8076    fn render_edit_prediction_popover(
 8077        &mut self,
 8078        text_bounds: &Bounds<Pixels>,
 8079        content_origin: gpui::Point<Pixels>,
 8080        right_margin: Pixels,
 8081        editor_snapshot: &EditorSnapshot,
 8082        visible_row_range: Range<DisplayRow>,
 8083        scroll_top: f32,
 8084        scroll_bottom: f32,
 8085        line_layouts: &[LineWithInvisibles],
 8086        line_height: Pixels,
 8087        scroll_pixel_position: gpui::Point<Pixels>,
 8088        newest_selection_head: Option<DisplayPoint>,
 8089        editor_width: Pixels,
 8090        style: &EditorStyle,
 8091        window: &mut Window,
 8092        cx: &mut App,
 8093    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8094        if self.mode().is_minimap() {
 8095            return None;
 8096        }
 8097        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8098
 8099        if self.edit_prediction_visible_in_cursor_popover(true) {
 8100            return None;
 8101        }
 8102
 8103        match &active_inline_completion.completion {
 8104            InlineCompletion::Move { target, .. } => {
 8105                let target_display_point = target.to_display_point(editor_snapshot);
 8106
 8107                if self.edit_prediction_requires_modifier() {
 8108                    if !self.edit_prediction_preview_is_active() {
 8109                        return None;
 8110                    }
 8111
 8112                    self.render_edit_prediction_modifier_jump_popover(
 8113                        text_bounds,
 8114                        content_origin,
 8115                        visible_row_range,
 8116                        line_layouts,
 8117                        line_height,
 8118                        scroll_pixel_position,
 8119                        newest_selection_head,
 8120                        target_display_point,
 8121                        window,
 8122                        cx,
 8123                    )
 8124                } else {
 8125                    self.render_edit_prediction_eager_jump_popover(
 8126                        text_bounds,
 8127                        content_origin,
 8128                        editor_snapshot,
 8129                        visible_row_range,
 8130                        scroll_top,
 8131                        scroll_bottom,
 8132                        line_height,
 8133                        scroll_pixel_position,
 8134                        target_display_point,
 8135                        editor_width,
 8136                        window,
 8137                        cx,
 8138                    )
 8139                }
 8140            }
 8141            InlineCompletion::Edit {
 8142                display_mode: EditDisplayMode::Inline,
 8143                ..
 8144            } => None,
 8145            InlineCompletion::Edit {
 8146                display_mode: EditDisplayMode::TabAccept,
 8147                edits,
 8148                ..
 8149            } => {
 8150                let range = &edits.first()?.0;
 8151                let target_display_point = range.end.to_display_point(editor_snapshot);
 8152
 8153                self.render_edit_prediction_end_of_line_popover(
 8154                    "Accept",
 8155                    editor_snapshot,
 8156                    visible_row_range,
 8157                    target_display_point,
 8158                    line_height,
 8159                    scroll_pixel_position,
 8160                    content_origin,
 8161                    editor_width,
 8162                    window,
 8163                    cx,
 8164                )
 8165            }
 8166            InlineCompletion::Edit {
 8167                edits,
 8168                edit_preview,
 8169                display_mode: EditDisplayMode::DiffPopover,
 8170                snapshot,
 8171            } => self.render_edit_prediction_diff_popover(
 8172                text_bounds,
 8173                content_origin,
 8174                right_margin,
 8175                editor_snapshot,
 8176                visible_row_range,
 8177                line_layouts,
 8178                line_height,
 8179                scroll_pixel_position,
 8180                newest_selection_head,
 8181                editor_width,
 8182                style,
 8183                edits,
 8184                edit_preview,
 8185                snapshot,
 8186                window,
 8187                cx,
 8188            ),
 8189        }
 8190    }
 8191
 8192    fn render_edit_prediction_modifier_jump_popover(
 8193        &mut self,
 8194        text_bounds: &Bounds<Pixels>,
 8195        content_origin: gpui::Point<Pixels>,
 8196        visible_row_range: Range<DisplayRow>,
 8197        line_layouts: &[LineWithInvisibles],
 8198        line_height: Pixels,
 8199        scroll_pixel_position: gpui::Point<Pixels>,
 8200        newest_selection_head: Option<DisplayPoint>,
 8201        target_display_point: DisplayPoint,
 8202        window: &mut Window,
 8203        cx: &mut App,
 8204    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8205        let scrolled_content_origin =
 8206            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8207
 8208        const SCROLL_PADDING_Y: Pixels = px(12.);
 8209
 8210        if target_display_point.row() < visible_row_range.start {
 8211            return self.render_edit_prediction_scroll_popover(
 8212                |_| SCROLL_PADDING_Y,
 8213                IconName::ArrowUp,
 8214                visible_row_range,
 8215                line_layouts,
 8216                newest_selection_head,
 8217                scrolled_content_origin,
 8218                window,
 8219                cx,
 8220            );
 8221        } else if target_display_point.row() >= visible_row_range.end {
 8222            return self.render_edit_prediction_scroll_popover(
 8223                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8224                IconName::ArrowDown,
 8225                visible_row_range,
 8226                line_layouts,
 8227                newest_selection_head,
 8228                scrolled_content_origin,
 8229                window,
 8230                cx,
 8231            );
 8232        }
 8233
 8234        const POLE_WIDTH: Pixels = px(2.);
 8235
 8236        let line_layout =
 8237            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8238        let target_column = target_display_point.column() as usize;
 8239
 8240        let target_x = line_layout.x_for_index(target_column);
 8241        let target_y =
 8242            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8243
 8244        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8245
 8246        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8247        border_color.l += 0.001;
 8248
 8249        let mut element = v_flex()
 8250            .items_end()
 8251            .when(flag_on_right, |el| el.items_start())
 8252            .child(if flag_on_right {
 8253                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8254                    .rounded_bl(px(0.))
 8255                    .rounded_tl(px(0.))
 8256                    .border_l_2()
 8257                    .border_color(border_color)
 8258            } else {
 8259                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8260                    .rounded_br(px(0.))
 8261                    .rounded_tr(px(0.))
 8262                    .border_r_2()
 8263                    .border_color(border_color)
 8264            })
 8265            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8266            .into_any();
 8267
 8268        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8269
 8270        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8271            - point(
 8272                if flag_on_right {
 8273                    POLE_WIDTH
 8274                } else {
 8275                    size.width - POLE_WIDTH
 8276                },
 8277                size.height - line_height,
 8278            );
 8279
 8280        origin.x = origin.x.max(content_origin.x);
 8281
 8282        element.prepaint_at(origin, window, cx);
 8283
 8284        Some((element, origin))
 8285    }
 8286
 8287    fn render_edit_prediction_scroll_popover(
 8288        &mut self,
 8289        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8290        scroll_icon: IconName,
 8291        visible_row_range: Range<DisplayRow>,
 8292        line_layouts: &[LineWithInvisibles],
 8293        newest_selection_head: Option<DisplayPoint>,
 8294        scrolled_content_origin: gpui::Point<Pixels>,
 8295        window: &mut Window,
 8296        cx: &mut App,
 8297    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8298        let mut element = self
 8299            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8300            .into_any();
 8301
 8302        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8303
 8304        let cursor = newest_selection_head?;
 8305        let cursor_row_layout =
 8306            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8307        let cursor_column = cursor.column() as usize;
 8308
 8309        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8310
 8311        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8312
 8313        element.prepaint_at(origin, window, cx);
 8314        Some((element, origin))
 8315    }
 8316
 8317    fn render_edit_prediction_eager_jump_popover(
 8318        &mut self,
 8319        text_bounds: &Bounds<Pixels>,
 8320        content_origin: gpui::Point<Pixels>,
 8321        editor_snapshot: &EditorSnapshot,
 8322        visible_row_range: Range<DisplayRow>,
 8323        scroll_top: f32,
 8324        scroll_bottom: f32,
 8325        line_height: Pixels,
 8326        scroll_pixel_position: gpui::Point<Pixels>,
 8327        target_display_point: DisplayPoint,
 8328        editor_width: Pixels,
 8329        window: &mut Window,
 8330        cx: &mut App,
 8331    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8332        if target_display_point.row().as_f32() < scroll_top {
 8333            let mut element = self
 8334                .render_edit_prediction_line_popover(
 8335                    "Jump to Edit",
 8336                    Some(IconName::ArrowUp),
 8337                    window,
 8338                    cx,
 8339                )?
 8340                .into_any();
 8341
 8342            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8343            let offset = point(
 8344                (text_bounds.size.width - size.width) / 2.,
 8345                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8346            );
 8347
 8348            let origin = text_bounds.origin + offset;
 8349            element.prepaint_at(origin, window, cx);
 8350            Some((element, origin))
 8351        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8352            let mut element = self
 8353                .render_edit_prediction_line_popover(
 8354                    "Jump to Edit",
 8355                    Some(IconName::ArrowDown),
 8356                    window,
 8357                    cx,
 8358                )?
 8359                .into_any();
 8360
 8361            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8362            let offset = point(
 8363                (text_bounds.size.width - size.width) / 2.,
 8364                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8365            );
 8366
 8367            let origin = text_bounds.origin + offset;
 8368            element.prepaint_at(origin, window, cx);
 8369            Some((element, origin))
 8370        } else {
 8371            self.render_edit_prediction_end_of_line_popover(
 8372                "Jump to Edit",
 8373                editor_snapshot,
 8374                visible_row_range,
 8375                target_display_point,
 8376                line_height,
 8377                scroll_pixel_position,
 8378                content_origin,
 8379                editor_width,
 8380                window,
 8381                cx,
 8382            )
 8383        }
 8384    }
 8385
 8386    fn render_edit_prediction_end_of_line_popover(
 8387        self: &mut Editor,
 8388        label: &'static str,
 8389        editor_snapshot: &EditorSnapshot,
 8390        visible_row_range: Range<DisplayRow>,
 8391        target_display_point: DisplayPoint,
 8392        line_height: Pixels,
 8393        scroll_pixel_position: gpui::Point<Pixels>,
 8394        content_origin: gpui::Point<Pixels>,
 8395        editor_width: Pixels,
 8396        window: &mut Window,
 8397        cx: &mut App,
 8398    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8399        let target_line_end = DisplayPoint::new(
 8400            target_display_point.row(),
 8401            editor_snapshot.line_len(target_display_point.row()),
 8402        );
 8403
 8404        let mut element = self
 8405            .render_edit_prediction_line_popover(label, None, window, cx)?
 8406            .into_any();
 8407
 8408        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8409
 8410        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8411
 8412        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8413        let mut origin = start_point
 8414            + line_origin
 8415            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8416        origin.x = origin.x.max(content_origin.x);
 8417
 8418        let max_x = content_origin.x + editor_width - size.width;
 8419
 8420        if origin.x > max_x {
 8421            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8422
 8423            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8424                origin.y += offset;
 8425                IconName::ArrowUp
 8426            } else {
 8427                origin.y -= offset;
 8428                IconName::ArrowDown
 8429            };
 8430
 8431            element = self
 8432                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8433                .into_any();
 8434
 8435            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8436
 8437            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8438        }
 8439
 8440        element.prepaint_at(origin, window, cx);
 8441        Some((element, origin))
 8442    }
 8443
 8444    fn render_edit_prediction_diff_popover(
 8445        self: &Editor,
 8446        text_bounds: &Bounds<Pixels>,
 8447        content_origin: gpui::Point<Pixels>,
 8448        right_margin: Pixels,
 8449        editor_snapshot: &EditorSnapshot,
 8450        visible_row_range: Range<DisplayRow>,
 8451        line_layouts: &[LineWithInvisibles],
 8452        line_height: Pixels,
 8453        scroll_pixel_position: gpui::Point<Pixels>,
 8454        newest_selection_head: Option<DisplayPoint>,
 8455        editor_width: Pixels,
 8456        style: &EditorStyle,
 8457        edits: &Vec<(Range<Anchor>, String)>,
 8458        edit_preview: &Option<language::EditPreview>,
 8459        snapshot: &language::BufferSnapshot,
 8460        window: &mut Window,
 8461        cx: &mut App,
 8462    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8463        let edit_start = edits
 8464            .first()
 8465            .unwrap()
 8466            .0
 8467            .start
 8468            .to_display_point(editor_snapshot);
 8469        let edit_end = edits
 8470            .last()
 8471            .unwrap()
 8472            .0
 8473            .end
 8474            .to_display_point(editor_snapshot);
 8475
 8476        let is_visible = visible_row_range.contains(&edit_start.row())
 8477            || visible_row_range.contains(&edit_end.row());
 8478        if !is_visible {
 8479            return None;
 8480        }
 8481
 8482        let highlighted_edits =
 8483            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8484
 8485        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8486        let line_count = highlighted_edits.text.lines().count();
 8487
 8488        const BORDER_WIDTH: Pixels = px(1.);
 8489
 8490        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8491        let has_keybind = keybind.is_some();
 8492
 8493        let mut element = h_flex()
 8494            .items_start()
 8495            .child(
 8496                h_flex()
 8497                    .bg(cx.theme().colors().editor_background)
 8498                    .border(BORDER_WIDTH)
 8499                    .shadow_sm()
 8500                    .border_color(cx.theme().colors().border)
 8501                    .rounded_l_lg()
 8502                    .when(line_count > 1, |el| el.rounded_br_lg())
 8503                    .pr_1()
 8504                    .child(styled_text),
 8505            )
 8506            .child(
 8507                h_flex()
 8508                    .h(line_height + BORDER_WIDTH * 2.)
 8509                    .px_1p5()
 8510                    .gap_1()
 8511                    // Workaround: For some reason, there's a gap if we don't do this
 8512                    .ml(-BORDER_WIDTH)
 8513                    .shadow(vec![gpui::BoxShadow {
 8514                        color: gpui::black().opacity(0.05),
 8515                        offset: point(px(1.), px(1.)),
 8516                        blur_radius: px(2.),
 8517                        spread_radius: px(0.),
 8518                    }])
 8519                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8520                    .border(BORDER_WIDTH)
 8521                    .border_color(cx.theme().colors().border)
 8522                    .rounded_r_lg()
 8523                    .id("edit_prediction_diff_popover_keybind")
 8524                    .when(!has_keybind, |el| {
 8525                        let status_colors = cx.theme().status();
 8526
 8527                        el.bg(status_colors.error_background)
 8528                            .border_color(status_colors.error.opacity(0.6))
 8529                            .child(Icon::new(IconName::Info).color(Color::Error))
 8530                            .cursor_default()
 8531                            .hoverable_tooltip(move |_window, cx| {
 8532                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8533                            })
 8534                    })
 8535                    .children(keybind),
 8536            )
 8537            .into_any();
 8538
 8539        let longest_row =
 8540            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8541        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8542            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8543        } else {
 8544            layout_line(
 8545                longest_row,
 8546                editor_snapshot,
 8547                style,
 8548                editor_width,
 8549                |_| false,
 8550                window,
 8551                cx,
 8552            )
 8553            .width
 8554        };
 8555
 8556        let viewport_bounds =
 8557            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8558                right: -right_margin,
 8559                ..Default::default()
 8560            });
 8561
 8562        let x_after_longest =
 8563            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8564                - scroll_pixel_position.x;
 8565
 8566        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8567
 8568        // Fully visible if it can be displayed within the window (allow overlapping other
 8569        // panes). However, this is only allowed if the popover starts within text_bounds.
 8570        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8571            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8572
 8573        let mut origin = if can_position_to_the_right {
 8574            point(
 8575                x_after_longest,
 8576                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8577                    - scroll_pixel_position.y,
 8578            )
 8579        } else {
 8580            let cursor_row = newest_selection_head.map(|head| head.row());
 8581            let above_edit = edit_start
 8582                .row()
 8583                .0
 8584                .checked_sub(line_count as u32)
 8585                .map(DisplayRow);
 8586            let below_edit = Some(edit_end.row() + 1);
 8587            let above_cursor =
 8588                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8589            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8590
 8591            // Place the edit popover adjacent to the edit if there is a location
 8592            // available that is onscreen and does not obscure the cursor. Otherwise,
 8593            // place it adjacent to the cursor.
 8594            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8595                .into_iter()
 8596                .flatten()
 8597                .find(|&start_row| {
 8598                    let end_row = start_row + line_count as u32;
 8599                    visible_row_range.contains(&start_row)
 8600                        && visible_row_range.contains(&end_row)
 8601                        && cursor_row.map_or(true, |cursor_row| {
 8602                            !((start_row..end_row).contains(&cursor_row))
 8603                        })
 8604                })?;
 8605
 8606            content_origin
 8607                + point(
 8608                    -scroll_pixel_position.x,
 8609                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8610                )
 8611        };
 8612
 8613        origin.x -= BORDER_WIDTH;
 8614
 8615        window.defer_draw(element, origin, 1);
 8616
 8617        // Do not return an element, since it will already be drawn due to defer_draw.
 8618        None
 8619    }
 8620
 8621    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8622        px(30.)
 8623    }
 8624
 8625    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8626        if self.read_only(cx) {
 8627            cx.theme().players().read_only()
 8628        } else {
 8629            self.style.as_ref().unwrap().local_player
 8630        }
 8631    }
 8632
 8633    fn render_edit_prediction_accept_keybind(
 8634        &self,
 8635        window: &mut Window,
 8636        cx: &App,
 8637    ) -> Option<AnyElement> {
 8638        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8639        let accept_keystroke = accept_binding.keystroke()?;
 8640
 8641        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8642
 8643        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8644            Color::Accent
 8645        } else {
 8646            Color::Muted
 8647        };
 8648
 8649        h_flex()
 8650            .px_0p5()
 8651            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8652            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8653            .text_size(TextSize::XSmall.rems(cx))
 8654            .child(h_flex().children(ui::render_modifiers(
 8655                &accept_keystroke.modifiers,
 8656                PlatformStyle::platform(),
 8657                Some(modifiers_color),
 8658                Some(IconSize::XSmall.rems().into()),
 8659                true,
 8660            )))
 8661            .when(is_platform_style_mac, |parent| {
 8662                parent.child(accept_keystroke.key.clone())
 8663            })
 8664            .when(!is_platform_style_mac, |parent| {
 8665                parent.child(
 8666                    Key::new(
 8667                        util::capitalize(&accept_keystroke.key),
 8668                        Some(Color::Default),
 8669                    )
 8670                    .size(Some(IconSize::XSmall.rems().into())),
 8671                )
 8672            })
 8673            .into_any()
 8674            .into()
 8675    }
 8676
 8677    fn render_edit_prediction_line_popover(
 8678        &self,
 8679        label: impl Into<SharedString>,
 8680        icon: Option<IconName>,
 8681        window: &mut Window,
 8682        cx: &App,
 8683    ) -> Option<Stateful<Div>> {
 8684        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8685
 8686        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8687        let has_keybind = keybind.is_some();
 8688
 8689        let result = h_flex()
 8690            .id("ep-line-popover")
 8691            .py_0p5()
 8692            .pl_1()
 8693            .pr(padding_right)
 8694            .gap_1()
 8695            .rounded_md()
 8696            .border_1()
 8697            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8698            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8699            .shadow_sm()
 8700            .when(!has_keybind, |el| {
 8701                let status_colors = cx.theme().status();
 8702
 8703                el.bg(status_colors.error_background)
 8704                    .border_color(status_colors.error.opacity(0.6))
 8705                    .pl_2()
 8706                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8707                    .cursor_default()
 8708                    .hoverable_tooltip(move |_window, cx| {
 8709                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8710                    })
 8711            })
 8712            .children(keybind)
 8713            .child(
 8714                Label::new(label)
 8715                    .size(LabelSize::Small)
 8716                    .when(!has_keybind, |el| {
 8717                        el.color(cx.theme().status().error.into()).strikethrough()
 8718                    }),
 8719            )
 8720            .when(!has_keybind, |el| {
 8721                el.child(
 8722                    h_flex().ml_1().child(
 8723                        Icon::new(IconName::Info)
 8724                            .size(IconSize::Small)
 8725                            .color(cx.theme().status().error.into()),
 8726                    ),
 8727                )
 8728            })
 8729            .when_some(icon, |element, icon| {
 8730                element.child(
 8731                    div()
 8732                        .mt(px(1.5))
 8733                        .child(Icon::new(icon).size(IconSize::Small)),
 8734                )
 8735            });
 8736
 8737        Some(result)
 8738    }
 8739
 8740    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8741        let accent_color = cx.theme().colors().text_accent;
 8742        let editor_bg_color = cx.theme().colors().editor_background;
 8743        editor_bg_color.blend(accent_color.opacity(0.1))
 8744    }
 8745
 8746    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8747        let accent_color = cx.theme().colors().text_accent;
 8748        let editor_bg_color = cx.theme().colors().editor_background;
 8749        editor_bg_color.blend(accent_color.opacity(0.6))
 8750    }
 8751
 8752    fn render_edit_prediction_cursor_popover(
 8753        &self,
 8754        min_width: Pixels,
 8755        max_width: Pixels,
 8756        cursor_point: Point,
 8757        style: &EditorStyle,
 8758        accept_keystroke: Option<&gpui::Keystroke>,
 8759        _window: &Window,
 8760        cx: &mut Context<Editor>,
 8761    ) -> Option<AnyElement> {
 8762        let provider = self.edit_prediction_provider.as_ref()?;
 8763
 8764        if provider.provider.needs_terms_acceptance(cx) {
 8765            return Some(
 8766                h_flex()
 8767                    .min_w(min_width)
 8768                    .flex_1()
 8769                    .px_2()
 8770                    .py_1()
 8771                    .gap_3()
 8772                    .elevation_2(cx)
 8773                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8774                    .id("accept-terms")
 8775                    .cursor_pointer()
 8776                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8777                    .on_click(cx.listener(|this, _event, window, cx| {
 8778                        cx.stop_propagation();
 8779                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8780                        window.dispatch_action(
 8781                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8782                            cx,
 8783                        );
 8784                    }))
 8785                    .child(
 8786                        h_flex()
 8787                            .flex_1()
 8788                            .gap_2()
 8789                            .child(Icon::new(IconName::ZedPredict))
 8790                            .child(Label::new("Accept Terms of Service"))
 8791                            .child(div().w_full())
 8792                            .child(
 8793                                Icon::new(IconName::ArrowUpRight)
 8794                                    .color(Color::Muted)
 8795                                    .size(IconSize::Small),
 8796                            )
 8797                            .into_any_element(),
 8798                    )
 8799                    .into_any(),
 8800            );
 8801        }
 8802
 8803        let is_refreshing = provider.provider.is_refreshing(cx);
 8804
 8805        fn pending_completion_container() -> Div {
 8806            h_flex()
 8807                .h_full()
 8808                .flex_1()
 8809                .gap_2()
 8810                .child(Icon::new(IconName::ZedPredict))
 8811        }
 8812
 8813        let completion = match &self.active_inline_completion {
 8814            Some(prediction) => {
 8815                if !self.has_visible_completions_menu() {
 8816                    const RADIUS: Pixels = px(6.);
 8817                    const BORDER_WIDTH: Pixels = px(1.);
 8818
 8819                    return Some(
 8820                        h_flex()
 8821                            .elevation_2(cx)
 8822                            .border(BORDER_WIDTH)
 8823                            .border_color(cx.theme().colors().border)
 8824                            .when(accept_keystroke.is_none(), |el| {
 8825                                el.border_color(cx.theme().status().error)
 8826                            })
 8827                            .rounded(RADIUS)
 8828                            .rounded_tl(px(0.))
 8829                            .overflow_hidden()
 8830                            .child(div().px_1p5().child(match &prediction.completion {
 8831                                InlineCompletion::Move { target, snapshot } => {
 8832                                    use text::ToPoint as _;
 8833                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8834                                    {
 8835                                        Icon::new(IconName::ZedPredictDown)
 8836                                    } else {
 8837                                        Icon::new(IconName::ZedPredictUp)
 8838                                    }
 8839                                }
 8840                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8841                            }))
 8842                            .child(
 8843                                h_flex()
 8844                                    .gap_1()
 8845                                    .py_1()
 8846                                    .px_2()
 8847                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8848                                    .border_l_1()
 8849                                    .border_color(cx.theme().colors().border)
 8850                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8851                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8852                                        el.child(
 8853                                            Label::new("Hold")
 8854                                                .size(LabelSize::Small)
 8855                                                .when(accept_keystroke.is_none(), |el| {
 8856                                                    el.strikethrough()
 8857                                                })
 8858                                                .line_height_style(LineHeightStyle::UiLabel),
 8859                                        )
 8860                                    })
 8861                                    .id("edit_prediction_cursor_popover_keybind")
 8862                                    .when(accept_keystroke.is_none(), |el| {
 8863                                        let status_colors = cx.theme().status();
 8864
 8865                                        el.bg(status_colors.error_background)
 8866                                            .border_color(status_colors.error.opacity(0.6))
 8867                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8868                                            .cursor_default()
 8869                                            .hoverable_tooltip(move |_window, cx| {
 8870                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8871                                                    .into()
 8872                                            })
 8873                                    })
 8874                                    .when_some(
 8875                                        accept_keystroke.as_ref(),
 8876                                        |el, accept_keystroke| {
 8877                                            el.child(h_flex().children(ui::render_modifiers(
 8878                                                &accept_keystroke.modifiers,
 8879                                                PlatformStyle::platform(),
 8880                                                Some(Color::Default),
 8881                                                Some(IconSize::XSmall.rems().into()),
 8882                                                false,
 8883                                            )))
 8884                                        },
 8885                                    ),
 8886                            )
 8887                            .into_any(),
 8888                    );
 8889                }
 8890
 8891                self.render_edit_prediction_cursor_popover_preview(
 8892                    prediction,
 8893                    cursor_point,
 8894                    style,
 8895                    cx,
 8896                )?
 8897            }
 8898
 8899            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8900                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8901                    stale_completion,
 8902                    cursor_point,
 8903                    style,
 8904                    cx,
 8905                )?,
 8906
 8907                None => {
 8908                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8909                }
 8910            },
 8911
 8912            None => pending_completion_container().child(Label::new("No Prediction")),
 8913        };
 8914
 8915        let completion = if is_refreshing {
 8916            completion
 8917                .with_animation(
 8918                    "loading-completion",
 8919                    Animation::new(Duration::from_secs(2))
 8920                        .repeat()
 8921                        .with_easing(pulsating_between(0.4, 0.8)),
 8922                    |label, delta| label.opacity(delta),
 8923                )
 8924                .into_any_element()
 8925        } else {
 8926            completion.into_any_element()
 8927        };
 8928
 8929        let has_completion = self.active_inline_completion.is_some();
 8930
 8931        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8932        Some(
 8933            h_flex()
 8934                .min_w(min_width)
 8935                .max_w(max_width)
 8936                .flex_1()
 8937                .elevation_2(cx)
 8938                .border_color(cx.theme().colors().border)
 8939                .child(
 8940                    div()
 8941                        .flex_1()
 8942                        .py_1()
 8943                        .px_2()
 8944                        .overflow_hidden()
 8945                        .child(completion),
 8946                )
 8947                .when_some(accept_keystroke, |el, accept_keystroke| {
 8948                    if !accept_keystroke.modifiers.modified() {
 8949                        return el;
 8950                    }
 8951
 8952                    el.child(
 8953                        h_flex()
 8954                            .h_full()
 8955                            .border_l_1()
 8956                            .rounded_r_lg()
 8957                            .border_color(cx.theme().colors().border)
 8958                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8959                            .gap_1()
 8960                            .py_1()
 8961                            .px_2()
 8962                            .child(
 8963                                h_flex()
 8964                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8965                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8966                                    .child(h_flex().children(ui::render_modifiers(
 8967                                        &accept_keystroke.modifiers,
 8968                                        PlatformStyle::platform(),
 8969                                        Some(if !has_completion {
 8970                                            Color::Muted
 8971                                        } else {
 8972                                            Color::Default
 8973                                        }),
 8974                                        None,
 8975                                        false,
 8976                                    ))),
 8977                            )
 8978                            .child(Label::new("Preview").into_any_element())
 8979                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8980                    )
 8981                })
 8982                .into_any(),
 8983        )
 8984    }
 8985
 8986    fn render_edit_prediction_cursor_popover_preview(
 8987        &self,
 8988        completion: &InlineCompletionState,
 8989        cursor_point: Point,
 8990        style: &EditorStyle,
 8991        cx: &mut Context<Editor>,
 8992    ) -> Option<Div> {
 8993        use text::ToPoint as _;
 8994
 8995        fn render_relative_row_jump(
 8996            prefix: impl Into<String>,
 8997            current_row: u32,
 8998            target_row: u32,
 8999        ) -> Div {
 9000            let (row_diff, arrow) = if target_row < current_row {
 9001                (current_row - target_row, IconName::ArrowUp)
 9002            } else {
 9003                (target_row - current_row, IconName::ArrowDown)
 9004            };
 9005
 9006            h_flex()
 9007                .child(
 9008                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9009                        .color(Color::Muted)
 9010                        .size(LabelSize::Small),
 9011                )
 9012                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9013        }
 9014
 9015        match &completion.completion {
 9016            InlineCompletion::Move {
 9017                target, snapshot, ..
 9018            } => Some(
 9019                h_flex()
 9020                    .px_2()
 9021                    .gap_2()
 9022                    .flex_1()
 9023                    .child(
 9024                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9025                            Icon::new(IconName::ZedPredictDown)
 9026                        } else {
 9027                            Icon::new(IconName::ZedPredictUp)
 9028                        },
 9029                    )
 9030                    .child(Label::new("Jump to Edit")),
 9031            ),
 9032
 9033            InlineCompletion::Edit {
 9034                edits,
 9035                edit_preview,
 9036                snapshot,
 9037                display_mode: _,
 9038            } => {
 9039                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9040
 9041                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9042                    &snapshot,
 9043                    &edits,
 9044                    edit_preview.as_ref()?,
 9045                    true,
 9046                    cx,
 9047                )
 9048                .first_line_preview();
 9049
 9050                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9051                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9052
 9053                let preview = h_flex()
 9054                    .gap_1()
 9055                    .min_w_16()
 9056                    .child(styled_text)
 9057                    .when(has_more_lines, |parent| parent.child(""));
 9058
 9059                let left = if first_edit_row != cursor_point.row {
 9060                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9061                        .into_any_element()
 9062                } else {
 9063                    Icon::new(IconName::ZedPredict).into_any_element()
 9064                };
 9065
 9066                Some(
 9067                    h_flex()
 9068                        .h_full()
 9069                        .flex_1()
 9070                        .gap_2()
 9071                        .pr_1()
 9072                        .overflow_x_hidden()
 9073                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9074                        .child(left)
 9075                        .child(preview),
 9076                )
 9077            }
 9078        }
 9079    }
 9080
 9081    pub fn render_context_menu(
 9082        &self,
 9083        style: &EditorStyle,
 9084        max_height_in_lines: u32,
 9085        window: &mut Window,
 9086        cx: &mut Context<Editor>,
 9087    ) -> Option<AnyElement> {
 9088        let menu = self.context_menu.borrow();
 9089        let menu = menu.as_ref()?;
 9090        if !menu.visible() {
 9091            return None;
 9092        };
 9093        Some(menu.render(style, max_height_in_lines, window, cx))
 9094    }
 9095
 9096    fn render_context_menu_aside(
 9097        &mut self,
 9098        max_size: Size<Pixels>,
 9099        window: &mut Window,
 9100        cx: &mut Context<Editor>,
 9101    ) -> Option<AnyElement> {
 9102        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9103            if menu.visible() {
 9104                menu.render_aside(max_size, window, cx)
 9105            } else {
 9106                None
 9107            }
 9108        })
 9109    }
 9110
 9111    fn hide_context_menu(
 9112        &mut self,
 9113        window: &mut Window,
 9114        cx: &mut Context<Self>,
 9115    ) -> Option<CodeContextMenu> {
 9116        cx.notify();
 9117        self.completion_tasks.clear();
 9118        let context_menu = self.context_menu.borrow_mut().take();
 9119        self.stale_inline_completion_in_menu.take();
 9120        self.update_visible_inline_completion(window, cx);
 9121        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9122            if let Some(completion_provider) = &self.completion_provider {
 9123                completion_provider.selection_changed(None, window, cx);
 9124            }
 9125        }
 9126        context_menu
 9127    }
 9128
 9129    fn show_snippet_choices(
 9130        &mut self,
 9131        choices: &Vec<String>,
 9132        selection: Range<Anchor>,
 9133        cx: &mut Context<Self>,
 9134    ) {
 9135        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9136            (Some(a), Some(b)) if a == b => a,
 9137            _ => {
 9138                log::error!("expected anchor range to have matching buffer IDs");
 9139                return;
 9140            }
 9141        };
 9142        let multi_buffer = self.buffer().read(cx);
 9143        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9144            return;
 9145        };
 9146
 9147        let id = post_inc(&mut self.next_completion_id);
 9148        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9149        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9150            CompletionsMenu::new_snippet_choices(
 9151                id,
 9152                true,
 9153                choices,
 9154                selection,
 9155                buffer,
 9156                snippet_sort_order,
 9157            ),
 9158        ));
 9159    }
 9160
 9161    pub fn insert_snippet(
 9162        &mut self,
 9163        insertion_ranges: &[Range<usize>],
 9164        snippet: Snippet,
 9165        window: &mut Window,
 9166        cx: &mut Context<Self>,
 9167    ) -> Result<()> {
 9168        struct Tabstop<T> {
 9169            is_end_tabstop: bool,
 9170            ranges: Vec<Range<T>>,
 9171            choices: Option<Vec<String>>,
 9172        }
 9173
 9174        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9175            let snippet_text: Arc<str> = snippet.text.clone().into();
 9176            let edits = insertion_ranges
 9177                .iter()
 9178                .cloned()
 9179                .map(|range| (range, snippet_text.clone()));
 9180            let autoindent_mode = AutoindentMode::Block {
 9181                original_indent_columns: Vec::new(),
 9182            };
 9183            buffer.edit(edits, Some(autoindent_mode), cx);
 9184
 9185            let snapshot = &*buffer.read(cx);
 9186            let snippet = &snippet;
 9187            snippet
 9188                .tabstops
 9189                .iter()
 9190                .map(|tabstop| {
 9191                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9192                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9193                    });
 9194                    let mut tabstop_ranges = tabstop
 9195                        .ranges
 9196                        .iter()
 9197                        .flat_map(|tabstop_range| {
 9198                            let mut delta = 0_isize;
 9199                            insertion_ranges.iter().map(move |insertion_range| {
 9200                                let insertion_start = insertion_range.start as isize + delta;
 9201                                delta +=
 9202                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9203
 9204                                let start = ((insertion_start + tabstop_range.start) as usize)
 9205                                    .min(snapshot.len());
 9206                                let end = ((insertion_start + tabstop_range.end) as usize)
 9207                                    .min(snapshot.len());
 9208                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9209                            })
 9210                        })
 9211                        .collect::<Vec<_>>();
 9212                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9213
 9214                    Tabstop {
 9215                        is_end_tabstop,
 9216                        ranges: tabstop_ranges,
 9217                        choices: tabstop.choices.clone(),
 9218                    }
 9219                })
 9220                .collect::<Vec<_>>()
 9221        });
 9222        if let Some(tabstop) = tabstops.first() {
 9223            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9224                // Reverse order so that the first range is the newest created selection.
 9225                // Completions will use it and autoscroll will prioritize it.
 9226                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9227            });
 9228
 9229            if let Some(choices) = &tabstop.choices {
 9230                if let Some(selection) = tabstop.ranges.first() {
 9231                    self.show_snippet_choices(choices, selection.clone(), cx)
 9232                }
 9233            }
 9234
 9235            // If we're already at the last tabstop and it's at the end of the snippet,
 9236            // we're done, we don't need to keep the state around.
 9237            if !tabstop.is_end_tabstop {
 9238                let choices = tabstops
 9239                    .iter()
 9240                    .map(|tabstop| tabstop.choices.clone())
 9241                    .collect();
 9242
 9243                let ranges = tabstops
 9244                    .into_iter()
 9245                    .map(|tabstop| tabstop.ranges)
 9246                    .collect::<Vec<_>>();
 9247
 9248                self.snippet_stack.push(SnippetState {
 9249                    active_index: 0,
 9250                    ranges,
 9251                    choices,
 9252                });
 9253            }
 9254
 9255            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9256            if self.autoclose_regions.is_empty() {
 9257                let snapshot = self.buffer.read(cx).snapshot(cx);
 9258                for selection in &mut self.selections.all::<Point>(cx) {
 9259                    let selection_head = selection.head();
 9260                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9261                        continue;
 9262                    };
 9263
 9264                    let mut bracket_pair = None;
 9265                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9266                    let prev_chars = snapshot
 9267                        .reversed_chars_at(selection_head)
 9268                        .collect::<String>();
 9269                    for (pair, enabled) in scope.brackets() {
 9270                        if enabled
 9271                            && pair.close
 9272                            && prev_chars.starts_with(pair.start.as_str())
 9273                            && next_chars.starts_with(pair.end.as_str())
 9274                        {
 9275                            bracket_pair = Some(pair.clone());
 9276                            break;
 9277                        }
 9278                    }
 9279                    if let Some(pair) = bracket_pair {
 9280                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9281                        let autoclose_enabled =
 9282                            self.use_autoclose && snapshot_settings.use_autoclose;
 9283                        if autoclose_enabled {
 9284                            let start = snapshot.anchor_after(selection_head);
 9285                            let end = snapshot.anchor_after(selection_head);
 9286                            self.autoclose_regions.push(AutocloseRegion {
 9287                                selection_id: selection.id,
 9288                                range: start..end,
 9289                                pair,
 9290                            });
 9291                        }
 9292                    }
 9293                }
 9294            }
 9295        }
 9296        Ok(())
 9297    }
 9298
 9299    pub fn move_to_next_snippet_tabstop(
 9300        &mut self,
 9301        window: &mut Window,
 9302        cx: &mut Context<Self>,
 9303    ) -> bool {
 9304        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9305    }
 9306
 9307    pub fn move_to_prev_snippet_tabstop(
 9308        &mut self,
 9309        window: &mut Window,
 9310        cx: &mut Context<Self>,
 9311    ) -> bool {
 9312        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9313    }
 9314
 9315    pub fn move_to_snippet_tabstop(
 9316        &mut self,
 9317        bias: Bias,
 9318        window: &mut Window,
 9319        cx: &mut Context<Self>,
 9320    ) -> bool {
 9321        if let Some(mut snippet) = self.snippet_stack.pop() {
 9322            match bias {
 9323                Bias::Left => {
 9324                    if snippet.active_index > 0 {
 9325                        snippet.active_index -= 1;
 9326                    } else {
 9327                        self.snippet_stack.push(snippet);
 9328                        return false;
 9329                    }
 9330                }
 9331                Bias::Right => {
 9332                    if snippet.active_index + 1 < snippet.ranges.len() {
 9333                        snippet.active_index += 1;
 9334                    } else {
 9335                        self.snippet_stack.push(snippet);
 9336                        return false;
 9337                    }
 9338                }
 9339            }
 9340            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9341                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9342                    // Reverse order so that the first range is the newest created selection.
 9343                    // Completions will use it and autoscroll will prioritize it.
 9344                    s.select_ranges(current_ranges.iter().rev().cloned())
 9345                });
 9346
 9347                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9348                    if let Some(selection) = current_ranges.first() {
 9349                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9350                    }
 9351                }
 9352
 9353                // If snippet state is not at the last tabstop, push it back on the stack
 9354                if snippet.active_index + 1 < snippet.ranges.len() {
 9355                    self.snippet_stack.push(snippet);
 9356                }
 9357                return true;
 9358            }
 9359        }
 9360
 9361        false
 9362    }
 9363
 9364    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9365        self.transact(window, cx, |this, window, cx| {
 9366            this.select_all(&SelectAll, window, cx);
 9367            this.insert("", window, cx);
 9368        });
 9369    }
 9370
 9371    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9372        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9373        self.transact(window, cx, |this, window, cx| {
 9374            this.select_autoclose_pair(window, cx);
 9375            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9376            if !this.linked_edit_ranges.is_empty() {
 9377                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9378                let snapshot = this.buffer.read(cx).snapshot(cx);
 9379
 9380                for selection in selections.iter() {
 9381                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9382                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9383                    if selection_start.buffer_id != selection_end.buffer_id {
 9384                        continue;
 9385                    }
 9386                    if let Some(ranges) =
 9387                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9388                    {
 9389                        for (buffer, entries) in ranges {
 9390                            linked_ranges.entry(buffer).or_default().extend(entries);
 9391                        }
 9392                    }
 9393                }
 9394            }
 9395
 9396            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9397            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9398            for selection in &mut selections {
 9399                if selection.is_empty() {
 9400                    let old_head = selection.head();
 9401                    let mut new_head =
 9402                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9403                            .to_point(&display_map);
 9404                    if let Some((buffer, line_buffer_range)) = display_map
 9405                        .buffer_snapshot
 9406                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9407                    {
 9408                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9409                        let indent_len = match indent_size.kind {
 9410                            IndentKind::Space => {
 9411                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9412                            }
 9413                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9414                        };
 9415                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9416                            let indent_len = indent_len.get();
 9417                            new_head = cmp::min(
 9418                                new_head,
 9419                                MultiBufferPoint::new(
 9420                                    old_head.row,
 9421                                    ((old_head.column - 1) / indent_len) * indent_len,
 9422                                ),
 9423                            );
 9424                        }
 9425                    }
 9426
 9427                    selection.set_head(new_head, SelectionGoal::None);
 9428                }
 9429            }
 9430
 9431            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9432                s.select(selections)
 9433            });
 9434            this.insert("", window, cx);
 9435            let empty_str: Arc<str> = Arc::from("");
 9436            for (buffer, edits) in linked_ranges {
 9437                let snapshot = buffer.read(cx).snapshot();
 9438                use text::ToPoint as TP;
 9439
 9440                let edits = edits
 9441                    .into_iter()
 9442                    .map(|range| {
 9443                        let end_point = TP::to_point(&range.end, &snapshot);
 9444                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9445
 9446                        if end_point == start_point {
 9447                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9448                                .saturating_sub(1);
 9449                            start_point =
 9450                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9451                        };
 9452
 9453                        (start_point..end_point, empty_str.clone())
 9454                    })
 9455                    .sorted_by_key(|(range, _)| range.start)
 9456                    .collect::<Vec<_>>();
 9457                buffer.update(cx, |this, cx| {
 9458                    this.edit(edits, None, cx);
 9459                })
 9460            }
 9461            this.refresh_inline_completion(true, false, window, cx);
 9462            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9463        });
 9464    }
 9465
 9466    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9467        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9468        self.transact(window, cx, |this, window, cx| {
 9469            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9470                s.move_with(|map, selection| {
 9471                    if selection.is_empty() {
 9472                        let cursor = movement::right(map, selection.head());
 9473                        selection.end = cursor;
 9474                        selection.reversed = true;
 9475                        selection.goal = SelectionGoal::None;
 9476                    }
 9477                })
 9478            });
 9479            this.insert("", window, cx);
 9480            this.refresh_inline_completion(true, false, window, cx);
 9481        });
 9482    }
 9483
 9484    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9486        if self.move_to_prev_snippet_tabstop(window, cx) {
 9487            return;
 9488        }
 9489        self.outdent(&Outdent, window, cx);
 9490    }
 9491
 9492    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9493        if self.move_to_next_snippet_tabstop(window, cx) {
 9494            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9495            return;
 9496        }
 9497        if self.read_only(cx) {
 9498            return;
 9499        }
 9500        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9501        let mut selections = self.selections.all_adjusted(cx);
 9502        let buffer = self.buffer.read(cx);
 9503        let snapshot = buffer.snapshot(cx);
 9504        let rows_iter = selections.iter().map(|s| s.head().row);
 9505        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9506
 9507        let has_some_cursor_in_whitespace = selections
 9508            .iter()
 9509            .filter(|selection| selection.is_empty())
 9510            .any(|selection| {
 9511                let cursor = selection.head();
 9512                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9513                cursor.column < current_indent.len
 9514            });
 9515
 9516        let mut edits = Vec::new();
 9517        let mut prev_edited_row = 0;
 9518        let mut row_delta = 0;
 9519        for selection in &mut selections {
 9520            if selection.start.row != prev_edited_row {
 9521                row_delta = 0;
 9522            }
 9523            prev_edited_row = selection.end.row;
 9524
 9525            // If the selection is non-empty, then increase the indentation of the selected lines.
 9526            if !selection.is_empty() {
 9527                row_delta =
 9528                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9529                continue;
 9530            }
 9531
 9532            let cursor = selection.head();
 9533            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9534            if let Some(suggested_indent) =
 9535                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9536            {
 9537                // Don't do anything if already at suggested indent
 9538                // and there is any other cursor which is not
 9539                if has_some_cursor_in_whitespace
 9540                    && cursor.column == current_indent.len
 9541                    && current_indent.len == suggested_indent.len
 9542                {
 9543                    continue;
 9544                }
 9545
 9546                // Adjust line and move cursor to suggested indent
 9547                // if cursor is not at suggested indent
 9548                if cursor.column < suggested_indent.len
 9549                    && cursor.column <= current_indent.len
 9550                    && current_indent.len <= suggested_indent.len
 9551                {
 9552                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9553                    selection.end = selection.start;
 9554                    if row_delta == 0 {
 9555                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9556                            cursor.row,
 9557                            current_indent,
 9558                            suggested_indent,
 9559                        ));
 9560                        row_delta = suggested_indent.len - current_indent.len;
 9561                    }
 9562                    continue;
 9563                }
 9564
 9565                // If current indent is more than suggested indent
 9566                // only move cursor to current indent and skip indent
 9567                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9568                    selection.start = Point::new(cursor.row, current_indent.len);
 9569                    selection.end = selection.start;
 9570                    continue;
 9571                }
 9572            }
 9573
 9574            // Otherwise, insert a hard or soft tab.
 9575            let settings = buffer.language_settings_at(cursor, cx);
 9576            let tab_size = if settings.hard_tabs {
 9577                IndentSize::tab()
 9578            } else {
 9579                let tab_size = settings.tab_size.get();
 9580                let indent_remainder = snapshot
 9581                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9582                    .flat_map(str::chars)
 9583                    .fold(row_delta % tab_size, |counter: u32, c| {
 9584                        if c == '\t' {
 9585                            0
 9586                        } else {
 9587                            (counter + 1) % tab_size
 9588                        }
 9589                    });
 9590
 9591                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9592                IndentSize::spaces(chars_to_next_tab_stop)
 9593            };
 9594            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9595            selection.end = selection.start;
 9596            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9597            row_delta += tab_size.len;
 9598        }
 9599
 9600        self.transact(window, cx, |this, window, cx| {
 9601            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9602            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9603                s.select(selections)
 9604            });
 9605            this.refresh_inline_completion(true, false, window, cx);
 9606        });
 9607    }
 9608
 9609    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9610        if self.read_only(cx) {
 9611            return;
 9612        }
 9613        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9614        let mut selections = self.selections.all::<Point>(cx);
 9615        let mut prev_edited_row = 0;
 9616        let mut row_delta = 0;
 9617        let mut edits = Vec::new();
 9618        let buffer = self.buffer.read(cx);
 9619        let snapshot = buffer.snapshot(cx);
 9620        for selection in &mut selections {
 9621            if selection.start.row != prev_edited_row {
 9622                row_delta = 0;
 9623            }
 9624            prev_edited_row = selection.end.row;
 9625
 9626            row_delta =
 9627                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9628        }
 9629
 9630        self.transact(window, cx, |this, window, cx| {
 9631            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9632            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9633                s.select(selections)
 9634            });
 9635        });
 9636    }
 9637
 9638    fn indent_selection(
 9639        buffer: &MultiBuffer,
 9640        snapshot: &MultiBufferSnapshot,
 9641        selection: &mut Selection<Point>,
 9642        edits: &mut Vec<(Range<Point>, String)>,
 9643        delta_for_start_row: u32,
 9644        cx: &App,
 9645    ) -> u32 {
 9646        let settings = buffer.language_settings_at(selection.start, cx);
 9647        let tab_size = settings.tab_size.get();
 9648        let indent_kind = if settings.hard_tabs {
 9649            IndentKind::Tab
 9650        } else {
 9651            IndentKind::Space
 9652        };
 9653        let mut start_row = selection.start.row;
 9654        let mut end_row = selection.end.row + 1;
 9655
 9656        // If a selection ends at the beginning of a line, don't indent
 9657        // that last line.
 9658        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9659            end_row -= 1;
 9660        }
 9661
 9662        // Avoid re-indenting a row that has already been indented by a
 9663        // previous selection, but still update this selection's column
 9664        // to reflect that indentation.
 9665        if delta_for_start_row > 0 {
 9666            start_row += 1;
 9667            selection.start.column += delta_for_start_row;
 9668            if selection.end.row == selection.start.row {
 9669                selection.end.column += delta_for_start_row;
 9670            }
 9671        }
 9672
 9673        let mut delta_for_end_row = 0;
 9674        let has_multiple_rows = start_row + 1 != end_row;
 9675        for row in start_row..end_row {
 9676            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9677            let indent_delta = match (current_indent.kind, indent_kind) {
 9678                (IndentKind::Space, IndentKind::Space) => {
 9679                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9680                    IndentSize::spaces(columns_to_next_tab_stop)
 9681                }
 9682                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9683                (_, IndentKind::Tab) => IndentSize::tab(),
 9684            };
 9685
 9686            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9687                0
 9688            } else {
 9689                selection.start.column
 9690            };
 9691            let row_start = Point::new(row, start);
 9692            edits.push((
 9693                row_start..row_start,
 9694                indent_delta.chars().collect::<String>(),
 9695            ));
 9696
 9697            // Update this selection's endpoints to reflect the indentation.
 9698            if row == selection.start.row {
 9699                selection.start.column += indent_delta.len;
 9700            }
 9701            if row == selection.end.row {
 9702                selection.end.column += indent_delta.len;
 9703                delta_for_end_row = indent_delta.len;
 9704            }
 9705        }
 9706
 9707        if selection.start.row == selection.end.row {
 9708            delta_for_start_row + delta_for_end_row
 9709        } else {
 9710            delta_for_end_row
 9711        }
 9712    }
 9713
 9714    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9715        if self.read_only(cx) {
 9716            return;
 9717        }
 9718        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9719        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9720        let selections = self.selections.all::<Point>(cx);
 9721        let mut deletion_ranges = Vec::new();
 9722        let mut last_outdent = None;
 9723        {
 9724            let buffer = self.buffer.read(cx);
 9725            let snapshot = buffer.snapshot(cx);
 9726            for selection in &selections {
 9727                let settings = buffer.language_settings_at(selection.start, cx);
 9728                let tab_size = settings.tab_size.get();
 9729                let mut rows = selection.spanned_rows(false, &display_map);
 9730
 9731                // Avoid re-outdenting a row that has already been outdented by a
 9732                // previous selection.
 9733                if let Some(last_row) = last_outdent {
 9734                    if last_row == rows.start {
 9735                        rows.start = rows.start.next_row();
 9736                    }
 9737                }
 9738                let has_multiple_rows = rows.len() > 1;
 9739                for row in rows.iter_rows() {
 9740                    let indent_size = snapshot.indent_size_for_line(row);
 9741                    if indent_size.len > 0 {
 9742                        let deletion_len = match indent_size.kind {
 9743                            IndentKind::Space => {
 9744                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9745                                if columns_to_prev_tab_stop == 0 {
 9746                                    tab_size
 9747                                } else {
 9748                                    columns_to_prev_tab_stop
 9749                                }
 9750                            }
 9751                            IndentKind::Tab => 1,
 9752                        };
 9753                        let start = if has_multiple_rows
 9754                            || deletion_len > selection.start.column
 9755                            || indent_size.len < selection.start.column
 9756                        {
 9757                            0
 9758                        } else {
 9759                            selection.start.column - deletion_len
 9760                        };
 9761                        deletion_ranges.push(
 9762                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9763                        );
 9764                        last_outdent = Some(row);
 9765                    }
 9766                }
 9767            }
 9768        }
 9769
 9770        self.transact(window, cx, |this, window, cx| {
 9771            this.buffer.update(cx, |buffer, cx| {
 9772                let empty_str: Arc<str> = Arc::default();
 9773                buffer.edit(
 9774                    deletion_ranges
 9775                        .into_iter()
 9776                        .map(|range| (range, empty_str.clone())),
 9777                    None,
 9778                    cx,
 9779                );
 9780            });
 9781            let selections = this.selections.all::<usize>(cx);
 9782            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9783                s.select(selections)
 9784            });
 9785        });
 9786    }
 9787
 9788    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9789        if self.read_only(cx) {
 9790            return;
 9791        }
 9792        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9793        let selections = self
 9794            .selections
 9795            .all::<usize>(cx)
 9796            .into_iter()
 9797            .map(|s| s.range());
 9798
 9799        self.transact(window, cx, |this, window, cx| {
 9800            this.buffer.update(cx, |buffer, cx| {
 9801                buffer.autoindent_ranges(selections, cx);
 9802            });
 9803            let selections = this.selections.all::<usize>(cx);
 9804            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9805                s.select(selections)
 9806            });
 9807        });
 9808    }
 9809
 9810    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9811        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9812        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9813        let selections = self.selections.all::<Point>(cx);
 9814
 9815        let mut new_cursors = Vec::new();
 9816        let mut edit_ranges = Vec::new();
 9817        let mut selections = selections.iter().peekable();
 9818        while let Some(selection) = selections.next() {
 9819            let mut rows = selection.spanned_rows(false, &display_map);
 9820            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9821
 9822            // Accumulate contiguous regions of rows that we want to delete.
 9823            while let Some(next_selection) = selections.peek() {
 9824                let next_rows = next_selection.spanned_rows(false, &display_map);
 9825                if next_rows.start <= rows.end {
 9826                    rows.end = next_rows.end;
 9827                    selections.next().unwrap();
 9828                } else {
 9829                    break;
 9830                }
 9831            }
 9832
 9833            let buffer = &display_map.buffer_snapshot;
 9834            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9835            let edit_end;
 9836            let cursor_buffer_row;
 9837            if buffer.max_point().row >= rows.end.0 {
 9838                // If there's a line after the range, delete the \n from the end of the row range
 9839                // and position the cursor on the next line.
 9840                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9841                cursor_buffer_row = rows.end;
 9842            } else {
 9843                // If there isn't a line after the range, delete the \n from the line before the
 9844                // start of the row range and position the cursor there.
 9845                edit_start = edit_start.saturating_sub(1);
 9846                edit_end = buffer.len();
 9847                cursor_buffer_row = rows.start.previous_row();
 9848            }
 9849
 9850            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9851            *cursor.column_mut() =
 9852                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9853
 9854            new_cursors.push((
 9855                selection.id,
 9856                buffer.anchor_after(cursor.to_point(&display_map)),
 9857            ));
 9858            edit_ranges.push(edit_start..edit_end);
 9859        }
 9860
 9861        self.transact(window, cx, |this, window, cx| {
 9862            let buffer = this.buffer.update(cx, |buffer, cx| {
 9863                let empty_str: Arc<str> = Arc::default();
 9864                buffer.edit(
 9865                    edit_ranges
 9866                        .into_iter()
 9867                        .map(|range| (range, empty_str.clone())),
 9868                    None,
 9869                    cx,
 9870                );
 9871                buffer.snapshot(cx)
 9872            });
 9873            let new_selections = new_cursors
 9874                .into_iter()
 9875                .map(|(id, cursor)| {
 9876                    let cursor = cursor.to_point(&buffer);
 9877                    Selection {
 9878                        id,
 9879                        start: cursor,
 9880                        end: cursor,
 9881                        reversed: false,
 9882                        goal: SelectionGoal::None,
 9883                    }
 9884                })
 9885                .collect();
 9886
 9887            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9888                s.select(new_selections);
 9889            });
 9890        });
 9891    }
 9892
 9893    pub fn join_lines_impl(
 9894        &mut self,
 9895        insert_whitespace: bool,
 9896        window: &mut Window,
 9897        cx: &mut Context<Self>,
 9898    ) {
 9899        if self.read_only(cx) {
 9900            return;
 9901        }
 9902        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9903        for selection in self.selections.all::<Point>(cx) {
 9904            let start = MultiBufferRow(selection.start.row);
 9905            // Treat single line selections as if they include the next line. Otherwise this action
 9906            // would do nothing for single line selections individual cursors.
 9907            let end = if selection.start.row == selection.end.row {
 9908                MultiBufferRow(selection.start.row + 1)
 9909            } else {
 9910                MultiBufferRow(selection.end.row)
 9911            };
 9912
 9913            if let Some(last_row_range) = row_ranges.last_mut() {
 9914                if start <= last_row_range.end {
 9915                    last_row_range.end = end;
 9916                    continue;
 9917                }
 9918            }
 9919            row_ranges.push(start..end);
 9920        }
 9921
 9922        let snapshot = self.buffer.read(cx).snapshot(cx);
 9923        let mut cursor_positions = Vec::new();
 9924        for row_range in &row_ranges {
 9925            let anchor = snapshot.anchor_before(Point::new(
 9926                row_range.end.previous_row().0,
 9927                snapshot.line_len(row_range.end.previous_row()),
 9928            ));
 9929            cursor_positions.push(anchor..anchor);
 9930        }
 9931
 9932        self.transact(window, cx, |this, window, cx| {
 9933            for row_range in row_ranges.into_iter().rev() {
 9934                for row in row_range.iter_rows().rev() {
 9935                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9936                    let next_line_row = row.next_row();
 9937                    let indent = snapshot.indent_size_for_line(next_line_row);
 9938                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9939
 9940                    let replace =
 9941                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9942                            " "
 9943                        } else {
 9944                            ""
 9945                        };
 9946
 9947                    this.buffer.update(cx, |buffer, cx| {
 9948                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9949                    });
 9950                }
 9951            }
 9952
 9953            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9954                s.select_anchor_ranges(cursor_positions)
 9955            });
 9956        });
 9957    }
 9958
 9959    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9960        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9961        self.join_lines_impl(true, window, cx);
 9962    }
 9963
 9964    pub fn sort_lines_case_sensitive(
 9965        &mut self,
 9966        _: &SortLinesCaseSensitive,
 9967        window: &mut Window,
 9968        cx: &mut Context<Self>,
 9969    ) {
 9970        self.manipulate_lines(window, cx, |lines| lines.sort())
 9971    }
 9972
 9973    pub fn sort_lines_case_insensitive(
 9974        &mut self,
 9975        _: &SortLinesCaseInsensitive,
 9976        window: &mut Window,
 9977        cx: &mut Context<Self>,
 9978    ) {
 9979        self.manipulate_lines(window, cx, |lines| {
 9980            lines.sort_by_key(|line| line.to_lowercase())
 9981        })
 9982    }
 9983
 9984    pub fn unique_lines_case_insensitive(
 9985        &mut self,
 9986        _: &UniqueLinesCaseInsensitive,
 9987        window: &mut Window,
 9988        cx: &mut Context<Self>,
 9989    ) {
 9990        self.manipulate_lines(window, cx, |lines| {
 9991            let mut seen = HashSet::default();
 9992            lines.retain(|line| seen.insert(line.to_lowercase()));
 9993        })
 9994    }
 9995
 9996    pub fn unique_lines_case_sensitive(
 9997        &mut self,
 9998        _: &UniqueLinesCaseSensitive,
 9999        window: &mut Window,
10000        cx: &mut Context<Self>,
10001    ) {
10002        self.manipulate_lines(window, cx, |lines| {
10003            let mut seen = HashSet::default();
10004            lines.retain(|line| seen.insert(*line));
10005        })
10006    }
10007
10008    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10009        let Some(project) = self.project.clone() else {
10010            return;
10011        };
10012        self.reload(project, window, cx)
10013            .detach_and_notify_err(window, cx);
10014    }
10015
10016    pub fn restore_file(
10017        &mut self,
10018        _: &::git::RestoreFile,
10019        window: &mut Window,
10020        cx: &mut Context<Self>,
10021    ) {
10022        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10023        let mut buffer_ids = HashSet::default();
10024        let snapshot = self.buffer().read(cx).snapshot(cx);
10025        for selection in self.selections.all::<usize>(cx) {
10026            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10027        }
10028
10029        let buffer = self.buffer().read(cx);
10030        let ranges = buffer_ids
10031            .into_iter()
10032            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10033            .collect::<Vec<_>>();
10034
10035        self.restore_hunks_in_ranges(ranges, window, cx);
10036    }
10037
10038    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10039        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10040        let selections = self
10041            .selections
10042            .all(cx)
10043            .into_iter()
10044            .map(|s| s.range())
10045            .collect();
10046        self.restore_hunks_in_ranges(selections, window, cx);
10047    }
10048
10049    pub fn restore_hunks_in_ranges(
10050        &mut self,
10051        ranges: Vec<Range<Point>>,
10052        window: &mut Window,
10053        cx: &mut Context<Editor>,
10054    ) {
10055        let mut revert_changes = HashMap::default();
10056        let chunk_by = self
10057            .snapshot(window, cx)
10058            .hunks_for_ranges(ranges)
10059            .into_iter()
10060            .chunk_by(|hunk| hunk.buffer_id);
10061        for (buffer_id, hunks) in &chunk_by {
10062            let hunks = hunks.collect::<Vec<_>>();
10063            for hunk in &hunks {
10064                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10065            }
10066            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10067        }
10068        drop(chunk_by);
10069        if !revert_changes.is_empty() {
10070            self.transact(window, cx, |editor, window, cx| {
10071                editor.restore(revert_changes, window, cx);
10072            });
10073        }
10074    }
10075
10076    pub fn open_active_item_in_terminal(
10077        &mut self,
10078        _: &OpenInTerminal,
10079        window: &mut Window,
10080        cx: &mut Context<Self>,
10081    ) {
10082        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10083            let project_path = buffer.read(cx).project_path(cx)?;
10084            let project = self.project.as_ref()?.read(cx);
10085            let entry = project.entry_for_path(&project_path, cx)?;
10086            let parent = match &entry.canonical_path {
10087                Some(canonical_path) => canonical_path.to_path_buf(),
10088                None => project.absolute_path(&project_path, cx)?,
10089            }
10090            .parent()?
10091            .to_path_buf();
10092            Some(parent)
10093        }) {
10094            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10095        }
10096    }
10097
10098    fn set_breakpoint_context_menu(
10099        &mut self,
10100        display_row: DisplayRow,
10101        position: Option<Anchor>,
10102        clicked_point: gpui::Point<Pixels>,
10103        window: &mut Window,
10104        cx: &mut Context<Self>,
10105    ) {
10106        if !cx.has_flag::<DebuggerFeatureFlag>() {
10107            return;
10108        }
10109        let source = self
10110            .buffer
10111            .read(cx)
10112            .snapshot(cx)
10113            .anchor_before(Point::new(display_row.0, 0u32));
10114
10115        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10116
10117        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10118            self,
10119            source,
10120            clicked_point,
10121            context_menu,
10122            window,
10123            cx,
10124        );
10125    }
10126
10127    fn add_edit_breakpoint_block(
10128        &mut self,
10129        anchor: Anchor,
10130        breakpoint: &Breakpoint,
10131        edit_action: BreakpointPromptEditAction,
10132        window: &mut Window,
10133        cx: &mut Context<Self>,
10134    ) {
10135        let weak_editor = cx.weak_entity();
10136        let bp_prompt = cx.new(|cx| {
10137            BreakpointPromptEditor::new(
10138                weak_editor,
10139                anchor,
10140                breakpoint.clone(),
10141                edit_action,
10142                window,
10143                cx,
10144            )
10145        });
10146
10147        let height = bp_prompt.update(cx, |this, cx| {
10148            this.prompt
10149                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10150        });
10151        let cloned_prompt = bp_prompt.clone();
10152        let blocks = vec![BlockProperties {
10153            style: BlockStyle::Sticky,
10154            placement: BlockPlacement::Above(anchor),
10155            height: Some(height),
10156            render: Arc::new(move |cx| {
10157                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10158                cloned_prompt.clone().into_any_element()
10159            }),
10160            priority: 0,
10161            render_in_minimap: true,
10162        }];
10163
10164        let focus_handle = bp_prompt.focus_handle(cx);
10165        window.focus(&focus_handle);
10166
10167        let block_ids = self.insert_blocks(blocks, None, cx);
10168        bp_prompt.update(cx, |prompt, _| {
10169            prompt.add_block_ids(block_ids);
10170        });
10171    }
10172
10173    pub(crate) fn breakpoint_at_row(
10174        &self,
10175        row: u32,
10176        window: &mut Window,
10177        cx: &mut Context<Self>,
10178    ) -> Option<(Anchor, Breakpoint)> {
10179        let snapshot = self.snapshot(window, cx);
10180        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10181
10182        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10183    }
10184
10185    pub(crate) fn breakpoint_at_anchor(
10186        &self,
10187        breakpoint_position: Anchor,
10188        snapshot: &EditorSnapshot,
10189        cx: &mut Context<Self>,
10190    ) -> Option<(Anchor, Breakpoint)> {
10191        let project = self.project.clone()?;
10192
10193        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10194            snapshot
10195                .buffer_snapshot
10196                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10197        })?;
10198
10199        let enclosing_excerpt = breakpoint_position.excerpt_id;
10200        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10201        let buffer_snapshot = buffer.read(cx).snapshot();
10202
10203        let row = buffer_snapshot
10204            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10205            .row;
10206
10207        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10208        let anchor_end = snapshot
10209            .buffer_snapshot
10210            .anchor_after(Point::new(row, line_len));
10211
10212        let bp = self
10213            .breakpoint_store
10214            .as_ref()?
10215            .read_with(cx, |breakpoint_store, cx| {
10216                breakpoint_store
10217                    .breakpoints(
10218                        &buffer,
10219                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10220                        &buffer_snapshot,
10221                        cx,
10222                    )
10223                    .next()
10224                    .and_then(|(bp, _)| {
10225                        let breakpoint_row = buffer_snapshot
10226                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10227                            .row;
10228
10229                        if breakpoint_row == row {
10230                            snapshot
10231                                .buffer_snapshot
10232                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10233                                .map(|position| (position, bp.bp.clone()))
10234                        } else {
10235                            None
10236                        }
10237                    })
10238            });
10239        bp
10240    }
10241
10242    pub fn edit_log_breakpoint(
10243        &mut self,
10244        _: &EditLogBreakpoint,
10245        window: &mut Window,
10246        cx: &mut Context<Self>,
10247    ) {
10248        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10249            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10250                message: None,
10251                state: BreakpointState::Enabled,
10252                condition: None,
10253                hit_condition: None,
10254            });
10255
10256            self.add_edit_breakpoint_block(
10257                anchor,
10258                &breakpoint,
10259                BreakpointPromptEditAction::Log,
10260                window,
10261                cx,
10262            );
10263        }
10264    }
10265
10266    fn breakpoints_at_cursors(
10267        &self,
10268        window: &mut Window,
10269        cx: &mut Context<Self>,
10270    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10271        let snapshot = self.snapshot(window, cx);
10272        let cursors = self
10273            .selections
10274            .disjoint_anchors()
10275            .into_iter()
10276            .map(|selection| {
10277                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10278
10279                let breakpoint_position = self
10280                    .breakpoint_at_row(cursor_position.row, window, cx)
10281                    .map(|bp| bp.0)
10282                    .unwrap_or_else(|| {
10283                        snapshot
10284                            .display_snapshot
10285                            .buffer_snapshot
10286                            .anchor_after(Point::new(cursor_position.row, 0))
10287                    });
10288
10289                let breakpoint = self
10290                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10291                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10292
10293                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10294            })
10295            // 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.
10296            .collect::<HashMap<Anchor, _>>();
10297
10298        cursors.into_iter().collect()
10299    }
10300
10301    pub fn enable_breakpoint(
10302        &mut self,
10303        _: &crate::actions::EnableBreakpoint,
10304        window: &mut Window,
10305        cx: &mut Context<Self>,
10306    ) {
10307        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10308            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10309                continue;
10310            };
10311            self.edit_breakpoint_at_anchor(
10312                anchor,
10313                breakpoint,
10314                BreakpointEditAction::InvertState,
10315                cx,
10316            );
10317        }
10318    }
10319
10320    pub fn disable_breakpoint(
10321        &mut self,
10322        _: &crate::actions::DisableBreakpoint,
10323        window: &mut Window,
10324        cx: &mut Context<Self>,
10325    ) {
10326        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10327            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10328                continue;
10329            };
10330            self.edit_breakpoint_at_anchor(
10331                anchor,
10332                breakpoint,
10333                BreakpointEditAction::InvertState,
10334                cx,
10335            );
10336        }
10337    }
10338
10339    pub fn toggle_breakpoint(
10340        &mut self,
10341        _: &crate::actions::ToggleBreakpoint,
10342        window: &mut Window,
10343        cx: &mut Context<Self>,
10344    ) {
10345        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10346            if let Some(breakpoint) = breakpoint {
10347                self.edit_breakpoint_at_anchor(
10348                    anchor,
10349                    breakpoint,
10350                    BreakpointEditAction::Toggle,
10351                    cx,
10352                );
10353            } else {
10354                self.edit_breakpoint_at_anchor(
10355                    anchor,
10356                    Breakpoint::new_standard(),
10357                    BreakpointEditAction::Toggle,
10358                    cx,
10359                );
10360            }
10361        }
10362    }
10363
10364    pub fn edit_breakpoint_at_anchor(
10365        &mut self,
10366        breakpoint_position: Anchor,
10367        breakpoint: Breakpoint,
10368        edit_action: BreakpointEditAction,
10369        cx: &mut Context<Self>,
10370    ) {
10371        let Some(breakpoint_store) = &self.breakpoint_store else {
10372            return;
10373        };
10374
10375        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10376            if breakpoint_position == Anchor::min() {
10377                self.buffer()
10378                    .read(cx)
10379                    .excerpt_buffer_ids()
10380                    .into_iter()
10381                    .next()
10382            } else {
10383                None
10384            }
10385        }) else {
10386            return;
10387        };
10388
10389        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10390            return;
10391        };
10392
10393        breakpoint_store.update(cx, |breakpoint_store, cx| {
10394            breakpoint_store.toggle_breakpoint(
10395                buffer,
10396                BreakpointWithPosition {
10397                    position: breakpoint_position.text_anchor,
10398                    bp: breakpoint,
10399                },
10400                edit_action,
10401                cx,
10402            );
10403        });
10404
10405        cx.notify();
10406    }
10407
10408    #[cfg(any(test, feature = "test-support"))]
10409    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10410        self.breakpoint_store.clone()
10411    }
10412
10413    pub fn prepare_restore_change(
10414        &self,
10415        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10416        hunk: &MultiBufferDiffHunk,
10417        cx: &mut App,
10418    ) -> Option<()> {
10419        if hunk.is_created_file() {
10420            return None;
10421        }
10422        let buffer = self.buffer.read(cx);
10423        let diff = buffer.diff_for(hunk.buffer_id)?;
10424        let buffer = buffer.buffer(hunk.buffer_id)?;
10425        let buffer = buffer.read(cx);
10426        let original_text = diff
10427            .read(cx)
10428            .base_text()
10429            .as_rope()
10430            .slice(hunk.diff_base_byte_range.clone());
10431        let buffer_snapshot = buffer.snapshot();
10432        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10433        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10434            probe
10435                .0
10436                .start
10437                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10438                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10439        }) {
10440            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10441            Some(())
10442        } else {
10443            None
10444        }
10445    }
10446
10447    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10448        self.manipulate_lines(window, cx, |lines| lines.reverse())
10449    }
10450
10451    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10452        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10453    }
10454
10455    fn manipulate_lines<Fn>(
10456        &mut self,
10457        window: &mut Window,
10458        cx: &mut Context<Self>,
10459        mut callback: Fn,
10460    ) where
10461        Fn: FnMut(&mut Vec<&str>),
10462    {
10463        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10464
10465        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10466        let buffer = self.buffer.read(cx).snapshot(cx);
10467
10468        let mut edits = Vec::new();
10469
10470        let selections = self.selections.all::<Point>(cx);
10471        let mut selections = selections.iter().peekable();
10472        let mut contiguous_row_selections = Vec::new();
10473        let mut new_selections = Vec::new();
10474        let mut added_lines = 0;
10475        let mut removed_lines = 0;
10476
10477        while let Some(selection) = selections.next() {
10478            let (start_row, end_row) = consume_contiguous_rows(
10479                &mut contiguous_row_selections,
10480                selection,
10481                &display_map,
10482                &mut selections,
10483            );
10484
10485            let start_point = Point::new(start_row.0, 0);
10486            let end_point = Point::new(
10487                end_row.previous_row().0,
10488                buffer.line_len(end_row.previous_row()),
10489            );
10490            let text = buffer
10491                .text_for_range(start_point..end_point)
10492                .collect::<String>();
10493
10494            let mut lines = text.split('\n').collect_vec();
10495
10496            let lines_before = lines.len();
10497            callback(&mut lines);
10498            let lines_after = lines.len();
10499
10500            edits.push((start_point..end_point, lines.join("\n")));
10501
10502            // Selections must change based on added and removed line count
10503            let start_row =
10504                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10505            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10506            new_selections.push(Selection {
10507                id: selection.id,
10508                start: start_row,
10509                end: end_row,
10510                goal: SelectionGoal::None,
10511                reversed: selection.reversed,
10512            });
10513
10514            if lines_after > lines_before {
10515                added_lines += lines_after - lines_before;
10516            } else if lines_before > lines_after {
10517                removed_lines += lines_before - lines_after;
10518            }
10519        }
10520
10521        self.transact(window, cx, |this, window, cx| {
10522            let buffer = this.buffer.update(cx, |buffer, cx| {
10523                buffer.edit(edits, None, cx);
10524                buffer.snapshot(cx)
10525            });
10526
10527            // Recalculate offsets on newly edited buffer
10528            let new_selections = new_selections
10529                .iter()
10530                .map(|s| {
10531                    let start_point = Point::new(s.start.0, 0);
10532                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10533                    Selection {
10534                        id: s.id,
10535                        start: buffer.point_to_offset(start_point),
10536                        end: buffer.point_to_offset(end_point),
10537                        goal: s.goal,
10538                        reversed: s.reversed,
10539                    }
10540                })
10541                .collect();
10542
10543            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10544                s.select(new_selections);
10545            });
10546
10547            this.request_autoscroll(Autoscroll::fit(), cx);
10548        });
10549    }
10550
10551    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10552        self.manipulate_text(window, cx, |text| {
10553            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10554            if has_upper_case_characters {
10555                text.to_lowercase()
10556            } else {
10557                text.to_uppercase()
10558            }
10559        })
10560    }
10561
10562    pub fn convert_to_upper_case(
10563        &mut self,
10564        _: &ConvertToUpperCase,
10565        window: &mut Window,
10566        cx: &mut Context<Self>,
10567    ) {
10568        self.manipulate_text(window, cx, |text| text.to_uppercase())
10569    }
10570
10571    pub fn convert_to_lower_case(
10572        &mut self,
10573        _: &ConvertToLowerCase,
10574        window: &mut Window,
10575        cx: &mut Context<Self>,
10576    ) {
10577        self.manipulate_text(window, cx, |text| text.to_lowercase())
10578    }
10579
10580    pub fn convert_to_title_case(
10581        &mut self,
10582        _: &ConvertToTitleCase,
10583        window: &mut Window,
10584        cx: &mut Context<Self>,
10585    ) {
10586        self.manipulate_text(window, cx, |text| {
10587            text.split('\n')
10588                .map(|line| line.to_case(Case::Title))
10589                .join("\n")
10590        })
10591    }
10592
10593    pub fn convert_to_snake_case(
10594        &mut self,
10595        _: &ConvertToSnakeCase,
10596        window: &mut Window,
10597        cx: &mut Context<Self>,
10598    ) {
10599        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10600    }
10601
10602    pub fn convert_to_kebab_case(
10603        &mut self,
10604        _: &ConvertToKebabCase,
10605        window: &mut Window,
10606        cx: &mut Context<Self>,
10607    ) {
10608        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10609    }
10610
10611    pub fn convert_to_upper_camel_case(
10612        &mut self,
10613        _: &ConvertToUpperCamelCase,
10614        window: &mut Window,
10615        cx: &mut Context<Self>,
10616    ) {
10617        self.manipulate_text(window, cx, |text| {
10618            text.split('\n')
10619                .map(|line| line.to_case(Case::UpperCamel))
10620                .join("\n")
10621        })
10622    }
10623
10624    pub fn convert_to_lower_camel_case(
10625        &mut self,
10626        _: &ConvertToLowerCamelCase,
10627        window: &mut Window,
10628        cx: &mut Context<Self>,
10629    ) {
10630        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10631    }
10632
10633    pub fn convert_to_opposite_case(
10634        &mut self,
10635        _: &ConvertToOppositeCase,
10636        window: &mut Window,
10637        cx: &mut Context<Self>,
10638    ) {
10639        self.manipulate_text(window, cx, |text| {
10640            text.chars()
10641                .fold(String::with_capacity(text.len()), |mut t, c| {
10642                    if c.is_uppercase() {
10643                        t.extend(c.to_lowercase());
10644                    } else {
10645                        t.extend(c.to_uppercase());
10646                    }
10647                    t
10648                })
10649        })
10650    }
10651
10652    pub fn convert_to_rot13(
10653        &mut self,
10654        _: &ConvertToRot13,
10655        window: &mut Window,
10656        cx: &mut Context<Self>,
10657    ) {
10658        self.manipulate_text(window, cx, |text| {
10659            text.chars()
10660                .map(|c| match c {
10661                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10662                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10663                    _ => c,
10664                })
10665                .collect()
10666        })
10667    }
10668
10669    pub fn convert_to_rot47(
10670        &mut self,
10671        _: &ConvertToRot47,
10672        window: &mut Window,
10673        cx: &mut Context<Self>,
10674    ) {
10675        self.manipulate_text(window, cx, |text| {
10676            text.chars()
10677                .map(|c| {
10678                    let code_point = c as u32;
10679                    if code_point >= 33 && code_point <= 126 {
10680                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10681                    }
10682                    c
10683                })
10684                .collect()
10685        })
10686    }
10687
10688    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10689    where
10690        Fn: FnMut(&str) -> String,
10691    {
10692        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10693        let buffer = self.buffer.read(cx).snapshot(cx);
10694
10695        let mut new_selections = Vec::new();
10696        let mut edits = Vec::new();
10697        let mut selection_adjustment = 0i32;
10698
10699        for selection in self.selections.all::<usize>(cx) {
10700            let selection_is_empty = selection.is_empty();
10701
10702            let (start, end) = if selection_is_empty {
10703                let word_range = movement::surrounding_word(
10704                    &display_map,
10705                    selection.start.to_display_point(&display_map),
10706                );
10707                let start = word_range.start.to_offset(&display_map, Bias::Left);
10708                let end = word_range.end.to_offset(&display_map, Bias::Left);
10709                (start, end)
10710            } else {
10711                (selection.start, selection.end)
10712            };
10713
10714            let text = buffer.text_for_range(start..end).collect::<String>();
10715            let old_length = text.len() as i32;
10716            let text = callback(&text);
10717
10718            new_selections.push(Selection {
10719                start: (start as i32 - selection_adjustment) as usize,
10720                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10721                goal: SelectionGoal::None,
10722                ..selection
10723            });
10724
10725            selection_adjustment += old_length - text.len() as i32;
10726
10727            edits.push((start..end, text));
10728        }
10729
10730        self.transact(window, cx, |this, window, cx| {
10731            this.buffer.update(cx, |buffer, cx| {
10732                buffer.edit(edits, None, cx);
10733            });
10734
10735            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10736                s.select(new_selections);
10737            });
10738
10739            this.request_autoscroll(Autoscroll::fit(), cx);
10740        });
10741    }
10742
10743    pub fn move_selection_on_drop(
10744        &mut self,
10745        selection: &Selection<Anchor>,
10746        target: DisplayPoint,
10747        is_cut: bool,
10748        window: &mut Window,
10749        cx: &mut Context<Self>,
10750    ) {
10751        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10752        let buffer = &display_map.buffer_snapshot;
10753        let mut edits = Vec::new();
10754        let insert_point = display_map
10755            .clip_point(target, Bias::Left)
10756            .to_point(&display_map);
10757        let text = buffer
10758            .text_for_range(selection.start..selection.end)
10759            .collect::<String>();
10760        if is_cut {
10761            edits.push(((selection.start..selection.end), String::new()));
10762        }
10763        let insert_anchor = buffer.anchor_before(insert_point);
10764        edits.push(((insert_anchor..insert_anchor), text));
10765        let last_edit_start = insert_anchor.bias_left(buffer);
10766        let last_edit_end = insert_anchor.bias_right(buffer);
10767        self.transact(window, cx, |this, window, cx| {
10768            this.buffer.update(cx, |buffer, cx| {
10769                buffer.edit(edits, None, cx);
10770            });
10771            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10772                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10773            });
10774        });
10775    }
10776
10777    pub fn clear_selection_drag_state(&mut self) {
10778        self.selection_drag_state = SelectionDragState::None;
10779    }
10780
10781    pub fn duplicate(
10782        &mut self,
10783        upwards: bool,
10784        whole_lines: bool,
10785        window: &mut Window,
10786        cx: &mut Context<Self>,
10787    ) {
10788        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10789
10790        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10791        let buffer = &display_map.buffer_snapshot;
10792        let selections = self.selections.all::<Point>(cx);
10793
10794        let mut edits = Vec::new();
10795        let mut selections_iter = selections.iter().peekable();
10796        while let Some(selection) = selections_iter.next() {
10797            let mut rows = selection.spanned_rows(false, &display_map);
10798            // duplicate line-wise
10799            if whole_lines || selection.start == selection.end {
10800                // Avoid duplicating the same lines twice.
10801                while let Some(next_selection) = selections_iter.peek() {
10802                    let next_rows = next_selection.spanned_rows(false, &display_map);
10803                    if next_rows.start < rows.end {
10804                        rows.end = next_rows.end;
10805                        selections_iter.next().unwrap();
10806                    } else {
10807                        break;
10808                    }
10809                }
10810
10811                // Copy the text from the selected row region and splice it either at the start
10812                // or end of the region.
10813                let start = Point::new(rows.start.0, 0);
10814                let end = Point::new(
10815                    rows.end.previous_row().0,
10816                    buffer.line_len(rows.end.previous_row()),
10817                );
10818                let text = buffer
10819                    .text_for_range(start..end)
10820                    .chain(Some("\n"))
10821                    .collect::<String>();
10822                let insert_location = if upwards {
10823                    Point::new(rows.end.0, 0)
10824                } else {
10825                    start
10826                };
10827                edits.push((insert_location..insert_location, text));
10828            } else {
10829                // duplicate character-wise
10830                let start = selection.start;
10831                let end = selection.end;
10832                let text = buffer.text_for_range(start..end).collect::<String>();
10833                edits.push((selection.end..selection.end, text));
10834            }
10835        }
10836
10837        self.transact(window, cx, |this, _, cx| {
10838            this.buffer.update(cx, |buffer, cx| {
10839                buffer.edit(edits, None, cx);
10840            });
10841
10842            this.request_autoscroll(Autoscroll::fit(), cx);
10843        });
10844    }
10845
10846    pub fn duplicate_line_up(
10847        &mut self,
10848        _: &DuplicateLineUp,
10849        window: &mut Window,
10850        cx: &mut Context<Self>,
10851    ) {
10852        self.duplicate(true, true, window, cx);
10853    }
10854
10855    pub fn duplicate_line_down(
10856        &mut self,
10857        _: &DuplicateLineDown,
10858        window: &mut Window,
10859        cx: &mut Context<Self>,
10860    ) {
10861        self.duplicate(false, true, window, cx);
10862    }
10863
10864    pub fn duplicate_selection(
10865        &mut self,
10866        _: &DuplicateSelection,
10867        window: &mut Window,
10868        cx: &mut Context<Self>,
10869    ) {
10870        self.duplicate(false, false, window, cx);
10871    }
10872
10873    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10875
10876        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10877        let buffer = self.buffer.read(cx).snapshot(cx);
10878
10879        let mut edits = Vec::new();
10880        let mut unfold_ranges = Vec::new();
10881        let mut refold_creases = Vec::new();
10882
10883        let selections = self.selections.all::<Point>(cx);
10884        let mut selections = selections.iter().peekable();
10885        let mut contiguous_row_selections = Vec::new();
10886        let mut new_selections = Vec::new();
10887
10888        while let Some(selection) = selections.next() {
10889            // Find all the selections that span a contiguous row range
10890            let (start_row, end_row) = consume_contiguous_rows(
10891                &mut contiguous_row_selections,
10892                selection,
10893                &display_map,
10894                &mut selections,
10895            );
10896
10897            // Move the text spanned by the row range to be before the line preceding the row range
10898            if start_row.0 > 0 {
10899                let range_to_move = Point::new(
10900                    start_row.previous_row().0,
10901                    buffer.line_len(start_row.previous_row()),
10902                )
10903                    ..Point::new(
10904                        end_row.previous_row().0,
10905                        buffer.line_len(end_row.previous_row()),
10906                    );
10907                let insertion_point = display_map
10908                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10909                    .0;
10910
10911                // Don't move lines across excerpts
10912                if buffer
10913                    .excerpt_containing(insertion_point..range_to_move.end)
10914                    .is_some()
10915                {
10916                    let text = buffer
10917                        .text_for_range(range_to_move.clone())
10918                        .flat_map(|s| s.chars())
10919                        .skip(1)
10920                        .chain(['\n'])
10921                        .collect::<String>();
10922
10923                    edits.push((
10924                        buffer.anchor_after(range_to_move.start)
10925                            ..buffer.anchor_before(range_to_move.end),
10926                        String::new(),
10927                    ));
10928                    let insertion_anchor = buffer.anchor_after(insertion_point);
10929                    edits.push((insertion_anchor..insertion_anchor, text));
10930
10931                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10932
10933                    // Move selections up
10934                    new_selections.extend(contiguous_row_selections.drain(..).map(
10935                        |mut selection| {
10936                            selection.start.row -= row_delta;
10937                            selection.end.row -= row_delta;
10938                            selection
10939                        },
10940                    ));
10941
10942                    // Move folds up
10943                    unfold_ranges.push(range_to_move.clone());
10944                    for fold in display_map.folds_in_range(
10945                        buffer.anchor_before(range_to_move.start)
10946                            ..buffer.anchor_after(range_to_move.end),
10947                    ) {
10948                        let mut start = fold.range.start.to_point(&buffer);
10949                        let mut end = fold.range.end.to_point(&buffer);
10950                        start.row -= row_delta;
10951                        end.row -= row_delta;
10952                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10953                    }
10954                }
10955            }
10956
10957            // If we didn't move line(s), preserve the existing selections
10958            new_selections.append(&mut contiguous_row_selections);
10959        }
10960
10961        self.transact(window, cx, |this, window, cx| {
10962            this.unfold_ranges(&unfold_ranges, true, true, cx);
10963            this.buffer.update(cx, |buffer, cx| {
10964                for (range, text) in edits {
10965                    buffer.edit([(range, text)], None, cx);
10966                }
10967            });
10968            this.fold_creases(refold_creases, true, window, cx);
10969            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10970                s.select(new_selections);
10971            })
10972        });
10973    }
10974
10975    pub fn move_line_down(
10976        &mut self,
10977        _: &MoveLineDown,
10978        window: &mut Window,
10979        cx: &mut Context<Self>,
10980    ) {
10981        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10982
10983        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10984        let buffer = self.buffer.read(cx).snapshot(cx);
10985
10986        let mut edits = Vec::new();
10987        let mut unfold_ranges = Vec::new();
10988        let mut refold_creases = Vec::new();
10989
10990        let selections = self.selections.all::<Point>(cx);
10991        let mut selections = selections.iter().peekable();
10992        let mut contiguous_row_selections = Vec::new();
10993        let mut new_selections = Vec::new();
10994
10995        while let Some(selection) = selections.next() {
10996            // Find all the selections that span a contiguous row range
10997            let (start_row, end_row) = consume_contiguous_rows(
10998                &mut contiguous_row_selections,
10999                selection,
11000                &display_map,
11001                &mut selections,
11002            );
11003
11004            // Move the text spanned by the row range to be after the last line of the row range
11005            if end_row.0 <= buffer.max_point().row {
11006                let range_to_move =
11007                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11008                let insertion_point = display_map
11009                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11010                    .0;
11011
11012                // Don't move lines across excerpt boundaries
11013                if buffer
11014                    .excerpt_containing(range_to_move.start..insertion_point)
11015                    .is_some()
11016                {
11017                    let mut text = String::from("\n");
11018                    text.extend(buffer.text_for_range(range_to_move.clone()));
11019                    text.pop(); // Drop trailing newline
11020                    edits.push((
11021                        buffer.anchor_after(range_to_move.start)
11022                            ..buffer.anchor_before(range_to_move.end),
11023                        String::new(),
11024                    ));
11025                    let insertion_anchor = buffer.anchor_after(insertion_point);
11026                    edits.push((insertion_anchor..insertion_anchor, text));
11027
11028                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11029
11030                    // Move selections down
11031                    new_selections.extend(contiguous_row_selections.drain(..).map(
11032                        |mut selection| {
11033                            selection.start.row += row_delta;
11034                            selection.end.row += row_delta;
11035                            selection
11036                        },
11037                    ));
11038
11039                    // Move folds down
11040                    unfold_ranges.push(range_to_move.clone());
11041                    for fold in display_map.folds_in_range(
11042                        buffer.anchor_before(range_to_move.start)
11043                            ..buffer.anchor_after(range_to_move.end),
11044                    ) {
11045                        let mut start = fold.range.start.to_point(&buffer);
11046                        let mut end = fold.range.end.to_point(&buffer);
11047                        start.row += row_delta;
11048                        end.row += row_delta;
11049                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11050                    }
11051                }
11052            }
11053
11054            // If we didn't move line(s), preserve the existing selections
11055            new_selections.append(&mut contiguous_row_selections);
11056        }
11057
11058        self.transact(window, cx, |this, window, cx| {
11059            this.unfold_ranges(&unfold_ranges, true, true, cx);
11060            this.buffer.update(cx, |buffer, cx| {
11061                for (range, text) in edits {
11062                    buffer.edit([(range, text)], None, cx);
11063                }
11064            });
11065            this.fold_creases(refold_creases, true, window, cx);
11066            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11067                s.select(new_selections)
11068            });
11069        });
11070    }
11071
11072    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11073        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11074        let text_layout_details = &self.text_layout_details(window);
11075        self.transact(window, cx, |this, window, cx| {
11076            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11077                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11078                s.move_with(|display_map, selection| {
11079                    if !selection.is_empty() {
11080                        return;
11081                    }
11082
11083                    let mut head = selection.head();
11084                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11085                    if head.column() == display_map.line_len(head.row()) {
11086                        transpose_offset = display_map
11087                            .buffer_snapshot
11088                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11089                    }
11090
11091                    if transpose_offset == 0 {
11092                        return;
11093                    }
11094
11095                    *head.column_mut() += 1;
11096                    head = display_map.clip_point(head, Bias::Right);
11097                    let goal = SelectionGoal::HorizontalPosition(
11098                        display_map
11099                            .x_for_display_point(head, text_layout_details)
11100                            .into(),
11101                    );
11102                    selection.collapse_to(head, goal);
11103
11104                    let transpose_start = display_map
11105                        .buffer_snapshot
11106                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11107                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11108                        let transpose_end = display_map
11109                            .buffer_snapshot
11110                            .clip_offset(transpose_offset + 1, Bias::Right);
11111                        if let Some(ch) =
11112                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11113                        {
11114                            edits.push((transpose_start..transpose_offset, String::new()));
11115                            edits.push((transpose_end..transpose_end, ch.to_string()));
11116                        }
11117                    }
11118                });
11119                edits
11120            });
11121            this.buffer
11122                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11123            let selections = this.selections.all::<usize>(cx);
11124            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11125                s.select(selections);
11126            });
11127        });
11128    }
11129
11130    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11131        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11132        self.rewrap_impl(RewrapOptions::default(), cx)
11133    }
11134
11135    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11136        let buffer = self.buffer.read(cx).snapshot(cx);
11137        let selections = self.selections.all::<Point>(cx);
11138
11139        // Shrink and split selections to respect paragraph boundaries.
11140        let ranges = selections.into_iter().flat_map(|selection| {
11141            let language_settings = buffer.language_settings_at(selection.head(), cx);
11142            let language_scope = buffer.language_scope_at(selection.head());
11143
11144            let Some(start_row) = (selection.start.row..=selection.end.row)
11145                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11146            else {
11147                return vec![];
11148            };
11149            let Some(end_row) = (selection.start.row..=selection.end.row)
11150                .rev()
11151                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11152            else {
11153                return vec![];
11154            };
11155
11156            let mut row = start_row;
11157            let mut ranges = Vec::new();
11158            while let Some(blank_row) =
11159                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11160            {
11161                let next_paragraph_start = (blank_row + 1..=end_row)
11162                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11163                    .unwrap();
11164                ranges.push((
11165                    language_settings.clone(),
11166                    language_scope.clone(),
11167                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11168                ));
11169                row = next_paragraph_start;
11170            }
11171            ranges.push((
11172                language_settings.clone(),
11173                language_scope.clone(),
11174                Point::new(row, 0)..Point::new(end_row, 0),
11175            ));
11176
11177            ranges
11178        });
11179
11180        let mut edits = Vec::new();
11181        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11182
11183        for (language_settings, language_scope, range) in ranges {
11184            let mut start_row = range.start.row;
11185            let mut end_row = range.end.row;
11186
11187            // Skip selections that overlap with a range that has already been rewrapped.
11188            let selection_range = start_row..end_row;
11189            if rewrapped_row_ranges
11190                .iter()
11191                .any(|range| range.overlaps(&selection_range))
11192            {
11193                continue;
11194            }
11195
11196            let tab_size = language_settings.tab_size;
11197
11198            // Since not all lines in the selection may be at the same indent
11199            // level, choose the indent size that is the most common between all
11200            // of the lines.
11201            //
11202            // If there is a tie, we use the deepest indent.
11203            let (indent_size, indent_end) = {
11204                let mut indent_size_occurrences = HashMap::default();
11205                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11206
11207                for row in start_row..=end_row {
11208                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11209                    rows_by_indent_size.entry(indent).or_default().push(row);
11210                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11211                }
11212
11213                let indent_size = indent_size_occurrences
11214                    .into_iter()
11215                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11216                    .map(|(indent, _)| indent)
11217                    .unwrap_or_default();
11218                let row = rows_by_indent_size[&indent_size][0];
11219                let indent_end = Point::new(row, indent_size.len);
11220
11221                (indent_size, indent_end)
11222            };
11223
11224            let mut line_prefix = indent_size.chars().collect::<String>();
11225
11226            let mut inside_comment = false;
11227            if let Some(comment_prefix) = language_scope.and_then(|language| {
11228                language
11229                    .line_comment_prefixes()
11230                    .iter()
11231                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11232                    .cloned()
11233            }) {
11234                line_prefix.push_str(&comment_prefix);
11235                inside_comment = true;
11236            }
11237
11238            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11239                RewrapBehavior::InComments => inside_comment,
11240                RewrapBehavior::InSelections => !range.is_empty(),
11241                RewrapBehavior::Anywhere => true,
11242            };
11243
11244            let should_rewrap = options.override_language_settings
11245                || allow_rewrap_based_on_language
11246                || self.hard_wrap.is_some();
11247            if !should_rewrap {
11248                continue;
11249            }
11250
11251            if range.is_empty() {
11252                'expand_upwards: while start_row > 0 {
11253                    let prev_row = start_row - 1;
11254                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11255                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11256                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11257                    {
11258                        start_row = prev_row;
11259                    } else {
11260                        break 'expand_upwards;
11261                    }
11262                }
11263
11264                'expand_downwards: while end_row < buffer.max_point().row {
11265                    let next_row = end_row + 1;
11266                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11267                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11268                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11269                    {
11270                        end_row = next_row;
11271                    } else {
11272                        break 'expand_downwards;
11273                    }
11274                }
11275            }
11276
11277            let start = Point::new(start_row, 0);
11278            let start_offset = start.to_offset(&buffer);
11279            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11280            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11281            let Some(lines_without_prefixes) = selection_text
11282                .lines()
11283                .map(|line| {
11284                    line.strip_prefix(&line_prefix)
11285                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11286                        .with_context(|| {
11287                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11288                        })
11289                })
11290                .collect::<Result<Vec<_>, _>>()
11291                .log_err()
11292            else {
11293                continue;
11294            };
11295
11296            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11297                buffer
11298                    .language_settings_at(Point::new(start_row, 0), cx)
11299                    .preferred_line_length as usize
11300            });
11301            let wrapped_text = wrap_with_prefix(
11302                line_prefix,
11303                lines_without_prefixes.join("\n"),
11304                wrap_column,
11305                tab_size,
11306                options.preserve_existing_whitespace,
11307            );
11308
11309            // TODO: should always use char-based diff while still supporting cursor behavior that
11310            // matches vim.
11311            let mut diff_options = DiffOptions::default();
11312            if options.override_language_settings {
11313                diff_options.max_word_diff_len = 0;
11314                diff_options.max_word_diff_line_count = 0;
11315            } else {
11316                diff_options.max_word_diff_len = usize::MAX;
11317                diff_options.max_word_diff_line_count = usize::MAX;
11318            }
11319
11320            for (old_range, new_text) in
11321                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11322            {
11323                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11324                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11325                edits.push((edit_start..edit_end, new_text));
11326            }
11327
11328            rewrapped_row_ranges.push(start_row..=end_row);
11329        }
11330
11331        self.buffer
11332            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11333    }
11334
11335    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11336        let mut text = String::new();
11337        let buffer = self.buffer.read(cx).snapshot(cx);
11338        let mut selections = self.selections.all::<Point>(cx);
11339        let mut clipboard_selections = Vec::with_capacity(selections.len());
11340        {
11341            let max_point = buffer.max_point();
11342            let mut is_first = true;
11343            for selection in &mut selections {
11344                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11345                if is_entire_line {
11346                    selection.start = Point::new(selection.start.row, 0);
11347                    if !selection.is_empty() && selection.end.column == 0 {
11348                        selection.end = cmp::min(max_point, selection.end);
11349                    } else {
11350                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11351                    }
11352                    selection.goal = SelectionGoal::None;
11353                }
11354                if is_first {
11355                    is_first = false;
11356                } else {
11357                    text += "\n";
11358                }
11359                let mut len = 0;
11360                for chunk in buffer.text_for_range(selection.start..selection.end) {
11361                    text.push_str(chunk);
11362                    len += chunk.len();
11363                }
11364                clipboard_selections.push(ClipboardSelection {
11365                    len,
11366                    is_entire_line,
11367                    first_line_indent: buffer
11368                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11369                        .len,
11370                });
11371            }
11372        }
11373
11374        self.transact(window, cx, |this, window, cx| {
11375            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11376                s.select(selections);
11377            });
11378            this.insert("", window, cx);
11379        });
11380        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11381    }
11382
11383    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11384        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11385        let item = self.cut_common(window, cx);
11386        cx.write_to_clipboard(item);
11387    }
11388
11389    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11390        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11391        self.change_selections(None, window, cx, |s| {
11392            s.move_with(|snapshot, sel| {
11393                if sel.is_empty() {
11394                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11395                }
11396            });
11397        });
11398        let item = self.cut_common(window, cx);
11399        cx.set_global(KillRing(item))
11400    }
11401
11402    pub fn kill_ring_yank(
11403        &mut self,
11404        _: &KillRingYank,
11405        window: &mut Window,
11406        cx: &mut Context<Self>,
11407    ) {
11408        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11409        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11410            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11411                (kill_ring.text().to_string(), kill_ring.metadata_json())
11412            } else {
11413                return;
11414            }
11415        } else {
11416            return;
11417        };
11418        self.do_paste(&text, metadata, false, window, cx);
11419    }
11420
11421    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11422        self.do_copy(true, cx);
11423    }
11424
11425    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11426        self.do_copy(false, cx);
11427    }
11428
11429    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11430        let selections = self.selections.all::<Point>(cx);
11431        let buffer = self.buffer.read(cx).read(cx);
11432        let mut text = String::new();
11433
11434        let mut clipboard_selections = Vec::with_capacity(selections.len());
11435        {
11436            let max_point = buffer.max_point();
11437            let mut is_first = true;
11438            for selection in &selections {
11439                let mut start = selection.start;
11440                let mut end = selection.end;
11441                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11442                if is_entire_line {
11443                    start = Point::new(start.row, 0);
11444                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11445                }
11446
11447                let mut trimmed_selections = Vec::new();
11448                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11449                    let row = MultiBufferRow(start.row);
11450                    let first_indent = buffer.indent_size_for_line(row);
11451                    if first_indent.len == 0 || start.column > first_indent.len {
11452                        trimmed_selections.push(start..end);
11453                    } else {
11454                        trimmed_selections.push(
11455                            Point::new(row.0, first_indent.len)
11456                                ..Point::new(row.0, buffer.line_len(row)),
11457                        );
11458                        for row in start.row + 1..=end.row {
11459                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11460                            if row == end.row {
11461                                line_len = end.column;
11462                            }
11463                            if line_len == 0 {
11464                                trimmed_selections
11465                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11466                                continue;
11467                            }
11468                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11469                            if row_indent_size.len >= first_indent.len {
11470                                trimmed_selections.push(
11471                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11472                                );
11473                            } else {
11474                                trimmed_selections.clear();
11475                                trimmed_selections.push(start..end);
11476                                break;
11477                            }
11478                        }
11479                    }
11480                } else {
11481                    trimmed_selections.push(start..end);
11482                }
11483
11484                for trimmed_range in trimmed_selections {
11485                    if is_first {
11486                        is_first = false;
11487                    } else {
11488                        text += "\n";
11489                    }
11490                    let mut len = 0;
11491                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11492                        text.push_str(chunk);
11493                        len += chunk.len();
11494                    }
11495                    clipboard_selections.push(ClipboardSelection {
11496                        len,
11497                        is_entire_line,
11498                        first_line_indent: buffer
11499                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11500                            .len,
11501                    });
11502                }
11503            }
11504        }
11505
11506        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11507            text,
11508            clipboard_selections,
11509        ));
11510    }
11511
11512    pub fn do_paste(
11513        &mut self,
11514        text: &String,
11515        clipboard_selections: Option<Vec<ClipboardSelection>>,
11516        handle_entire_lines: bool,
11517        window: &mut Window,
11518        cx: &mut Context<Self>,
11519    ) {
11520        if self.read_only(cx) {
11521            return;
11522        }
11523
11524        let clipboard_text = Cow::Borrowed(text);
11525
11526        self.transact(window, cx, |this, window, cx| {
11527            if let Some(mut clipboard_selections) = clipboard_selections {
11528                let old_selections = this.selections.all::<usize>(cx);
11529                let all_selections_were_entire_line =
11530                    clipboard_selections.iter().all(|s| s.is_entire_line);
11531                let first_selection_indent_column =
11532                    clipboard_selections.first().map(|s| s.first_line_indent);
11533                if clipboard_selections.len() != old_selections.len() {
11534                    clipboard_selections.drain(..);
11535                }
11536                let cursor_offset = this.selections.last::<usize>(cx).head();
11537                let mut auto_indent_on_paste = true;
11538
11539                this.buffer.update(cx, |buffer, cx| {
11540                    let snapshot = buffer.read(cx);
11541                    auto_indent_on_paste = snapshot
11542                        .language_settings_at(cursor_offset, cx)
11543                        .auto_indent_on_paste;
11544
11545                    let mut start_offset = 0;
11546                    let mut edits = Vec::new();
11547                    let mut original_indent_columns = Vec::new();
11548                    for (ix, selection) in old_selections.iter().enumerate() {
11549                        let to_insert;
11550                        let entire_line;
11551                        let original_indent_column;
11552                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11553                            let end_offset = start_offset + clipboard_selection.len;
11554                            to_insert = &clipboard_text[start_offset..end_offset];
11555                            entire_line = clipboard_selection.is_entire_line;
11556                            start_offset = end_offset + 1;
11557                            original_indent_column = Some(clipboard_selection.first_line_indent);
11558                        } else {
11559                            to_insert = clipboard_text.as_str();
11560                            entire_line = all_selections_were_entire_line;
11561                            original_indent_column = first_selection_indent_column
11562                        }
11563
11564                        // If the corresponding selection was empty when this slice of the
11565                        // clipboard text was written, then the entire line containing the
11566                        // selection was copied. If this selection is also currently empty,
11567                        // then paste the line before the current line of the buffer.
11568                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11569                            let column = selection.start.to_point(&snapshot).column as usize;
11570                            let line_start = selection.start - column;
11571                            line_start..line_start
11572                        } else {
11573                            selection.range()
11574                        };
11575
11576                        edits.push((range, to_insert));
11577                        original_indent_columns.push(original_indent_column);
11578                    }
11579                    drop(snapshot);
11580
11581                    buffer.edit(
11582                        edits,
11583                        if auto_indent_on_paste {
11584                            Some(AutoindentMode::Block {
11585                                original_indent_columns,
11586                            })
11587                        } else {
11588                            None
11589                        },
11590                        cx,
11591                    );
11592                });
11593
11594                let selections = this.selections.all::<usize>(cx);
11595                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11596                    s.select(selections)
11597                });
11598            } else {
11599                this.insert(&clipboard_text, window, cx);
11600            }
11601        });
11602    }
11603
11604    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11605        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11606        if let Some(item) = cx.read_from_clipboard() {
11607            let entries = item.entries();
11608
11609            match entries.first() {
11610                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11611                // of all the pasted entries.
11612                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11613                    .do_paste(
11614                        clipboard_string.text(),
11615                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11616                        true,
11617                        window,
11618                        cx,
11619                    ),
11620                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11621            }
11622        }
11623    }
11624
11625    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11626        if self.read_only(cx) {
11627            return;
11628        }
11629
11630        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11631
11632        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11633            if let Some((selections, _)) =
11634                self.selection_history.transaction(transaction_id).cloned()
11635            {
11636                self.change_selections(None, window, cx, |s| {
11637                    s.select_anchors(selections.to_vec());
11638                });
11639            } else {
11640                log::error!(
11641                    "No entry in selection_history found for undo. \
11642                     This may correspond to a bug where undo does not update the selection. \
11643                     If this is occurring, please add details to \
11644                     https://github.com/zed-industries/zed/issues/22692"
11645                );
11646            }
11647            self.request_autoscroll(Autoscroll::fit(), cx);
11648            self.unmark_text(window, cx);
11649            self.refresh_inline_completion(true, false, window, cx);
11650            cx.emit(EditorEvent::Edited { transaction_id });
11651            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11652        }
11653    }
11654
11655    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11656        if self.read_only(cx) {
11657            return;
11658        }
11659
11660        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11661
11662        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11663            if let Some((_, Some(selections))) =
11664                self.selection_history.transaction(transaction_id).cloned()
11665            {
11666                self.change_selections(None, window, cx, |s| {
11667                    s.select_anchors(selections.to_vec());
11668                });
11669            } else {
11670                log::error!(
11671                    "No entry in selection_history found for redo. \
11672                     This may correspond to a bug where undo does not update the selection. \
11673                     If this is occurring, please add details to \
11674                     https://github.com/zed-industries/zed/issues/22692"
11675                );
11676            }
11677            self.request_autoscroll(Autoscroll::fit(), cx);
11678            self.unmark_text(window, cx);
11679            self.refresh_inline_completion(true, false, window, cx);
11680            cx.emit(EditorEvent::Edited { transaction_id });
11681        }
11682    }
11683
11684    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11685        self.buffer
11686            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11687    }
11688
11689    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11690        self.buffer
11691            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11692    }
11693
11694    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11695        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11696        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11697            s.move_with(|map, selection| {
11698                let cursor = if selection.is_empty() {
11699                    movement::left(map, selection.start)
11700                } else {
11701                    selection.start
11702                };
11703                selection.collapse_to(cursor, SelectionGoal::None);
11704            });
11705        })
11706    }
11707
11708    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11709        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11710        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11711            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11712        })
11713    }
11714
11715    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11716        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11717        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11718            s.move_with(|map, selection| {
11719                let cursor = if selection.is_empty() {
11720                    movement::right(map, selection.end)
11721                } else {
11722                    selection.end
11723                };
11724                selection.collapse_to(cursor, SelectionGoal::None)
11725            });
11726        })
11727    }
11728
11729    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11730        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11731        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11732            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11733        })
11734    }
11735
11736    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11737        if self.take_rename(true, window, cx).is_some() {
11738            return;
11739        }
11740
11741        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11742            cx.propagate();
11743            return;
11744        }
11745
11746        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11747
11748        let text_layout_details = &self.text_layout_details(window);
11749        let selection_count = self.selections.count();
11750        let first_selection = self.selections.first_anchor();
11751
11752        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11753            s.move_with(|map, selection| {
11754                if !selection.is_empty() {
11755                    selection.goal = SelectionGoal::None;
11756                }
11757                let (cursor, goal) = movement::up(
11758                    map,
11759                    selection.start,
11760                    selection.goal,
11761                    false,
11762                    text_layout_details,
11763                );
11764                selection.collapse_to(cursor, goal);
11765            });
11766        });
11767
11768        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11769        {
11770            cx.propagate();
11771        }
11772    }
11773
11774    pub fn move_up_by_lines(
11775        &mut self,
11776        action: &MoveUpByLines,
11777        window: &mut Window,
11778        cx: &mut Context<Self>,
11779    ) {
11780        if self.take_rename(true, window, cx).is_some() {
11781            return;
11782        }
11783
11784        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11785            cx.propagate();
11786            return;
11787        }
11788
11789        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11790
11791        let text_layout_details = &self.text_layout_details(window);
11792
11793        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11794            s.move_with(|map, selection| {
11795                if !selection.is_empty() {
11796                    selection.goal = SelectionGoal::None;
11797                }
11798                let (cursor, goal) = movement::up_by_rows(
11799                    map,
11800                    selection.start,
11801                    action.lines,
11802                    selection.goal,
11803                    false,
11804                    text_layout_details,
11805                );
11806                selection.collapse_to(cursor, goal);
11807            });
11808        })
11809    }
11810
11811    pub fn move_down_by_lines(
11812        &mut self,
11813        action: &MoveDownByLines,
11814        window: &mut Window,
11815        cx: &mut Context<Self>,
11816    ) {
11817        if self.take_rename(true, window, cx).is_some() {
11818            return;
11819        }
11820
11821        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11822            cx.propagate();
11823            return;
11824        }
11825
11826        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11827
11828        let text_layout_details = &self.text_layout_details(window);
11829
11830        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11831            s.move_with(|map, selection| {
11832                if !selection.is_empty() {
11833                    selection.goal = SelectionGoal::None;
11834                }
11835                let (cursor, goal) = movement::down_by_rows(
11836                    map,
11837                    selection.start,
11838                    action.lines,
11839                    selection.goal,
11840                    false,
11841                    text_layout_details,
11842                );
11843                selection.collapse_to(cursor, goal);
11844            });
11845        })
11846    }
11847
11848    pub fn select_down_by_lines(
11849        &mut self,
11850        action: &SelectDownByLines,
11851        window: &mut Window,
11852        cx: &mut Context<Self>,
11853    ) {
11854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11855        let text_layout_details = &self.text_layout_details(window);
11856        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11857            s.move_heads_with(|map, head, goal| {
11858                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11859            })
11860        })
11861    }
11862
11863    pub fn select_up_by_lines(
11864        &mut self,
11865        action: &SelectUpByLines,
11866        window: &mut Window,
11867        cx: &mut Context<Self>,
11868    ) {
11869        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11870        let text_layout_details = &self.text_layout_details(window);
11871        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11872            s.move_heads_with(|map, head, goal| {
11873                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11874            })
11875        })
11876    }
11877
11878    pub fn select_page_up(
11879        &mut self,
11880        _: &SelectPageUp,
11881        window: &mut Window,
11882        cx: &mut Context<Self>,
11883    ) {
11884        let Some(row_count) = self.visible_row_count() else {
11885            return;
11886        };
11887
11888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11889
11890        let text_layout_details = &self.text_layout_details(window);
11891
11892        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11893            s.move_heads_with(|map, head, goal| {
11894                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11895            })
11896        })
11897    }
11898
11899    pub fn move_page_up(
11900        &mut self,
11901        action: &MovePageUp,
11902        window: &mut Window,
11903        cx: &mut Context<Self>,
11904    ) {
11905        if self.take_rename(true, window, cx).is_some() {
11906            return;
11907        }
11908
11909        if self
11910            .context_menu
11911            .borrow_mut()
11912            .as_mut()
11913            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11914            .unwrap_or(false)
11915        {
11916            return;
11917        }
11918
11919        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11920            cx.propagate();
11921            return;
11922        }
11923
11924        let Some(row_count) = self.visible_row_count() else {
11925            return;
11926        };
11927
11928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11929
11930        let autoscroll = if action.center_cursor {
11931            Autoscroll::center()
11932        } else {
11933            Autoscroll::fit()
11934        };
11935
11936        let text_layout_details = &self.text_layout_details(window);
11937
11938        self.change_selections(Some(autoscroll), window, cx, |s| {
11939            s.move_with(|map, selection| {
11940                if !selection.is_empty() {
11941                    selection.goal = SelectionGoal::None;
11942                }
11943                let (cursor, goal) = movement::up_by_rows(
11944                    map,
11945                    selection.end,
11946                    row_count,
11947                    selection.goal,
11948                    false,
11949                    text_layout_details,
11950                );
11951                selection.collapse_to(cursor, goal);
11952            });
11953        });
11954    }
11955
11956    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11958        let text_layout_details = &self.text_layout_details(window);
11959        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11960            s.move_heads_with(|map, head, goal| {
11961                movement::up(map, head, goal, false, text_layout_details)
11962            })
11963        })
11964    }
11965
11966    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11967        self.take_rename(true, window, cx);
11968
11969        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11970            cx.propagate();
11971            return;
11972        }
11973
11974        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11975
11976        let text_layout_details = &self.text_layout_details(window);
11977        let selection_count = self.selections.count();
11978        let first_selection = self.selections.first_anchor();
11979
11980        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11981            s.move_with(|map, selection| {
11982                if !selection.is_empty() {
11983                    selection.goal = SelectionGoal::None;
11984                }
11985                let (cursor, goal) = movement::down(
11986                    map,
11987                    selection.end,
11988                    selection.goal,
11989                    false,
11990                    text_layout_details,
11991                );
11992                selection.collapse_to(cursor, goal);
11993            });
11994        });
11995
11996        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11997        {
11998            cx.propagate();
11999        }
12000    }
12001
12002    pub fn select_page_down(
12003        &mut self,
12004        _: &SelectPageDown,
12005        window: &mut Window,
12006        cx: &mut Context<Self>,
12007    ) {
12008        let Some(row_count) = self.visible_row_count() else {
12009            return;
12010        };
12011
12012        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12013
12014        let text_layout_details = &self.text_layout_details(window);
12015
12016        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12017            s.move_heads_with(|map, head, goal| {
12018                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12019            })
12020        })
12021    }
12022
12023    pub fn move_page_down(
12024        &mut self,
12025        action: &MovePageDown,
12026        window: &mut Window,
12027        cx: &mut Context<Self>,
12028    ) {
12029        if self.take_rename(true, window, cx).is_some() {
12030            return;
12031        }
12032
12033        if self
12034            .context_menu
12035            .borrow_mut()
12036            .as_mut()
12037            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12038            .unwrap_or(false)
12039        {
12040            return;
12041        }
12042
12043        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12044            cx.propagate();
12045            return;
12046        }
12047
12048        let Some(row_count) = self.visible_row_count() else {
12049            return;
12050        };
12051
12052        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12053
12054        let autoscroll = if action.center_cursor {
12055            Autoscroll::center()
12056        } else {
12057            Autoscroll::fit()
12058        };
12059
12060        let text_layout_details = &self.text_layout_details(window);
12061        self.change_selections(Some(autoscroll), window, cx, |s| {
12062            s.move_with(|map, selection| {
12063                if !selection.is_empty() {
12064                    selection.goal = SelectionGoal::None;
12065                }
12066                let (cursor, goal) = movement::down_by_rows(
12067                    map,
12068                    selection.end,
12069                    row_count,
12070                    selection.goal,
12071                    false,
12072                    text_layout_details,
12073                );
12074                selection.collapse_to(cursor, goal);
12075            });
12076        });
12077    }
12078
12079    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12081        let text_layout_details = &self.text_layout_details(window);
12082        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12083            s.move_heads_with(|map, head, goal| {
12084                movement::down(map, head, goal, false, text_layout_details)
12085            })
12086        });
12087    }
12088
12089    pub fn context_menu_first(
12090        &mut self,
12091        _: &ContextMenuFirst,
12092        window: &mut Window,
12093        cx: &mut Context<Self>,
12094    ) {
12095        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12096            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12097        }
12098    }
12099
12100    pub fn context_menu_prev(
12101        &mut self,
12102        _: &ContextMenuPrevious,
12103        window: &mut Window,
12104        cx: &mut Context<Self>,
12105    ) {
12106        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12107            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12108        }
12109    }
12110
12111    pub fn context_menu_next(
12112        &mut self,
12113        _: &ContextMenuNext,
12114        window: &mut Window,
12115        cx: &mut Context<Self>,
12116    ) {
12117        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12118            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12119        }
12120    }
12121
12122    pub fn context_menu_last(
12123        &mut self,
12124        _: &ContextMenuLast,
12125        window: &mut Window,
12126        cx: &mut Context<Self>,
12127    ) {
12128        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12129            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12130        }
12131    }
12132
12133    pub fn move_to_previous_word_start(
12134        &mut self,
12135        _: &MoveToPreviousWordStart,
12136        window: &mut Window,
12137        cx: &mut Context<Self>,
12138    ) {
12139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12140        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12141            s.move_cursors_with(|map, head, _| {
12142                (
12143                    movement::previous_word_start(map, head),
12144                    SelectionGoal::None,
12145                )
12146            });
12147        })
12148    }
12149
12150    pub fn move_to_previous_subword_start(
12151        &mut self,
12152        _: &MoveToPreviousSubwordStart,
12153        window: &mut Window,
12154        cx: &mut Context<Self>,
12155    ) {
12156        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12157        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12158            s.move_cursors_with(|map, head, _| {
12159                (
12160                    movement::previous_subword_start(map, head),
12161                    SelectionGoal::None,
12162                )
12163            });
12164        })
12165    }
12166
12167    pub fn select_to_previous_word_start(
12168        &mut self,
12169        _: &SelectToPreviousWordStart,
12170        window: &mut Window,
12171        cx: &mut Context<Self>,
12172    ) {
12173        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12174        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12175            s.move_heads_with(|map, head, _| {
12176                (
12177                    movement::previous_word_start(map, head),
12178                    SelectionGoal::None,
12179                )
12180            });
12181        })
12182    }
12183
12184    pub fn select_to_previous_subword_start(
12185        &mut self,
12186        _: &SelectToPreviousSubwordStart,
12187        window: &mut Window,
12188        cx: &mut Context<Self>,
12189    ) {
12190        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12191        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12192            s.move_heads_with(|map, head, _| {
12193                (
12194                    movement::previous_subword_start(map, head),
12195                    SelectionGoal::None,
12196                )
12197            });
12198        })
12199    }
12200
12201    pub fn delete_to_previous_word_start(
12202        &mut self,
12203        action: &DeleteToPreviousWordStart,
12204        window: &mut Window,
12205        cx: &mut Context<Self>,
12206    ) {
12207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12208        self.transact(window, cx, |this, window, cx| {
12209            this.select_autoclose_pair(window, cx);
12210            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12211                s.move_with(|map, selection| {
12212                    if selection.is_empty() {
12213                        let cursor = if action.ignore_newlines {
12214                            movement::previous_word_start(map, selection.head())
12215                        } else {
12216                            movement::previous_word_start_or_newline(map, selection.head())
12217                        };
12218                        selection.set_head(cursor, SelectionGoal::None);
12219                    }
12220                });
12221            });
12222            this.insert("", window, cx);
12223        });
12224    }
12225
12226    pub fn delete_to_previous_subword_start(
12227        &mut self,
12228        _: &DeleteToPreviousSubwordStart,
12229        window: &mut Window,
12230        cx: &mut Context<Self>,
12231    ) {
12232        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12233        self.transact(window, cx, |this, window, cx| {
12234            this.select_autoclose_pair(window, cx);
12235            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12236                s.move_with(|map, selection| {
12237                    if selection.is_empty() {
12238                        let cursor = movement::previous_subword_start(map, selection.head());
12239                        selection.set_head(cursor, SelectionGoal::None);
12240                    }
12241                });
12242            });
12243            this.insert("", window, cx);
12244        });
12245    }
12246
12247    pub fn move_to_next_word_end(
12248        &mut self,
12249        _: &MoveToNextWordEnd,
12250        window: &mut Window,
12251        cx: &mut Context<Self>,
12252    ) {
12253        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12254        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12255            s.move_cursors_with(|map, head, _| {
12256                (movement::next_word_end(map, head), SelectionGoal::None)
12257            });
12258        })
12259    }
12260
12261    pub fn move_to_next_subword_end(
12262        &mut self,
12263        _: &MoveToNextSubwordEnd,
12264        window: &mut Window,
12265        cx: &mut Context<Self>,
12266    ) {
12267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12268        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12269            s.move_cursors_with(|map, head, _| {
12270                (movement::next_subword_end(map, head), SelectionGoal::None)
12271            });
12272        })
12273    }
12274
12275    pub fn select_to_next_word_end(
12276        &mut self,
12277        _: &SelectToNextWordEnd,
12278        window: &mut Window,
12279        cx: &mut Context<Self>,
12280    ) {
12281        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12282        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12283            s.move_heads_with(|map, head, _| {
12284                (movement::next_word_end(map, head), SelectionGoal::None)
12285            });
12286        })
12287    }
12288
12289    pub fn select_to_next_subword_end(
12290        &mut self,
12291        _: &SelectToNextSubwordEnd,
12292        window: &mut Window,
12293        cx: &mut Context<Self>,
12294    ) {
12295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12296        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12297            s.move_heads_with(|map, head, _| {
12298                (movement::next_subword_end(map, head), SelectionGoal::None)
12299            });
12300        })
12301    }
12302
12303    pub fn delete_to_next_word_end(
12304        &mut self,
12305        action: &DeleteToNextWordEnd,
12306        window: &mut Window,
12307        cx: &mut Context<Self>,
12308    ) {
12309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12310        self.transact(window, cx, |this, window, cx| {
12311            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12312                s.move_with(|map, selection| {
12313                    if selection.is_empty() {
12314                        let cursor = if action.ignore_newlines {
12315                            movement::next_word_end(map, selection.head())
12316                        } else {
12317                            movement::next_word_end_or_newline(map, selection.head())
12318                        };
12319                        selection.set_head(cursor, SelectionGoal::None);
12320                    }
12321                });
12322            });
12323            this.insert("", window, cx);
12324        });
12325    }
12326
12327    pub fn delete_to_next_subword_end(
12328        &mut self,
12329        _: &DeleteToNextSubwordEnd,
12330        window: &mut Window,
12331        cx: &mut Context<Self>,
12332    ) {
12333        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12334        self.transact(window, cx, |this, window, cx| {
12335            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12336                s.move_with(|map, selection| {
12337                    if selection.is_empty() {
12338                        let cursor = movement::next_subword_end(map, selection.head());
12339                        selection.set_head(cursor, SelectionGoal::None);
12340                    }
12341                });
12342            });
12343            this.insert("", window, cx);
12344        });
12345    }
12346
12347    pub fn move_to_beginning_of_line(
12348        &mut self,
12349        action: &MoveToBeginningOfLine,
12350        window: &mut Window,
12351        cx: &mut Context<Self>,
12352    ) {
12353        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12354        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12355            s.move_cursors_with(|map, head, _| {
12356                (
12357                    movement::indented_line_beginning(
12358                        map,
12359                        head,
12360                        action.stop_at_soft_wraps,
12361                        action.stop_at_indent,
12362                    ),
12363                    SelectionGoal::None,
12364                )
12365            });
12366        })
12367    }
12368
12369    pub fn select_to_beginning_of_line(
12370        &mut self,
12371        action: &SelectToBeginningOfLine,
12372        window: &mut Window,
12373        cx: &mut Context<Self>,
12374    ) {
12375        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12376        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12377            s.move_heads_with(|map, head, _| {
12378                (
12379                    movement::indented_line_beginning(
12380                        map,
12381                        head,
12382                        action.stop_at_soft_wraps,
12383                        action.stop_at_indent,
12384                    ),
12385                    SelectionGoal::None,
12386                )
12387            });
12388        });
12389    }
12390
12391    pub fn delete_to_beginning_of_line(
12392        &mut self,
12393        action: &DeleteToBeginningOfLine,
12394        window: &mut Window,
12395        cx: &mut Context<Self>,
12396    ) {
12397        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12398        self.transact(window, cx, |this, window, cx| {
12399            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12400                s.move_with(|_, selection| {
12401                    selection.reversed = true;
12402                });
12403            });
12404
12405            this.select_to_beginning_of_line(
12406                &SelectToBeginningOfLine {
12407                    stop_at_soft_wraps: false,
12408                    stop_at_indent: action.stop_at_indent,
12409                },
12410                window,
12411                cx,
12412            );
12413            this.backspace(&Backspace, window, cx);
12414        });
12415    }
12416
12417    pub fn move_to_end_of_line(
12418        &mut self,
12419        action: &MoveToEndOfLine,
12420        window: &mut Window,
12421        cx: &mut Context<Self>,
12422    ) {
12423        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12424        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12425            s.move_cursors_with(|map, head, _| {
12426                (
12427                    movement::line_end(map, head, action.stop_at_soft_wraps),
12428                    SelectionGoal::None,
12429                )
12430            });
12431        })
12432    }
12433
12434    pub fn select_to_end_of_line(
12435        &mut self,
12436        action: &SelectToEndOfLine,
12437        window: &mut Window,
12438        cx: &mut Context<Self>,
12439    ) {
12440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12441        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12442            s.move_heads_with(|map, head, _| {
12443                (
12444                    movement::line_end(map, head, action.stop_at_soft_wraps),
12445                    SelectionGoal::None,
12446                )
12447            });
12448        })
12449    }
12450
12451    pub fn delete_to_end_of_line(
12452        &mut self,
12453        _: &DeleteToEndOfLine,
12454        window: &mut Window,
12455        cx: &mut Context<Self>,
12456    ) {
12457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12458        self.transact(window, cx, |this, window, cx| {
12459            this.select_to_end_of_line(
12460                &SelectToEndOfLine {
12461                    stop_at_soft_wraps: false,
12462                },
12463                window,
12464                cx,
12465            );
12466            this.delete(&Delete, window, cx);
12467        });
12468    }
12469
12470    pub fn cut_to_end_of_line(
12471        &mut self,
12472        _: &CutToEndOfLine,
12473        window: &mut Window,
12474        cx: &mut Context<Self>,
12475    ) {
12476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12477        self.transact(window, cx, |this, window, cx| {
12478            this.select_to_end_of_line(
12479                &SelectToEndOfLine {
12480                    stop_at_soft_wraps: false,
12481                },
12482                window,
12483                cx,
12484            );
12485            this.cut(&Cut, window, cx);
12486        });
12487    }
12488
12489    pub fn move_to_start_of_paragraph(
12490        &mut self,
12491        _: &MoveToStartOfParagraph,
12492        window: &mut Window,
12493        cx: &mut Context<Self>,
12494    ) {
12495        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12496            cx.propagate();
12497            return;
12498        }
12499        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12500        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12501            s.move_with(|map, selection| {
12502                selection.collapse_to(
12503                    movement::start_of_paragraph(map, selection.head(), 1),
12504                    SelectionGoal::None,
12505                )
12506            });
12507        })
12508    }
12509
12510    pub fn move_to_end_of_paragraph(
12511        &mut self,
12512        _: &MoveToEndOfParagraph,
12513        window: &mut Window,
12514        cx: &mut Context<Self>,
12515    ) {
12516        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12517            cx.propagate();
12518            return;
12519        }
12520        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12521        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12522            s.move_with(|map, selection| {
12523                selection.collapse_to(
12524                    movement::end_of_paragraph(map, selection.head(), 1),
12525                    SelectionGoal::None,
12526                )
12527            });
12528        })
12529    }
12530
12531    pub fn select_to_start_of_paragraph(
12532        &mut self,
12533        _: &SelectToStartOfParagraph,
12534        window: &mut Window,
12535        cx: &mut Context<Self>,
12536    ) {
12537        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12538            cx.propagate();
12539            return;
12540        }
12541        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12542        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12543            s.move_heads_with(|map, head, _| {
12544                (
12545                    movement::start_of_paragraph(map, head, 1),
12546                    SelectionGoal::None,
12547                )
12548            });
12549        })
12550    }
12551
12552    pub fn select_to_end_of_paragraph(
12553        &mut self,
12554        _: &SelectToEndOfParagraph,
12555        window: &mut Window,
12556        cx: &mut Context<Self>,
12557    ) {
12558        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12559            cx.propagate();
12560            return;
12561        }
12562        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12563        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12564            s.move_heads_with(|map, head, _| {
12565                (
12566                    movement::end_of_paragraph(map, head, 1),
12567                    SelectionGoal::None,
12568                )
12569            });
12570        })
12571    }
12572
12573    pub fn move_to_start_of_excerpt(
12574        &mut self,
12575        _: &MoveToStartOfExcerpt,
12576        window: &mut Window,
12577        cx: &mut Context<Self>,
12578    ) {
12579        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12580            cx.propagate();
12581            return;
12582        }
12583        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12584        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12585            s.move_with(|map, selection| {
12586                selection.collapse_to(
12587                    movement::start_of_excerpt(
12588                        map,
12589                        selection.head(),
12590                        workspace::searchable::Direction::Prev,
12591                    ),
12592                    SelectionGoal::None,
12593                )
12594            });
12595        })
12596    }
12597
12598    pub fn move_to_start_of_next_excerpt(
12599        &mut self,
12600        _: &MoveToStartOfNextExcerpt,
12601        window: &mut Window,
12602        cx: &mut Context<Self>,
12603    ) {
12604        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12605            cx.propagate();
12606            return;
12607        }
12608
12609        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12610            s.move_with(|map, selection| {
12611                selection.collapse_to(
12612                    movement::start_of_excerpt(
12613                        map,
12614                        selection.head(),
12615                        workspace::searchable::Direction::Next,
12616                    ),
12617                    SelectionGoal::None,
12618                )
12619            });
12620        })
12621    }
12622
12623    pub fn move_to_end_of_excerpt(
12624        &mut self,
12625        _: &MoveToEndOfExcerpt,
12626        window: &mut Window,
12627        cx: &mut Context<Self>,
12628    ) {
12629        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12630            cx.propagate();
12631            return;
12632        }
12633        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12634        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12635            s.move_with(|map, selection| {
12636                selection.collapse_to(
12637                    movement::end_of_excerpt(
12638                        map,
12639                        selection.head(),
12640                        workspace::searchable::Direction::Next,
12641                    ),
12642                    SelectionGoal::None,
12643                )
12644            });
12645        })
12646    }
12647
12648    pub fn move_to_end_of_previous_excerpt(
12649        &mut self,
12650        _: &MoveToEndOfPreviousExcerpt,
12651        window: &mut Window,
12652        cx: &mut Context<Self>,
12653    ) {
12654        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12655            cx.propagate();
12656            return;
12657        }
12658        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12659        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12660            s.move_with(|map, selection| {
12661                selection.collapse_to(
12662                    movement::end_of_excerpt(
12663                        map,
12664                        selection.head(),
12665                        workspace::searchable::Direction::Prev,
12666                    ),
12667                    SelectionGoal::None,
12668                )
12669            });
12670        })
12671    }
12672
12673    pub fn select_to_start_of_excerpt(
12674        &mut self,
12675        _: &SelectToStartOfExcerpt,
12676        window: &mut Window,
12677        cx: &mut Context<Self>,
12678    ) {
12679        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12680            cx.propagate();
12681            return;
12682        }
12683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12684        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12685            s.move_heads_with(|map, head, _| {
12686                (
12687                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12688                    SelectionGoal::None,
12689                )
12690            });
12691        })
12692    }
12693
12694    pub fn select_to_start_of_next_excerpt(
12695        &mut self,
12696        _: &SelectToStartOfNextExcerpt,
12697        window: &mut Window,
12698        cx: &mut Context<Self>,
12699    ) {
12700        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12701            cx.propagate();
12702            return;
12703        }
12704        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12705        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12706            s.move_heads_with(|map, head, _| {
12707                (
12708                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12709                    SelectionGoal::None,
12710                )
12711            });
12712        })
12713    }
12714
12715    pub fn select_to_end_of_excerpt(
12716        &mut self,
12717        _: &SelectToEndOfExcerpt,
12718        window: &mut Window,
12719        cx: &mut Context<Self>,
12720    ) {
12721        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12722            cx.propagate();
12723            return;
12724        }
12725        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12726        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12727            s.move_heads_with(|map, head, _| {
12728                (
12729                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12730                    SelectionGoal::None,
12731                )
12732            });
12733        })
12734    }
12735
12736    pub fn select_to_end_of_previous_excerpt(
12737        &mut self,
12738        _: &SelectToEndOfPreviousExcerpt,
12739        window: &mut Window,
12740        cx: &mut Context<Self>,
12741    ) {
12742        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12743            cx.propagate();
12744            return;
12745        }
12746        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12747        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12748            s.move_heads_with(|map, head, _| {
12749                (
12750                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12751                    SelectionGoal::None,
12752                )
12753            });
12754        })
12755    }
12756
12757    pub fn move_to_beginning(
12758        &mut self,
12759        _: &MoveToBeginning,
12760        window: &mut Window,
12761        cx: &mut Context<Self>,
12762    ) {
12763        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12764            cx.propagate();
12765            return;
12766        }
12767        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12768        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12769            s.select_ranges(vec![0..0]);
12770        });
12771    }
12772
12773    pub fn select_to_beginning(
12774        &mut self,
12775        _: &SelectToBeginning,
12776        window: &mut Window,
12777        cx: &mut Context<Self>,
12778    ) {
12779        let mut selection = self.selections.last::<Point>(cx);
12780        selection.set_head(Point::zero(), SelectionGoal::None);
12781        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12782        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12783            s.select(vec![selection]);
12784        });
12785    }
12786
12787    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12788        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12789            cx.propagate();
12790            return;
12791        }
12792        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12793        let cursor = self.buffer.read(cx).read(cx).len();
12794        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12795            s.select_ranges(vec![cursor..cursor])
12796        });
12797    }
12798
12799    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12800        self.nav_history = nav_history;
12801    }
12802
12803    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12804        self.nav_history.as_ref()
12805    }
12806
12807    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12808        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12809    }
12810
12811    fn push_to_nav_history(
12812        &mut self,
12813        cursor_anchor: Anchor,
12814        new_position: Option<Point>,
12815        is_deactivate: bool,
12816        cx: &mut Context<Self>,
12817    ) {
12818        if let Some(nav_history) = self.nav_history.as_mut() {
12819            let buffer = self.buffer.read(cx).read(cx);
12820            let cursor_position = cursor_anchor.to_point(&buffer);
12821            let scroll_state = self.scroll_manager.anchor();
12822            let scroll_top_row = scroll_state.top_row(&buffer);
12823            drop(buffer);
12824
12825            if let Some(new_position) = new_position {
12826                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12827                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12828                    return;
12829                }
12830            }
12831
12832            nav_history.push(
12833                Some(NavigationData {
12834                    cursor_anchor,
12835                    cursor_position,
12836                    scroll_anchor: scroll_state,
12837                    scroll_top_row,
12838                }),
12839                cx,
12840            );
12841            cx.emit(EditorEvent::PushedToNavHistory {
12842                anchor: cursor_anchor,
12843                is_deactivate,
12844            })
12845        }
12846    }
12847
12848    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12849        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12850        let buffer = self.buffer.read(cx).snapshot(cx);
12851        let mut selection = self.selections.first::<usize>(cx);
12852        selection.set_head(buffer.len(), SelectionGoal::None);
12853        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12854            s.select(vec![selection]);
12855        });
12856    }
12857
12858    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12860        let end = self.buffer.read(cx).read(cx).len();
12861        self.change_selections(None, window, cx, |s| {
12862            s.select_ranges(vec![0..end]);
12863        });
12864    }
12865
12866    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12868        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12869        let mut selections = self.selections.all::<Point>(cx);
12870        let max_point = display_map.buffer_snapshot.max_point();
12871        for selection in &mut selections {
12872            let rows = selection.spanned_rows(true, &display_map);
12873            selection.start = Point::new(rows.start.0, 0);
12874            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12875            selection.reversed = false;
12876        }
12877        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12878            s.select(selections);
12879        });
12880    }
12881
12882    pub fn split_selection_into_lines(
12883        &mut self,
12884        _: &SplitSelectionIntoLines,
12885        window: &mut Window,
12886        cx: &mut Context<Self>,
12887    ) {
12888        let selections = self
12889            .selections
12890            .all::<Point>(cx)
12891            .into_iter()
12892            .map(|selection| selection.start..selection.end)
12893            .collect::<Vec<_>>();
12894        self.unfold_ranges(&selections, true, true, cx);
12895
12896        let mut new_selection_ranges = Vec::new();
12897        {
12898            let buffer = self.buffer.read(cx).read(cx);
12899            for selection in selections {
12900                for row in selection.start.row..selection.end.row {
12901                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12902                    new_selection_ranges.push(cursor..cursor);
12903                }
12904
12905                let is_multiline_selection = selection.start.row != selection.end.row;
12906                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12907                // so this action feels more ergonomic when paired with other selection operations
12908                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12909                if !should_skip_last {
12910                    new_selection_ranges.push(selection.end..selection.end);
12911                }
12912            }
12913        }
12914        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12915            s.select_ranges(new_selection_ranges);
12916        });
12917    }
12918
12919    pub fn add_selection_above(
12920        &mut self,
12921        _: &AddSelectionAbove,
12922        window: &mut Window,
12923        cx: &mut Context<Self>,
12924    ) {
12925        self.add_selection(true, window, cx);
12926    }
12927
12928    pub fn add_selection_below(
12929        &mut self,
12930        _: &AddSelectionBelow,
12931        window: &mut Window,
12932        cx: &mut Context<Self>,
12933    ) {
12934        self.add_selection(false, window, cx);
12935    }
12936
12937    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12938        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12939
12940        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12941        let all_selections = self.selections.all::<Point>(cx);
12942        let text_layout_details = self.text_layout_details(window);
12943
12944        let (mut columnar_selections, new_selections_to_columnarize) = {
12945            if let Some(state) = self.add_selections_state.as_ref() {
12946                let columnar_selection_ids: HashSet<_> = state
12947                    .groups
12948                    .iter()
12949                    .flat_map(|group| group.stack.iter())
12950                    .copied()
12951                    .collect();
12952
12953                all_selections
12954                    .into_iter()
12955                    .partition(|s| columnar_selection_ids.contains(&s.id))
12956            } else {
12957                (Vec::new(), all_selections)
12958            }
12959        };
12960
12961        let mut state = self
12962            .add_selections_state
12963            .take()
12964            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12965
12966        for selection in new_selections_to_columnarize {
12967            let range = selection.display_range(&display_map).sorted();
12968            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12969            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12970            let positions = start_x.min(end_x)..start_x.max(end_x);
12971            let mut stack = Vec::new();
12972            for row in range.start.row().0..=range.end.row().0 {
12973                if let Some(selection) = self.selections.build_columnar_selection(
12974                    &display_map,
12975                    DisplayRow(row),
12976                    &positions,
12977                    selection.reversed,
12978                    &text_layout_details,
12979                ) {
12980                    stack.push(selection.id);
12981                    columnar_selections.push(selection);
12982                }
12983            }
12984            if !stack.is_empty() {
12985                if above {
12986                    stack.reverse();
12987                }
12988                state.groups.push(AddSelectionsGroup { above, stack });
12989            }
12990        }
12991
12992        let mut final_selections = Vec::new();
12993        let end_row = if above {
12994            DisplayRow(0)
12995        } else {
12996            display_map.max_point().row()
12997        };
12998
12999        let mut last_added_item_per_group = HashMap::default();
13000        for group in state.groups.iter_mut() {
13001            if let Some(last_id) = group.stack.last() {
13002                last_added_item_per_group.insert(*last_id, group);
13003            }
13004        }
13005
13006        for selection in columnar_selections {
13007            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13008                if above == group.above {
13009                    let range = selection.display_range(&display_map).sorted();
13010                    debug_assert_eq!(range.start.row(), range.end.row());
13011                    let mut row = range.start.row();
13012                    let positions =
13013                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13014                            px(start)..px(end)
13015                        } else {
13016                            let start_x =
13017                                display_map.x_for_display_point(range.start, &text_layout_details);
13018                            let end_x =
13019                                display_map.x_for_display_point(range.end, &text_layout_details);
13020                            start_x.min(end_x)..start_x.max(end_x)
13021                        };
13022
13023                    let mut maybe_new_selection = None;
13024                    while row != end_row {
13025                        if above {
13026                            row.0 -= 1;
13027                        } else {
13028                            row.0 += 1;
13029                        }
13030                        if let Some(new_selection) = self.selections.build_columnar_selection(
13031                            &display_map,
13032                            row,
13033                            &positions,
13034                            selection.reversed,
13035                            &text_layout_details,
13036                        ) {
13037                            maybe_new_selection = Some(new_selection);
13038                            break;
13039                        }
13040                    }
13041
13042                    if let Some(new_selection) = maybe_new_selection {
13043                        group.stack.push(new_selection.id);
13044                        if above {
13045                            final_selections.push(new_selection);
13046                            final_selections.push(selection);
13047                        } else {
13048                            final_selections.push(selection);
13049                            final_selections.push(new_selection);
13050                        }
13051                    } else {
13052                        final_selections.push(selection);
13053                    }
13054                } else {
13055                    group.stack.pop();
13056                }
13057            } else {
13058                final_selections.push(selection);
13059            }
13060        }
13061
13062        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13063            s.select(final_selections);
13064        });
13065
13066        let final_selection_ids: HashSet<_> = self
13067            .selections
13068            .all::<Point>(cx)
13069            .iter()
13070            .map(|s| s.id)
13071            .collect();
13072        state.groups.retain_mut(|group| {
13073            // selections might get merged above so we remove invalid items from stacks
13074            group.stack.retain(|id| final_selection_ids.contains(id));
13075
13076            // single selection in stack can be treated as initial state
13077            group.stack.len() > 1
13078        });
13079
13080        if !state.groups.is_empty() {
13081            self.add_selections_state = Some(state);
13082        }
13083    }
13084
13085    fn select_match_ranges(
13086        &mut self,
13087        range: Range<usize>,
13088        reversed: bool,
13089        replace_newest: bool,
13090        auto_scroll: Option<Autoscroll>,
13091        window: &mut Window,
13092        cx: &mut Context<Editor>,
13093    ) {
13094        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13095        self.change_selections(auto_scroll, window, cx, |s| {
13096            if replace_newest {
13097                s.delete(s.newest_anchor().id);
13098            }
13099            if reversed {
13100                s.insert_range(range.end..range.start);
13101            } else {
13102                s.insert_range(range);
13103            }
13104        });
13105    }
13106
13107    pub fn select_next_match_internal(
13108        &mut self,
13109        display_map: &DisplaySnapshot,
13110        replace_newest: bool,
13111        autoscroll: Option<Autoscroll>,
13112        window: &mut Window,
13113        cx: &mut Context<Self>,
13114    ) -> Result<()> {
13115        let buffer = &display_map.buffer_snapshot;
13116        let mut selections = self.selections.all::<usize>(cx);
13117        if let Some(mut select_next_state) = self.select_next_state.take() {
13118            let query = &select_next_state.query;
13119            if !select_next_state.done {
13120                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13121                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13122                let mut next_selected_range = None;
13123
13124                let bytes_after_last_selection =
13125                    buffer.bytes_in_range(last_selection.end..buffer.len());
13126                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13127                let query_matches = query
13128                    .stream_find_iter(bytes_after_last_selection)
13129                    .map(|result| (last_selection.end, result))
13130                    .chain(
13131                        query
13132                            .stream_find_iter(bytes_before_first_selection)
13133                            .map(|result| (0, result)),
13134                    );
13135
13136                for (start_offset, query_match) in query_matches {
13137                    let query_match = query_match.unwrap(); // can only fail due to I/O
13138                    let offset_range =
13139                        start_offset + query_match.start()..start_offset + query_match.end();
13140                    let display_range = offset_range.start.to_display_point(display_map)
13141                        ..offset_range.end.to_display_point(display_map);
13142
13143                    if !select_next_state.wordwise
13144                        || (!movement::is_inside_word(display_map, display_range.start)
13145                            && !movement::is_inside_word(display_map, display_range.end))
13146                    {
13147                        // TODO: This is n^2, because we might check all the selections
13148                        if !selections
13149                            .iter()
13150                            .any(|selection| selection.range().overlaps(&offset_range))
13151                        {
13152                            next_selected_range = Some(offset_range);
13153                            break;
13154                        }
13155                    }
13156                }
13157
13158                if let Some(next_selected_range) = next_selected_range {
13159                    self.select_match_ranges(
13160                        next_selected_range,
13161                        last_selection.reversed,
13162                        replace_newest,
13163                        autoscroll,
13164                        window,
13165                        cx,
13166                    );
13167                } else {
13168                    select_next_state.done = true;
13169                }
13170            }
13171
13172            self.select_next_state = Some(select_next_state);
13173        } else {
13174            let mut only_carets = true;
13175            let mut same_text_selected = true;
13176            let mut selected_text = None;
13177
13178            let mut selections_iter = selections.iter().peekable();
13179            while let Some(selection) = selections_iter.next() {
13180                if selection.start != selection.end {
13181                    only_carets = false;
13182                }
13183
13184                if same_text_selected {
13185                    if selected_text.is_none() {
13186                        selected_text =
13187                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13188                    }
13189
13190                    if let Some(next_selection) = selections_iter.peek() {
13191                        if next_selection.range().len() == selection.range().len() {
13192                            let next_selected_text = buffer
13193                                .text_for_range(next_selection.range())
13194                                .collect::<String>();
13195                            if Some(next_selected_text) != selected_text {
13196                                same_text_selected = false;
13197                                selected_text = None;
13198                            }
13199                        } else {
13200                            same_text_selected = false;
13201                            selected_text = None;
13202                        }
13203                    }
13204                }
13205            }
13206
13207            if only_carets {
13208                for selection in &mut selections {
13209                    let word_range = movement::surrounding_word(
13210                        display_map,
13211                        selection.start.to_display_point(display_map),
13212                    );
13213                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13214                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13215                    selection.goal = SelectionGoal::None;
13216                    selection.reversed = false;
13217                    self.select_match_ranges(
13218                        selection.start..selection.end,
13219                        selection.reversed,
13220                        replace_newest,
13221                        autoscroll,
13222                        window,
13223                        cx,
13224                    );
13225                }
13226
13227                if selections.len() == 1 {
13228                    let selection = selections
13229                        .last()
13230                        .expect("ensured that there's only one selection");
13231                    let query = buffer
13232                        .text_for_range(selection.start..selection.end)
13233                        .collect::<String>();
13234                    let is_empty = query.is_empty();
13235                    let select_state = SelectNextState {
13236                        query: AhoCorasick::new(&[query])?,
13237                        wordwise: true,
13238                        done: is_empty,
13239                    };
13240                    self.select_next_state = Some(select_state);
13241                } else {
13242                    self.select_next_state = None;
13243                }
13244            } else if let Some(selected_text) = selected_text {
13245                self.select_next_state = Some(SelectNextState {
13246                    query: AhoCorasick::new(&[selected_text])?,
13247                    wordwise: false,
13248                    done: false,
13249                });
13250                self.select_next_match_internal(
13251                    display_map,
13252                    replace_newest,
13253                    autoscroll,
13254                    window,
13255                    cx,
13256                )?;
13257            }
13258        }
13259        Ok(())
13260    }
13261
13262    pub fn select_all_matches(
13263        &mut self,
13264        _action: &SelectAllMatches,
13265        window: &mut Window,
13266        cx: &mut Context<Self>,
13267    ) -> Result<()> {
13268        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13269
13270        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13271
13272        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13273        let Some(select_next_state) = self.select_next_state.as_mut() else {
13274            return Ok(());
13275        };
13276        if select_next_state.done {
13277            return Ok(());
13278        }
13279
13280        let mut new_selections = Vec::new();
13281
13282        let reversed = self.selections.oldest::<usize>(cx).reversed;
13283        let buffer = &display_map.buffer_snapshot;
13284        let query_matches = select_next_state
13285            .query
13286            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13287
13288        for query_match in query_matches.into_iter() {
13289            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13290            let offset_range = if reversed {
13291                query_match.end()..query_match.start()
13292            } else {
13293                query_match.start()..query_match.end()
13294            };
13295            let display_range = offset_range.start.to_display_point(&display_map)
13296                ..offset_range.end.to_display_point(&display_map);
13297
13298            if !select_next_state.wordwise
13299                || (!movement::is_inside_word(&display_map, display_range.start)
13300                    && !movement::is_inside_word(&display_map, display_range.end))
13301            {
13302                new_selections.push(offset_range.start..offset_range.end);
13303            }
13304        }
13305
13306        select_next_state.done = true;
13307        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13308        self.change_selections(None, window, cx, |selections| {
13309            selections.select_ranges(new_selections)
13310        });
13311
13312        Ok(())
13313    }
13314
13315    pub fn select_next(
13316        &mut self,
13317        action: &SelectNext,
13318        window: &mut Window,
13319        cx: &mut Context<Self>,
13320    ) -> Result<()> {
13321        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13322        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13323        self.select_next_match_internal(
13324            &display_map,
13325            action.replace_newest,
13326            Some(Autoscroll::newest()),
13327            window,
13328            cx,
13329        )?;
13330        Ok(())
13331    }
13332
13333    pub fn select_previous(
13334        &mut self,
13335        action: &SelectPrevious,
13336        window: &mut Window,
13337        cx: &mut Context<Self>,
13338    ) -> Result<()> {
13339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13340        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13341        let buffer = &display_map.buffer_snapshot;
13342        let mut selections = self.selections.all::<usize>(cx);
13343        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13344            let query = &select_prev_state.query;
13345            if !select_prev_state.done {
13346                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13347                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13348                let mut next_selected_range = None;
13349                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13350                let bytes_before_last_selection =
13351                    buffer.reversed_bytes_in_range(0..last_selection.start);
13352                let bytes_after_first_selection =
13353                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13354                let query_matches = query
13355                    .stream_find_iter(bytes_before_last_selection)
13356                    .map(|result| (last_selection.start, result))
13357                    .chain(
13358                        query
13359                            .stream_find_iter(bytes_after_first_selection)
13360                            .map(|result| (buffer.len(), result)),
13361                    );
13362                for (end_offset, query_match) in query_matches {
13363                    let query_match = query_match.unwrap(); // can only fail due to I/O
13364                    let offset_range =
13365                        end_offset - query_match.end()..end_offset - query_match.start();
13366                    let display_range = offset_range.start.to_display_point(&display_map)
13367                        ..offset_range.end.to_display_point(&display_map);
13368
13369                    if !select_prev_state.wordwise
13370                        || (!movement::is_inside_word(&display_map, display_range.start)
13371                            && !movement::is_inside_word(&display_map, display_range.end))
13372                    {
13373                        next_selected_range = Some(offset_range);
13374                        break;
13375                    }
13376                }
13377
13378                if let Some(next_selected_range) = next_selected_range {
13379                    self.select_match_ranges(
13380                        next_selected_range,
13381                        last_selection.reversed,
13382                        action.replace_newest,
13383                        Some(Autoscroll::newest()),
13384                        window,
13385                        cx,
13386                    );
13387                } else {
13388                    select_prev_state.done = true;
13389                }
13390            }
13391
13392            self.select_prev_state = Some(select_prev_state);
13393        } else {
13394            let mut only_carets = true;
13395            let mut same_text_selected = true;
13396            let mut selected_text = None;
13397
13398            let mut selections_iter = selections.iter().peekable();
13399            while let Some(selection) = selections_iter.next() {
13400                if selection.start != selection.end {
13401                    only_carets = false;
13402                }
13403
13404                if same_text_selected {
13405                    if selected_text.is_none() {
13406                        selected_text =
13407                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13408                    }
13409
13410                    if let Some(next_selection) = selections_iter.peek() {
13411                        if next_selection.range().len() == selection.range().len() {
13412                            let next_selected_text = buffer
13413                                .text_for_range(next_selection.range())
13414                                .collect::<String>();
13415                            if Some(next_selected_text) != selected_text {
13416                                same_text_selected = false;
13417                                selected_text = None;
13418                            }
13419                        } else {
13420                            same_text_selected = false;
13421                            selected_text = None;
13422                        }
13423                    }
13424                }
13425            }
13426
13427            if only_carets {
13428                for selection in &mut selections {
13429                    let word_range = movement::surrounding_word(
13430                        &display_map,
13431                        selection.start.to_display_point(&display_map),
13432                    );
13433                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13434                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13435                    selection.goal = SelectionGoal::None;
13436                    selection.reversed = false;
13437                    self.select_match_ranges(
13438                        selection.start..selection.end,
13439                        selection.reversed,
13440                        action.replace_newest,
13441                        Some(Autoscroll::newest()),
13442                        window,
13443                        cx,
13444                    );
13445                }
13446                if selections.len() == 1 {
13447                    let selection = selections
13448                        .last()
13449                        .expect("ensured that there's only one selection");
13450                    let query = buffer
13451                        .text_for_range(selection.start..selection.end)
13452                        .collect::<String>();
13453                    let is_empty = query.is_empty();
13454                    let select_state = SelectNextState {
13455                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13456                        wordwise: true,
13457                        done: is_empty,
13458                    };
13459                    self.select_prev_state = Some(select_state);
13460                } else {
13461                    self.select_prev_state = None;
13462                }
13463            } else if let Some(selected_text) = selected_text {
13464                self.select_prev_state = Some(SelectNextState {
13465                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13466                    wordwise: false,
13467                    done: false,
13468                });
13469                self.select_previous(action, window, cx)?;
13470            }
13471        }
13472        Ok(())
13473    }
13474
13475    pub fn find_next_match(
13476        &mut self,
13477        _: &FindNextMatch,
13478        window: &mut Window,
13479        cx: &mut Context<Self>,
13480    ) -> Result<()> {
13481        let selections = self.selections.disjoint_anchors();
13482        match selections.first() {
13483            Some(first) if selections.len() >= 2 => {
13484                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13485                    s.select_ranges([first.range()]);
13486                });
13487            }
13488            _ => self.select_next(
13489                &SelectNext {
13490                    replace_newest: true,
13491                },
13492                window,
13493                cx,
13494            )?,
13495        }
13496        Ok(())
13497    }
13498
13499    pub fn find_previous_match(
13500        &mut self,
13501        _: &FindPreviousMatch,
13502        window: &mut Window,
13503        cx: &mut Context<Self>,
13504    ) -> Result<()> {
13505        let selections = self.selections.disjoint_anchors();
13506        match selections.last() {
13507            Some(last) if selections.len() >= 2 => {
13508                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13509                    s.select_ranges([last.range()]);
13510                });
13511            }
13512            _ => self.select_previous(
13513                &SelectPrevious {
13514                    replace_newest: true,
13515                },
13516                window,
13517                cx,
13518            )?,
13519        }
13520        Ok(())
13521    }
13522
13523    pub fn toggle_comments(
13524        &mut self,
13525        action: &ToggleComments,
13526        window: &mut Window,
13527        cx: &mut Context<Self>,
13528    ) {
13529        if self.read_only(cx) {
13530            return;
13531        }
13532        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13533        let text_layout_details = &self.text_layout_details(window);
13534        self.transact(window, cx, |this, window, cx| {
13535            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13536            let mut edits = Vec::new();
13537            let mut selection_edit_ranges = Vec::new();
13538            let mut last_toggled_row = None;
13539            let snapshot = this.buffer.read(cx).read(cx);
13540            let empty_str: Arc<str> = Arc::default();
13541            let mut suffixes_inserted = Vec::new();
13542            let ignore_indent = action.ignore_indent;
13543
13544            fn comment_prefix_range(
13545                snapshot: &MultiBufferSnapshot,
13546                row: MultiBufferRow,
13547                comment_prefix: &str,
13548                comment_prefix_whitespace: &str,
13549                ignore_indent: bool,
13550            ) -> Range<Point> {
13551                let indent_size = if ignore_indent {
13552                    0
13553                } else {
13554                    snapshot.indent_size_for_line(row).len
13555                };
13556
13557                let start = Point::new(row.0, indent_size);
13558
13559                let mut line_bytes = snapshot
13560                    .bytes_in_range(start..snapshot.max_point())
13561                    .flatten()
13562                    .copied();
13563
13564                // If this line currently begins with the line comment prefix, then record
13565                // the range containing the prefix.
13566                if line_bytes
13567                    .by_ref()
13568                    .take(comment_prefix.len())
13569                    .eq(comment_prefix.bytes())
13570                {
13571                    // Include any whitespace that matches the comment prefix.
13572                    let matching_whitespace_len = line_bytes
13573                        .zip(comment_prefix_whitespace.bytes())
13574                        .take_while(|(a, b)| a == b)
13575                        .count() as u32;
13576                    let end = Point::new(
13577                        start.row,
13578                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13579                    );
13580                    start..end
13581                } else {
13582                    start..start
13583                }
13584            }
13585
13586            fn comment_suffix_range(
13587                snapshot: &MultiBufferSnapshot,
13588                row: MultiBufferRow,
13589                comment_suffix: &str,
13590                comment_suffix_has_leading_space: bool,
13591            ) -> Range<Point> {
13592                let end = Point::new(row.0, snapshot.line_len(row));
13593                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13594
13595                let mut line_end_bytes = snapshot
13596                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13597                    .flatten()
13598                    .copied();
13599
13600                let leading_space_len = if suffix_start_column > 0
13601                    && line_end_bytes.next() == Some(b' ')
13602                    && comment_suffix_has_leading_space
13603                {
13604                    1
13605                } else {
13606                    0
13607                };
13608
13609                // If this line currently begins with the line comment prefix, then record
13610                // the range containing the prefix.
13611                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13612                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13613                    start..end
13614                } else {
13615                    end..end
13616                }
13617            }
13618
13619            // TODO: Handle selections that cross excerpts
13620            for selection in &mut selections {
13621                let start_column = snapshot
13622                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13623                    .len;
13624                let language = if let Some(language) =
13625                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13626                {
13627                    language
13628                } else {
13629                    continue;
13630                };
13631
13632                selection_edit_ranges.clear();
13633
13634                // If multiple selections contain a given row, avoid processing that
13635                // row more than once.
13636                let mut start_row = MultiBufferRow(selection.start.row);
13637                if last_toggled_row == Some(start_row) {
13638                    start_row = start_row.next_row();
13639                }
13640                let end_row =
13641                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13642                        MultiBufferRow(selection.end.row - 1)
13643                    } else {
13644                        MultiBufferRow(selection.end.row)
13645                    };
13646                last_toggled_row = Some(end_row);
13647
13648                if start_row > end_row {
13649                    continue;
13650                }
13651
13652                // If the language has line comments, toggle those.
13653                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13654
13655                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13656                if ignore_indent {
13657                    full_comment_prefixes = full_comment_prefixes
13658                        .into_iter()
13659                        .map(|s| Arc::from(s.trim_end()))
13660                        .collect();
13661                }
13662
13663                if !full_comment_prefixes.is_empty() {
13664                    let first_prefix = full_comment_prefixes
13665                        .first()
13666                        .expect("prefixes is non-empty");
13667                    let prefix_trimmed_lengths = full_comment_prefixes
13668                        .iter()
13669                        .map(|p| p.trim_end_matches(' ').len())
13670                        .collect::<SmallVec<[usize; 4]>>();
13671
13672                    let mut all_selection_lines_are_comments = true;
13673
13674                    for row in start_row.0..=end_row.0 {
13675                        let row = MultiBufferRow(row);
13676                        if start_row < end_row && snapshot.is_line_blank(row) {
13677                            continue;
13678                        }
13679
13680                        let prefix_range = full_comment_prefixes
13681                            .iter()
13682                            .zip(prefix_trimmed_lengths.iter().copied())
13683                            .map(|(prefix, trimmed_prefix_len)| {
13684                                comment_prefix_range(
13685                                    snapshot.deref(),
13686                                    row,
13687                                    &prefix[..trimmed_prefix_len],
13688                                    &prefix[trimmed_prefix_len..],
13689                                    ignore_indent,
13690                                )
13691                            })
13692                            .max_by_key(|range| range.end.column - range.start.column)
13693                            .expect("prefixes is non-empty");
13694
13695                        if prefix_range.is_empty() {
13696                            all_selection_lines_are_comments = false;
13697                        }
13698
13699                        selection_edit_ranges.push(prefix_range);
13700                    }
13701
13702                    if all_selection_lines_are_comments {
13703                        edits.extend(
13704                            selection_edit_ranges
13705                                .iter()
13706                                .cloned()
13707                                .map(|range| (range, empty_str.clone())),
13708                        );
13709                    } else {
13710                        let min_column = selection_edit_ranges
13711                            .iter()
13712                            .map(|range| range.start.column)
13713                            .min()
13714                            .unwrap_or(0);
13715                        edits.extend(selection_edit_ranges.iter().map(|range| {
13716                            let position = Point::new(range.start.row, min_column);
13717                            (position..position, first_prefix.clone())
13718                        }));
13719                    }
13720                } else if let Some((full_comment_prefix, comment_suffix)) =
13721                    language.block_comment_delimiters()
13722                {
13723                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13724                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13725                    let prefix_range = comment_prefix_range(
13726                        snapshot.deref(),
13727                        start_row,
13728                        comment_prefix,
13729                        comment_prefix_whitespace,
13730                        ignore_indent,
13731                    );
13732                    let suffix_range = comment_suffix_range(
13733                        snapshot.deref(),
13734                        end_row,
13735                        comment_suffix.trim_start_matches(' '),
13736                        comment_suffix.starts_with(' '),
13737                    );
13738
13739                    if prefix_range.is_empty() || suffix_range.is_empty() {
13740                        edits.push((
13741                            prefix_range.start..prefix_range.start,
13742                            full_comment_prefix.clone(),
13743                        ));
13744                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13745                        suffixes_inserted.push((end_row, comment_suffix.len()));
13746                    } else {
13747                        edits.push((prefix_range, empty_str.clone()));
13748                        edits.push((suffix_range, empty_str.clone()));
13749                    }
13750                } else {
13751                    continue;
13752                }
13753            }
13754
13755            drop(snapshot);
13756            this.buffer.update(cx, |buffer, cx| {
13757                buffer.edit(edits, None, cx);
13758            });
13759
13760            // Adjust selections so that they end before any comment suffixes that
13761            // were inserted.
13762            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13763            let mut selections = this.selections.all::<Point>(cx);
13764            let snapshot = this.buffer.read(cx).read(cx);
13765            for selection in &mut selections {
13766                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13767                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13768                        Ordering::Less => {
13769                            suffixes_inserted.next();
13770                            continue;
13771                        }
13772                        Ordering::Greater => break,
13773                        Ordering::Equal => {
13774                            if selection.end.column == snapshot.line_len(row) {
13775                                if selection.is_empty() {
13776                                    selection.start.column -= suffix_len as u32;
13777                                }
13778                                selection.end.column -= suffix_len as u32;
13779                            }
13780                            break;
13781                        }
13782                    }
13783                }
13784            }
13785
13786            drop(snapshot);
13787            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13788                s.select(selections)
13789            });
13790
13791            let selections = this.selections.all::<Point>(cx);
13792            let selections_on_single_row = selections.windows(2).all(|selections| {
13793                selections[0].start.row == selections[1].start.row
13794                    && selections[0].end.row == selections[1].end.row
13795                    && selections[0].start.row == selections[0].end.row
13796            });
13797            let selections_selecting = selections
13798                .iter()
13799                .any(|selection| selection.start != selection.end);
13800            let advance_downwards = action.advance_downwards
13801                && selections_on_single_row
13802                && !selections_selecting
13803                && !matches!(this.mode, EditorMode::SingleLine { .. });
13804
13805            if advance_downwards {
13806                let snapshot = this.buffer.read(cx).snapshot(cx);
13807
13808                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13809                    s.move_cursors_with(|display_snapshot, display_point, _| {
13810                        let mut point = display_point.to_point(display_snapshot);
13811                        point.row += 1;
13812                        point = snapshot.clip_point(point, Bias::Left);
13813                        let display_point = point.to_display_point(display_snapshot);
13814                        let goal = SelectionGoal::HorizontalPosition(
13815                            display_snapshot
13816                                .x_for_display_point(display_point, text_layout_details)
13817                                .into(),
13818                        );
13819                        (display_point, goal)
13820                    })
13821                });
13822            }
13823        });
13824    }
13825
13826    pub fn select_enclosing_symbol(
13827        &mut self,
13828        _: &SelectEnclosingSymbol,
13829        window: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13833
13834        let buffer = self.buffer.read(cx).snapshot(cx);
13835        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13836
13837        fn update_selection(
13838            selection: &Selection<usize>,
13839            buffer_snap: &MultiBufferSnapshot,
13840        ) -> Option<Selection<usize>> {
13841            let cursor = selection.head();
13842            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13843            for symbol in symbols.iter().rev() {
13844                let start = symbol.range.start.to_offset(buffer_snap);
13845                let end = symbol.range.end.to_offset(buffer_snap);
13846                let new_range = start..end;
13847                if start < selection.start || end > selection.end {
13848                    return Some(Selection {
13849                        id: selection.id,
13850                        start: new_range.start,
13851                        end: new_range.end,
13852                        goal: SelectionGoal::None,
13853                        reversed: selection.reversed,
13854                    });
13855                }
13856            }
13857            None
13858        }
13859
13860        let mut selected_larger_symbol = false;
13861        let new_selections = old_selections
13862            .iter()
13863            .map(|selection| match update_selection(selection, &buffer) {
13864                Some(new_selection) => {
13865                    if new_selection.range() != selection.range() {
13866                        selected_larger_symbol = true;
13867                    }
13868                    new_selection
13869                }
13870                None => selection.clone(),
13871            })
13872            .collect::<Vec<_>>();
13873
13874        if selected_larger_symbol {
13875            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13876                s.select(new_selections);
13877            });
13878        }
13879    }
13880
13881    pub fn select_larger_syntax_node(
13882        &mut self,
13883        _: &SelectLargerSyntaxNode,
13884        window: &mut Window,
13885        cx: &mut Context<Self>,
13886    ) {
13887        let Some(visible_row_count) = self.visible_row_count() else {
13888            return;
13889        };
13890        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13891        if old_selections.is_empty() {
13892            return;
13893        }
13894
13895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13896
13897        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13898        let buffer = self.buffer.read(cx).snapshot(cx);
13899
13900        let mut selected_larger_node = false;
13901        let mut new_selections = old_selections
13902            .iter()
13903            .map(|selection| {
13904                let old_range = selection.start..selection.end;
13905
13906                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13907                    // manually select word at selection
13908                    if ["string_content", "inline"].contains(&node.kind()) {
13909                        let word_range = {
13910                            let display_point = buffer
13911                                .offset_to_point(old_range.start)
13912                                .to_display_point(&display_map);
13913                            let Range { start, end } =
13914                                movement::surrounding_word(&display_map, display_point);
13915                            start.to_point(&display_map).to_offset(&buffer)
13916                                ..end.to_point(&display_map).to_offset(&buffer)
13917                        };
13918                        // ignore if word is already selected
13919                        if !word_range.is_empty() && old_range != word_range {
13920                            let last_word_range = {
13921                                let display_point = buffer
13922                                    .offset_to_point(old_range.end)
13923                                    .to_display_point(&display_map);
13924                                let Range { start, end } =
13925                                    movement::surrounding_word(&display_map, display_point);
13926                                start.to_point(&display_map).to_offset(&buffer)
13927                                    ..end.to_point(&display_map).to_offset(&buffer)
13928                            };
13929                            // only select word if start and end point belongs to same word
13930                            if word_range == last_word_range {
13931                                selected_larger_node = true;
13932                                return Selection {
13933                                    id: selection.id,
13934                                    start: word_range.start,
13935                                    end: word_range.end,
13936                                    goal: SelectionGoal::None,
13937                                    reversed: selection.reversed,
13938                                };
13939                            }
13940                        }
13941                    }
13942                }
13943
13944                let mut new_range = old_range.clone();
13945                while let Some((_node, containing_range)) =
13946                    buffer.syntax_ancestor(new_range.clone())
13947                {
13948                    new_range = match containing_range {
13949                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13950                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13951                    };
13952                    if !display_map.intersects_fold(new_range.start)
13953                        && !display_map.intersects_fold(new_range.end)
13954                    {
13955                        break;
13956                    }
13957                }
13958
13959                selected_larger_node |= new_range != old_range;
13960                Selection {
13961                    id: selection.id,
13962                    start: new_range.start,
13963                    end: new_range.end,
13964                    goal: SelectionGoal::None,
13965                    reversed: selection.reversed,
13966                }
13967            })
13968            .collect::<Vec<_>>();
13969
13970        if !selected_larger_node {
13971            return; // don't put this call in the history
13972        }
13973
13974        // scroll based on transformation done to the last selection created by the user
13975        let (last_old, last_new) = old_selections
13976            .last()
13977            .zip(new_selections.last().cloned())
13978            .expect("old_selections isn't empty");
13979
13980        // revert selection
13981        let is_selection_reversed = {
13982            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13983            new_selections.last_mut().expect("checked above").reversed =
13984                should_newest_selection_be_reversed;
13985            should_newest_selection_be_reversed
13986        };
13987
13988        if selected_larger_node {
13989            self.select_syntax_node_history.disable_clearing = true;
13990            self.change_selections(None, window, cx, |s| {
13991                s.select(new_selections.clone());
13992            });
13993            self.select_syntax_node_history.disable_clearing = false;
13994        }
13995
13996        let start_row = last_new.start.to_display_point(&display_map).row().0;
13997        let end_row = last_new.end.to_display_point(&display_map).row().0;
13998        let selection_height = end_row - start_row + 1;
13999        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14000
14001        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14002        let scroll_behavior = if fits_on_the_screen {
14003            self.request_autoscroll(Autoscroll::fit(), cx);
14004            SelectSyntaxNodeScrollBehavior::FitSelection
14005        } else if is_selection_reversed {
14006            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14007            SelectSyntaxNodeScrollBehavior::CursorTop
14008        } else {
14009            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14010            SelectSyntaxNodeScrollBehavior::CursorBottom
14011        };
14012
14013        self.select_syntax_node_history.push((
14014            old_selections,
14015            scroll_behavior,
14016            is_selection_reversed,
14017        ));
14018    }
14019
14020    pub fn select_smaller_syntax_node(
14021        &mut self,
14022        _: &SelectSmallerSyntaxNode,
14023        window: &mut Window,
14024        cx: &mut Context<Self>,
14025    ) {
14026        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14027
14028        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14029            self.select_syntax_node_history.pop()
14030        {
14031            if let Some(selection) = selections.last_mut() {
14032                selection.reversed = is_selection_reversed;
14033            }
14034
14035            self.select_syntax_node_history.disable_clearing = true;
14036            self.change_selections(None, window, cx, |s| {
14037                s.select(selections.to_vec());
14038            });
14039            self.select_syntax_node_history.disable_clearing = false;
14040
14041            match scroll_behavior {
14042                SelectSyntaxNodeScrollBehavior::CursorTop => {
14043                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14044                }
14045                SelectSyntaxNodeScrollBehavior::FitSelection => {
14046                    self.request_autoscroll(Autoscroll::fit(), cx);
14047                }
14048                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14049                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14050                }
14051            }
14052        }
14053    }
14054
14055    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14056        if !EditorSettings::get_global(cx).gutter.runnables {
14057            self.clear_tasks();
14058            return Task::ready(());
14059        }
14060        let project = self.project.as_ref().map(Entity::downgrade);
14061        let task_sources = self.lsp_task_sources(cx);
14062        let multi_buffer = self.buffer.downgrade();
14063        cx.spawn_in(window, async move |editor, cx| {
14064            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14065            let Some(project) = project.and_then(|p| p.upgrade()) else {
14066                return;
14067            };
14068            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14069                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14070            }) else {
14071                return;
14072            };
14073
14074            let hide_runnables = project
14075                .update(cx, |project, cx| {
14076                    // Do not display any test indicators in non-dev server remote projects.
14077                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14078                })
14079                .unwrap_or(true);
14080            if hide_runnables {
14081                return;
14082            }
14083            let new_rows =
14084                cx.background_spawn({
14085                    let snapshot = display_snapshot.clone();
14086                    async move {
14087                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14088                    }
14089                })
14090                    .await;
14091            let Ok(lsp_tasks) =
14092                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14093            else {
14094                return;
14095            };
14096            let lsp_tasks = lsp_tasks.await;
14097
14098            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14099                lsp_tasks
14100                    .into_iter()
14101                    .flat_map(|(kind, tasks)| {
14102                        tasks.into_iter().filter_map(move |(location, task)| {
14103                            Some((kind.clone(), location?, task))
14104                        })
14105                    })
14106                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14107                        let buffer = location.target.buffer;
14108                        let buffer_snapshot = buffer.read(cx).snapshot();
14109                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14110                            |(excerpt_id, snapshot, _)| {
14111                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14112                                    display_snapshot
14113                                        .buffer_snapshot
14114                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14115                                } else {
14116                                    None
14117                                }
14118                            },
14119                        );
14120                        if let Some(offset) = offset {
14121                            let task_buffer_range =
14122                                location.target.range.to_point(&buffer_snapshot);
14123                            let context_buffer_range =
14124                                task_buffer_range.to_offset(&buffer_snapshot);
14125                            let context_range = BufferOffset(context_buffer_range.start)
14126                                ..BufferOffset(context_buffer_range.end);
14127
14128                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14129                                .or_insert_with(|| RunnableTasks {
14130                                    templates: Vec::new(),
14131                                    offset,
14132                                    column: task_buffer_range.start.column,
14133                                    extra_variables: HashMap::default(),
14134                                    context_range,
14135                                })
14136                                .templates
14137                                .push((kind, task.original_task().clone()));
14138                        }
14139
14140                        acc
14141                    })
14142            }) else {
14143                return;
14144            };
14145
14146            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14147                buffer.language_settings(cx).tasks.prefer_lsp
14148            }) else {
14149                return;
14150            };
14151
14152            let rows = Self::runnable_rows(
14153                project,
14154                display_snapshot,
14155                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14156                new_rows,
14157                cx.clone(),
14158            )
14159            .await;
14160            editor
14161                .update(cx, |editor, _| {
14162                    editor.clear_tasks();
14163                    for (key, mut value) in rows {
14164                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14165                            value.templates.extend(lsp_tasks.templates);
14166                        }
14167
14168                        editor.insert_tasks(key, value);
14169                    }
14170                    for (key, value) in lsp_tasks_by_rows {
14171                        editor.insert_tasks(key, value);
14172                    }
14173                })
14174                .ok();
14175        })
14176    }
14177    fn fetch_runnable_ranges(
14178        snapshot: &DisplaySnapshot,
14179        range: Range<Anchor>,
14180    ) -> Vec<language::RunnableRange> {
14181        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14182    }
14183
14184    fn runnable_rows(
14185        project: Entity<Project>,
14186        snapshot: DisplaySnapshot,
14187        prefer_lsp: bool,
14188        runnable_ranges: Vec<RunnableRange>,
14189        cx: AsyncWindowContext,
14190    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14191        cx.spawn(async move |cx| {
14192            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14193            for mut runnable in runnable_ranges {
14194                let Some(tasks) = cx
14195                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14196                    .ok()
14197                else {
14198                    continue;
14199                };
14200                let mut tasks = tasks.await;
14201
14202                if prefer_lsp {
14203                    tasks.retain(|(task_kind, _)| {
14204                        !matches!(task_kind, TaskSourceKind::Language { .. })
14205                    });
14206                }
14207                if tasks.is_empty() {
14208                    continue;
14209                }
14210
14211                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14212                let Some(row) = snapshot
14213                    .buffer_snapshot
14214                    .buffer_line_for_row(MultiBufferRow(point.row))
14215                    .map(|(_, range)| range.start.row)
14216                else {
14217                    continue;
14218                };
14219
14220                let context_range =
14221                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14222                runnable_rows.push((
14223                    (runnable.buffer_id, row),
14224                    RunnableTasks {
14225                        templates: tasks,
14226                        offset: snapshot
14227                            .buffer_snapshot
14228                            .anchor_before(runnable.run_range.start),
14229                        context_range,
14230                        column: point.column,
14231                        extra_variables: runnable.extra_captures,
14232                    },
14233                ));
14234            }
14235            runnable_rows
14236        })
14237    }
14238
14239    fn templates_with_tags(
14240        project: &Entity<Project>,
14241        runnable: &mut Runnable,
14242        cx: &mut App,
14243    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14244        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14245            let (worktree_id, file) = project
14246                .buffer_for_id(runnable.buffer, cx)
14247                .and_then(|buffer| buffer.read(cx).file())
14248                .map(|file| (file.worktree_id(cx), file.clone()))
14249                .unzip();
14250
14251            (
14252                project.task_store().read(cx).task_inventory().cloned(),
14253                worktree_id,
14254                file,
14255            )
14256        });
14257
14258        let tags = mem::take(&mut runnable.tags);
14259        let language = runnable.language.clone();
14260        cx.spawn(async move |cx| {
14261            let mut templates_with_tags = Vec::new();
14262            if let Some(inventory) = inventory {
14263                for RunnableTag(tag) in tags {
14264                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14265                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14266                    }) else {
14267                        return templates_with_tags;
14268                    };
14269                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14270                        move |(_, template)| {
14271                            template.tags.iter().any(|source_tag| source_tag == &tag)
14272                        },
14273                    ));
14274                }
14275            }
14276            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14277
14278            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14279                // Strongest source wins; if we have worktree tag binding, prefer that to
14280                // global and language bindings;
14281                // if we have a global binding, prefer that to language binding.
14282                let first_mismatch = templates_with_tags
14283                    .iter()
14284                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14285                if let Some(index) = first_mismatch {
14286                    templates_with_tags.truncate(index);
14287                }
14288            }
14289
14290            templates_with_tags
14291        })
14292    }
14293
14294    pub fn move_to_enclosing_bracket(
14295        &mut self,
14296        _: &MoveToEnclosingBracket,
14297        window: &mut Window,
14298        cx: &mut Context<Self>,
14299    ) {
14300        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14301        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14302            s.move_offsets_with(|snapshot, selection| {
14303                let Some(enclosing_bracket_ranges) =
14304                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14305                else {
14306                    return;
14307                };
14308
14309                let mut best_length = usize::MAX;
14310                let mut best_inside = false;
14311                let mut best_in_bracket_range = false;
14312                let mut best_destination = None;
14313                for (open, close) in enclosing_bracket_ranges {
14314                    let close = close.to_inclusive();
14315                    let length = close.end() - open.start;
14316                    let inside = selection.start >= open.end && selection.end <= *close.start();
14317                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14318                        || close.contains(&selection.head());
14319
14320                    // If best is next to a bracket and current isn't, skip
14321                    if !in_bracket_range && best_in_bracket_range {
14322                        continue;
14323                    }
14324
14325                    // Prefer smaller lengths unless best is inside and current isn't
14326                    if length > best_length && (best_inside || !inside) {
14327                        continue;
14328                    }
14329
14330                    best_length = length;
14331                    best_inside = inside;
14332                    best_in_bracket_range = in_bracket_range;
14333                    best_destination = Some(
14334                        if close.contains(&selection.start) && close.contains(&selection.end) {
14335                            if inside { open.end } else { open.start }
14336                        } else if inside {
14337                            *close.start()
14338                        } else {
14339                            *close.end()
14340                        },
14341                    );
14342                }
14343
14344                if let Some(destination) = best_destination {
14345                    selection.collapse_to(destination, SelectionGoal::None);
14346                }
14347            })
14348        });
14349    }
14350
14351    pub fn undo_selection(
14352        &mut self,
14353        _: &UndoSelection,
14354        window: &mut Window,
14355        cx: &mut Context<Self>,
14356    ) {
14357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14358        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14359            self.selection_history.mode = SelectionHistoryMode::Undoing;
14360            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14361                this.end_selection(window, cx);
14362                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14363                    s.select_anchors(entry.selections.to_vec())
14364                });
14365            });
14366            self.selection_history.mode = SelectionHistoryMode::Normal;
14367
14368            self.select_next_state = entry.select_next_state;
14369            self.select_prev_state = entry.select_prev_state;
14370            self.add_selections_state = entry.add_selections_state;
14371        }
14372    }
14373
14374    pub fn redo_selection(
14375        &mut self,
14376        _: &RedoSelection,
14377        window: &mut Window,
14378        cx: &mut Context<Self>,
14379    ) {
14380        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14381        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14382            self.selection_history.mode = SelectionHistoryMode::Redoing;
14383            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14384                this.end_selection(window, cx);
14385                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14386                    s.select_anchors(entry.selections.to_vec())
14387                });
14388            });
14389            self.selection_history.mode = SelectionHistoryMode::Normal;
14390
14391            self.select_next_state = entry.select_next_state;
14392            self.select_prev_state = entry.select_prev_state;
14393            self.add_selections_state = entry.add_selections_state;
14394        }
14395    }
14396
14397    pub fn expand_excerpts(
14398        &mut self,
14399        action: &ExpandExcerpts,
14400        _: &mut Window,
14401        cx: &mut Context<Self>,
14402    ) {
14403        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14404    }
14405
14406    pub fn expand_excerpts_down(
14407        &mut self,
14408        action: &ExpandExcerptsDown,
14409        _: &mut Window,
14410        cx: &mut Context<Self>,
14411    ) {
14412        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14413    }
14414
14415    pub fn expand_excerpts_up(
14416        &mut self,
14417        action: &ExpandExcerptsUp,
14418        _: &mut Window,
14419        cx: &mut Context<Self>,
14420    ) {
14421        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14422    }
14423
14424    pub fn expand_excerpts_for_direction(
14425        &mut self,
14426        lines: u32,
14427        direction: ExpandExcerptDirection,
14428
14429        cx: &mut Context<Self>,
14430    ) {
14431        let selections = self.selections.disjoint_anchors();
14432
14433        let lines = if lines == 0 {
14434            EditorSettings::get_global(cx).expand_excerpt_lines
14435        } else {
14436            lines
14437        };
14438
14439        self.buffer.update(cx, |buffer, cx| {
14440            let snapshot = buffer.snapshot(cx);
14441            let mut excerpt_ids = selections
14442                .iter()
14443                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14444                .collect::<Vec<_>>();
14445            excerpt_ids.sort();
14446            excerpt_ids.dedup();
14447            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14448        })
14449    }
14450
14451    pub fn expand_excerpt(
14452        &mut self,
14453        excerpt: ExcerptId,
14454        direction: ExpandExcerptDirection,
14455        window: &mut Window,
14456        cx: &mut Context<Self>,
14457    ) {
14458        let current_scroll_position = self.scroll_position(cx);
14459        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14460        let mut should_scroll_up = false;
14461
14462        if direction == ExpandExcerptDirection::Down {
14463            let multi_buffer = self.buffer.read(cx);
14464            let snapshot = multi_buffer.snapshot(cx);
14465            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14466                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14467                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14468                        let buffer_snapshot = buffer.read(cx).snapshot();
14469                        let excerpt_end_row =
14470                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14471                        let last_row = buffer_snapshot.max_point().row;
14472                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14473                        should_scroll_up = lines_below >= lines_to_expand;
14474                    }
14475                }
14476            }
14477        }
14478
14479        self.buffer.update(cx, |buffer, cx| {
14480            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14481        });
14482
14483        if should_scroll_up {
14484            let new_scroll_position =
14485                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14486            self.set_scroll_position(new_scroll_position, window, cx);
14487        }
14488    }
14489
14490    pub fn go_to_singleton_buffer_point(
14491        &mut self,
14492        point: Point,
14493        window: &mut Window,
14494        cx: &mut Context<Self>,
14495    ) {
14496        self.go_to_singleton_buffer_range(point..point, window, cx);
14497    }
14498
14499    pub fn go_to_singleton_buffer_range(
14500        &mut self,
14501        range: Range<Point>,
14502        window: &mut Window,
14503        cx: &mut Context<Self>,
14504    ) {
14505        let multibuffer = self.buffer().read(cx);
14506        let Some(buffer) = multibuffer.as_singleton() else {
14507            return;
14508        };
14509        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14510            return;
14511        };
14512        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14513            return;
14514        };
14515        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14516            s.select_anchor_ranges([start..end])
14517        });
14518    }
14519
14520    pub fn go_to_diagnostic(
14521        &mut self,
14522        _: &GoToDiagnostic,
14523        window: &mut Window,
14524        cx: &mut Context<Self>,
14525    ) {
14526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14527        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14528    }
14529
14530    pub fn go_to_prev_diagnostic(
14531        &mut self,
14532        _: &GoToPreviousDiagnostic,
14533        window: &mut Window,
14534        cx: &mut Context<Self>,
14535    ) {
14536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14537        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14538    }
14539
14540    pub fn go_to_diagnostic_impl(
14541        &mut self,
14542        direction: Direction,
14543        window: &mut Window,
14544        cx: &mut Context<Self>,
14545    ) {
14546        let buffer = self.buffer.read(cx).snapshot(cx);
14547        let selection = self.selections.newest::<usize>(cx);
14548
14549        let mut active_group_id = None;
14550        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14551            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14552                active_group_id = Some(active_group.group_id);
14553            }
14554        }
14555
14556        fn filtered(
14557            snapshot: EditorSnapshot,
14558            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14559        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14560            diagnostics
14561                .filter(|entry| entry.range.start != entry.range.end)
14562                .filter(|entry| !entry.diagnostic.is_unnecessary)
14563                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14564        }
14565
14566        let snapshot = self.snapshot(window, cx);
14567        let before = filtered(
14568            snapshot.clone(),
14569            buffer
14570                .diagnostics_in_range(0..selection.start)
14571                .filter(|entry| entry.range.start <= selection.start),
14572        );
14573        let after = filtered(
14574            snapshot,
14575            buffer
14576                .diagnostics_in_range(selection.start..buffer.len())
14577                .filter(|entry| entry.range.start >= selection.start),
14578        );
14579
14580        let mut found: Option<DiagnosticEntry<usize>> = None;
14581        if direction == Direction::Prev {
14582            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14583            {
14584                for diagnostic in prev_diagnostics.into_iter().rev() {
14585                    if diagnostic.range.start != selection.start
14586                        || active_group_id
14587                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14588                    {
14589                        found = Some(diagnostic);
14590                        break 'outer;
14591                    }
14592                }
14593            }
14594        } else {
14595            for diagnostic in after.chain(before) {
14596                if diagnostic.range.start != selection.start
14597                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14598                {
14599                    found = Some(diagnostic);
14600                    break;
14601                }
14602            }
14603        }
14604        let Some(next_diagnostic) = found else {
14605            return;
14606        };
14607
14608        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14609            return;
14610        };
14611        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14612            s.select_ranges(vec![
14613                next_diagnostic.range.start..next_diagnostic.range.start,
14614            ])
14615        });
14616        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14617        self.refresh_inline_completion(false, true, window, cx);
14618    }
14619
14620    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14622        let snapshot = self.snapshot(window, cx);
14623        let selection = self.selections.newest::<Point>(cx);
14624        self.go_to_hunk_before_or_after_position(
14625            &snapshot,
14626            selection.head(),
14627            Direction::Next,
14628            window,
14629            cx,
14630        );
14631    }
14632
14633    pub fn go_to_hunk_before_or_after_position(
14634        &mut self,
14635        snapshot: &EditorSnapshot,
14636        position: Point,
14637        direction: Direction,
14638        window: &mut Window,
14639        cx: &mut Context<Editor>,
14640    ) {
14641        let row = if direction == Direction::Next {
14642            self.hunk_after_position(snapshot, position)
14643                .map(|hunk| hunk.row_range.start)
14644        } else {
14645            self.hunk_before_position(snapshot, position)
14646        };
14647
14648        if let Some(row) = row {
14649            let destination = Point::new(row.0, 0);
14650            let autoscroll = Autoscroll::center();
14651
14652            self.unfold_ranges(&[destination..destination], false, false, cx);
14653            self.change_selections(Some(autoscroll), window, cx, |s| {
14654                s.select_ranges([destination..destination]);
14655            });
14656        }
14657    }
14658
14659    fn hunk_after_position(
14660        &mut self,
14661        snapshot: &EditorSnapshot,
14662        position: Point,
14663    ) -> Option<MultiBufferDiffHunk> {
14664        snapshot
14665            .buffer_snapshot
14666            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14667            .find(|hunk| hunk.row_range.start.0 > position.row)
14668            .or_else(|| {
14669                snapshot
14670                    .buffer_snapshot
14671                    .diff_hunks_in_range(Point::zero()..position)
14672                    .find(|hunk| hunk.row_range.end.0 < position.row)
14673            })
14674    }
14675
14676    fn go_to_prev_hunk(
14677        &mut self,
14678        _: &GoToPreviousHunk,
14679        window: &mut Window,
14680        cx: &mut Context<Self>,
14681    ) {
14682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14683        let snapshot = self.snapshot(window, cx);
14684        let selection = self.selections.newest::<Point>(cx);
14685        self.go_to_hunk_before_or_after_position(
14686            &snapshot,
14687            selection.head(),
14688            Direction::Prev,
14689            window,
14690            cx,
14691        );
14692    }
14693
14694    fn hunk_before_position(
14695        &mut self,
14696        snapshot: &EditorSnapshot,
14697        position: Point,
14698    ) -> Option<MultiBufferRow> {
14699        snapshot
14700            .buffer_snapshot
14701            .diff_hunk_before(position)
14702            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14703    }
14704
14705    fn go_to_next_change(
14706        &mut self,
14707        _: &GoToNextChange,
14708        window: &mut Window,
14709        cx: &mut Context<Self>,
14710    ) {
14711        if let Some(selections) = self
14712            .change_list
14713            .next_change(1, Direction::Next)
14714            .map(|s| s.to_vec())
14715        {
14716            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14717                let map = s.display_map();
14718                s.select_display_ranges(selections.iter().map(|a| {
14719                    let point = a.to_display_point(&map);
14720                    point..point
14721                }))
14722            })
14723        }
14724    }
14725
14726    fn go_to_previous_change(
14727        &mut self,
14728        _: &GoToPreviousChange,
14729        window: &mut Window,
14730        cx: &mut Context<Self>,
14731    ) {
14732        if let Some(selections) = self
14733            .change_list
14734            .next_change(1, Direction::Prev)
14735            .map(|s| s.to_vec())
14736        {
14737            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14738                let map = s.display_map();
14739                s.select_display_ranges(selections.iter().map(|a| {
14740                    let point = a.to_display_point(&map);
14741                    point..point
14742                }))
14743            })
14744        }
14745    }
14746
14747    fn go_to_line<T: 'static>(
14748        &mut self,
14749        position: Anchor,
14750        highlight_color: Option<Hsla>,
14751        window: &mut Window,
14752        cx: &mut Context<Self>,
14753    ) {
14754        let snapshot = self.snapshot(window, cx).display_snapshot;
14755        let position = position.to_point(&snapshot.buffer_snapshot);
14756        let start = snapshot
14757            .buffer_snapshot
14758            .clip_point(Point::new(position.row, 0), Bias::Left);
14759        let end = start + Point::new(1, 0);
14760        let start = snapshot.buffer_snapshot.anchor_before(start);
14761        let end = snapshot.buffer_snapshot.anchor_before(end);
14762
14763        self.highlight_rows::<T>(
14764            start..end,
14765            highlight_color
14766                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14767            Default::default(),
14768            cx,
14769        );
14770
14771        if self.buffer.read(cx).is_singleton() {
14772            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14773        }
14774    }
14775
14776    pub fn go_to_definition(
14777        &mut self,
14778        _: &GoToDefinition,
14779        window: &mut Window,
14780        cx: &mut Context<Self>,
14781    ) -> Task<Result<Navigated>> {
14782        let definition =
14783            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14784        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14785        cx.spawn_in(window, async move |editor, cx| {
14786            if definition.await? == Navigated::Yes {
14787                return Ok(Navigated::Yes);
14788            }
14789            match fallback_strategy {
14790                GoToDefinitionFallback::None => Ok(Navigated::No),
14791                GoToDefinitionFallback::FindAllReferences => {
14792                    match editor.update_in(cx, |editor, window, cx| {
14793                        editor.find_all_references(&FindAllReferences, window, cx)
14794                    })? {
14795                        Some(references) => references.await,
14796                        None => Ok(Navigated::No),
14797                    }
14798                }
14799            }
14800        })
14801    }
14802
14803    pub fn go_to_declaration(
14804        &mut self,
14805        _: &GoToDeclaration,
14806        window: &mut Window,
14807        cx: &mut Context<Self>,
14808    ) -> Task<Result<Navigated>> {
14809        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14810    }
14811
14812    pub fn go_to_declaration_split(
14813        &mut self,
14814        _: &GoToDeclaration,
14815        window: &mut Window,
14816        cx: &mut Context<Self>,
14817    ) -> Task<Result<Navigated>> {
14818        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14819    }
14820
14821    pub fn go_to_implementation(
14822        &mut self,
14823        _: &GoToImplementation,
14824        window: &mut Window,
14825        cx: &mut Context<Self>,
14826    ) -> Task<Result<Navigated>> {
14827        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14828    }
14829
14830    pub fn go_to_implementation_split(
14831        &mut self,
14832        _: &GoToImplementationSplit,
14833        window: &mut Window,
14834        cx: &mut Context<Self>,
14835    ) -> Task<Result<Navigated>> {
14836        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14837    }
14838
14839    pub fn go_to_type_definition(
14840        &mut self,
14841        _: &GoToTypeDefinition,
14842        window: &mut Window,
14843        cx: &mut Context<Self>,
14844    ) -> Task<Result<Navigated>> {
14845        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14846    }
14847
14848    pub fn go_to_definition_split(
14849        &mut self,
14850        _: &GoToDefinitionSplit,
14851        window: &mut Window,
14852        cx: &mut Context<Self>,
14853    ) -> Task<Result<Navigated>> {
14854        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14855    }
14856
14857    pub fn go_to_type_definition_split(
14858        &mut self,
14859        _: &GoToTypeDefinitionSplit,
14860        window: &mut Window,
14861        cx: &mut Context<Self>,
14862    ) -> Task<Result<Navigated>> {
14863        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14864    }
14865
14866    fn go_to_definition_of_kind(
14867        &mut self,
14868        kind: GotoDefinitionKind,
14869        split: bool,
14870        window: &mut Window,
14871        cx: &mut Context<Self>,
14872    ) -> Task<Result<Navigated>> {
14873        let Some(provider) = self.semantics_provider.clone() else {
14874            return Task::ready(Ok(Navigated::No));
14875        };
14876        let head = self.selections.newest::<usize>(cx).head();
14877        let buffer = self.buffer.read(cx);
14878        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14879            text_anchor
14880        } else {
14881            return Task::ready(Ok(Navigated::No));
14882        };
14883
14884        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14885            return Task::ready(Ok(Navigated::No));
14886        };
14887
14888        cx.spawn_in(window, async move |editor, cx| {
14889            let definitions = definitions.await?;
14890            let navigated = editor
14891                .update_in(cx, |editor, window, cx| {
14892                    editor.navigate_to_hover_links(
14893                        Some(kind),
14894                        definitions
14895                            .into_iter()
14896                            .filter(|location| {
14897                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14898                            })
14899                            .map(HoverLink::Text)
14900                            .collect::<Vec<_>>(),
14901                        split,
14902                        window,
14903                        cx,
14904                    )
14905                })?
14906                .await?;
14907            anyhow::Ok(navigated)
14908        })
14909    }
14910
14911    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14912        let selection = self.selections.newest_anchor();
14913        let head = selection.head();
14914        let tail = selection.tail();
14915
14916        let Some((buffer, start_position)) =
14917            self.buffer.read(cx).text_anchor_for_position(head, cx)
14918        else {
14919            return;
14920        };
14921
14922        let end_position = if head != tail {
14923            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14924                return;
14925            };
14926            Some(pos)
14927        } else {
14928            None
14929        };
14930
14931        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14932            let url = if let Some(end_pos) = end_position {
14933                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14934            } else {
14935                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14936            };
14937
14938            if let Some(url) = url {
14939                editor.update(cx, |_, cx| {
14940                    cx.open_url(&url);
14941                })
14942            } else {
14943                Ok(())
14944            }
14945        });
14946
14947        url_finder.detach();
14948    }
14949
14950    pub fn open_selected_filename(
14951        &mut self,
14952        _: &OpenSelectedFilename,
14953        window: &mut Window,
14954        cx: &mut Context<Self>,
14955    ) {
14956        let Some(workspace) = self.workspace() else {
14957            return;
14958        };
14959
14960        let position = self.selections.newest_anchor().head();
14961
14962        let Some((buffer, buffer_position)) =
14963            self.buffer.read(cx).text_anchor_for_position(position, cx)
14964        else {
14965            return;
14966        };
14967
14968        let project = self.project.clone();
14969
14970        cx.spawn_in(window, async move |_, cx| {
14971            let result = find_file(&buffer, project, buffer_position, cx).await;
14972
14973            if let Some((_, path)) = result {
14974                workspace
14975                    .update_in(cx, |workspace, window, cx| {
14976                        workspace.open_resolved_path(path, window, cx)
14977                    })?
14978                    .await?;
14979            }
14980            anyhow::Ok(())
14981        })
14982        .detach();
14983    }
14984
14985    pub(crate) fn navigate_to_hover_links(
14986        &mut self,
14987        kind: Option<GotoDefinitionKind>,
14988        mut definitions: Vec<HoverLink>,
14989        split: bool,
14990        window: &mut Window,
14991        cx: &mut Context<Editor>,
14992    ) -> Task<Result<Navigated>> {
14993        // If there is one definition, just open it directly
14994        if definitions.len() == 1 {
14995            let definition = definitions.pop().unwrap();
14996
14997            enum TargetTaskResult {
14998                Location(Option<Location>),
14999                AlreadyNavigated,
15000            }
15001
15002            let target_task = match definition {
15003                HoverLink::Text(link) => {
15004                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15005                }
15006                HoverLink::InlayHint(lsp_location, server_id) => {
15007                    let computation =
15008                        self.compute_target_location(lsp_location, server_id, window, cx);
15009                    cx.background_spawn(async move {
15010                        let location = computation.await?;
15011                        Ok(TargetTaskResult::Location(location))
15012                    })
15013                }
15014                HoverLink::Url(url) => {
15015                    cx.open_url(&url);
15016                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15017                }
15018                HoverLink::File(path) => {
15019                    if let Some(workspace) = self.workspace() {
15020                        cx.spawn_in(window, async move |_, cx| {
15021                            workspace
15022                                .update_in(cx, |workspace, window, cx| {
15023                                    workspace.open_resolved_path(path, window, cx)
15024                                })?
15025                                .await
15026                                .map(|_| TargetTaskResult::AlreadyNavigated)
15027                        })
15028                    } else {
15029                        Task::ready(Ok(TargetTaskResult::Location(None)))
15030                    }
15031                }
15032            };
15033            cx.spawn_in(window, async move |editor, cx| {
15034                let target = match target_task.await.context("target resolution task")? {
15035                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15036                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15037                    TargetTaskResult::Location(Some(target)) => target,
15038                };
15039
15040                editor.update_in(cx, |editor, window, cx| {
15041                    let Some(workspace) = editor.workspace() else {
15042                        return Navigated::No;
15043                    };
15044                    let pane = workspace.read(cx).active_pane().clone();
15045
15046                    let range = target.range.to_point(target.buffer.read(cx));
15047                    let range = editor.range_for_match(&range);
15048                    let range = collapse_multiline_range(range);
15049
15050                    if !split
15051                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15052                    {
15053                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15054                    } else {
15055                        window.defer(cx, move |window, cx| {
15056                            let target_editor: Entity<Self> =
15057                                workspace.update(cx, |workspace, cx| {
15058                                    let pane = if split {
15059                                        workspace.adjacent_pane(window, cx)
15060                                    } else {
15061                                        workspace.active_pane().clone()
15062                                    };
15063
15064                                    workspace.open_project_item(
15065                                        pane,
15066                                        target.buffer.clone(),
15067                                        true,
15068                                        true,
15069                                        window,
15070                                        cx,
15071                                    )
15072                                });
15073                            target_editor.update(cx, |target_editor, cx| {
15074                                // When selecting a definition in a different buffer, disable the nav history
15075                                // to avoid creating a history entry at the previous cursor location.
15076                                pane.update(cx, |pane, _| pane.disable_history());
15077                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15078                                pane.update(cx, |pane, _| pane.enable_history());
15079                            });
15080                        });
15081                    }
15082                    Navigated::Yes
15083                })
15084            })
15085        } else if !definitions.is_empty() {
15086            cx.spawn_in(window, async move |editor, cx| {
15087                let (title, location_tasks, workspace) = editor
15088                    .update_in(cx, |editor, window, cx| {
15089                        let tab_kind = match kind {
15090                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15091                            _ => "Definitions",
15092                        };
15093                        let title = definitions
15094                            .iter()
15095                            .find_map(|definition| match definition {
15096                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15097                                    let buffer = origin.buffer.read(cx);
15098                                    format!(
15099                                        "{} for {}",
15100                                        tab_kind,
15101                                        buffer
15102                                            .text_for_range(origin.range.clone())
15103                                            .collect::<String>()
15104                                    )
15105                                }),
15106                                HoverLink::InlayHint(_, _) => None,
15107                                HoverLink::Url(_) => None,
15108                                HoverLink::File(_) => None,
15109                            })
15110                            .unwrap_or(tab_kind.to_string());
15111                        let location_tasks = definitions
15112                            .into_iter()
15113                            .map(|definition| match definition {
15114                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15115                                HoverLink::InlayHint(lsp_location, server_id) => editor
15116                                    .compute_target_location(lsp_location, server_id, window, cx),
15117                                HoverLink::Url(_) => Task::ready(Ok(None)),
15118                                HoverLink::File(_) => Task::ready(Ok(None)),
15119                            })
15120                            .collect::<Vec<_>>();
15121                        (title, location_tasks, editor.workspace().clone())
15122                    })
15123                    .context("location tasks preparation")?;
15124
15125                let locations = future::join_all(location_tasks)
15126                    .await
15127                    .into_iter()
15128                    .filter_map(|location| location.transpose())
15129                    .collect::<Result<_>>()
15130                    .context("location tasks")?;
15131
15132                let Some(workspace) = workspace else {
15133                    return Ok(Navigated::No);
15134                };
15135                let opened = workspace
15136                    .update_in(cx, |workspace, window, cx| {
15137                        Self::open_locations_in_multibuffer(
15138                            workspace,
15139                            locations,
15140                            title,
15141                            split,
15142                            MultibufferSelectionMode::First,
15143                            window,
15144                            cx,
15145                        )
15146                    })
15147                    .ok();
15148
15149                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15150            })
15151        } else {
15152            Task::ready(Ok(Navigated::No))
15153        }
15154    }
15155
15156    fn compute_target_location(
15157        &self,
15158        lsp_location: lsp::Location,
15159        server_id: LanguageServerId,
15160        window: &mut Window,
15161        cx: &mut Context<Self>,
15162    ) -> Task<anyhow::Result<Option<Location>>> {
15163        let Some(project) = self.project.clone() else {
15164            return Task::ready(Ok(None));
15165        };
15166
15167        cx.spawn_in(window, async move |editor, cx| {
15168            let location_task = editor.update(cx, |_, cx| {
15169                project.update(cx, |project, cx| {
15170                    let language_server_name = project
15171                        .language_server_statuses(cx)
15172                        .find(|(id, _)| server_id == *id)
15173                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15174                    language_server_name.map(|language_server_name| {
15175                        project.open_local_buffer_via_lsp(
15176                            lsp_location.uri.clone(),
15177                            server_id,
15178                            language_server_name,
15179                            cx,
15180                        )
15181                    })
15182                })
15183            })?;
15184            let location = match location_task {
15185                Some(task) => Some({
15186                    let target_buffer_handle = task.await.context("open local buffer")?;
15187                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15188                        let target_start = target_buffer
15189                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15190                        let target_end = target_buffer
15191                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15192                        target_buffer.anchor_after(target_start)
15193                            ..target_buffer.anchor_before(target_end)
15194                    })?;
15195                    Location {
15196                        buffer: target_buffer_handle,
15197                        range,
15198                    }
15199                }),
15200                None => None,
15201            };
15202            Ok(location)
15203        })
15204    }
15205
15206    pub fn find_all_references(
15207        &mut self,
15208        _: &FindAllReferences,
15209        window: &mut Window,
15210        cx: &mut Context<Self>,
15211    ) -> Option<Task<Result<Navigated>>> {
15212        let selection = self.selections.newest::<usize>(cx);
15213        let multi_buffer = self.buffer.read(cx);
15214        let head = selection.head();
15215
15216        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15217        let head_anchor = multi_buffer_snapshot.anchor_at(
15218            head,
15219            if head < selection.tail() {
15220                Bias::Right
15221            } else {
15222                Bias::Left
15223            },
15224        );
15225
15226        match self
15227            .find_all_references_task_sources
15228            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15229        {
15230            Ok(_) => {
15231                log::info!(
15232                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15233                );
15234                return None;
15235            }
15236            Err(i) => {
15237                self.find_all_references_task_sources.insert(i, head_anchor);
15238            }
15239        }
15240
15241        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15242        let workspace = self.workspace()?;
15243        let project = workspace.read(cx).project().clone();
15244        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15245        Some(cx.spawn_in(window, async move |editor, cx| {
15246            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15247                if let Ok(i) = editor
15248                    .find_all_references_task_sources
15249                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15250                {
15251                    editor.find_all_references_task_sources.remove(i);
15252                }
15253            });
15254
15255            let locations = references.await?;
15256            if locations.is_empty() {
15257                return anyhow::Ok(Navigated::No);
15258            }
15259
15260            workspace.update_in(cx, |workspace, window, cx| {
15261                let title = locations
15262                    .first()
15263                    .as_ref()
15264                    .map(|location| {
15265                        let buffer = location.buffer.read(cx);
15266                        format!(
15267                            "References to `{}`",
15268                            buffer
15269                                .text_for_range(location.range.clone())
15270                                .collect::<String>()
15271                        )
15272                    })
15273                    .unwrap();
15274                Self::open_locations_in_multibuffer(
15275                    workspace,
15276                    locations,
15277                    title,
15278                    false,
15279                    MultibufferSelectionMode::First,
15280                    window,
15281                    cx,
15282                );
15283                Navigated::Yes
15284            })
15285        }))
15286    }
15287
15288    /// Opens a multibuffer with the given project locations in it
15289    pub fn open_locations_in_multibuffer(
15290        workspace: &mut Workspace,
15291        mut locations: Vec<Location>,
15292        title: String,
15293        split: bool,
15294        multibuffer_selection_mode: MultibufferSelectionMode,
15295        window: &mut Window,
15296        cx: &mut Context<Workspace>,
15297    ) {
15298        // If there are multiple definitions, open them in a multibuffer
15299        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15300        let mut locations = locations.into_iter().peekable();
15301        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15302        let capability = workspace.project().read(cx).capability();
15303
15304        let excerpt_buffer = cx.new(|cx| {
15305            let mut multibuffer = MultiBuffer::new(capability);
15306            while let Some(location) = locations.next() {
15307                let buffer = location.buffer.read(cx);
15308                let mut ranges_for_buffer = Vec::new();
15309                let range = location.range.to_point(buffer);
15310                ranges_for_buffer.push(range.clone());
15311
15312                while let Some(next_location) = locations.peek() {
15313                    if next_location.buffer == location.buffer {
15314                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15315                        locations.next();
15316                    } else {
15317                        break;
15318                    }
15319                }
15320
15321                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15322                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15323                    PathKey::for_buffer(&location.buffer, cx),
15324                    location.buffer.clone(),
15325                    ranges_for_buffer,
15326                    DEFAULT_MULTIBUFFER_CONTEXT,
15327                    cx,
15328                );
15329                ranges.extend(new_ranges)
15330            }
15331
15332            multibuffer.with_title(title)
15333        });
15334
15335        let editor = cx.new(|cx| {
15336            Editor::for_multibuffer(
15337                excerpt_buffer,
15338                Some(workspace.project().clone()),
15339                window,
15340                cx,
15341            )
15342        });
15343        editor.update(cx, |editor, cx| {
15344            match multibuffer_selection_mode {
15345                MultibufferSelectionMode::First => {
15346                    if let Some(first_range) = ranges.first() {
15347                        editor.change_selections(None, window, cx, |selections| {
15348                            selections.clear_disjoint();
15349                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15350                        });
15351                    }
15352                    editor.highlight_background::<Self>(
15353                        &ranges,
15354                        |theme| theme.editor_highlighted_line_background,
15355                        cx,
15356                    );
15357                }
15358                MultibufferSelectionMode::All => {
15359                    editor.change_selections(None, window, cx, |selections| {
15360                        selections.clear_disjoint();
15361                        selections.select_anchor_ranges(ranges);
15362                    });
15363                }
15364            }
15365            editor.register_buffers_with_language_servers(cx);
15366        });
15367
15368        let item = Box::new(editor);
15369        let item_id = item.item_id();
15370
15371        if split {
15372            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15373        } else {
15374            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15375                let (preview_item_id, preview_item_idx) =
15376                    workspace.active_pane().read_with(cx, |pane, _| {
15377                        (pane.preview_item_id(), pane.preview_item_idx())
15378                    });
15379
15380                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15381
15382                if let Some(preview_item_id) = preview_item_id {
15383                    workspace.active_pane().update(cx, |pane, cx| {
15384                        pane.remove_item(preview_item_id, false, false, window, cx);
15385                    });
15386                }
15387            } else {
15388                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15389            }
15390        }
15391        workspace.active_pane().update(cx, |pane, cx| {
15392            pane.set_preview_item_id(Some(item_id), cx);
15393        });
15394    }
15395
15396    pub fn rename(
15397        &mut self,
15398        _: &Rename,
15399        window: &mut Window,
15400        cx: &mut Context<Self>,
15401    ) -> Option<Task<Result<()>>> {
15402        use language::ToOffset as _;
15403
15404        let provider = self.semantics_provider.clone()?;
15405        let selection = self.selections.newest_anchor().clone();
15406        let (cursor_buffer, cursor_buffer_position) = self
15407            .buffer
15408            .read(cx)
15409            .text_anchor_for_position(selection.head(), cx)?;
15410        let (tail_buffer, cursor_buffer_position_end) = self
15411            .buffer
15412            .read(cx)
15413            .text_anchor_for_position(selection.tail(), cx)?;
15414        if tail_buffer != cursor_buffer {
15415            return None;
15416        }
15417
15418        let snapshot = cursor_buffer.read(cx).snapshot();
15419        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15420        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15421        let prepare_rename = provider
15422            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15423            .unwrap_or_else(|| Task::ready(Ok(None)));
15424        drop(snapshot);
15425
15426        Some(cx.spawn_in(window, async move |this, cx| {
15427            let rename_range = if let Some(range) = prepare_rename.await? {
15428                Some(range)
15429            } else {
15430                this.update(cx, |this, cx| {
15431                    let buffer = this.buffer.read(cx).snapshot(cx);
15432                    let mut buffer_highlights = this
15433                        .document_highlights_for_position(selection.head(), &buffer)
15434                        .filter(|highlight| {
15435                            highlight.start.excerpt_id == selection.head().excerpt_id
15436                                && highlight.end.excerpt_id == selection.head().excerpt_id
15437                        });
15438                    buffer_highlights
15439                        .next()
15440                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15441                })?
15442            };
15443            if let Some(rename_range) = rename_range {
15444                this.update_in(cx, |this, window, cx| {
15445                    let snapshot = cursor_buffer.read(cx).snapshot();
15446                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15447                    let cursor_offset_in_rename_range =
15448                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15449                    let cursor_offset_in_rename_range_end =
15450                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15451
15452                    this.take_rename(false, window, cx);
15453                    let buffer = this.buffer.read(cx).read(cx);
15454                    let cursor_offset = selection.head().to_offset(&buffer);
15455                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15456                    let rename_end = rename_start + rename_buffer_range.len();
15457                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15458                    let mut old_highlight_id = None;
15459                    let old_name: Arc<str> = buffer
15460                        .chunks(rename_start..rename_end, true)
15461                        .map(|chunk| {
15462                            if old_highlight_id.is_none() {
15463                                old_highlight_id = chunk.syntax_highlight_id;
15464                            }
15465                            chunk.text
15466                        })
15467                        .collect::<String>()
15468                        .into();
15469
15470                    drop(buffer);
15471
15472                    // Position the selection in the rename editor so that it matches the current selection.
15473                    this.show_local_selections = false;
15474                    let rename_editor = cx.new(|cx| {
15475                        let mut editor = Editor::single_line(window, cx);
15476                        editor.buffer.update(cx, |buffer, cx| {
15477                            buffer.edit([(0..0, old_name.clone())], None, cx)
15478                        });
15479                        let rename_selection_range = match cursor_offset_in_rename_range
15480                            .cmp(&cursor_offset_in_rename_range_end)
15481                        {
15482                            Ordering::Equal => {
15483                                editor.select_all(&SelectAll, window, cx);
15484                                return editor;
15485                            }
15486                            Ordering::Less => {
15487                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15488                            }
15489                            Ordering::Greater => {
15490                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15491                            }
15492                        };
15493                        if rename_selection_range.end > old_name.len() {
15494                            editor.select_all(&SelectAll, window, cx);
15495                        } else {
15496                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15497                                s.select_ranges([rename_selection_range]);
15498                            });
15499                        }
15500                        editor
15501                    });
15502                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15503                        if e == &EditorEvent::Focused {
15504                            cx.emit(EditorEvent::FocusedIn)
15505                        }
15506                    })
15507                    .detach();
15508
15509                    let write_highlights =
15510                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15511                    let read_highlights =
15512                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15513                    let ranges = write_highlights
15514                        .iter()
15515                        .flat_map(|(_, ranges)| ranges.iter())
15516                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15517                        .cloned()
15518                        .collect();
15519
15520                    this.highlight_text::<Rename>(
15521                        ranges,
15522                        HighlightStyle {
15523                            fade_out: Some(0.6),
15524                            ..Default::default()
15525                        },
15526                        cx,
15527                    );
15528                    let rename_focus_handle = rename_editor.focus_handle(cx);
15529                    window.focus(&rename_focus_handle);
15530                    let block_id = this.insert_blocks(
15531                        [BlockProperties {
15532                            style: BlockStyle::Flex,
15533                            placement: BlockPlacement::Below(range.start),
15534                            height: Some(1),
15535                            render: Arc::new({
15536                                let rename_editor = rename_editor.clone();
15537                                move |cx: &mut BlockContext| {
15538                                    let mut text_style = cx.editor_style.text.clone();
15539                                    if let Some(highlight_style) = old_highlight_id
15540                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15541                                    {
15542                                        text_style = text_style.highlight(highlight_style);
15543                                    }
15544                                    div()
15545                                        .block_mouse_except_scroll()
15546                                        .pl(cx.anchor_x)
15547                                        .child(EditorElement::new(
15548                                            &rename_editor,
15549                                            EditorStyle {
15550                                                background: cx.theme().system().transparent,
15551                                                local_player: cx.editor_style.local_player,
15552                                                text: text_style,
15553                                                scrollbar_width: cx.editor_style.scrollbar_width,
15554                                                syntax: cx.editor_style.syntax.clone(),
15555                                                status: cx.editor_style.status.clone(),
15556                                                inlay_hints_style: HighlightStyle {
15557                                                    font_weight: Some(FontWeight::BOLD),
15558                                                    ..make_inlay_hints_style(cx.app)
15559                                                },
15560                                                inline_completion_styles: make_suggestion_styles(
15561                                                    cx.app,
15562                                                ),
15563                                                ..EditorStyle::default()
15564                                            },
15565                                        ))
15566                                        .into_any_element()
15567                                }
15568                            }),
15569                            priority: 0,
15570                            render_in_minimap: true,
15571                        }],
15572                        Some(Autoscroll::fit()),
15573                        cx,
15574                    )[0];
15575                    this.pending_rename = Some(RenameState {
15576                        range,
15577                        old_name,
15578                        editor: rename_editor,
15579                        block_id,
15580                    });
15581                })?;
15582            }
15583
15584            Ok(())
15585        }))
15586    }
15587
15588    pub fn confirm_rename(
15589        &mut self,
15590        _: &ConfirmRename,
15591        window: &mut Window,
15592        cx: &mut Context<Self>,
15593    ) -> Option<Task<Result<()>>> {
15594        let rename = self.take_rename(false, window, cx)?;
15595        let workspace = self.workspace()?.downgrade();
15596        let (buffer, start) = self
15597            .buffer
15598            .read(cx)
15599            .text_anchor_for_position(rename.range.start, cx)?;
15600        let (end_buffer, _) = self
15601            .buffer
15602            .read(cx)
15603            .text_anchor_for_position(rename.range.end, cx)?;
15604        if buffer != end_buffer {
15605            return None;
15606        }
15607
15608        let old_name = rename.old_name;
15609        let new_name = rename.editor.read(cx).text(cx);
15610
15611        let rename = self.semantics_provider.as_ref()?.perform_rename(
15612            &buffer,
15613            start,
15614            new_name.clone(),
15615            cx,
15616        )?;
15617
15618        Some(cx.spawn_in(window, async move |editor, cx| {
15619            let project_transaction = rename.await?;
15620            Self::open_project_transaction(
15621                &editor,
15622                workspace,
15623                project_transaction,
15624                format!("Rename: {}{}", old_name, new_name),
15625                cx,
15626            )
15627            .await?;
15628
15629            editor.update(cx, |editor, cx| {
15630                editor.refresh_document_highlights(cx);
15631            })?;
15632            Ok(())
15633        }))
15634    }
15635
15636    fn take_rename(
15637        &mut self,
15638        moving_cursor: bool,
15639        window: &mut Window,
15640        cx: &mut Context<Self>,
15641    ) -> Option<RenameState> {
15642        let rename = self.pending_rename.take()?;
15643        if rename.editor.focus_handle(cx).is_focused(window) {
15644            window.focus(&self.focus_handle);
15645        }
15646
15647        self.remove_blocks(
15648            [rename.block_id].into_iter().collect(),
15649            Some(Autoscroll::fit()),
15650            cx,
15651        );
15652        self.clear_highlights::<Rename>(cx);
15653        self.show_local_selections = true;
15654
15655        if moving_cursor {
15656            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15657                editor.selections.newest::<usize>(cx).head()
15658            });
15659
15660            // Update the selection to match the position of the selection inside
15661            // the rename editor.
15662            let snapshot = self.buffer.read(cx).read(cx);
15663            let rename_range = rename.range.to_offset(&snapshot);
15664            let cursor_in_editor = snapshot
15665                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15666                .min(rename_range.end);
15667            drop(snapshot);
15668
15669            self.change_selections(None, window, cx, |s| {
15670                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15671            });
15672        } else {
15673            self.refresh_document_highlights(cx);
15674        }
15675
15676        Some(rename)
15677    }
15678
15679    pub fn pending_rename(&self) -> Option<&RenameState> {
15680        self.pending_rename.as_ref()
15681    }
15682
15683    fn format(
15684        &mut self,
15685        _: &Format,
15686        window: &mut Window,
15687        cx: &mut Context<Self>,
15688    ) -> Option<Task<Result<()>>> {
15689        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15690
15691        let project = match &self.project {
15692            Some(project) => project.clone(),
15693            None => return None,
15694        };
15695
15696        Some(self.perform_format(
15697            project,
15698            FormatTrigger::Manual,
15699            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15700            window,
15701            cx,
15702        ))
15703    }
15704
15705    fn format_selections(
15706        &mut self,
15707        _: &FormatSelections,
15708        window: &mut Window,
15709        cx: &mut Context<Self>,
15710    ) -> Option<Task<Result<()>>> {
15711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15712
15713        let project = match &self.project {
15714            Some(project) => project.clone(),
15715            None => return None,
15716        };
15717
15718        let ranges = self
15719            .selections
15720            .all_adjusted(cx)
15721            .into_iter()
15722            .map(|selection| selection.range())
15723            .collect_vec();
15724
15725        Some(self.perform_format(
15726            project,
15727            FormatTrigger::Manual,
15728            FormatTarget::Ranges(ranges),
15729            window,
15730            cx,
15731        ))
15732    }
15733
15734    fn perform_format(
15735        &mut self,
15736        project: Entity<Project>,
15737        trigger: FormatTrigger,
15738        target: FormatTarget,
15739        window: &mut Window,
15740        cx: &mut Context<Self>,
15741    ) -> Task<Result<()>> {
15742        let buffer = self.buffer.clone();
15743        let (buffers, target) = match target {
15744            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15745            FormatTarget::Ranges(selection_ranges) => {
15746                let multi_buffer = buffer.read(cx);
15747                let snapshot = multi_buffer.read(cx);
15748                let mut buffers = HashSet::default();
15749                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15750                    BTreeMap::new();
15751                for selection_range in selection_ranges {
15752                    for (buffer, buffer_range, _) in
15753                        snapshot.range_to_buffer_ranges(selection_range)
15754                    {
15755                        let buffer_id = buffer.remote_id();
15756                        let start = buffer.anchor_before(buffer_range.start);
15757                        let end = buffer.anchor_after(buffer_range.end);
15758                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15759                        buffer_id_to_ranges
15760                            .entry(buffer_id)
15761                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15762                            .or_insert_with(|| vec![start..end]);
15763                    }
15764                }
15765                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15766            }
15767        };
15768
15769        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15770        let selections_prev = transaction_id_prev
15771            .and_then(|transaction_id_prev| {
15772                // default to selections as they were after the last edit, if we have them,
15773                // instead of how they are now.
15774                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15775                // will take you back to where you made the last edit, instead of staying where you scrolled
15776                self.selection_history
15777                    .transaction(transaction_id_prev)
15778                    .map(|t| t.0.clone())
15779            })
15780            .unwrap_or_else(|| {
15781                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15782                self.selections.disjoint_anchors()
15783            });
15784
15785        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15786        let format = project.update(cx, |project, cx| {
15787            project.format(buffers, target, true, trigger, cx)
15788        });
15789
15790        cx.spawn_in(window, async move |editor, cx| {
15791            let transaction = futures::select_biased! {
15792                transaction = format.log_err().fuse() => transaction,
15793                () = timeout => {
15794                    log::warn!("timed out waiting for formatting");
15795                    None
15796                }
15797            };
15798
15799            buffer
15800                .update(cx, |buffer, cx| {
15801                    if let Some(transaction) = transaction {
15802                        if !buffer.is_singleton() {
15803                            buffer.push_transaction(&transaction.0, cx);
15804                        }
15805                    }
15806                    cx.notify();
15807                })
15808                .ok();
15809
15810            if let Some(transaction_id_now) =
15811                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15812            {
15813                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15814                if has_new_transaction {
15815                    _ = editor.update(cx, |editor, _| {
15816                        editor
15817                            .selection_history
15818                            .insert_transaction(transaction_id_now, selections_prev);
15819                    });
15820                }
15821            }
15822
15823            Ok(())
15824        })
15825    }
15826
15827    fn organize_imports(
15828        &mut self,
15829        _: &OrganizeImports,
15830        window: &mut Window,
15831        cx: &mut Context<Self>,
15832    ) -> Option<Task<Result<()>>> {
15833        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15834        let project = match &self.project {
15835            Some(project) => project.clone(),
15836            None => return None,
15837        };
15838        Some(self.perform_code_action_kind(
15839            project,
15840            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15841            window,
15842            cx,
15843        ))
15844    }
15845
15846    fn perform_code_action_kind(
15847        &mut self,
15848        project: Entity<Project>,
15849        kind: CodeActionKind,
15850        window: &mut Window,
15851        cx: &mut Context<Self>,
15852    ) -> Task<Result<()>> {
15853        let buffer = self.buffer.clone();
15854        let buffers = buffer.read(cx).all_buffers();
15855        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15856        let apply_action = project.update(cx, |project, cx| {
15857            project.apply_code_action_kind(buffers, kind, true, cx)
15858        });
15859        cx.spawn_in(window, async move |_, cx| {
15860            let transaction = futures::select_biased! {
15861                () = timeout => {
15862                    log::warn!("timed out waiting for executing code action");
15863                    None
15864                }
15865                transaction = apply_action.log_err().fuse() => transaction,
15866            };
15867            buffer
15868                .update(cx, |buffer, cx| {
15869                    // check if we need this
15870                    if let Some(transaction) = transaction {
15871                        if !buffer.is_singleton() {
15872                            buffer.push_transaction(&transaction.0, cx);
15873                        }
15874                    }
15875                    cx.notify();
15876                })
15877                .ok();
15878            Ok(())
15879        })
15880    }
15881
15882    fn restart_language_server(
15883        &mut self,
15884        _: &RestartLanguageServer,
15885        _: &mut Window,
15886        cx: &mut Context<Self>,
15887    ) {
15888        if let Some(project) = self.project.clone() {
15889            self.buffer.update(cx, |multi_buffer, cx| {
15890                project.update(cx, |project, cx| {
15891                    project.restart_language_servers_for_buffers(
15892                        multi_buffer.all_buffers().into_iter().collect(),
15893                        cx,
15894                    );
15895                });
15896            })
15897        }
15898    }
15899
15900    fn stop_language_server(
15901        &mut self,
15902        _: &StopLanguageServer,
15903        _: &mut Window,
15904        cx: &mut Context<Self>,
15905    ) {
15906        if let Some(project) = self.project.clone() {
15907            self.buffer.update(cx, |multi_buffer, cx| {
15908                project.update(cx, |project, cx| {
15909                    project.stop_language_servers_for_buffers(
15910                        multi_buffer.all_buffers().into_iter().collect(),
15911                        cx,
15912                    );
15913                    cx.emit(project::Event::RefreshInlayHints);
15914                });
15915            });
15916        }
15917    }
15918
15919    fn cancel_language_server_work(
15920        workspace: &mut Workspace,
15921        _: &actions::CancelLanguageServerWork,
15922        _: &mut Window,
15923        cx: &mut Context<Workspace>,
15924    ) {
15925        let project = workspace.project();
15926        let buffers = workspace
15927            .active_item(cx)
15928            .and_then(|item| item.act_as::<Editor>(cx))
15929            .map_or(HashSet::default(), |editor| {
15930                editor.read(cx).buffer.read(cx).all_buffers()
15931            });
15932        project.update(cx, |project, cx| {
15933            project.cancel_language_server_work_for_buffers(buffers, cx);
15934        });
15935    }
15936
15937    fn show_character_palette(
15938        &mut self,
15939        _: &ShowCharacterPalette,
15940        window: &mut Window,
15941        _: &mut Context<Self>,
15942    ) {
15943        window.show_character_palette();
15944    }
15945
15946    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15947        if self.mode.is_minimap() {
15948            return;
15949        }
15950
15951        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15952            let buffer = self.buffer.read(cx).snapshot(cx);
15953            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15954            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15955            let is_valid = buffer
15956                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15957                .any(|entry| {
15958                    entry.diagnostic.is_primary
15959                        && !entry.range.is_empty()
15960                        && entry.range.start == primary_range_start
15961                        && entry.diagnostic.message == active_diagnostics.active_message
15962                });
15963
15964            if !is_valid {
15965                self.dismiss_diagnostics(cx);
15966            }
15967        }
15968    }
15969
15970    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15971        match &self.active_diagnostics {
15972            ActiveDiagnostic::Group(group) => Some(group),
15973            _ => None,
15974        }
15975    }
15976
15977    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15978        self.dismiss_diagnostics(cx);
15979        self.active_diagnostics = ActiveDiagnostic::All;
15980    }
15981
15982    fn activate_diagnostics(
15983        &mut self,
15984        buffer_id: BufferId,
15985        diagnostic: DiagnosticEntry<usize>,
15986        window: &mut Window,
15987        cx: &mut Context<Self>,
15988    ) {
15989        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15990            return;
15991        }
15992        self.dismiss_diagnostics(cx);
15993        let snapshot = self.snapshot(window, cx);
15994        let buffer = self.buffer.read(cx).snapshot(cx);
15995        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15996            return;
15997        };
15998
15999        let diagnostic_group = buffer
16000            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16001            .collect::<Vec<_>>();
16002
16003        let blocks =
16004            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16005
16006        let blocks = self.display_map.update(cx, |display_map, cx| {
16007            display_map.insert_blocks(blocks, cx).into_iter().collect()
16008        });
16009        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16010            active_range: buffer.anchor_before(diagnostic.range.start)
16011                ..buffer.anchor_after(diagnostic.range.end),
16012            active_message: diagnostic.diagnostic.message.clone(),
16013            group_id: diagnostic.diagnostic.group_id,
16014            blocks,
16015        });
16016        cx.notify();
16017    }
16018
16019    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16020        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16021            return;
16022        };
16023
16024        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16025        if let ActiveDiagnostic::Group(group) = prev {
16026            self.display_map.update(cx, |display_map, cx| {
16027                display_map.remove_blocks(group.blocks, cx);
16028            });
16029            cx.notify();
16030        }
16031    }
16032
16033    /// Disable inline diagnostics rendering for this editor.
16034    pub fn disable_inline_diagnostics(&mut self) {
16035        self.inline_diagnostics_enabled = false;
16036        self.inline_diagnostics_update = Task::ready(());
16037        self.inline_diagnostics.clear();
16038    }
16039
16040    pub fn diagnostics_enabled(&self) -> bool {
16041        self.mode.is_full()
16042    }
16043
16044    pub fn inline_diagnostics_enabled(&self) -> bool {
16045        self.diagnostics_enabled() && self.inline_diagnostics_enabled
16046    }
16047
16048    pub fn show_inline_diagnostics(&self) -> bool {
16049        self.show_inline_diagnostics
16050    }
16051
16052    pub fn toggle_inline_diagnostics(
16053        &mut self,
16054        _: &ToggleInlineDiagnostics,
16055        window: &mut Window,
16056        cx: &mut Context<Editor>,
16057    ) {
16058        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16059        self.refresh_inline_diagnostics(false, window, cx);
16060    }
16061
16062    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16063        self.diagnostics_max_severity = severity;
16064        self.display_map.update(cx, |display_map, _| {
16065            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16066        });
16067    }
16068
16069    pub fn toggle_diagnostics(
16070        &mut self,
16071        _: &ToggleDiagnostics,
16072        window: &mut Window,
16073        cx: &mut Context<Editor>,
16074    ) {
16075        if !self.diagnostics_enabled() {
16076            return;
16077        }
16078
16079        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16080            EditorSettings::get_global(cx)
16081                .diagnostics_max_severity
16082                .filter(|severity| severity != &DiagnosticSeverity::Off)
16083                .unwrap_or(DiagnosticSeverity::Hint)
16084        } else {
16085            DiagnosticSeverity::Off
16086        };
16087        self.set_max_diagnostics_severity(new_severity, cx);
16088        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16089            self.active_diagnostics = ActiveDiagnostic::None;
16090            self.inline_diagnostics_update = Task::ready(());
16091            self.inline_diagnostics.clear();
16092        } else {
16093            self.refresh_inline_diagnostics(false, window, cx);
16094        }
16095
16096        cx.notify();
16097    }
16098
16099    pub fn toggle_minimap(
16100        &mut self,
16101        _: &ToggleMinimap,
16102        window: &mut Window,
16103        cx: &mut Context<Editor>,
16104    ) {
16105        if self.supports_minimap(cx) {
16106            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16107        }
16108    }
16109
16110    fn refresh_inline_diagnostics(
16111        &mut self,
16112        debounce: bool,
16113        window: &mut Window,
16114        cx: &mut Context<Self>,
16115    ) {
16116        let max_severity = ProjectSettings::get_global(cx)
16117            .diagnostics
16118            .inline
16119            .max_severity
16120            .unwrap_or(self.diagnostics_max_severity);
16121
16122        if !self.inline_diagnostics_enabled()
16123            || !self.show_inline_diagnostics
16124            || max_severity == DiagnosticSeverity::Off
16125        {
16126            self.inline_diagnostics_update = Task::ready(());
16127            self.inline_diagnostics.clear();
16128            return;
16129        }
16130
16131        let debounce_ms = ProjectSettings::get_global(cx)
16132            .diagnostics
16133            .inline
16134            .update_debounce_ms;
16135        let debounce = if debounce && debounce_ms > 0 {
16136            Some(Duration::from_millis(debounce_ms))
16137        } else {
16138            None
16139        };
16140        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16141            if let Some(debounce) = debounce {
16142                cx.background_executor().timer(debounce).await;
16143            }
16144            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16145                editor
16146                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16147                    .ok()
16148            }) else {
16149                return;
16150            };
16151
16152            let new_inline_diagnostics = cx
16153                .background_spawn(async move {
16154                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16155                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16156                        let message = diagnostic_entry
16157                            .diagnostic
16158                            .message
16159                            .split_once('\n')
16160                            .map(|(line, _)| line)
16161                            .map(SharedString::new)
16162                            .unwrap_or_else(|| {
16163                                SharedString::from(diagnostic_entry.diagnostic.message)
16164                            });
16165                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16166                        let (Ok(i) | Err(i)) = inline_diagnostics
16167                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16168                        inline_diagnostics.insert(
16169                            i,
16170                            (
16171                                start_anchor,
16172                                InlineDiagnostic {
16173                                    message,
16174                                    group_id: diagnostic_entry.diagnostic.group_id,
16175                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16176                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16177                                    severity: diagnostic_entry.diagnostic.severity,
16178                                },
16179                            ),
16180                        );
16181                    }
16182                    inline_diagnostics
16183                })
16184                .await;
16185
16186            editor
16187                .update(cx, |editor, cx| {
16188                    editor.inline_diagnostics = new_inline_diagnostics;
16189                    cx.notify();
16190                })
16191                .ok();
16192        });
16193    }
16194
16195    fn pull_diagnostics(
16196        &mut self,
16197        buffer_id: Option<BufferId>,
16198        window: &Window,
16199        cx: &mut Context<Self>,
16200    ) -> Option<()> {
16201        if !self.mode().is_full() {
16202            return None;
16203        }
16204        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16205            .diagnostics
16206            .lsp_pull_diagnostics;
16207        if !pull_diagnostics_settings.enabled {
16208            return None;
16209        }
16210        let project = self.project.as_ref()?.downgrade();
16211        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16212        let mut buffers = self.buffer.read(cx).all_buffers();
16213        if let Some(buffer_id) = buffer_id {
16214            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16215        }
16216
16217        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16218            cx.background_executor().timer(debounce).await;
16219
16220            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16221                buffers
16222                    .into_iter()
16223                    .flat_map(|buffer| {
16224                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16225                    })
16226                    .collect::<FuturesUnordered<_>>()
16227            }) else {
16228                return;
16229            };
16230
16231            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16232                match pull_task {
16233                    Ok(()) => {
16234                        if editor
16235                            .update_in(cx, |editor, window, cx| {
16236                                editor.update_diagnostics_state(window, cx);
16237                            })
16238                            .is_err()
16239                        {
16240                            return;
16241                        }
16242                    }
16243                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16244                }
16245            }
16246        });
16247
16248        Some(())
16249    }
16250
16251    pub fn set_selections_from_remote(
16252        &mut self,
16253        selections: Vec<Selection<Anchor>>,
16254        pending_selection: Option<Selection<Anchor>>,
16255        window: &mut Window,
16256        cx: &mut Context<Self>,
16257    ) {
16258        let old_cursor_position = self.selections.newest_anchor().head();
16259        self.selections.change_with(cx, |s| {
16260            s.select_anchors(selections);
16261            if let Some(pending_selection) = pending_selection {
16262                s.set_pending(pending_selection, SelectMode::Character);
16263            } else {
16264                s.clear_pending();
16265            }
16266        });
16267        self.selections_did_change(
16268            false,
16269            &old_cursor_position,
16270            SelectionEffects::default(),
16271            window,
16272            cx,
16273        );
16274    }
16275
16276    pub fn transact(
16277        &mut self,
16278        window: &mut Window,
16279        cx: &mut Context<Self>,
16280        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16281    ) -> Option<TransactionId> {
16282        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16283            this.start_transaction_at(Instant::now(), window, cx);
16284            update(this, window, cx);
16285            this.end_transaction_at(Instant::now(), cx)
16286        })
16287    }
16288
16289    pub fn start_transaction_at(
16290        &mut self,
16291        now: Instant,
16292        window: &mut Window,
16293        cx: &mut Context<Self>,
16294    ) {
16295        self.end_selection(window, cx);
16296        if let Some(tx_id) = self
16297            .buffer
16298            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16299        {
16300            self.selection_history
16301                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16302            cx.emit(EditorEvent::TransactionBegun {
16303                transaction_id: tx_id,
16304            })
16305        }
16306    }
16307
16308    pub fn end_transaction_at(
16309        &mut self,
16310        now: Instant,
16311        cx: &mut Context<Self>,
16312    ) -> Option<TransactionId> {
16313        if let Some(transaction_id) = self
16314            .buffer
16315            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16316        {
16317            if let Some((_, end_selections)) =
16318                self.selection_history.transaction_mut(transaction_id)
16319            {
16320                *end_selections = Some(self.selections.disjoint_anchors());
16321            } else {
16322                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16323            }
16324
16325            cx.emit(EditorEvent::Edited { transaction_id });
16326            Some(transaction_id)
16327        } else {
16328            None
16329        }
16330    }
16331
16332    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16333        if self.selection_mark_mode {
16334            self.change_selections(None, window, cx, |s| {
16335                s.move_with(|_, sel| {
16336                    sel.collapse_to(sel.head(), SelectionGoal::None);
16337                });
16338            })
16339        }
16340        self.selection_mark_mode = true;
16341        cx.notify();
16342    }
16343
16344    pub fn swap_selection_ends(
16345        &mut self,
16346        _: &actions::SwapSelectionEnds,
16347        window: &mut Window,
16348        cx: &mut Context<Self>,
16349    ) {
16350        self.change_selections(None, window, cx, |s| {
16351            s.move_with(|_, sel| {
16352                if sel.start != sel.end {
16353                    sel.reversed = !sel.reversed
16354                }
16355            });
16356        });
16357        self.request_autoscroll(Autoscroll::newest(), cx);
16358        cx.notify();
16359    }
16360
16361    pub fn toggle_fold(
16362        &mut self,
16363        _: &actions::ToggleFold,
16364        window: &mut Window,
16365        cx: &mut Context<Self>,
16366    ) {
16367        if self.is_singleton(cx) {
16368            let selection = self.selections.newest::<Point>(cx);
16369
16370            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16371            let range = if selection.is_empty() {
16372                let point = selection.head().to_display_point(&display_map);
16373                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16374                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16375                    .to_point(&display_map);
16376                start..end
16377            } else {
16378                selection.range()
16379            };
16380            if display_map.folds_in_range(range).next().is_some() {
16381                self.unfold_lines(&Default::default(), window, cx)
16382            } else {
16383                self.fold(&Default::default(), window, cx)
16384            }
16385        } else {
16386            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16387            let buffer_ids: HashSet<_> = self
16388                .selections
16389                .disjoint_anchor_ranges()
16390                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16391                .collect();
16392
16393            let should_unfold = buffer_ids
16394                .iter()
16395                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16396
16397            for buffer_id in buffer_ids {
16398                if should_unfold {
16399                    self.unfold_buffer(buffer_id, cx);
16400                } else {
16401                    self.fold_buffer(buffer_id, cx);
16402                }
16403            }
16404        }
16405    }
16406
16407    pub fn toggle_fold_recursive(
16408        &mut self,
16409        _: &actions::ToggleFoldRecursive,
16410        window: &mut Window,
16411        cx: &mut Context<Self>,
16412    ) {
16413        let selection = self.selections.newest::<Point>(cx);
16414
16415        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16416        let range = if selection.is_empty() {
16417            let point = selection.head().to_display_point(&display_map);
16418            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16419            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16420                .to_point(&display_map);
16421            start..end
16422        } else {
16423            selection.range()
16424        };
16425        if display_map.folds_in_range(range).next().is_some() {
16426            self.unfold_recursive(&Default::default(), window, cx)
16427        } else {
16428            self.fold_recursive(&Default::default(), window, cx)
16429        }
16430    }
16431
16432    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16433        if self.is_singleton(cx) {
16434            let mut to_fold = Vec::new();
16435            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16436            let selections = self.selections.all_adjusted(cx);
16437
16438            for selection in selections {
16439                let range = selection.range().sorted();
16440                let buffer_start_row = range.start.row;
16441
16442                if range.start.row != range.end.row {
16443                    let mut found = false;
16444                    let mut row = range.start.row;
16445                    while row <= range.end.row {
16446                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16447                        {
16448                            found = true;
16449                            row = crease.range().end.row + 1;
16450                            to_fold.push(crease);
16451                        } else {
16452                            row += 1
16453                        }
16454                    }
16455                    if found {
16456                        continue;
16457                    }
16458                }
16459
16460                for row in (0..=range.start.row).rev() {
16461                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16462                        if crease.range().end.row >= buffer_start_row {
16463                            to_fold.push(crease);
16464                            if row <= range.start.row {
16465                                break;
16466                            }
16467                        }
16468                    }
16469                }
16470            }
16471
16472            self.fold_creases(to_fold, true, window, cx);
16473        } else {
16474            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16475            let buffer_ids = self
16476                .selections
16477                .disjoint_anchor_ranges()
16478                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16479                .collect::<HashSet<_>>();
16480            for buffer_id in buffer_ids {
16481                self.fold_buffer(buffer_id, cx);
16482            }
16483        }
16484    }
16485
16486    fn fold_at_level(
16487        &mut self,
16488        fold_at: &FoldAtLevel,
16489        window: &mut Window,
16490        cx: &mut Context<Self>,
16491    ) {
16492        if !self.buffer.read(cx).is_singleton() {
16493            return;
16494        }
16495
16496        let fold_at_level = fold_at.0;
16497        let snapshot = self.buffer.read(cx).snapshot(cx);
16498        let mut to_fold = Vec::new();
16499        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16500
16501        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16502            while start_row < end_row {
16503                match self
16504                    .snapshot(window, cx)
16505                    .crease_for_buffer_row(MultiBufferRow(start_row))
16506                {
16507                    Some(crease) => {
16508                        let nested_start_row = crease.range().start.row + 1;
16509                        let nested_end_row = crease.range().end.row;
16510
16511                        if current_level < fold_at_level {
16512                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16513                        } else if current_level == fold_at_level {
16514                            to_fold.push(crease);
16515                        }
16516
16517                        start_row = nested_end_row + 1;
16518                    }
16519                    None => start_row += 1,
16520                }
16521            }
16522        }
16523
16524        self.fold_creases(to_fold, true, window, cx);
16525    }
16526
16527    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16528        if self.buffer.read(cx).is_singleton() {
16529            let mut fold_ranges = Vec::new();
16530            let snapshot = self.buffer.read(cx).snapshot(cx);
16531
16532            for row in 0..snapshot.max_row().0 {
16533                if let Some(foldable_range) = self
16534                    .snapshot(window, cx)
16535                    .crease_for_buffer_row(MultiBufferRow(row))
16536                {
16537                    fold_ranges.push(foldable_range);
16538                }
16539            }
16540
16541            self.fold_creases(fold_ranges, true, window, cx);
16542        } else {
16543            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16544                editor
16545                    .update_in(cx, |editor, _, cx| {
16546                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16547                            editor.fold_buffer(buffer_id, cx);
16548                        }
16549                    })
16550                    .ok();
16551            });
16552        }
16553    }
16554
16555    pub fn fold_function_bodies(
16556        &mut self,
16557        _: &actions::FoldFunctionBodies,
16558        window: &mut Window,
16559        cx: &mut Context<Self>,
16560    ) {
16561        let snapshot = self.buffer.read(cx).snapshot(cx);
16562
16563        let ranges = snapshot
16564            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16565            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16566            .collect::<Vec<_>>();
16567
16568        let creases = ranges
16569            .into_iter()
16570            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16571            .collect();
16572
16573        self.fold_creases(creases, true, window, cx);
16574    }
16575
16576    pub fn fold_recursive(
16577        &mut self,
16578        _: &actions::FoldRecursive,
16579        window: &mut Window,
16580        cx: &mut Context<Self>,
16581    ) {
16582        let mut to_fold = Vec::new();
16583        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16584        let selections = self.selections.all_adjusted(cx);
16585
16586        for selection in selections {
16587            let range = selection.range().sorted();
16588            let buffer_start_row = range.start.row;
16589
16590            if range.start.row != range.end.row {
16591                let mut found = false;
16592                for row in range.start.row..=range.end.row {
16593                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16594                        found = true;
16595                        to_fold.push(crease);
16596                    }
16597                }
16598                if found {
16599                    continue;
16600                }
16601            }
16602
16603            for row in (0..=range.start.row).rev() {
16604                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16605                    if crease.range().end.row >= buffer_start_row {
16606                        to_fold.push(crease);
16607                    } else {
16608                        break;
16609                    }
16610                }
16611            }
16612        }
16613
16614        self.fold_creases(to_fold, true, window, cx);
16615    }
16616
16617    pub fn fold_at(
16618        &mut self,
16619        buffer_row: MultiBufferRow,
16620        window: &mut Window,
16621        cx: &mut Context<Self>,
16622    ) {
16623        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16624
16625        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16626            let autoscroll = self
16627                .selections
16628                .all::<Point>(cx)
16629                .iter()
16630                .any(|selection| crease.range().overlaps(&selection.range()));
16631
16632            self.fold_creases(vec![crease], autoscroll, window, cx);
16633        }
16634    }
16635
16636    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16637        if self.is_singleton(cx) {
16638            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16639            let buffer = &display_map.buffer_snapshot;
16640            let selections = self.selections.all::<Point>(cx);
16641            let ranges = selections
16642                .iter()
16643                .map(|s| {
16644                    let range = s.display_range(&display_map).sorted();
16645                    let mut start = range.start.to_point(&display_map);
16646                    let mut end = range.end.to_point(&display_map);
16647                    start.column = 0;
16648                    end.column = buffer.line_len(MultiBufferRow(end.row));
16649                    start..end
16650                })
16651                .collect::<Vec<_>>();
16652
16653            self.unfold_ranges(&ranges, true, true, cx);
16654        } else {
16655            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16656            let buffer_ids = self
16657                .selections
16658                .disjoint_anchor_ranges()
16659                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16660                .collect::<HashSet<_>>();
16661            for buffer_id in buffer_ids {
16662                self.unfold_buffer(buffer_id, cx);
16663            }
16664        }
16665    }
16666
16667    pub fn unfold_recursive(
16668        &mut self,
16669        _: &UnfoldRecursive,
16670        _window: &mut Window,
16671        cx: &mut Context<Self>,
16672    ) {
16673        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16674        let selections = self.selections.all::<Point>(cx);
16675        let ranges = selections
16676            .iter()
16677            .map(|s| {
16678                let mut range = s.display_range(&display_map).sorted();
16679                *range.start.column_mut() = 0;
16680                *range.end.column_mut() = display_map.line_len(range.end.row());
16681                let start = range.start.to_point(&display_map);
16682                let end = range.end.to_point(&display_map);
16683                start..end
16684            })
16685            .collect::<Vec<_>>();
16686
16687        self.unfold_ranges(&ranges, true, true, cx);
16688    }
16689
16690    pub fn unfold_at(
16691        &mut self,
16692        buffer_row: MultiBufferRow,
16693        _window: &mut Window,
16694        cx: &mut Context<Self>,
16695    ) {
16696        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16697
16698        let intersection_range = Point::new(buffer_row.0, 0)
16699            ..Point::new(
16700                buffer_row.0,
16701                display_map.buffer_snapshot.line_len(buffer_row),
16702            );
16703
16704        let autoscroll = self
16705            .selections
16706            .all::<Point>(cx)
16707            .iter()
16708            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16709
16710        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16711    }
16712
16713    pub fn unfold_all(
16714        &mut self,
16715        _: &actions::UnfoldAll,
16716        _window: &mut Window,
16717        cx: &mut Context<Self>,
16718    ) {
16719        if self.buffer.read(cx).is_singleton() {
16720            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16721            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16722        } else {
16723            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16724                editor
16725                    .update(cx, |editor, cx| {
16726                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16727                            editor.unfold_buffer(buffer_id, cx);
16728                        }
16729                    })
16730                    .ok();
16731            });
16732        }
16733    }
16734
16735    pub fn fold_selected_ranges(
16736        &mut self,
16737        _: &FoldSelectedRanges,
16738        window: &mut Window,
16739        cx: &mut Context<Self>,
16740    ) {
16741        let selections = self.selections.all_adjusted(cx);
16742        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16743        let ranges = selections
16744            .into_iter()
16745            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16746            .collect::<Vec<_>>();
16747        self.fold_creases(ranges, true, window, cx);
16748    }
16749
16750    pub fn fold_ranges<T: ToOffset + Clone>(
16751        &mut self,
16752        ranges: Vec<Range<T>>,
16753        auto_scroll: bool,
16754        window: &mut Window,
16755        cx: &mut Context<Self>,
16756    ) {
16757        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16758        let ranges = ranges
16759            .into_iter()
16760            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16761            .collect::<Vec<_>>();
16762        self.fold_creases(ranges, auto_scroll, window, cx);
16763    }
16764
16765    pub fn fold_creases<T: ToOffset + Clone>(
16766        &mut self,
16767        creases: Vec<Crease<T>>,
16768        auto_scroll: bool,
16769        _window: &mut Window,
16770        cx: &mut Context<Self>,
16771    ) {
16772        if creases.is_empty() {
16773            return;
16774        }
16775
16776        let mut buffers_affected = HashSet::default();
16777        let multi_buffer = self.buffer().read(cx);
16778        for crease in &creases {
16779            if let Some((_, buffer, _)) =
16780                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16781            {
16782                buffers_affected.insert(buffer.read(cx).remote_id());
16783            };
16784        }
16785
16786        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16787
16788        if auto_scroll {
16789            self.request_autoscroll(Autoscroll::fit(), cx);
16790        }
16791
16792        cx.notify();
16793
16794        self.scrollbar_marker_state.dirty = true;
16795        self.folds_did_change(cx);
16796    }
16797
16798    /// Removes any folds whose ranges intersect any of the given ranges.
16799    pub fn unfold_ranges<T: ToOffset + Clone>(
16800        &mut self,
16801        ranges: &[Range<T>],
16802        inclusive: bool,
16803        auto_scroll: bool,
16804        cx: &mut Context<Self>,
16805    ) {
16806        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16807            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16808        });
16809        self.folds_did_change(cx);
16810    }
16811
16812    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16813        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16814            return;
16815        }
16816        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16817        self.display_map.update(cx, |display_map, cx| {
16818            display_map.fold_buffers([buffer_id], cx)
16819        });
16820        cx.emit(EditorEvent::BufferFoldToggled {
16821            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16822            folded: true,
16823        });
16824        cx.notify();
16825    }
16826
16827    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16828        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16829            return;
16830        }
16831        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16832        self.display_map.update(cx, |display_map, cx| {
16833            display_map.unfold_buffers([buffer_id], cx);
16834        });
16835        cx.emit(EditorEvent::BufferFoldToggled {
16836            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16837            folded: false,
16838        });
16839        cx.notify();
16840    }
16841
16842    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16843        self.display_map.read(cx).is_buffer_folded(buffer)
16844    }
16845
16846    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16847        self.display_map.read(cx).folded_buffers()
16848    }
16849
16850    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16851        self.display_map.update(cx, |display_map, cx| {
16852            display_map.disable_header_for_buffer(buffer_id, cx);
16853        });
16854        cx.notify();
16855    }
16856
16857    /// Removes any folds with the given ranges.
16858    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16859        &mut self,
16860        ranges: &[Range<T>],
16861        type_id: TypeId,
16862        auto_scroll: bool,
16863        cx: &mut Context<Self>,
16864    ) {
16865        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16866            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16867        });
16868        self.folds_did_change(cx);
16869    }
16870
16871    fn remove_folds_with<T: ToOffset + Clone>(
16872        &mut self,
16873        ranges: &[Range<T>],
16874        auto_scroll: bool,
16875        cx: &mut Context<Self>,
16876        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16877    ) {
16878        if ranges.is_empty() {
16879            return;
16880        }
16881
16882        let mut buffers_affected = HashSet::default();
16883        let multi_buffer = self.buffer().read(cx);
16884        for range in ranges {
16885            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16886                buffers_affected.insert(buffer.read(cx).remote_id());
16887            };
16888        }
16889
16890        self.display_map.update(cx, update);
16891
16892        if auto_scroll {
16893            self.request_autoscroll(Autoscroll::fit(), cx);
16894        }
16895
16896        cx.notify();
16897        self.scrollbar_marker_state.dirty = true;
16898        self.active_indent_guides_state.dirty = true;
16899    }
16900
16901    pub fn update_fold_widths(
16902        &mut self,
16903        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16904        cx: &mut Context<Self>,
16905    ) -> bool {
16906        self.display_map
16907            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16908    }
16909
16910    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16911        self.display_map.read(cx).fold_placeholder.clone()
16912    }
16913
16914    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16915        self.buffer.update(cx, |buffer, cx| {
16916            buffer.set_all_diff_hunks_expanded(cx);
16917        });
16918    }
16919
16920    pub fn expand_all_diff_hunks(
16921        &mut self,
16922        _: &ExpandAllDiffHunks,
16923        _window: &mut Window,
16924        cx: &mut Context<Self>,
16925    ) {
16926        self.buffer.update(cx, |buffer, cx| {
16927            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16928        });
16929    }
16930
16931    pub fn toggle_selected_diff_hunks(
16932        &mut self,
16933        _: &ToggleSelectedDiffHunks,
16934        _window: &mut Window,
16935        cx: &mut Context<Self>,
16936    ) {
16937        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16938        self.toggle_diff_hunks_in_ranges(ranges, cx);
16939    }
16940
16941    pub fn diff_hunks_in_ranges<'a>(
16942        &'a self,
16943        ranges: &'a [Range<Anchor>],
16944        buffer: &'a MultiBufferSnapshot,
16945    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16946        ranges.iter().flat_map(move |range| {
16947            let end_excerpt_id = range.end.excerpt_id;
16948            let range = range.to_point(buffer);
16949            let mut peek_end = range.end;
16950            if range.end.row < buffer.max_row().0 {
16951                peek_end = Point::new(range.end.row + 1, 0);
16952            }
16953            buffer
16954                .diff_hunks_in_range(range.start..peek_end)
16955                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16956        })
16957    }
16958
16959    pub fn has_stageable_diff_hunks_in_ranges(
16960        &self,
16961        ranges: &[Range<Anchor>],
16962        snapshot: &MultiBufferSnapshot,
16963    ) -> bool {
16964        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16965        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16966    }
16967
16968    pub fn toggle_staged_selected_diff_hunks(
16969        &mut self,
16970        _: &::git::ToggleStaged,
16971        _: &mut Window,
16972        cx: &mut Context<Self>,
16973    ) {
16974        let snapshot = self.buffer.read(cx).snapshot(cx);
16975        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16976        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16977        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16978    }
16979
16980    pub fn set_render_diff_hunk_controls(
16981        &mut self,
16982        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16983        cx: &mut Context<Self>,
16984    ) {
16985        self.render_diff_hunk_controls = render_diff_hunk_controls;
16986        cx.notify();
16987    }
16988
16989    pub fn stage_and_next(
16990        &mut self,
16991        _: &::git::StageAndNext,
16992        window: &mut Window,
16993        cx: &mut Context<Self>,
16994    ) {
16995        self.do_stage_or_unstage_and_next(true, window, cx);
16996    }
16997
16998    pub fn unstage_and_next(
16999        &mut self,
17000        _: &::git::UnstageAndNext,
17001        window: &mut Window,
17002        cx: &mut Context<Self>,
17003    ) {
17004        self.do_stage_or_unstage_and_next(false, window, cx);
17005    }
17006
17007    pub fn stage_or_unstage_diff_hunks(
17008        &mut self,
17009        stage: bool,
17010        ranges: Vec<Range<Anchor>>,
17011        cx: &mut Context<Self>,
17012    ) {
17013        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17014        cx.spawn(async move |this, cx| {
17015            task.await?;
17016            this.update(cx, |this, cx| {
17017                let snapshot = this.buffer.read(cx).snapshot(cx);
17018                let chunk_by = this
17019                    .diff_hunks_in_ranges(&ranges, &snapshot)
17020                    .chunk_by(|hunk| hunk.buffer_id);
17021                for (buffer_id, hunks) in &chunk_by {
17022                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17023                }
17024            })
17025        })
17026        .detach_and_log_err(cx);
17027    }
17028
17029    fn save_buffers_for_ranges_if_needed(
17030        &mut self,
17031        ranges: &[Range<Anchor>],
17032        cx: &mut Context<Editor>,
17033    ) -> Task<Result<()>> {
17034        let multibuffer = self.buffer.read(cx);
17035        let snapshot = multibuffer.read(cx);
17036        let buffer_ids: HashSet<_> = ranges
17037            .iter()
17038            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17039            .collect();
17040        drop(snapshot);
17041
17042        let mut buffers = HashSet::default();
17043        for buffer_id in buffer_ids {
17044            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17045                let buffer = buffer_entity.read(cx);
17046                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17047                {
17048                    buffers.insert(buffer_entity);
17049                }
17050            }
17051        }
17052
17053        if let Some(project) = &self.project {
17054            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17055        } else {
17056            Task::ready(Ok(()))
17057        }
17058    }
17059
17060    fn do_stage_or_unstage_and_next(
17061        &mut self,
17062        stage: bool,
17063        window: &mut Window,
17064        cx: &mut Context<Self>,
17065    ) {
17066        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17067
17068        if ranges.iter().any(|range| range.start != range.end) {
17069            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17070            return;
17071        }
17072
17073        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17074        let snapshot = self.snapshot(window, cx);
17075        let position = self.selections.newest::<Point>(cx).head();
17076        let mut row = snapshot
17077            .buffer_snapshot
17078            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17079            .find(|hunk| hunk.row_range.start.0 > position.row)
17080            .map(|hunk| hunk.row_range.start);
17081
17082        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17083        // Outside of the project diff editor, wrap around to the beginning.
17084        if !all_diff_hunks_expanded {
17085            row = row.or_else(|| {
17086                snapshot
17087                    .buffer_snapshot
17088                    .diff_hunks_in_range(Point::zero()..position)
17089                    .find(|hunk| hunk.row_range.end.0 < position.row)
17090                    .map(|hunk| hunk.row_range.start)
17091            });
17092        }
17093
17094        if let Some(row) = row {
17095            let destination = Point::new(row.0, 0);
17096            let autoscroll = Autoscroll::center();
17097
17098            self.unfold_ranges(&[destination..destination], false, false, cx);
17099            self.change_selections(Some(autoscroll), window, cx, |s| {
17100                s.select_ranges([destination..destination]);
17101            });
17102        }
17103    }
17104
17105    fn do_stage_or_unstage(
17106        &self,
17107        stage: bool,
17108        buffer_id: BufferId,
17109        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17110        cx: &mut App,
17111    ) -> Option<()> {
17112        let project = self.project.as_ref()?;
17113        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17114        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17115        let buffer_snapshot = buffer.read(cx).snapshot();
17116        let file_exists = buffer_snapshot
17117            .file()
17118            .is_some_and(|file| file.disk_state().exists());
17119        diff.update(cx, |diff, cx| {
17120            diff.stage_or_unstage_hunks(
17121                stage,
17122                &hunks
17123                    .map(|hunk| buffer_diff::DiffHunk {
17124                        buffer_range: hunk.buffer_range,
17125                        diff_base_byte_range: hunk.diff_base_byte_range,
17126                        secondary_status: hunk.secondary_status,
17127                        range: Point::zero()..Point::zero(), // unused
17128                    })
17129                    .collect::<Vec<_>>(),
17130                &buffer_snapshot,
17131                file_exists,
17132                cx,
17133            )
17134        });
17135        None
17136    }
17137
17138    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17139        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17140        self.buffer
17141            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17142    }
17143
17144    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17145        self.buffer.update(cx, |buffer, cx| {
17146            let ranges = vec![Anchor::min()..Anchor::max()];
17147            if !buffer.all_diff_hunks_expanded()
17148                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17149            {
17150                buffer.collapse_diff_hunks(ranges, cx);
17151                true
17152            } else {
17153                false
17154            }
17155        })
17156    }
17157
17158    fn toggle_diff_hunks_in_ranges(
17159        &mut self,
17160        ranges: Vec<Range<Anchor>>,
17161        cx: &mut Context<Editor>,
17162    ) {
17163        self.buffer.update(cx, |buffer, cx| {
17164            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17165            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17166        })
17167    }
17168
17169    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17170        self.buffer.update(cx, |buffer, cx| {
17171            let snapshot = buffer.snapshot(cx);
17172            let excerpt_id = range.end.excerpt_id;
17173            let point_range = range.to_point(&snapshot);
17174            let expand = !buffer.single_hunk_is_expanded(range, cx);
17175            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17176        })
17177    }
17178
17179    pub(crate) fn apply_all_diff_hunks(
17180        &mut self,
17181        _: &ApplyAllDiffHunks,
17182        window: &mut Window,
17183        cx: &mut Context<Self>,
17184    ) {
17185        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17186
17187        let buffers = self.buffer.read(cx).all_buffers();
17188        for branch_buffer in buffers {
17189            branch_buffer.update(cx, |branch_buffer, cx| {
17190                branch_buffer.merge_into_base(Vec::new(), cx);
17191            });
17192        }
17193
17194        if let Some(project) = self.project.clone() {
17195            self.save(
17196                SaveOptions {
17197                    format: true,
17198                    autosave: false,
17199                },
17200                project,
17201                window,
17202                cx,
17203            )
17204            .detach_and_log_err(cx);
17205        }
17206    }
17207
17208    pub(crate) fn apply_selected_diff_hunks(
17209        &mut self,
17210        _: &ApplyDiffHunk,
17211        window: &mut Window,
17212        cx: &mut Context<Self>,
17213    ) {
17214        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17215        let snapshot = self.snapshot(window, cx);
17216        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17217        let mut ranges_by_buffer = HashMap::default();
17218        self.transact(window, cx, |editor, _window, cx| {
17219            for hunk in hunks {
17220                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17221                    ranges_by_buffer
17222                        .entry(buffer.clone())
17223                        .or_insert_with(Vec::new)
17224                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17225                }
17226            }
17227
17228            for (buffer, ranges) in ranges_by_buffer {
17229                buffer.update(cx, |buffer, cx| {
17230                    buffer.merge_into_base(ranges, cx);
17231                });
17232            }
17233        });
17234
17235        if let Some(project) = self.project.clone() {
17236            self.save(
17237                SaveOptions {
17238                    format: true,
17239                    autosave: false,
17240                },
17241                project,
17242                window,
17243                cx,
17244            )
17245            .detach_and_log_err(cx);
17246        }
17247    }
17248
17249    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17250        if hovered != self.gutter_hovered {
17251            self.gutter_hovered = hovered;
17252            cx.notify();
17253        }
17254    }
17255
17256    pub fn insert_blocks(
17257        &mut self,
17258        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17259        autoscroll: Option<Autoscroll>,
17260        cx: &mut Context<Self>,
17261    ) -> Vec<CustomBlockId> {
17262        let blocks = self
17263            .display_map
17264            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17265        if let Some(autoscroll) = autoscroll {
17266            self.request_autoscroll(autoscroll, cx);
17267        }
17268        cx.notify();
17269        blocks
17270    }
17271
17272    pub fn resize_blocks(
17273        &mut self,
17274        heights: HashMap<CustomBlockId, u32>,
17275        autoscroll: Option<Autoscroll>,
17276        cx: &mut Context<Self>,
17277    ) {
17278        self.display_map
17279            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17280        if let Some(autoscroll) = autoscroll {
17281            self.request_autoscroll(autoscroll, cx);
17282        }
17283        cx.notify();
17284    }
17285
17286    pub fn replace_blocks(
17287        &mut self,
17288        renderers: HashMap<CustomBlockId, RenderBlock>,
17289        autoscroll: Option<Autoscroll>,
17290        cx: &mut Context<Self>,
17291    ) {
17292        self.display_map
17293            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17294        if let Some(autoscroll) = autoscroll {
17295            self.request_autoscroll(autoscroll, cx);
17296        }
17297        cx.notify();
17298    }
17299
17300    pub fn remove_blocks(
17301        &mut self,
17302        block_ids: HashSet<CustomBlockId>,
17303        autoscroll: Option<Autoscroll>,
17304        cx: &mut Context<Self>,
17305    ) {
17306        self.display_map.update(cx, |display_map, cx| {
17307            display_map.remove_blocks(block_ids, cx)
17308        });
17309        if let Some(autoscroll) = autoscroll {
17310            self.request_autoscroll(autoscroll, cx);
17311        }
17312        cx.notify();
17313    }
17314
17315    pub fn row_for_block(
17316        &self,
17317        block_id: CustomBlockId,
17318        cx: &mut Context<Self>,
17319    ) -> Option<DisplayRow> {
17320        self.display_map
17321            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17322    }
17323
17324    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17325        self.focused_block = Some(focused_block);
17326    }
17327
17328    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17329        self.focused_block.take()
17330    }
17331
17332    pub fn insert_creases(
17333        &mut self,
17334        creases: impl IntoIterator<Item = Crease<Anchor>>,
17335        cx: &mut Context<Self>,
17336    ) -> Vec<CreaseId> {
17337        self.display_map
17338            .update(cx, |map, cx| map.insert_creases(creases, cx))
17339    }
17340
17341    pub fn remove_creases(
17342        &mut self,
17343        ids: impl IntoIterator<Item = CreaseId>,
17344        cx: &mut Context<Self>,
17345    ) -> Vec<(CreaseId, Range<Anchor>)> {
17346        self.display_map
17347            .update(cx, |map, cx| map.remove_creases(ids, cx))
17348    }
17349
17350    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17351        self.display_map
17352            .update(cx, |map, cx| map.snapshot(cx))
17353            .longest_row()
17354    }
17355
17356    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17357        self.display_map
17358            .update(cx, |map, cx| map.snapshot(cx))
17359            .max_point()
17360    }
17361
17362    pub fn text(&self, cx: &App) -> String {
17363        self.buffer.read(cx).read(cx).text()
17364    }
17365
17366    pub fn is_empty(&self, cx: &App) -> bool {
17367        self.buffer.read(cx).read(cx).is_empty()
17368    }
17369
17370    pub fn text_option(&self, cx: &App) -> Option<String> {
17371        let text = self.text(cx);
17372        let text = text.trim();
17373
17374        if text.is_empty() {
17375            return None;
17376        }
17377
17378        Some(text.to_string())
17379    }
17380
17381    pub fn set_text(
17382        &mut self,
17383        text: impl Into<Arc<str>>,
17384        window: &mut Window,
17385        cx: &mut Context<Self>,
17386    ) {
17387        self.transact(window, cx, |this, _, cx| {
17388            this.buffer
17389                .read(cx)
17390                .as_singleton()
17391                .expect("you can only call set_text on editors for singleton buffers")
17392                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17393        });
17394    }
17395
17396    pub fn display_text(&self, cx: &mut App) -> String {
17397        self.display_map
17398            .update(cx, |map, cx| map.snapshot(cx))
17399            .text()
17400    }
17401
17402    fn create_minimap(
17403        &self,
17404        minimap_settings: MinimapSettings,
17405        window: &mut Window,
17406        cx: &mut Context<Self>,
17407    ) -> Option<Entity<Self>> {
17408        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17409            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17410    }
17411
17412    fn initialize_new_minimap(
17413        &self,
17414        minimap_settings: MinimapSettings,
17415        window: &mut Window,
17416        cx: &mut Context<Self>,
17417    ) -> Entity<Self> {
17418        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17419
17420        let mut minimap = Editor::new_internal(
17421            EditorMode::Minimap {
17422                parent: cx.weak_entity(),
17423            },
17424            self.buffer.clone(),
17425            self.project.clone(),
17426            Some(self.display_map.clone()),
17427            window,
17428            cx,
17429        );
17430        minimap.scroll_manager.clone_state(&self.scroll_manager);
17431        minimap.set_text_style_refinement(TextStyleRefinement {
17432            font_size: Some(MINIMAP_FONT_SIZE),
17433            font_weight: Some(MINIMAP_FONT_WEIGHT),
17434            ..Default::default()
17435        });
17436        minimap.update_minimap_configuration(minimap_settings, cx);
17437        cx.new(|_| minimap)
17438    }
17439
17440    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17441        let current_line_highlight = minimap_settings
17442            .current_line_highlight
17443            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17444        self.set_current_line_highlight(Some(current_line_highlight));
17445    }
17446
17447    pub fn minimap(&self) -> Option<&Entity<Self>> {
17448        self.minimap
17449            .as_ref()
17450            .filter(|_| self.minimap_visibility.visible())
17451    }
17452
17453    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17454        let mut wrap_guides = smallvec![];
17455
17456        if self.show_wrap_guides == Some(false) {
17457            return wrap_guides;
17458        }
17459
17460        let settings = self.buffer.read(cx).language_settings(cx);
17461        if settings.show_wrap_guides {
17462            match self.soft_wrap_mode(cx) {
17463                SoftWrap::Column(soft_wrap) => {
17464                    wrap_guides.push((soft_wrap as usize, true));
17465                }
17466                SoftWrap::Bounded(soft_wrap) => {
17467                    wrap_guides.push((soft_wrap as usize, true));
17468                }
17469                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17470            }
17471            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17472        }
17473
17474        wrap_guides
17475    }
17476
17477    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17478        let settings = self.buffer.read(cx).language_settings(cx);
17479        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17480        match mode {
17481            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17482                SoftWrap::None
17483            }
17484            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17485            language_settings::SoftWrap::PreferredLineLength => {
17486                SoftWrap::Column(settings.preferred_line_length)
17487            }
17488            language_settings::SoftWrap::Bounded => {
17489                SoftWrap::Bounded(settings.preferred_line_length)
17490            }
17491        }
17492    }
17493
17494    pub fn set_soft_wrap_mode(
17495        &mut self,
17496        mode: language_settings::SoftWrap,
17497
17498        cx: &mut Context<Self>,
17499    ) {
17500        self.soft_wrap_mode_override = Some(mode);
17501        cx.notify();
17502    }
17503
17504    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17505        self.hard_wrap = hard_wrap;
17506        cx.notify();
17507    }
17508
17509    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17510        self.text_style_refinement = Some(style);
17511    }
17512
17513    /// called by the Element so we know what style we were most recently rendered with.
17514    pub(crate) fn set_style(
17515        &mut self,
17516        style: EditorStyle,
17517        window: &mut Window,
17518        cx: &mut Context<Self>,
17519    ) {
17520        // We intentionally do not inform the display map about the minimap style
17521        // so that wrapping is not recalculated and stays consistent for the editor
17522        // and its linked minimap.
17523        if !self.mode.is_minimap() {
17524            let rem_size = window.rem_size();
17525            self.display_map.update(cx, |map, cx| {
17526                map.set_font(
17527                    style.text.font(),
17528                    style.text.font_size.to_pixels(rem_size),
17529                    cx,
17530                )
17531            });
17532        }
17533        self.style = Some(style);
17534    }
17535
17536    pub fn style(&self) -> Option<&EditorStyle> {
17537        self.style.as_ref()
17538    }
17539
17540    // Called by the element. This method is not designed to be called outside of the editor
17541    // element's layout code because it does not notify when rewrapping is computed synchronously.
17542    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17543        self.display_map
17544            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17545    }
17546
17547    pub fn set_soft_wrap(&mut self) {
17548        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17549    }
17550
17551    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17552        if self.soft_wrap_mode_override.is_some() {
17553            self.soft_wrap_mode_override.take();
17554        } else {
17555            let soft_wrap = match self.soft_wrap_mode(cx) {
17556                SoftWrap::GitDiff => return,
17557                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17558                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17559                    language_settings::SoftWrap::None
17560                }
17561            };
17562            self.soft_wrap_mode_override = Some(soft_wrap);
17563        }
17564        cx.notify();
17565    }
17566
17567    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17568        let Some(workspace) = self.workspace() else {
17569            return;
17570        };
17571        let fs = workspace.read(cx).app_state().fs.clone();
17572        let current_show = TabBarSettings::get_global(cx).show;
17573        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17574            setting.show = Some(!current_show);
17575        });
17576    }
17577
17578    pub fn toggle_indent_guides(
17579        &mut self,
17580        _: &ToggleIndentGuides,
17581        _: &mut Window,
17582        cx: &mut Context<Self>,
17583    ) {
17584        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17585            self.buffer
17586                .read(cx)
17587                .language_settings(cx)
17588                .indent_guides
17589                .enabled
17590        });
17591        self.show_indent_guides = Some(!currently_enabled);
17592        cx.notify();
17593    }
17594
17595    fn should_show_indent_guides(&self) -> Option<bool> {
17596        self.show_indent_guides
17597    }
17598
17599    pub fn toggle_line_numbers(
17600        &mut self,
17601        _: &ToggleLineNumbers,
17602        _: &mut Window,
17603        cx: &mut Context<Self>,
17604    ) {
17605        let mut editor_settings = EditorSettings::get_global(cx).clone();
17606        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17607        EditorSettings::override_global(editor_settings, cx);
17608    }
17609
17610    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17611        if let Some(show_line_numbers) = self.show_line_numbers {
17612            return show_line_numbers;
17613        }
17614        EditorSettings::get_global(cx).gutter.line_numbers
17615    }
17616
17617    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17618        self.use_relative_line_numbers
17619            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17620    }
17621
17622    pub fn toggle_relative_line_numbers(
17623        &mut self,
17624        _: &ToggleRelativeLineNumbers,
17625        _: &mut Window,
17626        cx: &mut Context<Self>,
17627    ) {
17628        let is_relative = self.should_use_relative_line_numbers(cx);
17629        self.set_relative_line_number(Some(!is_relative), cx)
17630    }
17631
17632    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17633        self.use_relative_line_numbers = is_relative;
17634        cx.notify();
17635    }
17636
17637    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17638        self.show_gutter = show_gutter;
17639        cx.notify();
17640    }
17641
17642    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17643        self.show_scrollbars = ScrollbarAxes {
17644            horizontal: show,
17645            vertical: show,
17646        };
17647        cx.notify();
17648    }
17649
17650    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17651        self.show_scrollbars.vertical = show;
17652        cx.notify();
17653    }
17654
17655    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17656        self.show_scrollbars.horizontal = show;
17657        cx.notify();
17658    }
17659
17660    pub fn set_minimap_visibility(
17661        &mut self,
17662        minimap_visibility: MinimapVisibility,
17663        window: &mut Window,
17664        cx: &mut Context<Self>,
17665    ) {
17666        if self.minimap_visibility != minimap_visibility {
17667            if minimap_visibility.visible() && self.minimap.is_none() {
17668                let minimap_settings = EditorSettings::get_global(cx).minimap;
17669                self.minimap =
17670                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17671            }
17672            self.minimap_visibility = minimap_visibility;
17673            cx.notify();
17674        }
17675    }
17676
17677    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17678        self.set_show_scrollbars(false, cx);
17679        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17680    }
17681
17682    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17683        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17684    }
17685
17686    /// Normally the text in full mode and auto height editors is padded on the
17687    /// left side by roughly half a character width for improved hit testing.
17688    ///
17689    /// Use this method to disable this for cases where this is not wanted (e.g.
17690    /// if you want to align the editor text with some other text above or below)
17691    /// or if you want to add this padding to single-line editors.
17692    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17693        self.offset_content = offset_content;
17694        cx.notify();
17695    }
17696
17697    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17698        self.show_line_numbers = Some(show_line_numbers);
17699        cx.notify();
17700    }
17701
17702    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17703        self.disable_expand_excerpt_buttons = true;
17704        cx.notify();
17705    }
17706
17707    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17708        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17709        cx.notify();
17710    }
17711
17712    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17713        self.show_code_actions = Some(show_code_actions);
17714        cx.notify();
17715    }
17716
17717    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17718        self.show_runnables = Some(show_runnables);
17719        cx.notify();
17720    }
17721
17722    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17723        self.show_breakpoints = Some(show_breakpoints);
17724        cx.notify();
17725    }
17726
17727    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17728        if self.display_map.read(cx).masked != masked {
17729            self.display_map.update(cx, |map, _| map.masked = masked);
17730        }
17731        cx.notify()
17732    }
17733
17734    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17735        self.show_wrap_guides = Some(show_wrap_guides);
17736        cx.notify();
17737    }
17738
17739    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17740        self.show_indent_guides = Some(show_indent_guides);
17741        cx.notify();
17742    }
17743
17744    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17745        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17746            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17747                if let Some(dir) = file.abs_path(cx).parent() {
17748                    return Some(dir.to_owned());
17749                }
17750            }
17751
17752            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17753                return Some(project_path.path.to_path_buf());
17754            }
17755        }
17756
17757        None
17758    }
17759
17760    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17761        self.active_excerpt(cx)?
17762            .1
17763            .read(cx)
17764            .file()
17765            .and_then(|f| f.as_local())
17766    }
17767
17768    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17769        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17770            let buffer = buffer.read(cx);
17771            if let Some(project_path) = buffer.project_path(cx) {
17772                let project = self.project.as_ref()?.read(cx);
17773                project.absolute_path(&project_path, cx)
17774            } else {
17775                buffer
17776                    .file()
17777                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17778            }
17779        })
17780    }
17781
17782    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17783        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17784            let project_path = buffer.read(cx).project_path(cx)?;
17785            let project = self.project.as_ref()?.read(cx);
17786            let entry = project.entry_for_path(&project_path, cx)?;
17787            let path = entry.path.to_path_buf();
17788            Some(path)
17789        })
17790    }
17791
17792    pub fn reveal_in_finder(
17793        &mut self,
17794        _: &RevealInFileManager,
17795        _window: &mut Window,
17796        cx: &mut Context<Self>,
17797    ) {
17798        if let Some(target) = self.target_file(cx) {
17799            cx.reveal_path(&target.abs_path(cx));
17800        }
17801    }
17802
17803    pub fn copy_path(
17804        &mut self,
17805        _: &zed_actions::workspace::CopyPath,
17806        _window: &mut Window,
17807        cx: &mut Context<Self>,
17808    ) {
17809        if let Some(path) = self.target_file_abs_path(cx) {
17810            if let Some(path) = path.to_str() {
17811                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17812            }
17813        }
17814    }
17815
17816    pub fn copy_relative_path(
17817        &mut self,
17818        _: &zed_actions::workspace::CopyRelativePath,
17819        _window: &mut Window,
17820        cx: &mut Context<Self>,
17821    ) {
17822        if let Some(path) = self.target_file_path(cx) {
17823            if let Some(path) = path.to_str() {
17824                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17825            }
17826        }
17827    }
17828
17829    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17830        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17831            buffer.read(cx).project_path(cx)
17832        } else {
17833            None
17834        }
17835    }
17836
17837    // Returns true if the editor handled a go-to-line request
17838    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17839        maybe!({
17840            let breakpoint_store = self.breakpoint_store.as_ref()?;
17841
17842            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17843            else {
17844                self.clear_row_highlights::<ActiveDebugLine>();
17845                return None;
17846            };
17847
17848            let position = active_stack_frame.position;
17849            let buffer_id = position.buffer_id?;
17850            let snapshot = self
17851                .project
17852                .as_ref()?
17853                .read(cx)
17854                .buffer_for_id(buffer_id, cx)?
17855                .read(cx)
17856                .snapshot();
17857
17858            let mut handled = false;
17859            for (id, ExcerptRange { context, .. }) in
17860                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17861            {
17862                if context.start.cmp(&position, &snapshot).is_ge()
17863                    || context.end.cmp(&position, &snapshot).is_lt()
17864                {
17865                    continue;
17866                }
17867                let snapshot = self.buffer.read(cx).snapshot(cx);
17868                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17869
17870                handled = true;
17871                self.clear_row_highlights::<ActiveDebugLine>();
17872
17873                self.go_to_line::<ActiveDebugLine>(
17874                    multibuffer_anchor,
17875                    Some(cx.theme().colors().editor_debugger_active_line_background),
17876                    window,
17877                    cx,
17878                );
17879
17880                cx.notify();
17881            }
17882
17883            handled.then_some(())
17884        })
17885        .is_some()
17886    }
17887
17888    pub fn copy_file_name_without_extension(
17889        &mut self,
17890        _: &CopyFileNameWithoutExtension,
17891        _: &mut Window,
17892        cx: &mut Context<Self>,
17893    ) {
17894        if let Some(file) = self.target_file(cx) {
17895            if let Some(file_stem) = file.path().file_stem() {
17896                if let Some(name) = file_stem.to_str() {
17897                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17898                }
17899            }
17900        }
17901    }
17902
17903    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17904        if let Some(file) = self.target_file(cx) {
17905            if let Some(file_name) = file.path().file_name() {
17906                if let Some(name) = file_name.to_str() {
17907                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17908                }
17909            }
17910        }
17911    }
17912
17913    pub fn toggle_git_blame(
17914        &mut self,
17915        _: &::git::Blame,
17916        window: &mut Window,
17917        cx: &mut Context<Self>,
17918    ) {
17919        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17920
17921        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17922            self.start_git_blame(true, window, cx);
17923        }
17924
17925        cx.notify();
17926    }
17927
17928    pub fn toggle_git_blame_inline(
17929        &mut self,
17930        _: &ToggleGitBlameInline,
17931        window: &mut Window,
17932        cx: &mut Context<Self>,
17933    ) {
17934        self.toggle_git_blame_inline_internal(true, window, cx);
17935        cx.notify();
17936    }
17937
17938    pub fn open_git_blame_commit(
17939        &mut self,
17940        _: &OpenGitBlameCommit,
17941        window: &mut Window,
17942        cx: &mut Context<Self>,
17943    ) {
17944        self.open_git_blame_commit_internal(window, cx);
17945    }
17946
17947    fn open_git_blame_commit_internal(
17948        &mut self,
17949        window: &mut Window,
17950        cx: &mut Context<Self>,
17951    ) -> Option<()> {
17952        let blame = self.blame.as_ref()?;
17953        let snapshot = self.snapshot(window, cx);
17954        let cursor = self.selections.newest::<Point>(cx).head();
17955        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17956        let blame_entry = blame
17957            .update(cx, |blame, cx| {
17958                blame
17959                    .blame_for_rows(
17960                        &[RowInfo {
17961                            buffer_id: Some(buffer.remote_id()),
17962                            buffer_row: Some(point.row),
17963                            ..Default::default()
17964                        }],
17965                        cx,
17966                    )
17967                    .next()
17968            })
17969            .flatten()?;
17970        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17971        let repo = blame.read(cx).repository(cx)?;
17972        let workspace = self.workspace()?.downgrade();
17973        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17974        None
17975    }
17976
17977    pub fn git_blame_inline_enabled(&self) -> bool {
17978        self.git_blame_inline_enabled
17979    }
17980
17981    pub fn toggle_selection_menu(
17982        &mut self,
17983        _: &ToggleSelectionMenu,
17984        _: &mut Window,
17985        cx: &mut Context<Self>,
17986    ) {
17987        self.show_selection_menu = self
17988            .show_selection_menu
17989            .map(|show_selections_menu| !show_selections_menu)
17990            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17991
17992        cx.notify();
17993    }
17994
17995    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17996        self.show_selection_menu
17997            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17998    }
17999
18000    fn start_git_blame(
18001        &mut self,
18002        user_triggered: bool,
18003        window: &mut Window,
18004        cx: &mut Context<Self>,
18005    ) {
18006        if let Some(project) = self.project.as_ref() {
18007            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18008                return;
18009            };
18010
18011            if buffer.read(cx).file().is_none() {
18012                return;
18013            }
18014
18015            let focused = self.focus_handle(cx).contains_focused(window, cx);
18016
18017            let project = project.clone();
18018            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18019            self.blame_subscription =
18020                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18021            self.blame = Some(blame);
18022        }
18023    }
18024
18025    fn toggle_git_blame_inline_internal(
18026        &mut self,
18027        user_triggered: bool,
18028        window: &mut Window,
18029        cx: &mut Context<Self>,
18030    ) {
18031        if self.git_blame_inline_enabled {
18032            self.git_blame_inline_enabled = false;
18033            self.show_git_blame_inline = false;
18034            self.show_git_blame_inline_delay_task.take();
18035        } else {
18036            self.git_blame_inline_enabled = true;
18037            self.start_git_blame_inline(user_triggered, window, cx);
18038        }
18039
18040        cx.notify();
18041    }
18042
18043    fn start_git_blame_inline(
18044        &mut self,
18045        user_triggered: bool,
18046        window: &mut Window,
18047        cx: &mut Context<Self>,
18048    ) {
18049        self.start_git_blame(user_triggered, window, cx);
18050
18051        if ProjectSettings::get_global(cx)
18052            .git
18053            .inline_blame_delay()
18054            .is_some()
18055        {
18056            self.start_inline_blame_timer(window, cx);
18057        } else {
18058            self.show_git_blame_inline = true
18059        }
18060    }
18061
18062    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18063        self.blame.as_ref()
18064    }
18065
18066    pub fn show_git_blame_gutter(&self) -> bool {
18067        self.show_git_blame_gutter
18068    }
18069
18070    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18071        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18072    }
18073
18074    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18075        self.show_git_blame_inline
18076            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18077            && !self.newest_selection_head_on_empty_line(cx)
18078            && self.has_blame_entries(cx)
18079    }
18080
18081    fn has_blame_entries(&self, cx: &App) -> bool {
18082        self.blame()
18083            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18084    }
18085
18086    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18087        let cursor_anchor = self.selections.newest_anchor().head();
18088
18089        let snapshot = self.buffer.read(cx).snapshot(cx);
18090        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18091
18092        snapshot.line_len(buffer_row) == 0
18093    }
18094
18095    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18096        let buffer_and_selection = maybe!({
18097            let selection = self.selections.newest::<Point>(cx);
18098            let selection_range = selection.range();
18099
18100            let multi_buffer = self.buffer().read(cx);
18101            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18102            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18103
18104            let (buffer, range, _) = if selection.reversed {
18105                buffer_ranges.first()
18106            } else {
18107                buffer_ranges.last()
18108            }?;
18109
18110            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18111                ..text::ToPoint::to_point(&range.end, &buffer).row;
18112            Some((
18113                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18114                selection,
18115            ))
18116        });
18117
18118        let Some((buffer, selection)) = buffer_and_selection else {
18119            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18120        };
18121
18122        let Some(project) = self.project.as_ref() else {
18123            return Task::ready(Err(anyhow!("editor does not have project")));
18124        };
18125
18126        project.update(cx, |project, cx| {
18127            project.get_permalink_to_line(&buffer, selection, cx)
18128        })
18129    }
18130
18131    pub fn copy_permalink_to_line(
18132        &mut self,
18133        _: &CopyPermalinkToLine,
18134        window: &mut Window,
18135        cx: &mut Context<Self>,
18136    ) {
18137        let permalink_task = self.get_permalink_to_line(cx);
18138        let workspace = self.workspace();
18139
18140        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18141            Ok(permalink) => {
18142                cx.update(|_, cx| {
18143                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18144                })
18145                .ok();
18146            }
18147            Err(err) => {
18148                let message = format!("Failed to copy permalink: {err}");
18149
18150                anyhow::Result::<()>::Err(err).log_err();
18151
18152                if let Some(workspace) = workspace {
18153                    workspace
18154                        .update_in(cx, |workspace, _, cx| {
18155                            struct CopyPermalinkToLine;
18156
18157                            workspace.show_toast(
18158                                Toast::new(
18159                                    NotificationId::unique::<CopyPermalinkToLine>(),
18160                                    message,
18161                                ),
18162                                cx,
18163                            )
18164                        })
18165                        .ok();
18166                }
18167            }
18168        })
18169        .detach();
18170    }
18171
18172    pub fn copy_file_location(
18173        &mut self,
18174        _: &CopyFileLocation,
18175        _: &mut Window,
18176        cx: &mut Context<Self>,
18177    ) {
18178        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18179        if let Some(file) = self.target_file(cx) {
18180            if let Some(path) = file.path().to_str() {
18181                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18182            }
18183        }
18184    }
18185
18186    pub fn open_permalink_to_line(
18187        &mut self,
18188        _: &OpenPermalinkToLine,
18189        window: &mut Window,
18190        cx: &mut Context<Self>,
18191    ) {
18192        let permalink_task = self.get_permalink_to_line(cx);
18193        let workspace = self.workspace();
18194
18195        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18196            Ok(permalink) => {
18197                cx.update(|_, cx| {
18198                    cx.open_url(permalink.as_ref());
18199                })
18200                .ok();
18201            }
18202            Err(err) => {
18203                let message = format!("Failed to open permalink: {err}");
18204
18205                anyhow::Result::<()>::Err(err).log_err();
18206
18207                if let Some(workspace) = workspace {
18208                    workspace
18209                        .update(cx, |workspace, cx| {
18210                            struct OpenPermalinkToLine;
18211
18212                            workspace.show_toast(
18213                                Toast::new(
18214                                    NotificationId::unique::<OpenPermalinkToLine>(),
18215                                    message,
18216                                ),
18217                                cx,
18218                            )
18219                        })
18220                        .ok();
18221                }
18222            }
18223        })
18224        .detach();
18225    }
18226
18227    pub fn insert_uuid_v4(
18228        &mut self,
18229        _: &InsertUuidV4,
18230        window: &mut Window,
18231        cx: &mut Context<Self>,
18232    ) {
18233        self.insert_uuid(UuidVersion::V4, window, cx);
18234    }
18235
18236    pub fn insert_uuid_v7(
18237        &mut self,
18238        _: &InsertUuidV7,
18239        window: &mut Window,
18240        cx: &mut Context<Self>,
18241    ) {
18242        self.insert_uuid(UuidVersion::V7, window, cx);
18243    }
18244
18245    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18246        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18247        self.transact(window, cx, |this, window, cx| {
18248            let edits = this
18249                .selections
18250                .all::<Point>(cx)
18251                .into_iter()
18252                .map(|selection| {
18253                    let uuid = match version {
18254                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18255                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18256                    };
18257
18258                    (selection.range(), uuid.to_string())
18259                });
18260            this.edit(edits, cx);
18261            this.refresh_inline_completion(true, false, window, cx);
18262        });
18263    }
18264
18265    pub fn open_selections_in_multibuffer(
18266        &mut self,
18267        _: &OpenSelectionsInMultibuffer,
18268        window: &mut Window,
18269        cx: &mut Context<Self>,
18270    ) {
18271        let multibuffer = self.buffer.read(cx);
18272
18273        let Some(buffer) = multibuffer.as_singleton() else {
18274            return;
18275        };
18276
18277        let Some(workspace) = self.workspace() else {
18278            return;
18279        };
18280
18281        let locations = self
18282            .selections
18283            .disjoint_anchors()
18284            .iter()
18285            .map(|range| Location {
18286                buffer: buffer.clone(),
18287                range: range.start.text_anchor..range.end.text_anchor,
18288            })
18289            .collect::<Vec<_>>();
18290
18291        let title = multibuffer.title(cx).to_string();
18292
18293        cx.spawn_in(window, async move |_, cx| {
18294            workspace.update_in(cx, |workspace, window, cx| {
18295                Self::open_locations_in_multibuffer(
18296                    workspace,
18297                    locations,
18298                    format!("Selections for '{title}'"),
18299                    false,
18300                    MultibufferSelectionMode::All,
18301                    window,
18302                    cx,
18303                );
18304            })
18305        })
18306        .detach();
18307    }
18308
18309    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18310    /// last highlight added will be used.
18311    ///
18312    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18313    pub fn highlight_rows<T: 'static>(
18314        &mut self,
18315        range: Range<Anchor>,
18316        color: Hsla,
18317        options: RowHighlightOptions,
18318        cx: &mut Context<Self>,
18319    ) {
18320        let snapshot = self.buffer().read(cx).snapshot(cx);
18321        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18322        let ix = row_highlights.binary_search_by(|highlight| {
18323            Ordering::Equal
18324                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18325                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18326        });
18327
18328        if let Err(mut ix) = ix {
18329            let index = post_inc(&mut self.highlight_order);
18330
18331            // If this range intersects with the preceding highlight, then merge it with
18332            // the preceding highlight. Otherwise insert a new highlight.
18333            let mut merged = false;
18334            if ix > 0 {
18335                let prev_highlight = &mut row_highlights[ix - 1];
18336                if prev_highlight
18337                    .range
18338                    .end
18339                    .cmp(&range.start, &snapshot)
18340                    .is_ge()
18341                {
18342                    ix -= 1;
18343                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18344                        prev_highlight.range.end = range.end;
18345                    }
18346                    merged = true;
18347                    prev_highlight.index = index;
18348                    prev_highlight.color = color;
18349                    prev_highlight.options = options;
18350                }
18351            }
18352
18353            if !merged {
18354                row_highlights.insert(
18355                    ix,
18356                    RowHighlight {
18357                        range: range.clone(),
18358                        index,
18359                        color,
18360                        options,
18361                        type_id: TypeId::of::<T>(),
18362                    },
18363                );
18364            }
18365
18366            // If any of the following highlights intersect with this one, merge them.
18367            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18368                let highlight = &row_highlights[ix];
18369                if next_highlight
18370                    .range
18371                    .start
18372                    .cmp(&highlight.range.end, &snapshot)
18373                    .is_le()
18374                {
18375                    if next_highlight
18376                        .range
18377                        .end
18378                        .cmp(&highlight.range.end, &snapshot)
18379                        .is_gt()
18380                    {
18381                        row_highlights[ix].range.end = next_highlight.range.end;
18382                    }
18383                    row_highlights.remove(ix + 1);
18384                } else {
18385                    break;
18386                }
18387            }
18388        }
18389    }
18390
18391    /// Remove any highlighted row ranges of the given type that intersect the
18392    /// given ranges.
18393    pub fn remove_highlighted_rows<T: 'static>(
18394        &mut self,
18395        ranges_to_remove: Vec<Range<Anchor>>,
18396        cx: &mut Context<Self>,
18397    ) {
18398        let snapshot = self.buffer().read(cx).snapshot(cx);
18399        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18400        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18401        row_highlights.retain(|highlight| {
18402            while let Some(range_to_remove) = ranges_to_remove.peek() {
18403                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18404                    Ordering::Less | Ordering::Equal => {
18405                        ranges_to_remove.next();
18406                    }
18407                    Ordering::Greater => {
18408                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18409                            Ordering::Less | Ordering::Equal => {
18410                                return false;
18411                            }
18412                            Ordering::Greater => break,
18413                        }
18414                    }
18415                }
18416            }
18417
18418            true
18419        })
18420    }
18421
18422    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18423    pub fn clear_row_highlights<T: 'static>(&mut self) {
18424        self.highlighted_rows.remove(&TypeId::of::<T>());
18425    }
18426
18427    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18428    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18429        self.highlighted_rows
18430            .get(&TypeId::of::<T>())
18431            .map_or(&[] as &[_], |vec| vec.as_slice())
18432            .iter()
18433            .map(|highlight| (highlight.range.clone(), highlight.color))
18434    }
18435
18436    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18437    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18438    /// Allows to ignore certain kinds of highlights.
18439    pub fn highlighted_display_rows(
18440        &self,
18441        window: &mut Window,
18442        cx: &mut App,
18443    ) -> BTreeMap<DisplayRow, LineHighlight> {
18444        let snapshot = self.snapshot(window, cx);
18445        let mut used_highlight_orders = HashMap::default();
18446        self.highlighted_rows
18447            .iter()
18448            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18449            .fold(
18450                BTreeMap::<DisplayRow, LineHighlight>::new(),
18451                |mut unique_rows, highlight| {
18452                    let start = highlight.range.start.to_display_point(&snapshot);
18453                    let end = highlight.range.end.to_display_point(&snapshot);
18454                    let start_row = start.row().0;
18455                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18456                        && end.column() == 0
18457                    {
18458                        end.row().0.saturating_sub(1)
18459                    } else {
18460                        end.row().0
18461                    };
18462                    for row in start_row..=end_row {
18463                        let used_index =
18464                            used_highlight_orders.entry(row).or_insert(highlight.index);
18465                        if highlight.index >= *used_index {
18466                            *used_index = highlight.index;
18467                            unique_rows.insert(
18468                                DisplayRow(row),
18469                                LineHighlight {
18470                                    include_gutter: highlight.options.include_gutter,
18471                                    border: None,
18472                                    background: highlight.color.into(),
18473                                    type_id: Some(highlight.type_id),
18474                                },
18475                            );
18476                        }
18477                    }
18478                    unique_rows
18479                },
18480            )
18481    }
18482
18483    pub fn highlighted_display_row_for_autoscroll(
18484        &self,
18485        snapshot: &DisplaySnapshot,
18486    ) -> Option<DisplayRow> {
18487        self.highlighted_rows
18488            .values()
18489            .flat_map(|highlighted_rows| highlighted_rows.iter())
18490            .filter_map(|highlight| {
18491                if highlight.options.autoscroll {
18492                    Some(highlight.range.start.to_display_point(snapshot).row())
18493                } else {
18494                    None
18495                }
18496            })
18497            .min()
18498    }
18499
18500    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18501        self.highlight_background::<SearchWithinRange>(
18502            ranges,
18503            |colors| colors.editor_document_highlight_read_background,
18504            cx,
18505        )
18506    }
18507
18508    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18509        self.breadcrumb_header = Some(new_header);
18510    }
18511
18512    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18513        self.clear_background_highlights::<SearchWithinRange>(cx);
18514    }
18515
18516    pub fn highlight_background<T: 'static>(
18517        &mut self,
18518        ranges: &[Range<Anchor>],
18519        color_fetcher: fn(&ThemeColors) -> Hsla,
18520        cx: &mut Context<Self>,
18521    ) {
18522        self.background_highlights
18523            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18524        self.scrollbar_marker_state.dirty = true;
18525        cx.notify();
18526    }
18527
18528    pub fn clear_background_highlights<T: 'static>(
18529        &mut self,
18530        cx: &mut Context<Self>,
18531    ) -> Option<BackgroundHighlight> {
18532        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18533        if !text_highlights.1.is_empty() {
18534            self.scrollbar_marker_state.dirty = true;
18535            cx.notify();
18536        }
18537        Some(text_highlights)
18538    }
18539
18540    pub fn highlight_gutter<T: 'static>(
18541        &mut self,
18542        ranges: impl Into<Vec<Range<Anchor>>>,
18543        color_fetcher: fn(&App) -> Hsla,
18544        cx: &mut Context<Self>,
18545    ) {
18546        self.gutter_highlights
18547            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18548        cx.notify();
18549    }
18550
18551    pub fn clear_gutter_highlights<T: 'static>(
18552        &mut self,
18553        cx: &mut Context<Self>,
18554    ) -> Option<GutterHighlight> {
18555        cx.notify();
18556        self.gutter_highlights.remove(&TypeId::of::<T>())
18557    }
18558
18559    pub fn insert_gutter_highlight<T: 'static>(
18560        &mut self,
18561        range: Range<Anchor>,
18562        color_fetcher: fn(&App) -> Hsla,
18563        cx: &mut Context<Self>,
18564    ) {
18565        let snapshot = self.buffer().read(cx).snapshot(cx);
18566        let mut highlights = self
18567            .gutter_highlights
18568            .remove(&TypeId::of::<T>())
18569            .map(|(_, highlights)| highlights)
18570            .unwrap_or_default();
18571        let ix = highlights.binary_search_by(|highlight| {
18572            Ordering::Equal
18573                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18574                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18575        });
18576        if let Err(ix) = ix {
18577            highlights.insert(ix, range);
18578        }
18579        self.gutter_highlights
18580            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18581    }
18582
18583    pub fn remove_gutter_highlights<T: 'static>(
18584        &mut self,
18585        ranges_to_remove: Vec<Range<Anchor>>,
18586        cx: &mut Context<Self>,
18587    ) {
18588        let snapshot = self.buffer().read(cx).snapshot(cx);
18589        let Some((color_fetcher, mut gutter_highlights)) =
18590            self.gutter_highlights.remove(&TypeId::of::<T>())
18591        else {
18592            return;
18593        };
18594        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18595        gutter_highlights.retain(|highlight| {
18596            while let Some(range_to_remove) = ranges_to_remove.peek() {
18597                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18598                    Ordering::Less | Ordering::Equal => {
18599                        ranges_to_remove.next();
18600                    }
18601                    Ordering::Greater => {
18602                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18603                            Ordering::Less | Ordering::Equal => {
18604                                return false;
18605                            }
18606                            Ordering::Greater => break,
18607                        }
18608                    }
18609                }
18610            }
18611
18612            true
18613        });
18614        self.gutter_highlights
18615            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18616    }
18617
18618    #[cfg(feature = "test-support")]
18619    pub fn all_text_background_highlights(
18620        &self,
18621        window: &mut Window,
18622        cx: &mut Context<Self>,
18623    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18624        let snapshot = self.snapshot(window, cx);
18625        let buffer = &snapshot.buffer_snapshot;
18626        let start = buffer.anchor_before(0);
18627        let end = buffer.anchor_after(buffer.len());
18628        let theme = cx.theme().colors();
18629        self.background_highlights_in_range(start..end, &snapshot, theme)
18630    }
18631
18632    #[cfg(feature = "test-support")]
18633    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18634        let snapshot = self.buffer().read(cx).snapshot(cx);
18635
18636        let highlights = self
18637            .background_highlights
18638            .get(&TypeId::of::<items::BufferSearchHighlights>());
18639
18640        if let Some((_color, ranges)) = highlights {
18641            ranges
18642                .iter()
18643                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18644                .collect_vec()
18645        } else {
18646            vec![]
18647        }
18648    }
18649
18650    fn document_highlights_for_position<'a>(
18651        &'a self,
18652        position: Anchor,
18653        buffer: &'a MultiBufferSnapshot,
18654    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18655        let read_highlights = self
18656            .background_highlights
18657            .get(&TypeId::of::<DocumentHighlightRead>())
18658            .map(|h| &h.1);
18659        let write_highlights = self
18660            .background_highlights
18661            .get(&TypeId::of::<DocumentHighlightWrite>())
18662            .map(|h| &h.1);
18663        let left_position = position.bias_left(buffer);
18664        let right_position = position.bias_right(buffer);
18665        read_highlights
18666            .into_iter()
18667            .chain(write_highlights)
18668            .flat_map(move |ranges| {
18669                let start_ix = match ranges.binary_search_by(|probe| {
18670                    let cmp = probe.end.cmp(&left_position, buffer);
18671                    if cmp.is_ge() {
18672                        Ordering::Greater
18673                    } else {
18674                        Ordering::Less
18675                    }
18676                }) {
18677                    Ok(i) | Err(i) => i,
18678                };
18679
18680                ranges[start_ix..]
18681                    .iter()
18682                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18683            })
18684    }
18685
18686    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18687        self.background_highlights
18688            .get(&TypeId::of::<T>())
18689            .map_or(false, |(_, highlights)| !highlights.is_empty())
18690    }
18691
18692    pub fn background_highlights_in_range(
18693        &self,
18694        search_range: Range<Anchor>,
18695        display_snapshot: &DisplaySnapshot,
18696        theme: &ThemeColors,
18697    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18698        let mut results = Vec::new();
18699        for (color_fetcher, ranges) in self.background_highlights.values() {
18700            let color = color_fetcher(theme);
18701            let start_ix = match ranges.binary_search_by(|probe| {
18702                let cmp = probe
18703                    .end
18704                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18705                if cmp.is_gt() {
18706                    Ordering::Greater
18707                } else {
18708                    Ordering::Less
18709                }
18710            }) {
18711                Ok(i) | Err(i) => i,
18712            };
18713            for range in &ranges[start_ix..] {
18714                if range
18715                    .start
18716                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18717                    .is_ge()
18718                {
18719                    break;
18720                }
18721
18722                let start = range.start.to_display_point(display_snapshot);
18723                let end = range.end.to_display_point(display_snapshot);
18724                results.push((start..end, color))
18725            }
18726        }
18727        results
18728    }
18729
18730    pub fn background_highlight_row_ranges<T: 'static>(
18731        &self,
18732        search_range: Range<Anchor>,
18733        display_snapshot: &DisplaySnapshot,
18734        count: usize,
18735    ) -> Vec<RangeInclusive<DisplayPoint>> {
18736        let mut results = Vec::new();
18737        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18738            return vec![];
18739        };
18740
18741        let start_ix = match ranges.binary_search_by(|probe| {
18742            let cmp = probe
18743                .end
18744                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18745            if cmp.is_gt() {
18746                Ordering::Greater
18747            } else {
18748                Ordering::Less
18749            }
18750        }) {
18751            Ok(i) | Err(i) => i,
18752        };
18753        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18754            if let (Some(start_display), Some(end_display)) = (start, end) {
18755                results.push(
18756                    start_display.to_display_point(display_snapshot)
18757                        ..=end_display.to_display_point(display_snapshot),
18758                );
18759            }
18760        };
18761        let mut start_row: Option<Point> = None;
18762        let mut end_row: Option<Point> = None;
18763        if ranges.len() > count {
18764            return Vec::new();
18765        }
18766        for range in &ranges[start_ix..] {
18767            if range
18768                .start
18769                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18770                .is_ge()
18771            {
18772                break;
18773            }
18774            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18775            if let Some(current_row) = &end_row {
18776                if end.row == current_row.row {
18777                    continue;
18778                }
18779            }
18780            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18781            if start_row.is_none() {
18782                assert_eq!(end_row, None);
18783                start_row = Some(start);
18784                end_row = Some(end);
18785                continue;
18786            }
18787            if let Some(current_end) = end_row.as_mut() {
18788                if start.row > current_end.row + 1 {
18789                    push_region(start_row, end_row);
18790                    start_row = Some(start);
18791                    end_row = Some(end);
18792                } else {
18793                    // Merge two hunks.
18794                    *current_end = end;
18795                }
18796            } else {
18797                unreachable!();
18798            }
18799        }
18800        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18801        push_region(start_row, end_row);
18802        results
18803    }
18804
18805    pub fn gutter_highlights_in_range(
18806        &self,
18807        search_range: Range<Anchor>,
18808        display_snapshot: &DisplaySnapshot,
18809        cx: &App,
18810    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18811        let mut results = Vec::new();
18812        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18813            let color = color_fetcher(cx);
18814            let start_ix = match ranges.binary_search_by(|probe| {
18815                let cmp = probe
18816                    .end
18817                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18818                if cmp.is_gt() {
18819                    Ordering::Greater
18820                } else {
18821                    Ordering::Less
18822                }
18823            }) {
18824                Ok(i) | Err(i) => i,
18825            };
18826            for range in &ranges[start_ix..] {
18827                if range
18828                    .start
18829                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18830                    .is_ge()
18831                {
18832                    break;
18833                }
18834
18835                let start = range.start.to_display_point(display_snapshot);
18836                let end = range.end.to_display_point(display_snapshot);
18837                results.push((start..end, color))
18838            }
18839        }
18840        results
18841    }
18842
18843    /// Get the text ranges corresponding to the redaction query
18844    pub fn redacted_ranges(
18845        &self,
18846        search_range: Range<Anchor>,
18847        display_snapshot: &DisplaySnapshot,
18848        cx: &App,
18849    ) -> Vec<Range<DisplayPoint>> {
18850        display_snapshot
18851            .buffer_snapshot
18852            .redacted_ranges(search_range, |file| {
18853                if let Some(file) = file {
18854                    file.is_private()
18855                        && EditorSettings::get(
18856                            Some(SettingsLocation {
18857                                worktree_id: file.worktree_id(cx),
18858                                path: file.path().as_ref(),
18859                            }),
18860                            cx,
18861                        )
18862                        .redact_private_values
18863                } else {
18864                    false
18865                }
18866            })
18867            .map(|range| {
18868                range.start.to_display_point(display_snapshot)
18869                    ..range.end.to_display_point(display_snapshot)
18870            })
18871            .collect()
18872    }
18873
18874    pub fn highlight_text<T: 'static>(
18875        &mut self,
18876        ranges: Vec<Range<Anchor>>,
18877        style: HighlightStyle,
18878        cx: &mut Context<Self>,
18879    ) {
18880        self.display_map.update(cx, |map, _| {
18881            map.highlight_text(TypeId::of::<T>(), ranges, style)
18882        });
18883        cx.notify();
18884    }
18885
18886    pub(crate) fn highlight_inlays<T: 'static>(
18887        &mut self,
18888        highlights: Vec<InlayHighlight>,
18889        style: HighlightStyle,
18890        cx: &mut Context<Self>,
18891    ) {
18892        self.display_map.update(cx, |map, _| {
18893            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18894        });
18895        cx.notify();
18896    }
18897
18898    pub fn text_highlights<'a, T: 'static>(
18899        &'a self,
18900        cx: &'a App,
18901    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18902        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18903    }
18904
18905    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18906        let cleared = self
18907            .display_map
18908            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18909        if cleared {
18910            cx.notify();
18911        }
18912    }
18913
18914    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18915        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18916            && self.focus_handle.is_focused(window)
18917    }
18918
18919    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18920        self.show_cursor_when_unfocused = is_enabled;
18921        cx.notify();
18922    }
18923
18924    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18925        cx.notify();
18926    }
18927
18928    fn on_debug_session_event(
18929        &mut self,
18930        _session: Entity<Session>,
18931        event: &SessionEvent,
18932        cx: &mut Context<Self>,
18933    ) {
18934        match event {
18935            SessionEvent::InvalidateInlineValue => {
18936                self.refresh_inline_values(cx);
18937            }
18938            _ => {}
18939        }
18940    }
18941
18942    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18943        let Some(project) = self.project.clone() else {
18944            return;
18945        };
18946
18947        if !self.inline_value_cache.enabled {
18948            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18949            self.splice_inlays(&inlays, Vec::new(), cx);
18950            return;
18951        }
18952
18953        let current_execution_position = self
18954            .highlighted_rows
18955            .get(&TypeId::of::<ActiveDebugLine>())
18956            .and_then(|lines| lines.last().map(|line| line.range.start));
18957
18958        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18959            let inline_values = editor
18960                .update(cx, |editor, cx| {
18961                    let Some(current_execution_position) = current_execution_position else {
18962                        return Some(Task::ready(Ok(Vec::new())));
18963                    };
18964
18965                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18966                        let snapshot = buffer.snapshot(cx);
18967
18968                        let excerpt = snapshot.excerpt_containing(
18969                            current_execution_position..current_execution_position,
18970                        )?;
18971
18972                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18973                    })?;
18974
18975                    let range =
18976                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18977
18978                    project.inline_values(buffer, range, cx)
18979                })
18980                .ok()
18981                .flatten()?
18982                .await
18983                .context("refreshing debugger inlays")
18984                .log_err()?;
18985
18986            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18987
18988            for (buffer_id, inline_value) in inline_values
18989                .into_iter()
18990                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18991            {
18992                buffer_inline_values
18993                    .entry(buffer_id)
18994                    .or_default()
18995                    .push(inline_value);
18996            }
18997
18998            editor
18999                .update(cx, |editor, cx| {
19000                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19001                    let mut new_inlays = Vec::default();
19002
19003                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19004                        let buffer_id = buffer_snapshot.remote_id();
19005                        buffer_inline_values
19006                            .get(&buffer_id)
19007                            .into_iter()
19008                            .flatten()
19009                            .for_each(|hint| {
19010                                let inlay = Inlay::debugger_hint(
19011                                    post_inc(&mut editor.next_inlay_id),
19012                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19013                                    hint.text(),
19014                                );
19015
19016                                new_inlays.push(inlay);
19017                            });
19018                    }
19019
19020                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19021                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19022
19023                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19024                })
19025                .ok()?;
19026            Some(())
19027        });
19028    }
19029
19030    fn on_buffer_event(
19031        &mut self,
19032        multibuffer: &Entity<MultiBuffer>,
19033        event: &multi_buffer::Event,
19034        window: &mut Window,
19035        cx: &mut Context<Self>,
19036    ) {
19037        match event {
19038            multi_buffer::Event::Edited {
19039                singleton_buffer_edited,
19040                edited_buffer,
19041            } => {
19042                self.scrollbar_marker_state.dirty = true;
19043                self.active_indent_guides_state.dirty = true;
19044                self.refresh_active_diagnostics(cx);
19045                self.refresh_code_actions(window, cx);
19046                self.refresh_selected_text_highlights(true, window, cx);
19047                refresh_matching_bracket_highlights(self, window, cx);
19048                if self.has_active_inline_completion() {
19049                    self.update_visible_inline_completion(window, cx);
19050                }
19051                if let Some(project) = self.project.as_ref() {
19052                    if let Some(edited_buffer) = edited_buffer {
19053                        project.update(cx, |project, cx| {
19054                            self.registered_buffers
19055                                .entry(edited_buffer.read(cx).remote_id())
19056                                .or_insert_with(|| {
19057                                    project
19058                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19059                                });
19060                        });
19061                        if edited_buffer.read(cx).file().is_some() {
19062                            self.pull_diagnostics(
19063                                Some(edited_buffer.read(cx).remote_id()),
19064                                window,
19065                                cx,
19066                            );
19067                        }
19068                    }
19069                }
19070                cx.emit(EditorEvent::BufferEdited);
19071                cx.emit(SearchEvent::MatchesInvalidated);
19072                if *singleton_buffer_edited {
19073                    if let Some(buffer) = edited_buffer {
19074                        if buffer.read(cx).file().is_none() {
19075                            cx.emit(EditorEvent::TitleChanged);
19076                        }
19077                    }
19078                    if let Some(project) = &self.project {
19079                        #[allow(clippy::mutable_key_type)]
19080                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19081                            multibuffer
19082                                .all_buffers()
19083                                .into_iter()
19084                                .filter_map(|buffer| {
19085                                    buffer.update(cx, |buffer, cx| {
19086                                        let language = buffer.language()?;
19087                                        let should_discard = project.update(cx, |project, cx| {
19088                                            project.is_local()
19089                                                && !project.has_language_servers_for(buffer, cx)
19090                                        });
19091                                        should_discard.not().then_some(language.clone())
19092                                    })
19093                                })
19094                                .collect::<HashSet<_>>()
19095                        });
19096                        if !languages_affected.is_empty() {
19097                            self.refresh_inlay_hints(
19098                                InlayHintRefreshReason::BufferEdited(languages_affected),
19099                                cx,
19100                            );
19101                        }
19102                    }
19103                }
19104
19105                let Some(project) = &self.project else { return };
19106                let (telemetry, is_via_ssh) = {
19107                    let project = project.read(cx);
19108                    let telemetry = project.client().telemetry().clone();
19109                    let is_via_ssh = project.is_via_ssh();
19110                    (telemetry, is_via_ssh)
19111                };
19112                refresh_linked_ranges(self, window, cx);
19113                telemetry.log_edit_event("editor", is_via_ssh);
19114            }
19115            multi_buffer::Event::ExcerptsAdded {
19116                buffer,
19117                predecessor,
19118                excerpts,
19119            } => {
19120                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19121                let buffer_id = buffer.read(cx).remote_id();
19122                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19123                    if let Some(project) = &self.project {
19124                        update_uncommitted_diff_for_buffer(
19125                            cx.entity(),
19126                            project,
19127                            [buffer.clone()],
19128                            self.buffer.clone(),
19129                            cx,
19130                        )
19131                        .detach();
19132                    }
19133                }
19134                cx.emit(EditorEvent::ExcerptsAdded {
19135                    buffer: buffer.clone(),
19136                    predecessor: *predecessor,
19137                    excerpts: excerpts.clone(),
19138                });
19139                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19140            }
19141            multi_buffer::Event::ExcerptsRemoved {
19142                ids,
19143                removed_buffer_ids,
19144            } => {
19145                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19146                let buffer = self.buffer.read(cx);
19147                self.registered_buffers
19148                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19149                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19150                cx.emit(EditorEvent::ExcerptsRemoved {
19151                    ids: ids.clone(),
19152                    removed_buffer_ids: removed_buffer_ids.clone(),
19153                })
19154            }
19155            multi_buffer::Event::ExcerptsEdited {
19156                excerpt_ids,
19157                buffer_ids,
19158            } => {
19159                self.display_map.update(cx, |map, cx| {
19160                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19161                });
19162                cx.emit(EditorEvent::ExcerptsEdited {
19163                    ids: excerpt_ids.clone(),
19164                })
19165            }
19166            multi_buffer::Event::ExcerptsExpanded { ids } => {
19167                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19168                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19169            }
19170            multi_buffer::Event::Reparsed(buffer_id) => {
19171                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19172                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19173
19174                cx.emit(EditorEvent::Reparsed(*buffer_id));
19175            }
19176            multi_buffer::Event::DiffHunksToggled => {
19177                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19178            }
19179            multi_buffer::Event::LanguageChanged(buffer_id) => {
19180                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19181                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19182                cx.emit(EditorEvent::Reparsed(*buffer_id));
19183                cx.notify();
19184            }
19185            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19186            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19187            multi_buffer::Event::FileHandleChanged
19188            | multi_buffer::Event::Reloaded
19189            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19190            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19191            multi_buffer::Event::DiagnosticsUpdated => {
19192                self.update_diagnostics_state(window, cx);
19193            }
19194            _ => {}
19195        };
19196    }
19197
19198    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19199        self.refresh_active_diagnostics(cx);
19200        self.refresh_inline_diagnostics(true, window, cx);
19201        self.scrollbar_marker_state.dirty = true;
19202        cx.notify();
19203    }
19204
19205    pub fn start_temporary_diff_override(&mut self) {
19206        self.load_diff_task.take();
19207        self.temporary_diff_override = true;
19208    }
19209
19210    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19211        self.temporary_diff_override = false;
19212        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19213        self.buffer.update(cx, |buffer, cx| {
19214            buffer.set_all_diff_hunks_collapsed(cx);
19215        });
19216
19217        if let Some(project) = self.project.clone() {
19218            self.load_diff_task = Some(
19219                update_uncommitted_diff_for_buffer(
19220                    cx.entity(),
19221                    &project,
19222                    self.buffer.read(cx).all_buffers(),
19223                    self.buffer.clone(),
19224                    cx,
19225                )
19226                .shared(),
19227            );
19228        }
19229    }
19230
19231    fn on_display_map_changed(
19232        &mut self,
19233        _: Entity<DisplayMap>,
19234        _: &mut Window,
19235        cx: &mut Context<Self>,
19236    ) {
19237        cx.notify();
19238    }
19239
19240    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19241        let new_severity = if self.diagnostics_enabled() {
19242            EditorSettings::get_global(cx)
19243                .diagnostics_max_severity
19244                .unwrap_or(DiagnosticSeverity::Hint)
19245        } else {
19246            DiagnosticSeverity::Off
19247        };
19248        self.set_max_diagnostics_severity(new_severity, cx);
19249        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19250        self.update_edit_prediction_settings(cx);
19251        self.refresh_inline_completion(true, false, window, cx);
19252        self.refresh_inlay_hints(
19253            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19254                self.selections.newest_anchor().head(),
19255                &self.buffer.read(cx).snapshot(cx),
19256                cx,
19257            )),
19258            cx,
19259        );
19260
19261        let old_cursor_shape = self.cursor_shape;
19262
19263        {
19264            let editor_settings = EditorSettings::get_global(cx);
19265            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19266            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19267            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19268            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19269            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19270        }
19271
19272        if old_cursor_shape != self.cursor_shape {
19273            cx.emit(EditorEvent::CursorShapeChanged);
19274        }
19275
19276        let project_settings = ProjectSettings::get_global(cx);
19277        self.serialize_dirty_buffers =
19278            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19279
19280        if self.mode.is_full() {
19281            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19282            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19283            if self.show_inline_diagnostics != show_inline_diagnostics {
19284                self.show_inline_diagnostics = show_inline_diagnostics;
19285                self.refresh_inline_diagnostics(false, window, cx);
19286            }
19287
19288            if self.git_blame_inline_enabled != inline_blame_enabled {
19289                self.toggle_git_blame_inline_internal(false, window, cx);
19290            }
19291
19292            let minimap_settings = EditorSettings::get_global(cx).minimap;
19293            if self.minimap_visibility != MinimapVisibility::Disabled {
19294                if self.minimap_visibility.settings_visibility()
19295                    != minimap_settings.minimap_enabled()
19296                {
19297                    self.set_minimap_visibility(
19298                        MinimapVisibility::for_mode(self.mode(), cx),
19299                        window,
19300                        cx,
19301                    );
19302                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19303                    minimap_entity.update(cx, |minimap_editor, cx| {
19304                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19305                    })
19306                }
19307            }
19308        }
19309
19310        cx.notify();
19311    }
19312
19313    pub fn set_searchable(&mut self, searchable: bool) {
19314        self.searchable = searchable;
19315    }
19316
19317    pub fn searchable(&self) -> bool {
19318        self.searchable
19319    }
19320
19321    fn open_proposed_changes_editor(
19322        &mut self,
19323        _: &OpenProposedChangesEditor,
19324        window: &mut Window,
19325        cx: &mut Context<Self>,
19326    ) {
19327        let Some(workspace) = self.workspace() else {
19328            cx.propagate();
19329            return;
19330        };
19331
19332        let selections = self.selections.all::<usize>(cx);
19333        let multi_buffer = self.buffer.read(cx);
19334        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19335        let mut new_selections_by_buffer = HashMap::default();
19336        for selection in selections {
19337            for (buffer, range, _) in
19338                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19339            {
19340                let mut range = range.to_point(buffer);
19341                range.start.column = 0;
19342                range.end.column = buffer.line_len(range.end.row);
19343                new_selections_by_buffer
19344                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19345                    .or_insert(Vec::new())
19346                    .push(range)
19347            }
19348        }
19349
19350        let proposed_changes_buffers = new_selections_by_buffer
19351            .into_iter()
19352            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19353            .collect::<Vec<_>>();
19354        let proposed_changes_editor = cx.new(|cx| {
19355            ProposedChangesEditor::new(
19356                "Proposed changes",
19357                proposed_changes_buffers,
19358                self.project.clone(),
19359                window,
19360                cx,
19361            )
19362        });
19363
19364        window.defer(cx, move |window, cx| {
19365            workspace.update(cx, |workspace, cx| {
19366                workspace.active_pane().update(cx, |pane, cx| {
19367                    pane.add_item(
19368                        Box::new(proposed_changes_editor),
19369                        true,
19370                        true,
19371                        None,
19372                        window,
19373                        cx,
19374                    );
19375                });
19376            });
19377        });
19378    }
19379
19380    pub fn open_excerpts_in_split(
19381        &mut self,
19382        _: &OpenExcerptsSplit,
19383        window: &mut Window,
19384        cx: &mut Context<Self>,
19385    ) {
19386        self.open_excerpts_common(None, true, window, cx)
19387    }
19388
19389    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19390        self.open_excerpts_common(None, false, window, cx)
19391    }
19392
19393    fn open_excerpts_common(
19394        &mut self,
19395        jump_data: Option<JumpData>,
19396        split: bool,
19397        window: &mut Window,
19398        cx: &mut Context<Self>,
19399    ) {
19400        let Some(workspace) = self.workspace() else {
19401            cx.propagate();
19402            return;
19403        };
19404
19405        if self.buffer.read(cx).is_singleton() {
19406            cx.propagate();
19407            return;
19408        }
19409
19410        let mut new_selections_by_buffer = HashMap::default();
19411        match &jump_data {
19412            Some(JumpData::MultiBufferPoint {
19413                excerpt_id,
19414                position,
19415                anchor,
19416                line_offset_from_top,
19417            }) => {
19418                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19419                if let Some(buffer) = multi_buffer_snapshot
19420                    .buffer_id_for_excerpt(*excerpt_id)
19421                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19422                {
19423                    let buffer_snapshot = buffer.read(cx).snapshot();
19424                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19425                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19426                    } else {
19427                        buffer_snapshot.clip_point(*position, Bias::Left)
19428                    };
19429                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19430                    new_selections_by_buffer.insert(
19431                        buffer,
19432                        (
19433                            vec![jump_to_offset..jump_to_offset],
19434                            Some(*line_offset_from_top),
19435                        ),
19436                    );
19437                }
19438            }
19439            Some(JumpData::MultiBufferRow {
19440                row,
19441                line_offset_from_top,
19442            }) => {
19443                let point = MultiBufferPoint::new(row.0, 0);
19444                if let Some((buffer, buffer_point, _)) =
19445                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19446                {
19447                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19448                    new_selections_by_buffer
19449                        .entry(buffer)
19450                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19451                        .0
19452                        .push(buffer_offset..buffer_offset)
19453                }
19454            }
19455            None => {
19456                let selections = self.selections.all::<usize>(cx);
19457                let multi_buffer = self.buffer.read(cx);
19458                for selection in selections {
19459                    for (snapshot, range, _, anchor) in multi_buffer
19460                        .snapshot(cx)
19461                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19462                    {
19463                        if let Some(anchor) = anchor {
19464                            // selection is in a deleted hunk
19465                            let Some(buffer_id) = anchor.buffer_id else {
19466                                continue;
19467                            };
19468                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19469                                continue;
19470                            };
19471                            let offset = text::ToOffset::to_offset(
19472                                &anchor.text_anchor,
19473                                &buffer_handle.read(cx).snapshot(),
19474                            );
19475                            let range = offset..offset;
19476                            new_selections_by_buffer
19477                                .entry(buffer_handle)
19478                                .or_insert((Vec::new(), None))
19479                                .0
19480                                .push(range)
19481                        } else {
19482                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19483                            else {
19484                                continue;
19485                            };
19486                            new_selections_by_buffer
19487                                .entry(buffer_handle)
19488                                .or_insert((Vec::new(), None))
19489                                .0
19490                                .push(range)
19491                        }
19492                    }
19493                }
19494            }
19495        }
19496
19497        new_selections_by_buffer
19498            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19499
19500        if new_selections_by_buffer.is_empty() {
19501            return;
19502        }
19503
19504        // We defer the pane interaction because we ourselves are a workspace item
19505        // and activating a new item causes the pane to call a method on us reentrantly,
19506        // which panics if we're on the stack.
19507        window.defer(cx, move |window, cx| {
19508            workspace.update(cx, |workspace, cx| {
19509                let pane = if split {
19510                    workspace.adjacent_pane(window, cx)
19511                } else {
19512                    workspace.active_pane().clone()
19513                };
19514
19515                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19516                    let editor = buffer
19517                        .read(cx)
19518                        .file()
19519                        .is_none()
19520                        .then(|| {
19521                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19522                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19523                            // Instead, we try to activate the existing editor in the pane first.
19524                            let (editor, pane_item_index) =
19525                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19526                                    let editor = item.downcast::<Editor>()?;
19527                                    let singleton_buffer =
19528                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19529                                    if singleton_buffer == buffer {
19530                                        Some((editor, i))
19531                                    } else {
19532                                        None
19533                                    }
19534                                })?;
19535                            pane.update(cx, |pane, cx| {
19536                                pane.activate_item(pane_item_index, true, true, window, cx)
19537                            });
19538                            Some(editor)
19539                        })
19540                        .flatten()
19541                        .unwrap_or_else(|| {
19542                            workspace.open_project_item::<Self>(
19543                                pane.clone(),
19544                                buffer,
19545                                true,
19546                                true,
19547                                window,
19548                                cx,
19549                            )
19550                        });
19551
19552                    editor.update(cx, |editor, cx| {
19553                        let autoscroll = match scroll_offset {
19554                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19555                            None => Autoscroll::newest(),
19556                        };
19557                        let nav_history = editor.nav_history.take();
19558                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19559                            s.select_ranges(ranges);
19560                        });
19561                        editor.nav_history = nav_history;
19562                    });
19563                }
19564            })
19565        });
19566    }
19567
19568    // For now, don't allow opening excerpts in buffers that aren't backed by
19569    // regular project files.
19570    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19571        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19572    }
19573
19574    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19575        let snapshot = self.buffer.read(cx).read(cx);
19576        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19577        Some(
19578            ranges
19579                .iter()
19580                .map(move |range| {
19581                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19582                })
19583                .collect(),
19584        )
19585    }
19586
19587    fn selection_replacement_ranges(
19588        &self,
19589        range: Range<OffsetUtf16>,
19590        cx: &mut App,
19591    ) -> Vec<Range<OffsetUtf16>> {
19592        let selections = self.selections.all::<OffsetUtf16>(cx);
19593        let newest_selection = selections
19594            .iter()
19595            .max_by_key(|selection| selection.id)
19596            .unwrap();
19597        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19598        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19599        let snapshot = self.buffer.read(cx).read(cx);
19600        selections
19601            .into_iter()
19602            .map(|mut selection| {
19603                selection.start.0 =
19604                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19605                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19606                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19607                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19608            })
19609            .collect()
19610    }
19611
19612    fn report_editor_event(
19613        &self,
19614        event_type: &'static str,
19615        file_extension: Option<String>,
19616        cx: &App,
19617    ) {
19618        if cfg!(any(test, feature = "test-support")) {
19619            return;
19620        }
19621
19622        let Some(project) = &self.project else { return };
19623
19624        // If None, we are in a file without an extension
19625        let file = self
19626            .buffer
19627            .read(cx)
19628            .as_singleton()
19629            .and_then(|b| b.read(cx).file());
19630        let file_extension = file_extension.or(file
19631            .as_ref()
19632            .and_then(|file| Path::new(file.file_name(cx)).extension())
19633            .and_then(|e| e.to_str())
19634            .map(|a| a.to_string()));
19635
19636        let vim_mode = vim_enabled(cx);
19637
19638        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19639        let copilot_enabled = edit_predictions_provider
19640            == language::language_settings::EditPredictionProvider::Copilot;
19641        let copilot_enabled_for_language = self
19642            .buffer
19643            .read(cx)
19644            .language_settings(cx)
19645            .show_edit_predictions;
19646
19647        let project = project.read(cx);
19648        telemetry::event!(
19649            event_type,
19650            file_extension,
19651            vim_mode,
19652            copilot_enabled,
19653            copilot_enabled_for_language,
19654            edit_predictions_provider,
19655            is_via_ssh = project.is_via_ssh(),
19656        );
19657    }
19658
19659    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19660    /// with each line being an array of {text, highlight} objects.
19661    fn copy_highlight_json(
19662        &mut self,
19663        _: &CopyHighlightJson,
19664        window: &mut Window,
19665        cx: &mut Context<Self>,
19666    ) {
19667        #[derive(Serialize)]
19668        struct Chunk<'a> {
19669            text: String,
19670            highlight: Option<&'a str>,
19671        }
19672
19673        let snapshot = self.buffer.read(cx).snapshot(cx);
19674        let range = self
19675            .selected_text_range(false, window, cx)
19676            .and_then(|selection| {
19677                if selection.range.is_empty() {
19678                    None
19679                } else {
19680                    Some(selection.range)
19681                }
19682            })
19683            .unwrap_or_else(|| 0..snapshot.len());
19684
19685        let chunks = snapshot.chunks(range, true);
19686        let mut lines = Vec::new();
19687        let mut line: VecDeque<Chunk> = VecDeque::new();
19688
19689        let Some(style) = self.style.as_ref() else {
19690            return;
19691        };
19692
19693        for chunk in chunks {
19694            let highlight = chunk
19695                .syntax_highlight_id
19696                .and_then(|id| id.name(&style.syntax));
19697            let mut chunk_lines = chunk.text.split('\n').peekable();
19698            while let Some(text) = chunk_lines.next() {
19699                let mut merged_with_last_token = false;
19700                if let Some(last_token) = line.back_mut() {
19701                    if last_token.highlight == highlight {
19702                        last_token.text.push_str(text);
19703                        merged_with_last_token = true;
19704                    }
19705                }
19706
19707                if !merged_with_last_token {
19708                    line.push_back(Chunk {
19709                        text: text.into(),
19710                        highlight,
19711                    });
19712                }
19713
19714                if chunk_lines.peek().is_some() {
19715                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19716                        line.pop_front();
19717                    }
19718                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19719                        line.pop_back();
19720                    }
19721
19722                    lines.push(mem::take(&mut line));
19723                }
19724            }
19725        }
19726
19727        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19728            return;
19729        };
19730        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19731    }
19732
19733    pub fn open_context_menu(
19734        &mut self,
19735        _: &OpenContextMenu,
19736        window: &mut Window,
19737        cx: &mut Context<Self>,
19738    ) {
19739        self.request_autoscroll(Autoscroll::newest(), cx);
19740        let position = self.selections.newest_display(cx).start;
19741        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19742    }
19743
19744    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19745        &self.inlay_hint_cache
19746    }
19747
19748    pub fn replay_insert_event(
19749        &mut self,
19750        text: &str,
19751        relative_utf16_range: Option<Range<isize>>,
19752        window: &mut Window,
19753        cx: &mut Context<Self>,
19754    ) {
19755        if !self.input_enabled {
19756            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19757            return;
19758        }
19759        if let Some(relative_utf16_range) = relative_utf16_range {
19760            let selections = self.selections.all::<OffsetUtf16>(cx);
19761            self.change_selections(None, window, cx, |s| {
19762                let new_ranges = selections.into_iter().map(|range| {
19763                    let start = OffsetUtf16(
19764                        range
19765                            .head()
19766                            .0
19767                            .saturating_add_signed(relative_utf16_range.start),
19768                    );
19769                    let end = OffsetUtf16(
19770                        range
19771                            .head()
19772                            .0
19773                            .saturating_add_signed(relative_utf16_range.end),
19774                    );
19775                    start..end
19776                });
19777                s.select_ranges(new_ranges);
19778            });
19779        }
19780
19781        self.handle_input(text, window, cx);
19782    }
19783
19784    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19785        let Some(provider) = self.semantics_provider.as_ref() else {
19786            return false;
19787        };
19788
19789        let mut supports = false;
19790        self.buffer().update(cx, |this, cx| {
19791            this.for_each_buffer(|buffer| {
19792                supports |= provider.supports_inlay_hints(buffer, cx);
19793            });
19794        });
19795
19796        supports
19797    }
19798
19799    pub fn is_focused(&self, window: &Window) -> bool {
19800        self.focus_handle.is_focused(window)
19801    }
19802
19803    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19804        cx.emit(EditorEvent::Focused);
19805
19806        if let Some(descendant) = self
19807            .last_focused_descendant
19808            .take()
19809            .and_then(|descendant| descendant.upgrade())
19810        {
19811            window.focus(&descendant);
19812        } else {
19813            if let Some(blame) = self.blame.as_ref() {
19814                blame.update(cx, GitBlame::focus)
19815            }
19816
19817            self.blink_manager.update(cx, BlinkManager::enable);
19818            self.show_cursor_names(window, cx);
19819            self.buffer.update(cx, |buffer, cx| {
19820                buffer.finalize_last_transaction(cx);
19821                if self.leader_id.is_none() {
19822                    buffer.set_active_selections(
19823                        &self.selections.disjoint_anchors(),
19824                        self.selections.line_mode,
19825                        self.cursor_shape,
19826                        cx,
19827                    );
19828                }
19829            });
19830        }
19831    }
19832
19833    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19834        cx.emit(EditorEvent::FocusedIn)
19835    }
19836
19837    fn handle_focus_out(
19838        &mut self,
19839        event: FocusOutEvent,
19840        _window: &mut Window,
19841        cx: &mut Context<Self>,
19842    ) {
19843        if event.blurred != self.focus_handle {
19844            self.last_focused_descendant = Some(event.blurred);
19845        }
19846        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19847    }
19848
19849    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19850        self.blink_manager.update(cx, BlinkManager::disable);
19851        self.buffer
19852            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19853
19854        if let Some(blame) = self.blame.as_ref() {
19855            blame.update(cx, GitBlame::blur)
19856        }
19857        if !self.hover_state.focused(window, cx) {
19858            hide_hover(self, cx);
19859        }
19860        if !self
19861            .context_menu
19862            .borrow()
19863            .as_ref()
19864            .is_some_and(|context_menu| context_menu.focused(window, cx))
19865        {
19866            self.hide_context_menu(window, cx);
19867        }
19868        self.discard_inline_completion(false, cx);
19869        cx.emit(EditorEvent::Blurred);
19870        cx.notify();
19871    }
19872
19873    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19874        let mut pending: String = window
19875            .pending_input_keystrokes()
19876            .into_iter()
19877            .flatten()
19878            .filter_map(|keystroke| {
19879                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19880                    keystroke.key_char.clone()
19881                } else {
19882                    None
19883                }
19884            })
19885            .collect();
19886
19887        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19888            pending = "".to_string();
19889        }
19890
19891        let existing_pending = self
19892            .text_highlights::<PendingInput>(cx)
19893            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19894        if existing_pending.is_none() && pending.is_empty() {
19895            return;
19896        }
19897        let transaction =
19898            self.transact(window, cx, |this, window, cx| {
19899                let selections = this.selections.all::<usize>(cx);
19900                let edits = selections
19901                    .iter()
19902                    .map(|selection| (selection.end..selection.end, pending.clone()));
19903                this.edit(edits, cx);
19904                this.change_selections(None, window, cx, |s| {
19905                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19906                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19907                    }));
19908                });
19909                if let Some(existing_ranges) = existing_pending {
19910                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19911                    this.edit(edits, cx);
19912                }
19913            });
19914
19915        let snapshot = self.snapshot(window, cx);
19916        let ranges = self
19917            .selections
19918            .all::<usize>(cx)
19919            .into_iter()
19920            .map(|selection| {
19921                snapshot.buffer_snapshot.anchor_after(selection.end)
19922                    ..snapshot
19923                        .buffer_snapshot
19924                        .anchor_before(selection.end + pending.len())
19925            })
19926            .collect();
19927
19928        if pending.is_empty() {
19929            self.clear_highlights::<PendingInput>(cx);
19930        } else {
19931            self.highlight_text::<PendingInput>(
19932                ranges,
19933                HighlightStyle {
19934                    underline: Some(UnderlineStyle {
19935                        thickness: px(1.),
19936                        color: None,
19937                        wavy: false,
19938                    }),
19939                    ..Default::default()
19940                },
19941                cx,
19942            );
19943        }
19944
19945        self.ime_transaction = self.ime_transaction.or(transaction);
19946        if let Some(transaction) = self.ime_transaction {
19947            self.buffer.update(cx, |buffer, cx| {
19948                buffer.group_until_transaction(transaction, cx);
19949            });
19950        }
19951
19952        if self.text_highlights::<PendingInput>(cx).is_none() {
19953            self.ime_transaction.take();
19954        }
19955    }
19956
19957    pub fn register_action_renderer(
19958        &mut self,
19959        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
19960    ) -> Subscription {
19961        let id = self.next_editor_action_id.post_inc();
19962        self.editor_actions
19963            .borrow_mut()
19964            .insert(id, Box::new(listener));
19965
19966        let editor_actions = self.editor_actions.clone();
19967        Subscription::new(move || {
19968            editor_actions.borrow_mut().remove(&id);
19969        })
19970    }
19971
19972    pub fn register_action<A: Action>(
19973        &mut self,
19974        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19975    ) -> Subscription {
19976        let id = self.next_editor_action_id.post_inc();
19977        let listener = Arc::new(listener);
19978        self.editor_actions.borrow_mut().insert(
19979            id,
19980            Box::new(move |_, window, _| {
19981                let listener = listener.clone();
19982                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19983                    let action = action.downcast_ref().unwrap();
19984                    if phase == DispatchPhase::Bubble {
19985                        listener(action, window, cx)
19986                    }
19987                })
19988            }),
19989        );
19990
19991        let editor_actions = self.editor_actions.clone();
19992        Subscription::new(move || {
19993            editor_actions.borrow_mut().remove(&id);
19994        })
19995    }
19996
19997    pub fn file_header_size(&self) -> u32 {
19998        FILE_HEADER_HEIGHT
19999    }
20000
20001    pub fn restore(
20002        &mut self,
20003        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20004        window: &mut Window,
20005        cx: &mut Context<Self>,
20006    ) {
20007        let workspace = self.workspace();
20008        let project = self.project.as_ref();
20009        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20010            let mut tasks = Vec::new();
20011            for (buffer_id, changes) in revert_changes {
20012                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20013                    buffer.update(cx, |buffer, cx| {
20014                        buffer.edit(
20015                            changes
20016                                .into_iter()
20017                                .map(|(range, text)| (range, text.to_string())),
20018                            None,
20019                            cx,
20020                        );
20021                    });
20022
20023                    if let Some(project) =
20024                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20025                    {
20026                        project.update(cx, |project, cx| {
20027                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20028                        })
20029                    }
20030                }
20031            }
20032            tasks
20033        });
20034        cx.spawn_in(window, async move |_, cx| {
20035            for (buffer, task) in save_tasks {
20036                let result = task.await;
20037                if result.is_err() {
20038                    let Some(path) = buffer
20039                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20040                        .ok()
20041                    else {
20042                        continue;
20043                    };
20044                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20045                        let Some(task) = cx
20046                            .update_window_entity(&workspace, |workspace, window, cx| {
20047                                workspace
20048                                    .open_path_preview(path, None, false, false, false, window, cx)
20049                            })
20050                            .ok()
20051                        else {
20052                            continue;
20053                        };
20054                        task.await.log_err();
20055                    }
20056                }
20057            }
20058        })
20059        .detach();
20060        self.change_selections(None, window, cx, |selections| selections.refresh());
20061    }
20062
20063    pub fn to_pixel_point(
20064        &self,
20065        source: multi_buffer::Anchor,
20066        editor_snapshot: &EditorSnapshot,
20067        window: &mut Window,
20068    ) -> Option<gpui::Point<Pixels>> {
20069        let source_point = source.to_display_point(editor_snapshot);
20070        self.display_to_pixel_point(source_point, editor_snapshot, window)
20071    }
20072
20073    pub fn display_to_pixel_point(
20074        &self,
20075        source: DisplayPoint,
20076        editor_snapshot: &EditorSnapshot,
20077        window: &mut Window,
20078    ) -> Option<gpui::Point<Pixels>> {
20079        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20080        let text_layout_details = self.text_layout_details(window);
20081        let scroll_top = text_layout_details
20082            .scroll_anchor
20083            .scroll_position(editor_snapshot)
20084            .y;
20085
20086        if source.row().as_f32() < scroll_top.floor() {
20087            return None;
20088        }
20089        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20090        let source_y = line_height * (source.row().as_f32() - scroll_top);
20091        Some(gpui::Point::new(source_x, source_y))
20092    }
20093
20094    pub fn has_visible_completions_menu(&self) -> bool {
20095        !self.edit_prediction_preview_is_active()
20096            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20097                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20098            })
20099    }
20100
20101    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20102        if self.mode.is_minimap() {
20103            return;
20104        }
20105        self.addons
20106            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20107    }
20108
20109    pub fn unregister_addon<T: Addon>(&mut self) {
20110        self.addons.remove(&std::any::TypeId::of::<T>());
20111    }
20112
20113    pub fn addon<T: Addon>(&self) -> Option<&T> {
20114        let type_id = std::any::TypeId::of::<T>();
20115        self.addons
20116            .get(&type_id)
20117            .and_then(|item| item.to_any().downcast_ref::<T>())
20118    }
20119
20120    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20121        let type_id = std::any::TypeId::of::<T>();
20122        self.addons
20123            .get_mut(&type_id)
20124            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20125    }
20126
20127    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20128        let text_layout_details = self.text_layout_details(window);
20129        let style = &text_layout_details.editor_style;
20130        let font_id = window.text_system().resolve_font(&style.text.font());
20131        let font_size = style.text.font_size.to_pixels(window.rem_size());
20132        let line_height = style.text.line_height_in_pixels(window.rem_size());
20133        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20134
20135        gpui::Size::new(em_width, line_height)
20136    }
20137
20138    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20139        self.load_diff_task.clone()
20140    }
20141
20142    fn read_metadata_from_db(
20143        &mut self,
20144        item_id: u64,
20145        workspace_id: WorkspaceId,
20146        window: &mut Window,
20147        cx: &mut Context<Editor>,
20148    ) {
20149        if self.is_singleton(cx)
20150            && !self.mode.is_minimap()
20151            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20152        {
20153            let buffer_snapshot = OnceCell::new();
20154
20155            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20156                if !folds.is_empty() {
20157                    let snapshot =
20158                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20159                    self.fold_ranges(
20160                        folds
20161                            .into_iter()
20162                            .map(|(start, end)| {
20163                                snapshot.clip_offset(start, Bias::Left)
20164                                    ..snapshot.clip_offset(end, Bias::Right)
20165                            })
20166                            .collect(),
20167                        false,
20168                        window,
20169                        cx,
20170                    );
20171                }
20172            }
20173
20174            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20175                if !selections.is_empty() {
20176                    let snapshot =
20177                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20178                    // skip adding the initial selection to selection history
20179                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20180                    self.change_selections(None, window, cx, |s| {
20181                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20182                            snapshot.clip_offset(start, Bias::Left)
20183                                ..snapshot.clip_offset(end, Bias::Right)
20184                        }));
20185                    });
20186                    self.selection_history.mode = SelectionHistoryMode::Normal;
20187                }
20188            };
20189        }
20190
20191        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20192    }
20193}
20194
20195fn vim_enabled(cx: &App) -> bool {
20196    cx.global::<SettingsStore>()
20197        .raw_user_settings()
20198        .get("vim_mode")
20199        == Some(&serde_json::Value::Bool(true))
20200}
20201
20202fn process_completion_for_edit(
20203    completion: &Completion,
20204    intent: CompletionIntent,
20205    buffer: &Entity<Buffer>,
20206    cursor_position: &text::Anchor,
20207    cx: &mut Context<Editor>,
20208) -> CompletionEdit {
20209    let buffer = buffer.read(cx);
20210    let buffer_snapshot = buffer.snapshot();
20211    let (snippet, new_text) = if completion.is_snippet() {
20212        // Workaround for typescript language server issues so that methods don't expand within
20213        // strings and functions with type expressions. The previous point is used because the query
20214        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20215        let mut snippet_source = completion.new_text.clone();
20216        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20217        previous_point.column = previous_point.column.saturating_sub(1);
20218        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20219            if scope.prefers_label_for_snippet_in_completion() {
20220                if let Some(label) = completion.label() {
20221                    if matches!(
20222                        completion.kind(),
20223                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20224                    ) {
20225                        snippet_source = label;
20226                    }
20227                }
20228            }
20229        }
20230        match Snippet::parse(&snippet_source).log_err() {
20231            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20232            None => (None, completion.new_text.clone()),
20233        }
20234    } else {
20235        (None, completion.new_text.clone())
20236    };
20237
20238    let mut range_to_replace = {
20239        let replace_range = &completion.replace_range;
20240        if let CompletionSource::Lsp {
20241            insert_range: Some(insert_range),
20242            ..
20243        } = &completion.source
20244        {
20245            debug_assert_eq!(
20246                insert_range.start, replace_range.start,
20247                "insert_range and replace_range should start at the same position"
20248            );
20249            debug_assert!(
20250                insert_range
20251                    .start
20252                    .cmp(&cursor_position, &buffer_snapshot)
20253                    .is_le(),
20254                "insert_range should start before or at cursor position"
20255            );
20256            debug_assert!(
20257                replace_range
20258                    .start
20259                    .cmp(&cursor_position, &buffer_snapshot)
20260                    .is_le(),
20261                "replace_range should start before or at cursor position"
20262            );
20263            debug_assert!(
20264                insert_range
20265                    .end
20266                    .cmp(&cursor_position, &buffer_snapshot)
20267                    .is_le(),
20268                "insert_range should end before or at cursor position"
20269            );
20270
20271            let should_replace = match intent {
20272                CompletionIntent::CompleteWithInsert => false,
20273                CompletionIntent::CompleteWithReplace => true,
20274                CompletionIntent::Complete | CompletionIntent::Compose => {
20275                    let insert_mode =
20276                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20277                            .completions
20278                            .lsp_insert_mode;
20279                    match insert_mode {
20280                        LspInsertMode::Insert => false,
20281                        LspInsertMode::Replace => true,
20282                        LspInsertMode::ReplaceSubsequence => {
20283                            let mut text_to_replace = buffer.chars_for_range(
20284                                buffer.anchor_before(replace_range.start)
20285                                    ..buffer.anchor_after(replace_range.end),
20286                            );
20287                            let mut current_needle = text_to_replace.next();
20288                            for haystack_ch in completion.label.text.chars() {
20289                                if let Some(needle_ch) = current_needle {
20290                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20291                                        current_needle = text_to_replace.next();
20292                                    }
20293                                }
20294                            }
20295                            current_needle.is_none()
20296                        }
20297                        LspInsertMode::ReplaceSuffix => {
20298                            if replace_range
20299                                .end
20300                                .cmp(&cursor_position, &buffer_snapshot)
20301                                .is_gt()
20302                            {
20303                                let range_after_cursor = *cursor_position..replace_range.end;
20304                                let text_after_cursor = buffer
20305                                    .text_for_range(
20306                                        buffer.anchor_before(range_after_cursor.start)
20307                                            ..buffer.anchor_after(range_after_cursor.end),
20308                                    )
20309                                    .collect::<String>()
20310                                    .to_ascii_lowercase();
20311                                completion
20312                                    .label
20313                                    .text
20314                                    .to_ascii_lowercase()
20315                                    .ends_with(&text_after_cursor)
20316                            } else {
20317                                true
20318                            }
20319                        }
20320                    }
20321                }
20322            };
20323
20324            if should_replace {
20325                replace_range.clone()
20326            } else {
20327                insert_range.clone()
20328            }
20329        } else {
20330            replace_range.clone()
20331        }
20332    };
20333
20334    if range_to_replace
20335        .end
20336        .cmp(&cursor_position, &buffer_snapshot)
20337        .is_lt()
20338    {
20339        range_to_replace.end = *cursor_position;
20340    }
20341
20342    CompletionEdit {
20343        new_text,
20344        replace_range: range_to_replace.to_offset(&buffer),
20345        snippet,
20346    }
20347}
20348
20349struct CompletionEdit {
20350    new_text: String,
20351    replace_range: Range<usize>,
20352    snippet: Option<Snippet>,
20353}
20354
20355fn insert_extra_newline_brackets(
20356    buffer: &MultiBufferSnapshot,
20357    range: Range<usize>,
20358    language: &language::LanguageScope,
20359) -> bool {
20360    let leading_whitespace_len = buffer
20361        .reversed_chars_at(range.start)
20362        .take_while(|c| c.is_whitespace() && *c != '\n')
20363        .map(|c| c.len_utf8())
20364        .sum::<usize>();
20365    let trailing_whitespace_len = buffer
20366        .chars_at(range.end)
20367        .take_while(|c| c.is_whitespace() && *c != '\n')
20368        .map(|c| c.len_utf8())
20369        .sum::<usize>();
20370    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20371
20372    language.brackets().any(|(pair, enabled)| {
20373        let pair_start = pair.start.trim_end();
20374        let pair_end = pair.end.trim_start();
20375
20376        enabled
20377            && pair.newline
20378            && buffer.contains_str_at(range.end, pair_end)
20379            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20380    })
20381}
20382
20383fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20384    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20385        [(buffer, range, _)] => (*buffer, range.clone()),
20386        _ => return false,
20387    };
20388    let pair = {
20389        let mut result: Option<BracketMatch> = None;
20390
20391        for pair in buffer
20392            .all_bracket_ranges(range.clone())
20393            .filter(move |pair| {
20394                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20395            })
20396        {
20397            let len = pair.close_range.end - pair.open_range.start;
20398
20399            if let Some(existing) = &result {
20400                let existing_len = existing.close_range.end - existing.open_range.start;
20401                if len > existing_len {
20402                    continue;
20403                }
20404            }
20405
20406            result = Some(pair);
20407        }
20408
20409        result
20410    };
20411    let Some(pair) = pair else {
20412        return false;
20413    };
20414    pair.newline_only
20415        && buffer
20416            .chars_for_range(pair.open_range.end..range.start)
20417            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20418            .all(|c| c.is_whitespace() && c != '\n')
20419}
20420
20421fn update_uncommitted_diff_for_buffer(
20422    editor: Entity<Editor>,
20423    project: &Entity<Project>,
20424    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20425    buffer: Entity<MultiBuffer>,
20426    cx: &mut App,
20427) -> Task<()> {
20428    let mut tasks = Vec::new();
20429    project.update(cx, |project, cx| {
20430        for buffer in buffers {
20431            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20432                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20433            }
20434        }
20435    });
20436    cx.spawn(async move |cx| {
20437        let diffs = future::join_all(tasks).await;
20438        if editor
20439            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20440            .unwrap_or(false)
20441        {
20442            return;
20443        }
20444
20445        buffer
20446            .update(cx, |buffer, cx| {
20447                for diff in diffs.into_iter().flatten() {
20448                    buffer.add_diff(diff, cx);
20449                }
20450            })
20451            .ok();
20452    })
20453}
20454
20455fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20456    let tab_size = tab_size.get() as usize;
20457    let mut width = offset;
20458
20459    for ch in text.chars() {
20460        width += if ch == '\t' {
20461            tab_size - (width % tab_size)
20462        } else {
20463            1
20464        };
20465    }
20466
20467    width - offset
20468}
20469
20470#[cfg(test)]
20471mod tests {
20472    use super::*;
20473
20474    #[test]
20475    fn test_string_size_with_expanded_tabs() {
20476        let nz = |val| NonZeroU32::new(val).unwrap();
20477        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20478        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20479        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20480        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20481        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20482        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20483        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20484        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20485    }
20486}
20487
20488/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20489struct WordBreakingTokenizer<'a> {
20490    input: &'a str,
20491}
20492
20493impl<'a> WordBreakingTokenizer<'a> {
20494    fn new(input: &'a str) -> Self {
20495        Self { input }
20496    }
20497}
20498
20499fn is_char_ideographic(ch: char) -> bool {
20500    use unicode_script::Script::*;
20501    use unicode_script::UnicodeScript;
20502    matches!(ch.script(), Han | Tangut | Yi)
20503}
20504
20505fn is_grapheme_ideographic(text: &str) -> bool {
20506    text.chars().any(is_char_ideographic)
20507}
20508
20509fn is_grapheme_whitespace(text: &str) -> bool {
20510    text.chars().any(|x| x.is_whitespace())
20511}
20512
20513fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20514    text.chars().next().map_or(false, |ch| {
20515        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20516    })
20517}
20518
20519#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20520enum WordBreakToken<'a> {
20521    Word { token: &'a str, grapheme_len: usize },
20522    InlineWhitespace { token: &'a str, grapheme_len: usize },
20523    Newline,
20524}
20525
20526impl<'a> Iterator for WordBreakingTokenizer<'a> {
20527    /// Yields a span, the count of graphemes in the token, and whether it was
20528    /// whitespace. Note that it also breaks at word boundaries.
20529    type Item = WordBreakToken<'a>;
20530
20531    fn next(&mut self) -> Option<Self::Item> {
20532        use unicode_segmentation::UnicodeSegmentation;
20533        if self.input.is_empty() {
20534            return None;
20535        }
20536
20537        let mut iter = self.input.graphemes(true).peekable();
20538        let mut offset = 0;
20539        let mut grapheme_len = 0;
20540        if let Some(first_grapheme) = iter.next() {
20541            let is_newline = first_grapheme == "\n";
20542            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20543            offset += first_grapheme.len();
20544            grapheme_len += 1;
20545            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20546                if let Some(grapheme) = iter.peek().copied() {
20547                    if should_stay_with_preceding_ideograph(grapheme) {
20548                        offset += grapheme.len();
20549                        grapheme_len += 1;
20550                    }
20551                }
20552            } else {
20553                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20554                let mut next_word_bound = words.peek().copied();
20555                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20556                    next_word_bound = words.next();
20557                }
20558                while let Some(grapheme) = iter.peek().copied() {
20559                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20560                        break;
20561                    };
20562                    if is_grapheme_whitespace(grapheme) != is_whitespace
20563                        || (grapheme == "\n") != is_newline
20564                    {
20565                        break;
20566                    };
20567                    offset += grapheme.len();
20568                    grapheme_len += 1;
20569                    iter.next();
20570                }
20571            }
20572            let token = &self.input[..offset];
20573            self.input = &self.input[offset..];
20574            if token == "\n" {
20575                Some(WordBreakToken::Newline)
20576            } else if is_whitespace {
20577                Some(WordBreakToken::InlineWhitespace {
20578                    token,
20579                    grapheme_len,
20580                })
20581            } else {
20582                Some(WordBreakToken::Word {
20583                    token,
20584                    grapheme_len,
20585                })
20586            }
20587        } else {
20588            None
20589        }
20590    }
20591}
20592
20593#[test]
20594fn test_word_breaking_tokenizer() {
20595    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20596        ("", &[]),
20597        ("  ", &[whitespace("  ", 2)]),
20598        ("Ʒ", &[word("Ʒ", 1)]),
20599        ("Ǽ", &[word("Ǽ", 1)]),
20600        ("", &[word("", 1)]),
20601        ("⋑⋑", &[word("⋑⋑", 2)]),
20602        (
20603            "原理,进而",
20604            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20605        ),
20606        (
20607            "hello world",
20608            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20609        ),
20610        (
20611            "hello, world",
20612            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20613        ),
20614        (
20615            "  hello world",
20616            &[
20617                whitespace("  ", 2),
20618                word("hello", 5),
20619                whitespace(" ", 1),
20620                word("world", 5),
20621            ],
20622        ),
20623        (
20624            "这是什么 \n 钢笔",
20625            &[
20626                word("", 1),
20627                word("", 1),
20628                word("", 1),
20629                word("", 1),
20630                whitespace(" ", 1),
20631                newline(),
20632                whitespace(" ", 1),
20633                word("", 1),
20634                word("", 1),
20635            ],
20636        ),
20637        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20638    ];
20639
20640    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20641        WordBreakToken::Word {
20642            token,
20643            grapheme_len,
20644        }
20645    }
20646
20647    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20648        WordBreakToken::InlineWhitespace {
20649            token,
20650            grapheme_len,
20651        }
20652    }
20653
20654    fn newline() -> WordBreakToken<'static> {
20655        WordBreakToken::Newline
20656    }
20657
20658    for (input, result) in tests {
20659        assert_eq!(
20660            WordBreakingTokenizer::new(input)
20661                .collect::<Vec<_>>()
20662                .as_slice(),
20663            *result,
20664        );
20665    }
20666}
20667
20668fn wrap_with_prefix(
20669    line_prefix: String,
20670    unwrapped_text: String,
20671    wrap_column: usize,
20672    tab_size: NonZeroU32,
20673    preserve_existing_whitespace: bool,
20674) -> String {
20675    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20676    let mut wrapped_text = String::new();
20677    let mut current_line = line_prefix.clone();
20678
20679    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20680    let mut current_line_len = line_prefix_len;
20681    let mut in_whitespace = false;
20682    for token in tokenizer {
20683        let have_preceding_whitespace = in_whitespace;
20684        match token {
20685            WordBreakToken::Word {
20686                token,
20687                grapheme_len,
20688            } => {
20689                in_whitespace = false;
20690                if current_line_len + grapheme_len > wrap_column
20691                    && current_line_len != line_prefix_len
20692                {
20693                    wrapped_text.push_str(current_line.trim_end());
20694                    wrapped_text.push('\n');
20695                    current_line.truncate(line_prefix.len());
20696                    current_line_len = line_prefix_len;
20697                }
20698                current_line.push_str(token);
20699                current_line_len += grapheme_len;
20700            }
20701            WordBreakToken::InlineWhitespace {
20702                mut token,
20703                mut grapheme_len,
20704            } => {
20705                in_whitespace = true;
20706                if have_preceding_whitespace && !preserve_existing_whitespace {
20707                    continue;
20708                }
20709                if !preserve_existing_whitespace {
20710                    token = " ";
20711                    grapheme_len = 1;
20712                }
20713                if current_line_len + grapheme_len > wrap_column {
20714                    wrapped_text.push_str(current_line.trim_end());
20715                    wrapped_text.push('\n');
20716                    current_line.truncate(line_prefix.len());
20717                    current_line_len = line_prefix_len;
20718                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20719                    current_line.push_str(token);
20720                    current_line_len += grapheme_len;
20721                }
20722            }
20723            WordBreakToken::Newline => {
20724                in_whitespace = true;
20725                if preserve_existing_whitespace {
20726                    wrapped_text.push_str(current_line.trim_end());
20727                    wrapped_text.push('\n');
20728                    current_line.truncate(line_prefix.len());
20729                    current_line_len = line_prefix_len;
20730                } else if have_preceding_whitespace {
20731                    continue;
20732                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20733                {
20734                    wrapped_text.push_str(current_line.trim_end());
20735                    wrapped_text.push('\n');
20736                    current_line.truncate(line_prefix.len());
20737                    current_line_len = line_prefix_len;
20738                } else if current_line_len != line_prefix_len {
20739                    current_line.push(' ');
20740                    current_line_len += 1;
20741                }
20742            }
20743        }
20744    }
20745
20746    if !current_line.is_empty() {
20747        wrapped_text.push_str(&current_line);
20748    }
20749    wrapped_text
20750}
20751
20752#[test]
20753fn test_wrap_with_prefix() {
20754    assert_eq!(
20755        wrap_with_prefix(
20756            "# ".to_string(),
20757            "abcdefg".to_string(),
20758            4,
20759            NonZeroU32::new(4).unwrap(),
20760            false,
20761        ),
20762        "# abcdefg"
20763    );
20764    assert_eq!(
20765        wrap_with_prefix(
20766            "".to_string(),
20767            "\thello world".to_string(),
20768            8,
20769            NonZeroU32::new(4).unwrap(),
20770            false,
20771        ),
20772        "hello\nworld"
20773    );
20774    assert_eq!(
20775        wrap_with_prefix(
20776            "// ".to_string(),
20777            "xx \nyy zz aa bb cc".to_string(),
20778            12,
20779            NonZeroU32::new(4).unwrap(),
20780            false,
20781        ),
20782        "// xx yy zz\n// aa bb cc"
20783    );
20784    assert_eq!(
20785        wrap_with_prefix(
20786            String::new(),
20787            "这是什么 \n 钢笔".to_string(),
20788            3,
20789            NonZeroU32::new(4).unwrap(),
20790            false,
20791        ),
20792        "这是什\n么 钢\n"
20793    );
20794}
20795
20796pub trait CollaborationHub {
20797    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20798    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20799    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20800}
20801
20802impl CollaborationHub for Entity<Project> {
20803    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20804        self.read(cx).collaborators()
20805    }
20806
20807    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20808        self.read(cx).user_store().read(cx).participant_indices()
20809    }
20810
20811    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20812        let this = self.read(cx);
20813        let user_ids = this.collaborators().values().map(|c| c.user_id);
20814        this.user_store().read(cx).participant_names(user_ids, cx)
20815    }
20816}
20817
20818pub trait SemanticsProvider {
20819    fn hover(
20820        &self,
20821        buffer: &Entity<Buffer>,
20822        position: text::Anchor,
20823        cx: &mut App,
20824    ) -> Option<Task<Vec<project::Hover>>>;
20825
20826    fn inline_values(
20827        &self,
20828        buffer_handle: Entity<Buffer>,
20829        range: Range<text::Anchor>,
20830        cx: &mut App,
20831    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20832
20833    fn inlay_hints(
20834        &self,
20835        buffer_handle: Entity<Buffer>,
20836        range: Range<text::Anchor>,
20837        cx: &mut App,
20838    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20839
20840    fn resolve_inlay_hint(
20841        &self,
20842        hint: InlayHint,
20843        buffer_handle: Entity<Buffer>,
20844        server_id: LanguageServerId,
20845        cx: &mut App,
20846    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20847
20848    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20849
20850    fn document_highlights(
20851        &self,
20852        buffer: &Entity<Buffer>,
20853        position: text::Anchor,
20854        cx: &mut App,
20855    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20856
20857    fn definitions(
20858        &self,
20859        buffer: &Entity<Buffer>,
20860        position: text::Anchor,
20861        kind: GotoDefinitionKind,
20862        cx: &mut App,
20863    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20864
20865    fn range_for_rename(
20866        &self,
20867        buffer: &Entity<Buffer>,
20868        position: text::Anchor,
20869        cx: &mut App,
20870    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20871
20872    fn perform_rename(
20873        &self,
20874        buffer: &Entity<Buffer>,
20875        position: text::Anchor,
20876        new_name: String,
20877        cx: &mut App,
20878    ) -> Option<Task<Result<ProjectTransaction>>>;
20879
20880    fn pull_diagnostics_for_buffer(
20881        &self,
20882        buffer: Entity<Buffer>,
20883        cx: &mut App,
20884    ) -> Task<anyhow::Result<()>>;
20885}
20886
20887pub trait CompletionProvider {
20888    fn completions(
20889        &self,
20890        excerpt_id: ExcerptId,
20891        buffer: &Entity<Buffer>,
20892        buffer_position: text::Anchor,
20893        trigger: CompletionContext,
20894        window: &mut Window,
20895        cx: &mut Context<Editor>,
20896    ) -> Task<Result<Vec<CompletionResponse>>>;
20897
20898    fn resolve_completions(
20899        &self,
20900        _buffer: Entity<Buffer>,
20901        _completion_indices: Vec<usize>,
20902        _completions: Rc<RefCell<Box<[Completion]>>>,
20903        _cx: &mut Context<Editor>,
20904    ) -> Task<Result<bool>> {
20905        Task::ready(Ok(false))
20906    }
20907
20908    fn apply_additional_edits_for_completion(
20909        &self,
20910        _buffer: Entity<Buffer>,
20911        _completions: Rc<RefCell<Box<[Completion]>>>,
20912        _completion_index: usize,
20913        _push_to_history: bool,
20914        _cx: &mut Context<Editor>,
20915    ) -> Task<Result<Option<language::Transaction>>> {
20916        Task::ready(Ok(None))
20917    }
20918
20919    fn is_completion_trigger(
20920        &self,
20921        buffer: &Entity<Buffer>,
20922        position: language::Anchor,
20923        text: &str,
20924        trigger_in_words: bool,
20925        menu_is_open: bool,
20926        cx: &mut Context<Editor>,
20927    ) -> bool;
20928
20929    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20930
20931    fn sort_completions(&self) -> bool {
20932        true
20933    }
20934
20935    fn filter_completions(&self) -> bool {
20936        true
20937    }
20938}
20939
20940pub trait CodeActionProvider {
20941    fn id(&self) -> Arc<str>;
20942
20943    fn code_actions(
20944        &self,
20945        buffer: &Entity<Buffer>,
20946        range: Range<text::Anchor>,
20947        window: &mut Window,
20948        cx: &mut App,
20949    ) -> Task<Result<Vec<CodeAction>>>;
20950
20951    fn apply_code_action(
20952        &self,
20953        buffer_handle: Entity<Buffer>,
20954        action: CodeAction,
20955        excerpt_id: ExcerptId,
20956        push_to_history: bool,
20957        window: &mut Window,
20958        cx: &mut App,
20959    ) -> Task<Result<ProjectTransaction>>;
20960}
20961
20962impl CodeActionProvider for Entity<Project> {
20963    fn id(&self) -> Arc<str> {
20964        "project".into()
20965    }
20966
20967    fn code_actions(
20968        &self,
20969        buffer: &Entity<Buffer>,
20970        range: Range<text::Anchor>,
20971        _window: &mut Window,
20972        cx: &mut App,
20973    ) -> Task<Result<Vec<CodeAction>>> {
20974        self.update(cx, |project, cx| {
20975            let code_lens = project.code_lens(buffer, range.clone(), cx);
20976            let code_actions = project.code_actions(buffer, range, None, cx);
20977            cx.background_spawn(async move {
20978                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20979                Ok(code_lens
20980                    .context("code lens fetch")?
20981                    .into_iter()
20982                    .chain(code_actions.context("code action fetch")?)
20983                    .collect())
20984            })
20985        })
20986    }
20987
20988    fn apply_code_action(
20989        &self,
20990        buffer_handle: Entity<Buffer>,
20991        action: CodeAction,
20992        _excerpt_id: ExcerptId,
20993        push_to_history: bool,
20994        _window: &mut Window,
20995        cx: &mut App,
20996    ) -> Task<Result<ProjectTransaction>> {
20997        self.update(cx, |project, cx| {
20998            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20999        })
21000    }
21001}
21002
21003fn snippet_completions(
21004    project: &Project,
21005    buffer: &Entity<Buffer>,
21006    buffer_position: text::Anchor,
21007    cx: &mut App,
21008) -> Task<Result<CompletionResponse>> {
21009    let languages = buffer.read(cx).languages_at(buffer_position);
21010    let snippet_store = project.snippets().read(cx);
21011
21012    let scopes: Vec<_> = languages
21013        .iter()
21014        .filter_map(|language| {
21015            let language_name = language.lsp_id();
21016            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21017
21018            if snippets.is_empty() {
21019                None
21020            } else {
21021                Some((language.default_scope(), snippets))
21022            }
21023        })
21024        .collect();
21025
21026    if scopes.is_empty() {
21027        return Task::ready(Ok(CompletionResponse {
21028            completions: vec![],
21029            is_incomplete: false,
21030        }));
21031    }
21032
21033    let snapshot = buffer.read(cx).text_snapshot();
21034    let chars: String = snapshot
21035        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21036        .collect();
21037    let executor = cx.background_executor().clone();
21038
21039    cx.background_spawn(async move {
21040        let mut is_incomplete = false;
21041        let mut completions: Vec<Completion> = Vec::new();
21042        for (scope, snippets) in scopes.into_iter() {
21043            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21044            let mut last_word = chars
21045                .chars()
21046                .take_while(|c| classifier.is_word(*c))
21047                .collect::<String>();
21048            last_word = last_word.chars().rev().collect();
21049
21050            if last_word.is_empty() {
21051                return Ok(CompletionResponse {
21052                    completions: vec![],
21053                    is_incomplete: true,
21054                });
21055            }
21056
21057            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21058            let to_lsp = |point: &text::Anchor| {
21059                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21060                point_to_lsp(end)
21061            };
21062            let lsp_end = to_lsp(&buffer_position);
21063
21064            let candidates = snippets
21065                .iter()
21066                .enumerate()
21067                .flat_map(|(ix, snippet)| {
21068                    snippet
21069                        .prefix
21070                        .iter()
21071                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21072                })
21073                .collect::<Vec<StringMatchCandidate>>();
21074
21075            const MAX_RESULTS: usize = 100;
21076            let mut matches = fuzzy::match_strings(
21077                &candidates,
21078                &last_word,
21079                last_word.chars().any(|c| c.is_uppercase()),
21080                MAX_RESULTS,
21081                &Default::default(),
21082                executor.clone(),
21083            )
21084            .await;
21085
21086            if matches.len() >= MAX_RESULTS {
21087                is_incomplete = true;
21088            }
21089
21090            // Remove all candidates where the query's start does not match the start of any word in the candidate
21091            if let Some(query_start) = last_word.chars().next() {
21092                matches.retain(|string_match| {
21093                    split_words(&string_match.string).any(|word| {
21094                        // Check that the first codepoint of the word as lowercase matches the first
21095                        // codepoint of the query as lowercase
21096                        word.chars()
21097                            .flat_map(|codepoint| codepoint.to_lowercase())
21098                            .zip(query_start.to_lowercase())
21099                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21100                    })
21101                });
21102            }
21103
21104            let matched_strings = matches
21105                .into_iter()
21106                .map(|m| m.string)
21107                .collect::<HashSet<_>>();
21108
21109            completions.extend(snippets.iter().filter_map(|snippet| {
21110                let matching_prefix = snippet
21111                    .prefix
21112                    .iter()
21113                    .find(|prefix| matched_strings.contains(*prefix))?;
21114                let start = as_offset - last_word.len();
21115                let start = snapshot.anchor_before(start);
21116                let range = start..buffer_position;
21117                let lsp_start = to_lsp(&start);
21118                let lsp_range = lsp::Range {
21119                    start: lsp_start,
21120                    end: lsp_end,
21121                };
21122                Some(Completion {
21123                    replace_range: range,
21124                    new_text: snippet.body.clone(),
21125                    source: CompletionSource::Lsp {
21126                        insert_range: None,
21127                        server_id: LanguageServerId(usize::MAX),
21128                        resolved: true,
21129                        lsp_completion: Box::new(lsp::CompletionItem {
21130                            label: snippet.prefix.first().unwrap().clone(),
21131                            kind: Some(CompletionItemKind::SNIPPET),
21132                            label_details: snippet.description.as_ref().map(|description| {
21133                                lsp::CompletionItemLabelDetails {
21134                                    detail: Some(description.clone()),
21135                                    description: None,
21136                                }
21137                            }),
21138                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21139                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21140                                lsp::InsertReplaceEdit {
21141                                    new_text: snippet.body.clone(),
21142                                    insert: lsp_range,
21143                                    replace: lsp_range,
21144                                },
21145                            )),
21146                            filter_text: Some(snippet.body.clone()),
21147                            sort_text: Some(char::MAX.to_string()),
21148                            ..lsp::CompletionItem::default()
21149                        }),
21150                        lsp_defaults: None,
21151                    },
21152                    label: CodeLabel {
21153                        text: matching_prefix.clone(),
21154                        runs: Vec::new(),
21155                        filter_range: 0..matching_prefix.len(),
21156                    },
21157                    icon_path: None,
21158                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21159                        single_line: snippet.name.clone().into(),
21160                        plain_text: snippet
21161                            .description
21162                            .clone()
21163                            .map(|description| description.into()),
21164                    }),
21165                    insert_text_mode: None,
21166                    confirm: None,
21167                })
21168            }))
21169        }
21170
21171        Ok(CompletionResponse {
21172            completions,
21173            is_incomplete,
21174        })
21175    })
21176}
21177
21178impl CompletionProvider for Entity<Project> {
21179    fn completions(
21180        &self,
21181        _excerpt_id: ExcerptId,
21182        buffer: &Entity<Buffer>,
21183        buffer_position: text::Anchor,
21184        options: CompletionContext,
21185        _window: &mut Window,
21186        cx: &mut Context<Editor>,
21187    ) -> Task<Result<Vec<CompletionResponse>>> {
21188        self.update(cx, |project, cx| {
21189            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21190            let project_completions = project.completions(buffer, buffer_position, options, cx);
21191            cx.background_spawn(async move {
21192                let mut responses = project_completions.await?;
21193                let snippets = snippets.await?;
21194                if !snippets.completions.is_empty() {
21195                    responses.push(snippets);
21196                }
21197                Ok(responses)
21198            })
21199        })
21200    }
21201
21202    fn resolve_completions(
21203        &self,
21204        buffer: Entity<Buffer>,
21205        completion_indices: Vec<usize>,
21206        completions: Rc<RefCell<Box<[Completion]>>>,
21207        cx: &mut Context<Editor>,
21208    ) -> Task<Result<bool>> {
21209        self.update(cx, |project, cx| {
21210            project.lsp_store().update(cx, |lsp_store, cx| {
21211                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21212            })
21213        })
21214    }
21215
21216    fn apply_additional_edits_for_completion(
21217        &self,
21218        buffer: Entity<Buffer>,
21219        completions: Rc<RefCell<Box<[Completion]>>>,
21220        completion_index: usize,
21221        push_to_history: bool,
21222        cx: &mut Context<Editor>,
21223    ) -> Task<Result<Option<language::Transaction>>> {
21224        self.update(cx, |project, cx| {
21225            project.lsp_store().update(cx, |lsp_store, cx| {
21226                lsp_store.apply_additional_edits_for_completion(
21227                    buffer,
21228                    completions,
21229                    completion_index,
21230                    push_to_history,
21231                    cx,
21232                )
21233            })
21234        })
21235    }
21236
21237    fn is_completion_trigger(
21238        &self,
21239        buffer: &Entity<Buffer>,
21240        position: language::Anchor,
21241        text: &str,
21242        trigger_in_words: bool,
21243        menu_is_open: bool,
21244        cx: &mut Context<Editor>,
21245    ) -> bool {
21246        let mut chars = text.chars();
21247        let char = if let Some(char) = chars.next() {
21248            char
21249        } else {
21250            return false;
21251        };
21252        if chars.next().is_some() {
21253            return false;
21254        }
21255
21256        let buffer = buffer.read(cx);
21257        let snapshot = buffer.snapshot();
21258        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21259            return false;
21260        }
21261        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21262        if trigger_in_words && classifier.is_word(char) {
21263            return true;
21264        }
21265
21266        buffer.completion_triggers().contains(text)
21267    }
21268}
21269
21270impl SemanticsProvider for Entity<Project> {
21271    fn hover(
21272        &self,
21273        buffer: &Entity<Buffer>,
21274        position: text::Anchor,
21275        cx: &mut App,
21276    ) -> Option<Task<Vec<project::Hover>>> {
21277        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21278    }
21279
21280    fn document_highlights(
21281        &self,
21282        buffer: &Entity<Buffer>,
21283        position: text::Anchor,
21284        cx: &mut App,
21285    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21286        Some(self.update(cx, |project, cx| {
21287            project.document_highlights(buffer, position, cx)
21288        }))
21289    }
21290
21291    fn definitions(
21292        &self,
21293        buffer: &Entity<Buffer>,
21294        position: text::Anchor,
21295        kind: GotoDefinitionKind,
21296        cx: &mut App,
21297    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21298        Some(self.update(cx, |project, cx| match kind {
21299            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21300            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21301            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21302            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21303        }))
21304    }
21305
21306    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21307        // TODO: make this work for remote projects
21308        self.update(cx, |project, cx| {
21309            if project
21310                .active_debug_session(cx)
21311                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21312            {
21313                return true;
21314            }
21315
21316            buffer.update(cx, |buffer, cx| {
21317                project.any_language_server_supports_inlay_hints(buffer, cx)
21318            })
21319        })
21320    }
21321
21322    fn inline_values(
21323        &self,
21324        buffer_handle: Entity<Buffer>,
21325
21326        range: Range<text::Anchor>,
21327        cx: &mut App,
21328    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21329        self.update(cx, |project, cx| {
21330            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21331
21332            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21333        })
21334    }
21335
21336    fn inlay_hints(
21337        &self,
21338        buffer_handle: Entity<Buffer>,
21339        range: Range<text::Anchor>,
21340        cx: &mut App,
21341    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21342        Some(self.update(cx, |project, cx| {
21343            project.inlay_hints(buffer_handle, range, cx)
21344        }))
21345    }
21346
21347    fn resolve_inlay_hint(
21348        &self,
21349        hint: InlayHint,
21350        buffer_handle: Entity<Buffer>,
21351        server_id: LanguageServerId,
21352        cx: &mut App,
21353    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21354        Some(self.update(cx, |project, cx| {
21355            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21356        }))
21357    }
21358
21359    fn range_for_rename(
21360        &self,
21361        buffer: &Entity<Buffer>,
21362        position: text::Anchor,
21363        cx: &mut App,
21364    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21365        Some(self.update(cx, |project, cx| {
21366            let buffer = buffer.clone();
21367            let task = project.prepare_rename(buffer.clone(), position, cx);
21368            cx.spawn(async move |_, cx| {
21369                Ok(match task.await? {
21370                    PrepareRenameResponse::Success(range) => Some(range),
21371                    PrepareRenameResponse::InvalidPosition => None,
21372                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21373                        // Fallback on using TreeSitter info to determine identifier range
21374                        buffer.read_with(cx, |buffer, _| {
21375                            let snapshot = buffer.snapshot();
21376                            let (range, kind) = snapshot.surrounding_word(position);
21377                            if kind != Some(CharKind::Word) {
21378                                return None;
21379                            }
21380                            Some(
21381                                snapshot.anchor_before(range.start)
21382                                    ..snapshot.anchor_after(range.end),
21383                            )
21384                        })?
21385                    }
21386                })
21387            })
21388        }))
21389    }
21390
21391    fn perform_rename(
21392        &self,
21393        buffer: &Entity<Buffer>,
21394        position: text::Anchor,
21395        new_name: String,
21396        cx: &mut App,
21397    ) -> Option<Task<Result<ProjectTransaction>>> {
21398        Some(self.update(cx, |project, cx| {
21399            project.perform_rename(buffer.clone(), position, new_name, cx)
21400        }))
21401    }
21402
21403    fn pull_diagnostics_for_buffer(
21404        &self,
21405        buffer: Entity<Buffer>,
21406        cx: &mut App,
21407    ) -> Task<anyhow::Result<()>> {
21408        let diagnostics = self.update(cx, |project, cx| {
21409            project
21410                .lsp_store()
21411                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21412        });
21413        let project = self.clone();
21414        cx.spawn(async move |cx| {
21415            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21416            project.update(cx, |project, cx| {
21417                project.lsp_store().update(cx, |lsp_store, cx| {
21418                    for diagnostics_set in diagnostics {
21419                        let LspPullDiagnostics::Response {
21420                            server_id,
21421                            uri,
21422                            diagnostics,
21423                        } = diagnostics_set
21424                        else {
21425                            continue;
21426                        };
21427
21428                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21429                        let disk_based_sources = adapter
21430                            .as_ref()
21431                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21432                            .unwrap_or(&[]);
21433                        match diagnostics {
21434                            PulledDiagnostics::Unchanged { result_id } => {
21435                                lsp_store
21436                                    .merge_diagnostics(
21437                                        server_id,
21438                                        lsp::PublishDiagnosticsParams {
21439                                            uri: uri.clone(),
21440                                            diagnostics: Vec::new(),
21441                                            version: None,
21442                                        },
21443                                        Some(result_id),
21444                                        DiagnosticSourceKind::Pulled,
21445                                        disk_based_sources,
21446                                        |_, _| true,
21447                                        cx,
21448                                    )
21449                                    .log_err();
21450                            }
21451                            PulledDiagnostics::Changed {
21452                                diagnostics,
21453                                result_id,
21454                            } => {
21455                                lsp_store
21456                                    .merge_diagnostics(
21457                                        server_id,
21458                                        lsp::PublishDiagnosticsParams {
21459                                            uri: uri.clone(),
21460                                            diagnostics,
21461                                            version: None,
21462                                        },
21463                                        result_id,
21464                                        DiagnosticSourceKind::Pulled,
21465                                        disk_based_sources,
21466                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21467                                            DiagnosticSourceKind::Pulled => false,
21468                                            DiagnosticSourceKind::Other
21469                                            | DiagnosticSourceKind::Pushed => true,
21470                                        },
21471                                        cx,
21472                                    )
21473                                    .log_err();
21474                            }
21475                        }
21476                    }
21477                })
21478            })
21479        })
21480    }
21481}
21482
21483fn inlay_hint_settings(
21484    location: Anchor,
21485    snapshot: &MultiBufferSnapshot,
21486    cx: &mut Context<Editor>,
21487) -> InlayHintSettings {
21488    let file = snapshot.file_at(location);
21489    let language = snapshot.language_at(location).map(|l| l.name());
21490    language_settings(language, file, cx).inlay_hints
21491}
21492
21493fn consume_contiguous_rows(
21494    contiguous_row_selections: &mut Vec<Selection<Point>>,
21495    selection: &Selection<Point>,
21496    display_map: &DisplaySnapshot,
21497    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21498) -> (MultiBufferRow, MultiBufferRow) {
21499    contiguous_row_selections.push(selection.clone());
21500    let start_row = MultiBufferRow(selection.start.row);
21501    let mut end_row = ending_row(selection, display_map);
21502
21503    while let Some(next_selection) = selections.peek() {
21504        if next_selection.start.row <= end_row.0 {
21505            end_row = ending_row(next_selection, display_map);
21506            contiguous_row_selections.push(selections.next().unwrap().clone());
21507        } else {
21508            break;
21509        }
21510    }
21511    (start_row, end_row)
21512}
21513
21514fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21515    if next_selection.end.column > 0 || next_selection.is_empty() {
21516        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21517    } else {
21518        MultiBufferRow(next_selection.end.row)
21519    }
21520}
21521
21522impl EditorSnapshot {
21523    pub fn remote_selections_in_range<'a>(
21524        &'a self,
21525        range: &'a Range<Anchor>,
21526        collaboration_hub: &dyn CollaborationHub,
21527        cx: &'a App,
21528    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21529        let participant_names = collaboration_hub.user_names(cx);
21530        let participant_indices = collaboration_hub.user_participant_indices(cx);
21531        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21532        let collaborators_by_replica_id = collaborators_by_peer_id
21533            .values()
21534            .map(|collaborator| (collaborator.replica_id, collaborator))
21535            .collect::<HashMap<_, _>>();
21536        self.buffer_snapshot
21537            .selections_in_range(range, false)
21538            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21539                if replica_id == AGENT_REPLICA_ID {
21540                    Some(RemoteSelection {
21541                        replica_id,
21542                        selection,
21543                        cursor_shape,
21544                        line_mode,
21545                        collaborator_id: CollaboratorId::Agent,
21546                        user_name: Some("Agent".into()),
21547                        color: cx.theme().players().agent(),
21548                    })
21549                } else {
21550                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21551                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21552                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21553                    Some(RemoteSelection {
21554                        replica_id,
21555                        selection,
21556                        cursor_shape,
21557                        line_mode,
21558                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21559                        user_name,
21560                        color: if let Some(index) = participant_index {
21561                            cx.theme().players().color_for_participant(index.0)
21562                        } else {
21563                            cx.theme().players().absent()
21564                        },
21565                    })
21566                }
21567            })
21568    }
21569
21570    pub fn hunks_for_ranges(
21571        &self,
21572        ranges: impl IntoIterator<Item = Range<Point>>,
21573    ) -> Vec<MultiBufferDiffHunk> {
21574        let mut hunks = Vec::new();
21575        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21576            HashMap::default();
21577        for query_range in ranges {
21578            let query_rows =
21579                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21580            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21581                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21582            ) {
21583                // Include deleted hunks that are adjacent to the query range, because
21584                // otherwise they would be missed.
21585                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21586                if hunk.status().is_deleted() {
21587                    intersects_range |= hunk.row_range.start == query_rows.end;
21588                    intersects_range |= hunk.row_range.end == query_rows.start;
21589                }
21590                if intersects_range {
21591                    if !processed_buffer_rows
21592                        .entry(hunk.buffer_id)
21593                        .or_default()
21594                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21595                    {
21596                        continue;
21597                    }
21598                    hunks.push(hunk);
21599                }
21600            }
21601        }
21602
21603        hunks
21604    }
21605
21606    fn display_diff_hunks_for_rows<'a>(
21607        &'a self,
21608        display_rows: Range<DisplayRow>,
21609        folded_buffers: &'a HashSet<BufferId>,
21610    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21611        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21612        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21613
21614        self.buffer_snapshot
21615            .diff_hunks_in_range(buffer_start..buffer_end)
21616            .filter_map(|hunk| {
21617                if folded_buffers.contains(&hunk.buffer_id) {
21618                    return None;
21619                }
21620
21621                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21622                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21623
21624                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21625                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21626
21627                let display_hunk = if hunk_display_start.column() != 0 {
21628                    DisplayDiffHunk::Folded {
21629                        display_row: hunk_display_start.row(),
21630                    }
21631                } else {
21632                    let mut end_row = hunk_display_end.row();
21633                    if hunk_display_end.column() > 0 {
21634                        end_row.0 += 1;
21635                    }
21636                    let is_created_file = hunk.is_created_file();
21637                    DisplayDiffHunk::Unfolded {
21638                        status: hunk.status(),
21639                        diff_base_byte_range: hunk.diff_base_byte_range,
21640                        display_row_range: hunk_display_start.row()..end_row,
21641                        multi_buffer_range: Anchor::range_in_buffer(
21642                            hunk.excerpt_id,
21643                            hunk.buffer_id,
21644                            hunk.buffer_range,
21645                        ),
21646                        is_created_file,
21647                    }
21648                };
21649
21650                Some(display_hunk)
21651            })
21652    }
21653
21654    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21655        self.display_snapshot.buffer_snapshot.language_at(position)
21656    }
21657
21658    pub fn is_focused(&self) -> bool {
21659        self.is_focused
21660    }
21661
21662    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21663        self.placeholder_text.as_ref()
21664    }
21665
21666    pub fn scroll_position(&self) -> gpui::Point<f32> {
21667        self.scroll_anchor.scroll_position(&self.display_snapshot)
21668    }
21669
21670    fn gutter_dimensions(
21671        &self,
21672        font_id: FontId,
21673        font_size: Pixels,
21674        max_line_number_width: Pixels,
21675        cx: &App,
21676    ) -> Option<GutterDimensions> {
21677        if !self.show_gutter {
21678            return None;
21679        }
21680
21681        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21682        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21683
21684        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21685            matches!(
21686                ProjectSettings::get_global(cx).git.git_gutter,
21687                Some(GitGutterSetting::TrackedFiles)
21688            )
21689        });
21690        let gutter_settings = EditorSettings::get_global(cx).gutter;
21691        let show_line_numbers = self
21692            .show_line_numbers
21693            .unwrap_or(gutter_settings.line_numbers);
21694        let line_gutter_width = if show_line_numbers {
21695            // Avoid flicker-like gutter resizes when the line number gains another digit by
21696            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21697            let min_width_for_number_on_gutter =
21698                ch_advance * gutter_settings.min_line_number_digits as f32;
21699            max_line_number_width.max(min_width_for_number_on_gutter)
21700        } else {
21701            0.0.into()
21702        };
21703
21704        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21705        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21706
21707        let git_blame_entries_width =
21708            self.git_blame_gutter_max_author_length
21709                .map(|max_author_length| {
21710                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21711                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21712
21713                    /// The number of characters to dedicate to gaps and margins.
21714                    const SPACING_WIDTH: usize = 4;
21715
21716                    let max_char_count = max_author_length.min(renderer.max_author_length())
21717                        + ::git::SHORT_SHA_LENGTH
21718                        + MAX_RELATIVE_TIMESTAMP.len()
21719                        + SPACING_WIDTH;
21720
21721                    ch_advance * max_char_count
21722                });
21723
21724        let is_singleton = self.buffer_snapshot.is_singleton();
21725
21726        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21727        left_padding += if !is_singleton {
21728            ch_width * 4.0
21729        } else if show_runnables || show_breakpoints {
21730            ch_width * 3.0
21731        } else if show_git_gutter && show_line_numbers {
21732            ch_width * 2.0
21733        } else if show_git_gutter || show_line_numbers {
21734            ch_width
21735        } else {
21736            px(0.)
21737        };
21738
21739        let shows_folds = is_singleton && gutter_settings.folds;
21740
21741        let right_padding = if shows_folds && show_line_numbers {
21742            ch_width * 4.0
21743        } else if shows_folds || (!is_singleton && show_line_numbers) {
21744            ch_width * 3.0
21745        } else if show_line_numbers {
21746            ch_width
21747        } else {
21748            px(0.)
21749        };
21750
21751        Some(GutterDimensions {
21752            left_padding,
21753            right_padding,
21754            width: line_gutter_width + left_padding + right_padding,
21755            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21756            git_blame_entries_width,
21757        })
21758    }
21759
21760    pub fn render_crease_toggle(
21761        &self,
21762        buffer_row: MultiBufferRow,
21763        row_contains_cursor: bool,
21764        editor: Entity<Editor>,
21765        window: &mut Window,
21766        cx: &mut App,
21767    ) -> Option<AnyElement> {
21768        let folded = self.is_line_folded(buffer_row);
21769        let mut is_foldable = false;
21770
21771        if let Some(crease) = self
21772            .crease_snapshot
21773            .query_row(buffer_row, &self.buffer_snapshot)
21774        {
21775            is_foldable = true;
21776            match crease {
21777                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21778                    if let Some(render_toggle) = render_toggle {
21779                        let toggle_callback =
21780                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21781                                if folded {
21782                                    editor.update(cx, |editor, cx| {
21783                                        editor.fold_at(buffer_row, window, cx)
21784                                    });
21785                                } else {
21786                                    editor.update(cx, |editor, cx| {
21787                                        editor.unfold_at(buffer_row, window, cx)
21788                                    });
21789                                }
21790                            });
21791                        return Some((render_toggle)(
21792                            buffer_row,
21793                            folded,
21794                            toggle_callback,
21795                            window,
21796                            cx,
21797                        ));
21798                    }
21799                }
21800            }
21801        }
21802
21803        is_foldable |= self.starts_indent(buffer_row);
21804
21805        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21806            Some(
21807                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21808                    .toggle_state(folded)
21809                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21810                        if folded {
21811                            this.unfold_at(buffer_row, window, cx);
21812                        } else {
21813                            this.fold_at(buffer_row, window, cx);
21814                        }
21815                    }))
21816                    .into_any_element(),
21817            )
21818        } else {
21819            None
21820        }
21821    }
21822
21823    pub fn render_crease_trailer(
21824        &self,
21825        buffer_row: MultiBufferRow,
21826        window: &mut Window,
21827        cx: &mut App,
21828    ) -> Option<AnyElement> {
21829        let folded = self.is_line_folded(buffer_row);
21830        if let Crease::Inline { render_trailer, .. } = self
21831            .crease_snapshot
21832            .query_row(buffer_row, &self.buffer_snapshot)?
21833        {
21834            let render_trailer = render_trailer.as_ref()?;
21835            Some(render_trailer(buffer_row, folded, window, cx))
21836        } else {
21837            None
21838        }
21839    }
21840}
21841
21842impl Deref for EditorSnapshot {
21843    type Target = DisplaySnapshot;
21844
21845    fn deref(&self) -> &Self::Target {
21846        &self.display_snapshot
21847    }
21848}
21849
21850#[derive(Clone, Debug, PartialEq, Eq)]
21851pub enum EditorEvent {
21852    InputIgnored {
21853        text: Arc<str>,
21854    },
21855    InputHandled {
21856        utf16_range_to_replace: Option<Range<isize>>,
21857        text: Arc<str>,
21858    },
21859    ExcerptsAdded {
21860        buffer: Entity<Buffer>,
21861        predecessor: ExcerptId,
21862        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21863    },
21864    ExcerptsRemoved {
21865        ids: Vec<ExcerptId>,
21866        removed_buffer_ids: Vec<BufferId>,
21867    },
21868    BufferFoldToggled {
21869        ids: Vec<ExcerptId>,
21870        folded: bool,
21871    },
21872    ExcerptsEdited {
21873        ids: Vec<ExcerptId>,
21874    },
21875    ExcerptsExpanded {
21876        ids: Vec<ExcerptId>,
21877    },
21878    BufferEdited,
21879    Edited {
21880        transaction_id: clock::Lamport,
21881    },
21882    Reparsed(BufferId),
21883    Focused,
21884    FocusedIn,
21885    Blurred,
21886    DirtyChanged,
21887    Saved,
21888    TitleChanged,
21889    DiffBaseChanged,
21890    SelectionsChanged {
21891        local: bool,
21892    },
21893    ScrollPositionChanged {
21894        local: bool,
21895        autoscroll: bool,
21896    },
21897    Closed,
21898    TransactionUndone {
21899        transaction_id: clock::Lamport,
21900    },
21901    TransactionBegun {
21902        transaction_id: clock::Lamport,
21903    },
21904    Reloaded,
21905    CursorShapeChanged,
21906    PushedToNavHistory {
21907        anchor: Anchor,
21908        is_deactivate: bool,
21909    },
21910}
21911
21912impl EventEmitter<EditorEvent> for Editor {}
21913
21914impl Focusable for Editor {
21915    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21916        self.focus_handle.clone()
21917    }
21918}
21919
21920impl Render for Editor {
21921    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21922        let settings = ThemeSettings::get_global(cx);
21923
21924        let mut text_style = match self.mode {
21925            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21926                color: cx.theme().colors().editor_foreground,
21927                font_family: settings.ui_font.family.clone(),
21928                font_features: settings.ui_font.features.clone(),
21929                font_fallbacks: settings.ui_font.fallbacks.clone(),
21930                font_size: rems(0.875).into(),
21931                font_weight: settings.ui_font.weight,
21932                line_height: relative(settings.buffer_line_height.value()),
21933                ..Default::default()
21934            },
21935            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21936                color: cx.theme().colors().editor_foreground,
21937                font_family: settings.buffer_font.family.clone(),
21938                font_features: settings.buffer_font.features.clone(),
21939                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21940                font_size: settings.buffer_font_size(cx).into(),
21941                font_weight: settings.buffer_font.weight,
21942                line_height: relative(settings.buffer_line_height.value()),
21943                ..Default::default()
21944            },
21945        };
21946        if let Some(text_style_refinement) = &self.text_style_refinement {
21947            text_style.refine(text_style_refinement)
21948        }
21949
21950        let background = match self.mode {
21951            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21952            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
21953            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21954            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21955        };
21956
21957        EditorElement::new(
21958            &cx.entity(),
21959            EditorStyle {
21960                background,
21961                local_player: cx.theme().players().local(),
21962                text: text_style,
21963                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21964                syntax: cx.theme().syntax().clone(),
21965                status: cx.theme().status().clone(),
21966                inlay_hints_style: make_inlay_hints_style(cx),
21967                inline_completion_styles: make_suggestion_styles(cx),
21968                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21969                show_underlines: !self.mode.is_minimap(),
21970            },
21971        )
21972    }
21973}
21974
21975impl EntityInputHandler for Editor {
21976    fn text_for_range(
21977        &mut self,
21978        range_utf16: Range<usize>,
21979        adjusted_range: &mut Option<Range<usize>>,
21980        _: &mut Window,
21981        cx: &mut Context<Self>,
21982    ) -> Option<String> {
21983        let snapshot = self.buffer.read(cx).read(cx);
21984        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21985        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21986        if (start.0..end.0) != range_utf16 {
21987            adjusted_range.replace(start.0..end.0);
21988        }
21989        Some(snapshot.text_for_range(start..end).collect())
21990    }
21991
21992    fn selected_text_range(
21993        &mut self,
21994        ignore_disabled_input: bool,
21995        _: &mut Window,
21996        cx: &mut Context<Self>,
21997    ) -> Option<UTF16Selection> {
21998        // Prevent the IME menu from appearing when holding down an alphabetic key
21999        // while input is disabled.
22000        if !ignore_disabled_input && !self.input_enabled {
22001            return None;
22002        }
22003
22004        let selection = self.selections.newest::<OffsetUtf16>(cx);
22005        let range = selection.range();
22006
22007        Some(UTF16Selection {
22008            range: range.start.0..range.end.0,
22009            reversed: selection.reversed,
22010        })
22011    }
22012
22013    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22014        let snapshot = self.buffer.read(cx).read(cx);
22015        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22016        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22017    }
22018
22019    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22020        self.clear_highlights::<InputComposition>(cx);
22021        self.ime_transaction.take();
22022    }
22023
22024    fn replace_text_in_range(
22025        &mut self,
22026        range_utf16: Option<Range<usize>>,
22027        text: &str,
22028        window: &mut Window,
22029        cx: &mut Context<Self>,
22030    ) {
22031        if !self.input_enabled {
22032            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22033            return;
22034        }
22035
22036        self.transact(window, cx, |this, window, cx| {
22037            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22038                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22039                Some(this.selection_replacement_ranges(range_utf16, cx))
22040            } else {
22041                this.marked_text_ranges(cx)
22042            };
22043
22044            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22045                let newest_selection_id = this.selections.newest_anchor().id;
22046                this.selections
22047                    .all::<OffsetUtf16>(cx)
22048                    .iter()
22049                    .zip(ranges_to_replace.iter())
22050                    .find_map(|(selection, range)| {
22051                        if selection.id == newest_selection_id {
22052                            Some(
22053                                (range.start.0 as isize - selection.head().0 as isize)
22054                                    ..(range.end.0 as isize - selection.head().0 as isize),
22055                            )
22056                        } else {
22057                            None
22058                        }
22059                    })
22060            });
22061
22062            cx.emit(EditorEvent::InputHandled {
22063                utf16_range_to_replace: range_to_replace,
22064                text: text.into(),
22065            });
22066
22067            if let Some(new_selected_ranges) = new_selected_ranges {
22068                this.change_selections(None, window, cx, |selections| {
22069                    selections.select_ranges(new_selected_ranges)
22070                });
22071                this.backspace(&Default::default(), window, cx);
22072            }
22073
22074            this.handle_input(text, window, cx);
22075        });
22076
22077        if let Some(transaction) = self.ime_transaction {
22078            self.buffer.update(cx, |buffer, cx| {
22079                buffer.group_until_transaction(transaction, cx);
22080            });
22081        }
22082
22083        self.unmark_text(window, cx);
22084    }
22085
22086    fn replace_and_mark_text_in_range(
22087        &mut self,
22088        range_utf16: Option<Range<usize>>,
22089        text: &str,
22090        new_selected_range_utf16: Option<Range<usize>>,
22091        window: &mut Window,
22092        cx: &mut Context<Self>,
22093    ) {
22094        if !self.input_enabled {
22095            return;
22096        }
22097
22098        let transaction = self.transact(window, cx, |this, window, cx| {
22099            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22100                let snapshot = this.buffer.read(cx).read(cx);
22101                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22102                    for marked_range in &mut marked_ranges {
22103                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22104                        marked_range.start.0 += relative_range_utf16.start;
22105                        marked_range.start =
22106                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22107                        marked_range.end =
22108                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22109                    }
22110                }
22111                Some(marked_ranges)
22112            } else if let Some(range_utf16) = range_utf16 {
22113                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22114                Some(this.selection_replacement_ranges(range_utf16, cx))
22115            } else {
22116                None
22117            };
22118
22119            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22120                let newest_selection_id = this.selections.newest_anchor().id;
22121                this.selections
22122                    .all::<OffsetUtf16>(cx)
22123                    .iter()
22124                    .zip(ranges_to_replace.iter())
22125                    .find_map(|(selection, range)| {
22126                        if selection.id == newest_selection_id {
22127                            Some(
22128                                (range.start.0 as isize - selection.head().0 as isize)
22129                                    ..(range.end.0 as isize - selection.head().0 as isize),
22130                            )
22131                        } else {
22132                            None
22133                        }
22134                    })
22135            });
22136
22137            cx.emit(EditorEvent::InputHandled {
22138                utf16_range_to_replace: range_to_replace,
22139                text: text.into(),
22140            });
22141
22142            if let Some(ranges) = ranges_to_replace {
22143                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22144            }
22145
22146            let marked_ranges = {
22147                let snapshot = this.buffer.read(cx).read(cx);
22148                this.selections
22149                    .disjoint_anchors()
22150                    .iter()
22151                    .map(|selection| {
22152                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22153                    })
22154                    .collect::<Vec<_>>()
22155            };
22156
22157            if text.is_empty() {
22158                this.unmark_text(window, cx);
22159            } else {
22160                this.highlight_text::<InputComposition>(
22161                    marked_ranges.clone(),
22162                    HighlightStyle {
22163                        underline: Some(UnderlineStyle {
22164                            thickness: px(1.),
22165                            color: None,
22166                            wavy: false,
22167                        }),
22168                        ..Default::default()
22169                    },
22170                    cx,
22171                );
22172            }
22173
22174            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22175            let use_autoclose = this.use_autoclose;
22176            let use_auto_surround = this.use_auto_surround;
22177            this.set_use_autoclose(false);
22178            this.set_use_auto_surround(false);
22179            this.handle_input(text, window, cx);
22180            this.set_use_autoclose(use_autoclose);
22181            this.set_use_auto_surround(use_auto_surround);
22182
22183            if let Some(new_selected_range) = new_selected_range_utf16 {
22184                let snapshot = this.buffer.read(cx).read(cx);
22185                let new_selected_ranges = marked_ranges
22186                    .into_iter()
22187                    .map(|marked_range| {
22188                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22189                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22190                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22191                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22192                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22193                    })
22194                    .collect::<Vec<_>>();
22195
22196                drop(snapshot);
22197                this.change_selections(None, window, cx, |selections| {
22198                    selections.select_ranges(new_selected_ranges)
22199                });
22200            }
22201        });
22202
22203        self.ime_transaction = self.ime_transaction.or(transaction);
22204        if let Some(transaction) = self.ime_transaction {
22205            self.buffer.update(cx, |buffer, cx| {
22206                buffer.group_until_transaction(transaction, cx);
22207            });
22208        }
22209
22210        if self.text_highlights::<InputComposition>(cx).is_none() {
22211            self.ime_transaction.take();
22212        }
22213    }
22214
22215    fn bounds_for_range(
22216        &mut self,
22217        range_utf16: Range<usize>,
22218        element_bounds: gpui::Bounds<Pixels>,
22219        window: &mut Window,
22220        cx: &mut Context<Self>,
22221    ) -> Option<gpui::Bounds<Pixels>> {
22222        let text_layout_details = self.text_layout_details(window);
22223        let gpui::Size {
22224            width: em_width,
22225            height: line_height,
22226        } = self.character_size(window);
22227
22228        let snapshot = self.snapshot(window, cx);
22229        let scroll_position = snapshot.scroll_position();
22230        let scroll_left = scroll_position.x * em_width;
22231
22232        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22233        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22234            + self.gutter_dimensions.width
22235            + self.gutter_dimensions.margin;
22236        let y = line_height * (start.row().as_f32() - scroll_position.y);
22237
22238        Some(Bounds {
22239            origin: element_bounds.origin + point(x, y),
22240            size: size(em_width, line_height),
22241        })
22242    }
22243
22244    fn character_index_for_point(
22245        &mut self,
22246        point: gpui::Point<Pixels>,
22247        _window: &mut Window,
22248        _cx: &mut Context<Self>,
22249    ) -> Option<usize> {
22250        let position_map = self.last_position_map.as_ref()?;
22251        if !position_map.text_hitbox.contains(&point) {
22252            return None;
22253        }
22254        let display_point = position_map.point_for_position(point).previous_valid;
22255        let anchor = position_map
22256            .snapshot
22257            .display_point_to_anchor(display_point, Bias::Left);
22258        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22259        Some(utf16_offset.0)
22260    }
22261}
22262
22263trait SelectionExt {
22264    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22265    fn spanned_rows(
22266        &self,
22267        include_end_if_at_line_start: bool,
22268        map: &DisplaySnapshot,
22269    ) -> Range<MultiBufferRow>;
22270}
22271
22272impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22273    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22274        let start = self
22275            .start
22276            .to_point(&map.buffer_snapshot)
22277            .to_display_point(map);
22278        let end = self
22279            .end
22280            .to_point(&map.buffer_snapshot)
22281            .to_display_point(map);
22282        if self.reversed {
22283            end..start
22284        } else {
22285            start..end
22286        }
22287    }
22288
22289    fn spanned_rows(
22290        &self,
22291        include_end_if_at_line_start: bool,
22292        map: &DisplaySnapshot,
22293    ) -> Range<MultiBufferRow> {
22294        let start = self.start.to_point(&map.buffer_snapshot);
22295        let mut end = self.end.to_point(&map.buffer_snapshot);
22296        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22297            end.row -= 1;
22298        }
22299
22300        let buffer_start = map.prev_line_boundary(start).0;
22301        let buffer_end = map.next_line_boundary(end).0;
22302        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22303    }
22304}
22305
22306impl<T: InvalidationRegion> InvalidationStack<T> {
22307    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22308    where
22309        S: Clone + ToOffset,
22310    {
22311        while let Some(region) = self.last() {
22312            let all_selections_inside_invalidation_ranges =
22313                if selections.len() == region.ranges().len() {
22314                    selections
22315                        .iter()
22316                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22317                        .all(|(selection, invalidation_range)| {
22318                            let head = selection.head().to_offset(buffer);
22319                            invalidation_range.start <= head && invalidation_range.end >= head
22320                        })
22321                } else {
22322                    false
22323                };
22324
22325            if all_selections_inside_invalidation_ranges {
22326                break;
22327            } else {
22328                self.pop();
22329            }
22330        }
22331    }
22332}
22333
22334impl<T> Default for InvalidationStack<T> {
22335    fn default() -> Self {
22336        Self(Default::default())
22337    }
22338}
22339
22340impl<T> Deref for InvalidationStack<T> {
22341    type Target = Vec<T>;
22342
22343    fn deref(&self) -> &Self::Target {
22344        &self.0
22345    }
22346}
22347
22348impl<T> DerefMut for InvalidationStack<T> {
22349    fn deref_mut(&mut self) -> &mut Self::Target {
22350        &mut self.0
22351    }
22352}
22353
22354impl InvalidationRegion for SnippetState {
22355    fn ranges(&self) -> &[Range<Anchor>] {
22356        &self.ranges[self.active_index]
22357    }
22358}
22359
22360fn inline_completion_edit_text(
22361    current_snapshot: &BufferSnapshot,
22362    edits: &[(Range<Anchor>, String)],
22363    edit_preview: &EditPreview,
22364    include_deletions: bool,
22365    cx: &App,
22366) -> HighlightedText {
22367    let edits = edits
22368        .iter()
22369        .map(|(anchor, text)| {
22370            (
22371                anchor.start.text_anchor..anchor.end.text_anchor,
22372                text.clone(),
22373            )
22374        })
22375        .collect::<Vec<_>>();
22376
22377    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22378}
22379
22380pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22381    match severity {
22382        lsp::DiagnosticSeverity::ERROR => colors.error,
22383        lsp::DiagnosticSeverity::WARNING => colors.warning,
22384        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22385        lsp::DiagnosticSeverity::HINT => colors.info,
22386        _ => colors.ignored,
22387    }
22388}
22389
22390pub fn styled_runs_for_code_label<'a>(
22391    label: &'a CodeLabel,
22392    syntax_theme: &'a theme::SyntaxTheme,
22393) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22394    let fade_out = HighlightStyle {
22395        fade_out: Some(0.35),
22396        ..Default::default()
22397    };
22398
22399    let mut prev_end = label.filter_range.end;
22400    label
22401        .runs
22402        .iter()
22403        .enumerate()
22404        .flat_map(move |(ix, (range, highlight_id))| {
22405            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22406                style
22407            } else {
22408                return Default::default();
22409            };
22410            let mut muted_style = style;
22411            muted_style.highlight(fade_out);
22412
22413            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22414            if range.start >= label.filter_range.end {
22415                if range.start > prev_end {
22416                    runs.push((prev_end..range.start, fade_out));
22417                }
22418                runs.push((range.clone(), muted_style));
22419            } else if range.end <= label.filter_range.end {
22420                runs.push((range.clone(), style));
22421            } else {
22422                runs.push((range.start..label.filter_range.end, style));
22423                runs.push((label.filter_range.end..range.end, muted_style));
22424            }
22425            prev_end = cmp::max(prev_end, range.end);
22426
22427            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22428                runs.push((prev_end..label.text.len(), fade_out));
22429            }
22430
22431            runs
22432        })
22433}
22434
22435pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22436    let mut prev_index = 0;
22437    let mut prev_codepoint: Option<char> = None;
22438    text.char_indices()
22439        .chain([(text.len(), '\0')])
22440        .filter_map(move |(index, codepoint)| {
22441            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22442            let is_boundary = index == text.len()
22443                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22444                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22445            if is_boundary {
22446                let chunk = &text[prev_index..index];
22447                prev_index = index;
22448                Some(chunk)
22449            } else {
22450                None
22451            }
22452        })
22453}
22454
22455pub trait RangeToAnchorExt: Sized {
22456    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22457
22458    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22459        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22460        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22461    }
22462}
22463
22464impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22465    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22466        let start_offset = self.start.to_offset(snapshot);
22467        let end_offset = self.end.to_offset(snapshot);
22468        if start_offset == end_offset {
22469            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22470        } else {
22471            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22472        }
22473    }
22474}
22475
22476pub trait RowExt {
22477    fn as_f32(&self) -> f32;
22478
22479    fn next_row(&self) -> Self;
22480
22481    fn previous_row(&self) -> Self;
22482
22483    fn minus(&self, other: Self) -> u32;
22484}
22485
22486impl RowExt for DisplayRow {
22487    fn as_f32(&self) -> f32 {
22488        self.0 as f32
22489    }
22490
22491    fn next_row(&self) -> Self {
22492        Self(self.0 + 1)
22493    }
22494
22495    fn previous_row(&self) -> Self {
22496        Self(self.0.saturating_sub(1))
22497    }
22498
22499    fn minus(&self, other: Self) -> u32 {
22500        self.0 - other.0
22501    }
22502}
22503
22504impl RowExt for MultiBufferRow {
22505    fn as_f32(&self) -> f32 {
22506        self.0 as f32
22507    }
22508
22509    fn next_row(&self) -> Self {
22510        Self(self.0 + 1)
22511    }
22512
22513    fn previous_row(&self) -> Self {
22514        Self(self.0.saturating_sub(1))
22515    }
22516
22517    fn minus(&self, other: Self) -> u32 {
22518        self.0 - other.0
22519    }
22520}
22521
22522trait RowRangeExt {
22523    type Row;
22524
22525    fn len(&self) -> usize;
22526
22527    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22528}
22529
22530impl RowRangeExt for Range<MultiBufferRow> {
22531    type Row = MultiBufferRow;
22532
22533    fn len(&self) -> usize {
22534        (self.end.0 - self.start.0) as usize
22535    }
22536
22537    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22538        (self.start.0..self.end.0).map(MultiBufferRow)
22539    }
22540}
22541
22542impl RowRangeExt for Range<DisplayRow> {
22543    type Row = DisplayRow;
22544
22545    fn len(&self) -> usize {
22546        (self.end.0 - self.start.0) as usize
22547    }
22548
22549    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22550        (self.start.0..self.end.0).map(DisplayRow)
22551    }
22552}
22553
22554/// If select range has more than one line, we
22555/// just point the cursor to range.start.
22556fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22557    if range.start.row == range.end.row {
22558        range
22559    } else {
22560        range.start..range.start
22561    }
22562}
22563pub struct KillRing(ClipboardItem);
22564impl Global for KillRing {}
22565
22566const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22567
22568enum BreakpointPromptEditAction {
22569    Log,
22570    Condition,
22571    HitCondition,
22572}
22573
22574struct BreakpointPromptEditor {
22575    pub(crate) prompt: Entity<Editor>,
22576    editor: WeakEntity<Editor>,
22577    breakpoint_anchor: Anchor,
22578    breakpoint: Breakpoint,
22579    edit_action: BreakpointPromptEditAction,
22580    block_ids: HashSet<CustomBlockId>,
22581    editor_margins: Arc<Mutex<EditorMargins>>,
22582    _subscriptions: Vec<Subscription>,
22583}
22584
22585impl BreakpointPromptEditor {
22586    const MAX_LINES: u8 = 4;
22587
22588    fn new(
22589        editor: WeakEntity<Editor>,
22590        breakpoint_anchor: Anchor,
22591        breakpoint: Breakpoint,
22592        edit_action: BreakpointPromptEditAction,
22593        window: &mut Window,
22594        cx: &mut Context<Self>,
22595    ) -> Self {
22596        let base_text = match edit_action {
22597            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22598            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22599            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22600        }
22601        .map(|msg| msg.to_string())
22602        .unwrap_or_default();
22603
22604        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22605        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22606
22607        let prompt = cx.new(|cx| {
22608            let mut prompt = Editor::new(
22609                EditorMode::AutoHeight {
22610                    min_lines: 1,
22611                    max_lines: Self::MAX_LINES as usize,
22612                },
22613                buffer,
22614                None,
22615                window,
22616                cx,
22617            );
22618            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22619            prompt.set_show_cursor_when_unfocused(false, cx);
22620            prompt.set_placeholder_text(
22621                match edit_action {
22622                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22623                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22624                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22625                },
22626                cx,
22627            );
22628
22629            prompt
22630        });
22631
22632        Self {
22633            prompt,
22634            editor,
22635            breakpoint_anchor,
22636            breakpoint,
22637            edit_action,
22638            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22639            block_ids: Default::default(),
22640            _subscriptions: vec![],
22641        }
22642    }
22643
22644    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22645        self.block_ids.extend(block_ids)
22646    }
22647
22648    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22649        if let Some(editor) = self.editor.upgrade() {
22650            let message = self
22651                .prompt
22652                .read(cx)
22653                .buffer
22654                .read(cx)
22655                .as_singleton()
22656                .expect("A multi buffer in breakpoint prompt isn't possible")
22657                .read(cx)
22658                .as_rope()
22659                .to_string();
22660
22661            editor.update(cx, |editor, cx| {
22662                editor.edit_breakpoint_at_anchor(
22663                    self.breakpoint_anchor,
22664                    self.breakpoint.clone(),
22665                    match self.edit_action {
22666                        BreakpointPromptEditAction::Log => {
22667                            BreakpointEditAction::EditLogMessage(message.into())
22668                        }
22669                        BreakpointPromptEditAction::Condition => {
22670                            BreakpointEditAction::EditCondition(message.into())
22671                        }
22672                        BreakpointPromptEditAction::HitCondition => {
22673                            BreakpointEditAction::EditHitCondition(message.into())
22674                        }
22675                    },
22676                    cx,
22677                );
22678
22679                editor.remove_blocks(self.block_ids.clone(), None, cx);
22680                cx.focus_self(window);
22681            });
22682        }
22683    }
22684
22685    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22686        self.editor
22687            .update(cx, |editor, cx| {
22688                editor.remove_blocks(self.block_ids.clone(), None, cx);
22689                window.focus(&editor.focus_handle);
22690            })
22691            .log_err();
22692    }
22693
22694    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22695        let settings = ThemeSettings::get_global(cx);
22696        let text_style = TextStyle {
22697            color: if self.prompt.read(cx).read_only(cx) {
22698                cx.theme().colors().text_disabled
22699            } else {
22700                cx.theme().colors().text
22701            },
22702            font_family: settings.buffer_font.family.clone(),
22703            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22704            font_size: settings.buffer_font_size(cx).into(),
22705            font_weight: settings.buffer_font.weight,
22706            line_height: relative(settings.buffer_line_height.value()),
22707            ..Default::default()
22708        };
22709        EditorElement::new(
22710            &self.prompt,
22711            EditorStyle {
22712                background: cx.theme().colors().editor_background,
22713                local_player: cx.theme().players().local(),
22714                text: text_style,
22715                ..Default::default()
22716            },
22717        )
22718    }
22719}
22720
22721impl Render for BreakpointPromptEditor {
22722    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22723        let editor_margins = *self.editor_margins.lock();
22724        let gutter_dimensions = editor_margins.gutter;
22725        h_flex()
22726            .key_context("Editor")
22727            .bg(cx.theme().colors().editor_background)
22728            .border_y_1()
22729            .border_color(cx.theme().status().info_border)
22730            .size_full()
22731            .py(window.line_height() / 2.5)
22732            .on_action(cx.listener(Self::confirm))
22733            .on_action(cx.listener(Self::cancel))
22734            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22735            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22736    }
22737}
22738
22739impl Focusable for BreakpointPromptEditor {
22740    fn focus_handle(&self, cx: &App) -> FocusHandle {
22741        self.prompt.focus_handle(cx)
22742    }
22743}
22744
22745fn all_edits_insertions_or_deletions(
22746    edits: &Vec<(Range<Anchor>, String)>,
22747    snapshot: &MultiBufferSnapshot,
22748) -> bool {
22749    let mut all_insertions = true;
22750    let mut all_deletions = true;
22751
22752    for (range, new_text) in edits.iter() {
22753        let range_is_empty = range.to_offset(&snapshot).is_empty();
22754        let text_is_empty = new_text.is_empty();
22755
22756        if range_is_empty != text_is_empty {
22757            if range_is_empty {
22758                all_deletions = false;
22759            } else {
22760                all_insertions = false;
22761            }
22762        } else {
22763            return false;
22764        }
22765
22766        if !all_insertions && !all_deletions {
22767            return false;
22768        }
22769    }
22770    all_insertions || all_deletions
22771}
22772
22773struct MissingEditPredictionKeybindingTooltip;
22774
22775impl Render for MissingEditPredictionKeybindingTooltip {
22776    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22777        ui::tooltip_container(window, cx, |container, _, cx| {
22778            container
22779                .flex_shrink_0()
22780                .max_w_80()
22781                .min_h(rems_from_px(124.))
22782                .justify_between()
22783                .child(
22784                    v_flex()
22785                        .flex_1()
22786                        .text_ui_sm(cx)
22787                        .child(Label::new("Conflict with Accept Keybinding"))
22788                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22789                )
22790                .child(
22791                    h_flex()
22792                        .pb_1()
22793                        .gap_1()
22794                        .items_end()
22795                        .w_full()
22796                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22797                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22798                        }))
22799                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22800                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22801                        })),
22802                )
22803        })
22804    }
22805}
22806
22807#[derive(Debug, Clone, Copy, PartialEq)]
22808pub struct LineHighlight {
22809    pub background: Background,
22810    pub border: Option<gpui::Hsla>,
22811    pub include_gutter: bool,
22812    pub type_id: Option<TypeId>,
22813}
22814
22815fn render_diff_hunk_controls(
22816    row: u32,
22817    status: &DiffHunkStatus,
22818    hunk_range: Range<Anchor>,
22819    is_created_file: bool,
22820    line_height: Pixels,
22821    editor: &Entity<Editor>,
22822    _window: &mut Window,
22823    cx: &mut App,
22824) -> AnyElement {
22825    h_flex()
22826        .h(line_height)
22827        .mr_1()
22828        .gap_1()
22829        .px_0p5()
22830        .pb_1()
22831        .border_x_1()
22832        .border_b_1()
22833        .border_color(cx.theme().colors().border_variant)
22834        .rounded_b_lg()
22835        .bg(cx.theme().colors().editor_background)
22836        .gap_1()
22837        .block_mouse_except_scroll()
22838        .shadow_md()
22839        .child(if status.has_secondary_hunk() {
22840            Button::new(("stage", row as u64), "Stage")
22841                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22842                .tooltip({
22843                    let focus_handle = editor.focus_handle(cx);
22844                    move |window, cx| {
22845                        Tooltip::for_action_in(
22846                            "Stage Hunk",
22847                            &::git::ToggleStaged,
22848                            &focus_handle,
22849                            window,
22850                            cx,
22851                        )
22852                    }
22853                })
22854                .on_click({
22855                    let editor = editor.clone();
22856                    move |_event, _window, cx| {
22857                        editor.update(cx, |editor, cx| {
22858                            editor.stage_or_unstage_diff_hunks(
22859                                true,
22860                                vec![hunk_range.start..hunk_range.start],
22861                                cx,
22862                            );
22863                        });
22864                    }
22865                })
22866        } else {
22867            Button::new(("unstage", row as u64), "Unstage")
22868                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22869                .tooltip({
22870                    let focus_handle = editor.focus_handle(cx);
22871                    move |window, cx| {
22872                        Tooltip::for_action_in(
22873                            "Unstage Hunk",
22874                            &::git::ToggleStaged,
22875                            &focus_handle,
22876                            window,
22877                            cx,
22878                        )
22879                    }
22880                })
22881                .on_click({
22882                    let editor = editor.clone();
22883                    move |_event, _window, cx| {
22884                        editor.update(cx, |editor, cx| {
22885                            editor.stage_or_unstage_diff_hunks(
22886                                false,
22887                                vec![hunk_range.start..hunk_range.start],
22888                                cx,
22889                            );
22890                        });
22891                    }
22892                })
22893        })
22894        .child(
22895            Button::new(("restore", row as u64), "Restore")
22896                .tooltip({
22897                    let focus_handle = editor.focus_handle(cx);
22898                    move |window, cx| {
22899                        Tooltip::for_action_in(
22900                            "Restore Hunk",
22901                            &::git::Restore,
22902                            &focus_handle,
22903                            window,
22904                            cx,
22905                        )
22906                    }
22907                })
22908                .on_click({
22909                    let editor = editor.clone();
22910                    move |_event, window, cx| {
22911                        editor.update(cx, |editor, cx| {
22912                            let snapshot = editor.snapshot(window, cx);
22913                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22914                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22915                        });
22916                    }
22917                })
22918                .disabled(is_created_file),
22919        )
22920        .when(
22921            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22922            |el| {
22923                el.child(
22924                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22925                        .shape(IconButtonShape::Square)
22926                        .icon_size(IconSize::Small)
22927                        // .disabled(!has_multiple_hunks)
22928                        .tooltip({
22929                            let focus_handle = editor.focus_handle(cx);
22930                            move |window, cx| {
22931                                Tooltip::for_action_in(
22932                                    "Next Hunk",
22933                                    &GoToHunk,
22934                                    &focus_handle,
22935                                    window,
22936                                    cx,
22937                                )
22938                            }
22939                        })
22940                        .on_click({
22941                            let editor = editor.clone();
22942                            move |_event, window, cx| {
22943                                editor.update(cx, |editor, cx| {
22944                                    let snapshot = editor.snapshot(window, cx);
22945                                    let position =
22946                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22947                                    editor.go_to_hunk_before_or_after_position(
22948                                        &snapshot,
22949                                        position,
22950                                        Direction::Next,
22951                                        window,
22952                                        cx,
22953                                    );
22954                                    editor.expand_selected_diff_hunks(cx);
22955                                });
22956                            }
22957                        }),
22958                )
22959                .child(
22960                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22961                        .shape(IconButtonShape::Square)
22962                        .icon_size(IconSize::Small)
22963                        // .disabled(!has_multiple_hunks)
22964                        .tooltip({
22965                            let focus_handle = editor.focus_handle(cx);
22966                            move |window, cx| {
22967                                Tooltip::for_action_in(
22968                                    "Previous Hunk",
22969                                    &GoToPreviousHunk,
22970                                    &focus_handle,
22971                                    window,
22972                                    cx,
22973                                )
22974                            }
22975                        })
22976                        .on_click({
22977                            let editor = editor.clone();
22978                            move |_event, window, cx| {
22979                                editor.update(cx, |editor, cx| {
22980                                    let snapshot = editor.snapshot(window, cx);
22981                                    let point =
22982                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22983                                    editor.go_to_hunk_before_or_after_position(
22984                                        &snapshot,
22985                                        point,
22986                                        Direction::Prev,
22987                                        window,
22988                                        cx,
22989                                    );
22990                                    editor.expand_selected_diff_hunks(cx);
22991                                });
22992                            }
22993                        }),
22994                )
22995            },
22996        )
22997        .into_any_element()
22998}