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, Theme, 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
  707#[derive(Clone)]
  708pub struct BackgroundHighlight {
  709    pub range: Range<Anchor>,
  710    pub color_fetcher: fn(&Theme) -> Hsla,
  711}
  712
  713type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  714
  715#[derive(Default)]
  716struct ScrollbarMarkerState {
  717    scrollbar_size: Size<Pixels>,
  718    dirty: bool,
  719    markers: Arc<[PaintQuad]>,
  720    pending_refresh: Option<Task<Result<()>>>,
  721}
  722
  723impl ScrollbarMarkerState {
  724    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  725        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  726    }
  727}
  728
  729#[derive(Clone, Copy, PartialEq, Eq)]
  730pub enum MinimapVisibility {
  731    Disabled,
  732    Enabled {
  733        /// The configuration currently present in the users settings.
  734        setting_configuration: bool,
  735        /// Whether to override the currently set visibility from the users setting.
  736        toggle_override: bool,
  737    },
  738}
  739
  740impl MinimapVisibility {
  741    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  742        if mode.is_full() {
  743            Self::Enabled {
  744                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  745                toggle_override: false,
  746            }
  747        } else {
  748            Self::Disabled
  749        }
  750    }
  751
  752    fn hidden(&self) -> Self {
  753        match *self {
  754            Self::Enabled {
  755                setting_configuration,
  756                ..
  757            } => Self::Enabled {
  758                setting_configuration,
  759                toggle_override: setting_configuration,
  760            },
  761            Self::Disabled => Self::Disabled,
  762        }
  763    }
  764
  765    fn disabled(&self) -> bool {
  766        match *self {
  767            Self::Disabled => true,
  768            _ => false,
  769        }
  770    }
  771
  772    fn settings_visibility(&self) -> bool {
  773        match *self {
  774            Self::Enabled {
  775                setting_configuration,
  776                ..
  777            } => setting_configuration,
  778            _ => false,
  779        }
  780    }
  781
  782    fn visible(&self) -> bool {
  783        match *self {
  784            Self::Enabled {
  785                setting_configuration,
  786                toggle_override,
  787            } => setting_configuration ^ toggle_override,
  788            _ => false,
  789        }
  790    }
  791
  792    fn toggle_visibility(&self) -> Self {
  793        match *self {
  794            Self::Enabled {
  795                toggle_override,
  796                setting_configuration,
  797            } => Self::Enabled {
  798                setting_configuration,
  799                toggle_override: !toggle_override,
  800            },
  801            Self::Disabled => Self::Disabled,
  802        }
  803    }
  804}
  805
  806#[derive(Clone, Debug)]
  807struct RunnableTasks {
  808    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  809    offset: multi_buffer::Anchor,
  810    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  811    column: u32,
  812    // Values of all named captures, including those starting with '_'
  813    extra_variables: HashMap<String, String>,
  814    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  815    context_range: Range<BufferOffset>,
  816}
  817
  818impl RunnableTasks {
  819    fn resolve<'a>(
  820        &'a self,
  821        cx: &'a task::TaskContext,
  822    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  823        self.templates.iter().filter_map(|(kind, template)| {
  824            template
  825                .resolve_task(&kind.to_id_base(), cx)
  826                .map(|task| (kind.clone(), task))
  827        })
  828    }
  829}
  830
  831#[derive(Clone)]
  832pub struct ResolvedTasks {
  833    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  834    position: Anchor,
  835}
  836
  837#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  838struct BufferOffset(usize);
  839
  840// Addons allow storing per-editor state in other crates (e.g. Vim)
  841pub trait Addon: 'static {
  842    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  843
  844    fn render_buffer_header_controls(
  845        &self,
  846        _: &ExcerptInfo,
  847        _: &Window,
  848        _: &App,
  849    ) -> Option<AnyElement> {
  850        None
  851    }
  852
  853    fn to_any(&self) -> &dyn std::any::Any;
  854
  855    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  856        None
  857    }
  858}
  859
  860/// A set of caret positions, registered when the editor was edited.
  861pub struct ChangeList {
  862    changes: Vec<Vec<Anchor>>,
  863    /// Currently "selected" change.
  864    position: Option<usize>,
  865}
  866
  867impl ChangeList {
  868    pub fn new() -> Self {
  869        Self {
  870            changes: Vec::new(),
  871            position: None,
  872        }
  873    }
  874
  875    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  876    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  877    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  878        if self.changes.is_empty() {
  879            return None;
  880        }
  881
  882        let prev = self.position.unwrap_or(self.changes.len());
  883        let next = if direction == Direction::Prev {
  884            prev.saturating_sub(count)
  885        } else {
  886            (prev + count).min(self.changes.len() - 1)
  887        };
  888        self.position = Some(next);
  889        self.changes.get(next).map(|anchors| anchors.as_slice())
  890    }
  891
  892    /// Adds a new change to the list, resetting the change list position.
  893    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  894        self.position.take();
  895        if pop_state {
  896            self.changes.pop();
  897        }
  898        self.changes.push(new_positions.clone());
  899    }
  900
  901    pub fn last(&self) -> Option<&[Anchor]> {
  902        self.changes.last().map(|anchors| anchors.as_slice())
  903    }
  904}
  905
  906#[derive(Clone)]
  907struct InlineBlamePopoverState {
  908    scroll_handle: ScrollHandle,
  909    commit_message: Option<ParsedCommitMessage>,
  910    markdown: Entity<Markdown>,
  911}
  912
  913struct InlineBlamePopover {
  914    position: gpui::Point<Pixels>,
  915    hide_task: Option<Task<()>>,
  916    popover_bounds: Option<Bounds<Pixels>>,
  917    popover_state: InlineBlamePopoverState,
  918}
  919
  920enum SelectionDragState {
  921    /// State when no drag related activity is detected.
  922    None,
  923    /// State when the mouse is down on a selection that is about to be dragged.
  924    ReadyToDrag {
  925        selection: Selection<Anchor>,
  926        click_position: gpui::Point<Pixels>,
  927        mouse_down_time: Instant,
  928    },
  929    /// State when the mouse is dragging the selection in the editor.
  930    Dragging {
  931        selection: Selection<Anchor>,
  932        drop_cursor: Selection<Anchor>,
  933        hide_drop_cursor: bool,
  934    },
  935}
  936
  937enum ColumnarSelectionState {
  938    FromMouse {
  939        selection_tail: Anchor,
  940        display_point: Option<DisplayPoint>,
  941    },
  942    FromSelection {
  943        selection_tail: Anchor,
  944    },
  945}
  946
  947/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  948/// a breakpoint on them.
  949#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  950struct PhantomBreakpointIndicator {
  951    display_row: DisplayRow,
  952    /// There's a small debounce between hovering over the line and showing the indicator.
  953    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  954    is_active: bool,
  955    collides_with_existing_breakpoint: bool,
  956}
  957
  958/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  959///
  960/// See the [module level documentation](self) for more information.
  961pub struct Editor {
  962    focus_handle: FocusHandle,
  963    last_focused_descendant: Option<WeakFocusHandle>,
  964    /// The text buffer being edited
  965    buffer: Entity<MultiBuffer>,
  966    /// Map of how text in the buffer should be displayed.
  967    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  968    pub display_map: Entity<DisplayMap>,
  969    pub selections: SelectionsCollection,
  970    pub scroll_manager: ScrollManager,
  971    /// When inline assist editors are linked, they all render cursors because
  972    /// typing enters text into each of them, even the ones that aren't focused.
  973    pub(crate) show_cursor_when_unfocused: bool,
  974    columnar_selection_state: Option<ColumnarSelectionState>,
  975    add_selections_state: Option<AddSelectionsState>,
  976    select_next_state: Option<SelectNextState>,
  977    select_prev_state: Option<SelectNextState>,
  978    selection_history: SelectionHistory,
  979    defer_selection_effects: bool,
  980    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  981    autoclose_regions: Vec<AutocloseRegion>,
  982    snippet_stack: InvalidationStack<SnippetState>,
  983    select_syntax_node_history: SelectSyntaxNodeHistory,
  984    ime_transaction: Option<TransactionId>,
  985    pub diagnostics_max_severity: DiagnosticSeverity,
  986    active_diagnostics: ActiveDiagnostic,
  987    show_inline_diagnostics: bool,
  988    inline_diagnostics_update: Task<()>,
  989    inline_diagnostics_enabled: bool,
  990    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  991    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  992    hard_wrap: Option<usize>,
  993
  994    // TODO: make this a access method
  995    pub project: Option<Entity<Project>>,
  996    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  997    completion_provider: Option<Rc<dyn CompletionProvider>>,
  998    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  999    blink_manager: Entity<BlinkManager>,
 1000    show_cursor_names: bool,
 1001    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1002    pub show_local_selections: bool,
 1003    mode: EditorMode,
 1004    show_breadcrumbs: bool,
 1005    show_gutter: bool,
 1006    show_scrollbars: ScrollbarAxes,
 1007    minimap_visibility: MinimapVisibility,
 1008    offset_content: bool,
 1009    disable_expand_excerpt_buttons: bool,
 1010    show_line_numbers: Option<bool>,
 1011    use_relative_line_numbers: Option<bool>,
 1012    show_git_diff_gutter: Option<bool>,
 1013    show_code_actions: Option<bool>,
 1014    show_runnables: Option<bool>,
 1015    show_breakpoints: Option<bool>,
 1016    show_wrap_guides: Option<bool>,
 1017    show_indent_guides: Option<bool>,
 1018    placeholder_text: Option<Arc<str>>,
 1019    highlight_order: usize,
 1020    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1021    background_highlights: TreeMap<TypeId, Vec<BackgroundHighlight>>,
 1022    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1023    scrollbar_marker_state: ScrollbarMarkerState,
 1024    active_indent_guides_state: ActiveIndentGuidesState,
 1025    nav_history: Option<ItemNavHistory>,
 1026    context_menu: RefCell<Option<CodeContextMenu>>,
 1027    context_menu_options: Option<ContextMenuOptions>,
 1028    mouse_context_menu: Option<MouseContextMenu>,
 1029    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1030    inline_blame_popover: Option<InlineBlamePopover>,
 1031    inline_blame_popover_show_task: Option<Task<()>>,
 1032    signature_help_state: SignatureHelpState,
 1033    auto_signature_help: Option<bool>,
 1034    find_all_references_task_sources: Vec<Anchor>,
 1035    next_completion_id: CompletionId,
 1036    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1037    code_actions_task: Option<Task<Result<()>>>,
 1038    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1039    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1040    document_highlights_task: Option<Task<()>>,
 1041    linked_editing_range_task: Option<Task<Option<()>>>,
 1042    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1043    pending_rename: Option<RenameState>,
 1044    searchable: bool,
 1045    cursor_shape: CursorShape,
 1046    current_line_highlight: Option<CurrentLineHighlight>,
 1047    collapse_matches: bool,
 1048    autoindent_mode: Option<AutoindentMode>,
 1049    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1050    input_enabled: bool,
 1051    use_modal_editing: bool,
 1052    read_only: bool,
 1053    leader_id: Option<CollaboratorId>,
 1054    remote_id: Option<ViewId>,
 1055    pub hover_state: HoverState,
 1056    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1057    gutter_hovered: bool,
 1058    hovered_link_state: Option<HoveredLinkState>,
 1059    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1060    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1061    active_inline_completion: Option<InlineCompletionState>,
 1062    /// Used to prevent flickering as the user types while the menu is open
 1063    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1064    edit_prediction_settings: EditPredictionSettings,
 1065    inline_completions_hidden_for_vim_mode: bool,
 1066    show_inline_completions_override: Option<bool>,
 1067    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1068    edit_prediction_preview: EditPredictionPreview,
 1069    edit_prediction_indent_conflict: bool,
 1070    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1071    inlay_hint_cache: InlayHintCache,
 1072    next_inlay_id: usize,
 1073    _subscriptions: Vec<Subscription>,
 1074    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1075    gutter_dimensions: GutterDimensions,
 1076    style: Option<EditorStyle>,
 1077    text_style_refinement: Option<TextStyleRefinement>,
 1078    next_editor_action_id: EditorActionId,
 1079    editor_actions: Rc<
 1080        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1081    >,
 1082    use_autoclose: bool,
 1083    use_auto_surround: bool,
 1084    auto_replace_emoji_shortcode: bool,
 1085    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1086    show_git_blame_gutter: bool,
 1087    show_git_blame_inline: bool,
 1088    show_git_blame_inline_delay_task: Option<Task<()>>,
 1089    git_blame_inline_enabled: bool,
 1090    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1091    serialize_dirty_buffers: bool,
 1092    show_selection_menu: Option<bool>,
 1093    blame: Option<Entity<GitBlame>>,
 1094    blame_subscription: Option<Subscription>,
 1095    custom_context_menu: Option<
 1096        Box<
 1097            dyn 'static
 1098                + Fn(
 1099                    &mut Self,
 1100                    DisplayPoint,
 1101                    &mut Window,
 1102                    &mut Context<Self>,
 1103                ) -> Option<Entity<ui::ContextMenu>>,
 1104        >,
 1105    >,
 1106    last_bounds: Option<Bounds<Pixels>>,
 1107    last_position_map: Option<Rc<PositionMap>>,
 1108    expect_bounds_change: Option<Bounds<Pixels>>,
 1109    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1110    tasks_update_task: Option<Task<()>>,
 1111    breakpoint_store: Option<Entity<BreakpointStore>>,
 1112    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1113    hovered_diff_hunk_row: Option<DisplayRow>,
 1114    pull_diagnostics_task: Task<()>,
 1115    in_project_search: bool,
 1116    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1117    breadcrumb_header: Option<String>,
 1118    focused_block: Option<FocusedBlock>,
 1119    next_scroll_position: NextScrollCursorCenterTopBottom,
 1120    addons: HashMap<TypeId, Box<dyn Addon>>,
 1121    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1122    load_diff_task: Option<Shared<Task<()>>>,
 1123    /// Whether we are temporarily displaying a diff other than git's
 1124    temporary_diff_override: bool,
 1125    selection_mark_mode: bool,
 1126    toggle_fold_multiple_buffers: Task<()>,
 1127    _scroll_cursor_center_top_bottom_task: Task<()>,
 1128    serialize_selections: Task<()>,
 1129    serialize_folds: Task<()>,
 1130    mouse_cursor_hidden: bool,
 1131    minimap: Option<Entity<Self>>,
 1132    hide_mouse_mode: HideMouseMode,
 1133    pub change_list: ChangeList,
 1134    inline_value_cache: InlineValueCache,
 1135    selection_drag_state: SelectionDragState,
 1136    drag_and_drop_selection_enabled: bool,
 1137}
 1138
 1139#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1140enum NextScrollCursorCenterTopBottom {
 1141    #[default]
 1142    Center,
 1143    Top,
 1144    Bottom,
 1145}
 1146
 1147impl NextScrollCursorCenterTopBottom {
 1148    fn next(&self) -> Self {
 1149        match self {
 1150            Self::Center => Self::Top,
 1151            Self::Top => Self::Bottom,
 1152            Self::Bottom => Self::Center,
 1153        }
 1154    }
 1155}
 1156
 1157#[derive(Clone)]
 1158pub struct EditorSnapshot {
 1159    pub mode: EditorMode,
 1160    show_gutter: bool,
 1161    show_line_numbers: Option<bool>,
 1162    show_git_diff_gutter: Option<bool>,
 1163    show_code_actions: Option<bool>,
 1164    show_runnables: Option<bool>,
 1165    show_breakpoints: Option<bool>,
 1166    git_blame_gutter_max_author_length: Option<usize>,
 1167    pub display_snapshot: DisplaySnapshot,
 1168    pub placeholder_text: Option<Arc<str>>,
 1169    is_focused: bool,
 1170    scroll_anchor: ScrollAnchor,
 1171    ongoing_scroll: OngoingScroll,
 1172    current_line_highlight: CurrentLineHighlight,
 1173    gutter_hovered: bool,
 1174}
 1175
 1176#[derive(Default, Debug, Clone, Copy)]
 1177pub struct GutterDimensions {
 1178    pub left_padding: Pixels,
 1179    pub right_padding: Pixels,
 1180    pub width: Pixels,
 1181    pub margin: Pixels,
 1182    pub git_blame_entries_width: Option<Pixels>,
 1183}
 1184
 1185impl GutterDimensions {
 1186    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1187        Self {
 1188            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1189            ..Default::default()
 1190        }
 1191    }
 1192
 1193    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1194        -cx.text_system().descent(font_id, font_size)
 1195    }
 1196    /// The full width of the space taken up by the gutter.
 1197    pub fn full_width(&self) -> Pixels {
 1198        self.margin + self.width
 1199    }
 1200
 1201    /// The width of the space reserved for the fold indicators,
 1202    /// use alongside 'justify_end' and `gutter_width` to
 1203    /// right align content with the line numbers
 1204    pub fn fold_area_width(&self) -> Pixels {
 1205        self.margin + self.right_padding
 1206    }
 1207}
 1208
 1209#[derive(Debug)]
 1210pub struct RemoteSelection {
 1211    pub replica_id: ReplicaId,
 1212    pub selection: Selection<Anchor>,
 1213    pub cursor_shape: CursorShape,
 1214    pub collaborator_id: CollaboratorId,
 1215    pub line_mode: bool,
 1216    pub user_name: Option<SharedString>,
 1217    pub color: PlayerColor,
 1218}
 1219
 1220#[derive(Clone, Debug)]
 1221struct SelectionHistoryEntry {
 1222    selections: Arc<[Selection<Anchor>]>,
 1223    select_next_state: Option<SelectNextState>,
 1224    select_prev_state: Option<SelectNextState>,
 1225    add_selections_state: Option<AddSelectionsState>,
 1226}
 1227
 1228#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1229enum SelectionHistoryMode {
 1230    Normal,
 1231    Undoing,
 1232    Redoing,
 1233    Skipping,
 1234}
 1235
 1236#[derive(Clone, PartialEq, Eq, Hash)]
 1237struct HoveredCursor {
 1238    replica_id: u16,
 1239    selection_id: usize,
 1240}
 1241
 1242impl Default for SelectionHistoryMode {
 1243    fn default() -> Self {
 1244        Self::Normal
 1245    }
 1246}
 1247
 1248#[derive(Debug)]
 1249pub struct SelectionEffects {
 1250    nav_history: bool,
 1251    completions: bool,
 1252    scroll: Option<Autoscroll>,
 1253}
 1254
 1255impl Default for SelectionEffects {
 1256    fn default() -> Self {
 1257        Self {
 1258            nav_history: true,
 1259            completions: true,
 1260            scroll: Some(Autoscroll::fit()),
 1261        }
 1262    }
 1263}
 1264impl SelectionEffects {
 1265    pub fn scroll(scroll: Autoscroll) -> Self {
 1266        Self {
 1267            scroll: Some(scroll),
 1268            ..Default::default()
 1269        }
 1270    }
 1271
 1272    pub fn no_scroll() -> Self {
 1273        Self {
 1274            scroll: None,
 1275            ..Default::default()
 1276        }
 1277    }
 1278
 1279    pub fn completions(self, completions: bool) -> Self {
 1280        Self {
 1281            completions,
 1282            ..self
 1283        }
 1284    }
 1285
 1286    pub fn nav_history(self, nav_history: bool) -> Self {
 1287        Self {
 1288            nav_history,
 1289            ..self
 1290        }
 1291    }
 1292}
 1293
 1294struct DeferredSelectionEffectsState {
 1295    changed: bool,
 1296    effects: SelectionEffects,
 1297    old_cursor_position: Anchor,
 1298    history_entry: SelectionHistoryEntry,
 1299}
 1300
 1301#[derive(Default)]
 1302struct SelectionHistory {
 1303    #[allow(clippy::type_complexity)]
 1304    selections_by_transaction:
 1305        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1306    mode: SelectionHistoryMode,
 1307    undo_stack: VecDeque<SelectionHistoryEntry>,
 1308    redo_stack: VecDeque<SelectionHistoryEntry>,
 1309}
 1310
 1311impl SelectionHistory {
 1312    #[track_caller]
 1313    fn insert_transaction(
 1314        &mut self,
 1315        transaction_id: TransactionId,
 1316        selections: Arc<[Selection<Anchor>]>,
 1317    ) {
 1318        if selections.is_empty() {
 1319            log::error!(
 1320                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1321                std::panic::Location::caller()
 1322            );
 1323            return;
 1324        }
 1325        self.selections_by_transaction
 1326            .insert(transaction_id, (selections, None));
 1327    }
 1328
 1329    #[allow(clippy::type_complexity)]
 1330    fn transaction(
 1331        &self,
 1332        transaction_id: TransactionId,
 1333    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1334        self.selections_by_transaction.get(&transaction_id)
 1335    }
 1336
 1337    #[allow(clippy::type_complexity)]
 1338    fn transaction_mut(
 1339        &mut self,
 1340        transaction_id: TransactionId,
 1341    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1342        self.selections_by_transaction.get_mut(&transaction_id)
 1343    }
 1344
 1345    fn push(&mut self, entry: SelectionHistoryEntry) {
 1346        if !entry.selections.is_empty() {
 1347            match self.mode {
 1348                SelectionHistoryMode::Normal => {
 1349                    self.push_undo(entry);
 1350                    self.redo_stack.clear();
 1351                }
 1352                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1353                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1354                SelectionHistoryMode::Skipping => {}
 1355            }
 1356        }
 1357    }
 1358
 1359    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1360        if self
 1361            .undo_stack
 1362            .back()
 1363            .map_or(true, |e| e.selections != entry.selections)
 1364        {
 1365            self.undo_stack.push_back(entry);
 1366            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1367                self.undo_stack.pop_front();
 1368            }
 1369        }
 1370    }
 1371
 1372    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1373        if self
 1374            .redo_stack
 1375            .back()
 1376            .map_or(true, |e| e.selections != entry.selections)
 1377        {
 1378            self.redo_stack.push_back(entry);
 1379            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1380                self.redo_stack.pop_front();
 1381            }
 1382        }
 1383    }
 1384}
 1385
 1386#[derive(Clone, Copy)]
 1387pub struct RowHighlightOptions {
 1388    pub autoscroll: bool,
 1389    pub include_gutter: bool,
 1390}
 1391
 1392impl Default for RowHighlightOptions {
 1393    fn default() -> Self {
 1394        Self {
 1395            autoscroll: Default::default(),
 1396            include_gutter: true,
 1397        }
 1398    }
 1399}
 1400
 1401struct RowHighlight {
 1402    index: usize,
 1403    range: Range<Anchor>,
 1404    color: Hsla,
 1405    options: RowHighlightOptions,
 1406    type_id: TypeId,
 1407}
 1408
 1409#[derive(Clone, Debug)]
 1410struct AddSelectionsState {
 1411    groups: Vec<AddSelectionsGroup>,
 1412}
 1413
 1414#[derive(Clone, Debug)]
 1415struct AddSelectionsGroup {
 1416    above: bool,
 1417    stack: Vec<usize>,
 1418}
 1419
 1420#[derive(Clone)]
 1421struct SelectNextState {
 1422    query: AhoCorasick,
 1423    wordwise: bool,
 1424    done: bool,
 1425}
 1426
 1427impl std::fmt::Debug for SelectNextState {
 1428    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1429        f.debug_struct(std::any::type_name::<Self>())
 1430            .field("wordwise", &self.wordwise)
 1431            .field("done", &self.done)
 1432            .finish()
 1433    }
 1434}
 1435
 1436#[derive(Debug)]
 1437struct AutocloseRegion {
 1438    selection_id: usize,
 1439    range: Range<Anchor>,
 1440    pair: BracketPair,
 1441}
 1442
 1443#[derive(Debug)]
 1444struct SnippetState {
 1445    ranges: Vec<Vec<Range<Anchor>>>,
 1446    active_index: usize,
 1447    choices: Vec<Option<Vec<String>>>,
 1448}
 1449
 1450#[doc(hidden)]
 1451pub struct RenameState {
 1452    pub range: Range<Anchor>,
 1453    pub old_name: Arc<str>,
 1454    pub editor: Entity<Editor>,
 1455    block_id: CustomBlockId,
 1456}
 1457
 1458struct InvalidationStack<T>(Vec<T>);
 1459
 1460struct RegisteredInlineCompletionProvider {
 1461    provider: Arc<dyn InlineCompletionProviderHandle>,
 1462    _subscription: Subscription,
 1463}
 1464
 1465#[derive(Debug, PartialEq, Eq)]
 1466pub struct ActiveDiagnosticGroup {
 1467    pub active_range: Range<Anchor>,
 1468    pub active_message: String,
 1469    pub group_id: usize,
 1470    pub blocks: HashSet<CustomBlockId>,
 1471}
 1472
 1473#[derive(Debug, PartialEq, Eq)]
 1474
 1475pub(crate) enum ActiveDiagnostic {
 1476    None,
 1477    All,
 1478    Group(ActiveDiagnosticGroup),
 1479}
 1480
 1481#[derive(Serialize, Deserialize, Clone, Debug)]
 1482pub struct ClipboardSelection {
 1483    /// The number of bytes in this selection.
 1484    pub len: usize,
 1485    /// Whether this was a full-line selection.
 1486    pub is_entire_line: bool,
 1487    /// The indentation of the first line when this content was originally copied.
 1488    pub first_line_indent: u32,
 1489}
 1490
 1491// selections, scroll behavior, was newest selection reversed
 1492type SelectSyntaxNodeHistoryState = (
 1493    Box<[Selection<usize>]>,
 1494    SelectSyntaxNodeScrollBehavior,
 1495    bool,
 1496);
 1497
 1498#[derive(Default)]
 1499struct SelectSyntaxNodeHistory {
 1500    stack: Vec<SelectSyntaxNodeHistoryState>,
 1501    // disable temporarily to allow changing selections without losing the stack
 1502    pub disable_clearing: bool,
 1503}
 1504
 1505impl SelectSyntaxNodeHistory {
 1506    pub fn try_clear(&mut self) {
 1507        if !self.disable_clearing {
 1508            self.stack.clear();
 1509        }
 1510    }
 1511
 1512    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1513        self.stack.push(selection);
 1514    }
 1515
 1516    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1517        self.stack.pop()
 1518    }
 1519}
 1520
 1521enum SelectSyntaxNodeScrollBehavior {
 1522    CursorTop,
 1523    FitSelection,
 1524    CursorBottom,
 1525}
 1526
 1527#[derive(Debug)]
 1528pub(crate) struct NavigationData {
 1529    cursor_anchor: Anchor,
 1530    cursor_position: Point,
 1531    scroll_anchor: ScrollAnchor,
 1532    scroll_top_row: u32,
 1533}
 1534
 1535#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1536pub enum GotoDefinitionKind {
 1537    Symbol,
 1538    Declaration,
 1539    Type,
 1540    Implementation,
 1541}
 1542
 1543#[derive(Debug, Clone)]
 1544enum InlayHintRefreshReason {
 1545    ModifiersChanged(bool),
 1546    Toggle(bool),
 1547    SettingsChange(InlayHintSettings),
 1548    NewLinesShown,
 1549    BufferEdited(HashSet<Arc<Language>>),
 1550    RefreshRequested,
 1551    ExcerptsRemoved(Vec<ExcerptId>),
 1552}
 1553
 1554impl InlayHintRefreshReason {
 1555    fn description(&self) -> &'static str {
 1556        match self {
 1557            Self::ModifiersChanged(_) => "modifiers changed",
 1558            Self::Toggle(_) => "toggle",
 1559            Self::SettingsChange(_) => "settings change",
 1560            Self::NewLinesShown => "new lines shown",
 1561            Self::BufferEdited(_) => "buffer edited",
 1562            Self::RefreshRequested => "refresh requested",
 1563            Self::ExcerptsRemoved(_) => "excerpts removed",
 1564        }
 1565    }
 1566}
 1567
 1568pub enum FormatTarget {
 1569    Buffers(HashSet<Entity<Buffer>>),
 1570    Ranges(Vec<Range<MultiBufferPoint>>),
 1571}
 1572
 1573pub(crate) struct FocusedBlock {
 1574    id: BlockId,
 1575    focus_handle: WeakFocusHandle,
 1576}
 1577
 1578#[derive(Clone)]
 1579enum JumpData {
 1580    MultiBufferRow {
 1581        row: MultiBufferRow,
 1582        line_offset_from_top: u32,
 1583    },
 1584    MultiBufferPoint {
 1585        excerpt_id: ExcerptId,
 1586        position: Point,
 1587        anchor: text::Anchor,
 1588        line_offset_from_top: u32,
 1589    },
 1590}
 1591
 1592pub enum MultibufferSelectionMode {
 1593    First,
 1594    All,
 1595}
 1596
 1597#[derive(Clone, Copy, Debug, Default)]
 1598pub struct RewrapOptions {
 1599    pub override_language_settings: bool,
 1600    pub preserve_existing_whitespace: bool,
 1601}
 1602
 1603impl Editor {
 1604    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1605        let buffer = cx.new(|cx| Buffer::local("", cx));
 1606        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1607        Self::new(
 1608            EditorMode::SingleLine { auto_width: false },
 1609            buffer,
 1610            None,
 1611            window,
 1612            cx,
 1613        )
 1614    }
 1615
 1616    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1617        let buffer = cx.new(|cx| Buffer::local("", cx));
 1618        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1619        Self::new(EditorMode::full(), buffer, None, window, cx)
 1620    }
 1621
 1622    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1623        let buffer = cx.new(|cx| Buffer::local("", cx));
 1624        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1625        Self::new(
 1626            EditorMode::SingleLine { auto_width: true },
 1627            buffer,
 1628            None,
 1629            window,
 1630            cx,
 1631        )
 1632    }
 1633
 1634    pub fn auto_height(
 1635        min_lines: usize,
 1636        max_lines: usize,
 1637        window: &mut Window,
 1638        cx: &mut Context<Self>,
 1639    ) -> Self {
 1640        let buffer = cx.new(|cx| Buffer::local("", cx));
 1641        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1642        Self::new(
 1643            EditorMode::AutoHeight {
 1644                min_lines,
 1645                max_lines,
 1646            },
 1647            buffer,
 1648            None,
 1649            window,
 1650            cx,
 1651        )
 1652    }
 1653
 1654    pub fn for_buffer(
 1655        buffer: Entity<Buffer>,
 1656        project: Option<Entity<Project>>,
 1657        window: &mut Window,
 1658        cx: &mut Context<Self>,
 1659    ) -> Self {
 1660        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1661        Self::new(EditorMode::full(), buffer, project, window, cx)
 1662    }
 1663
 1664    pub fn for_multibuffer(
 1665        buffer: Entity<MultiBuffer>,
 1666        project: Option<Entity<Project>>,
 1667        window: &mut Window,
 1668        cx: &mut Context<Self>,
 1669    ) -> Self {
 1670        Self::new(EditorMode::full(), buffer, project, window, cx)
 1671    }
 1672
 1673    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1674        let mut clone = Self::new(
 1675            self.mode.clone(),
 1676            self.buffer.clone(),
 1677            self.project.clone(),
 1678            window,
 1679            cx,
 1680        );
 1681        self.display_map.update(cx, |display_map, cx| {
 1682            let snapshot = display_map.snapshot(cx);
 1683            clone.display_map.update(cx, |display_map, cx| {
 1684                display_map.set_state(&snapshot, cx);
 1685            });
 1686        });
 1687        clone.folds_did_change(cx);
 1688        clone.selections.clone_state(&self.selections);
 1689        clone.scroll_manager.clone_state(&self.scroll_manager);
 1690        clone.searchable = self.searchable;
 1691        clone.read_only = self.read_only;
 1692        clone
 1693    }
 1694
 1695    pub fn new(
 1696        mode: EditorMode,
 1697        buffer: Entity<MultiBuffer>,
 1698        project: Option<Entity<Project>>,
 1699        window: &mut Window,
 1700        cx: &mut Context<Self>,
 1701    ) -> Self {
 1702        Editor::new_internal(mode, buffer, project, None, window, cx)
 1703    }
 1704
 1705    fn new_internal(
 1706        mode: EditorMode,
 1707        buffer: Entity<MultiBuffer>,
 1708        project: Option<Entity<Project>>,
 1709        display_map: Option<Entity<DisplayMap>>,
 1710        window: &mut Window,
 1711        cx: &mut Context<Self>,
 1712    ) -> Self {
 1713        debug_assert!(
 1714            display_map.is_none() || mode.is_minimap(),
 1715            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1716        );
 1717
 1718        let full_mode = mode.is_full();
 1719        let diagnostics_max_severity = if full_mode {
 1720            EditorSettings::get_global(cx)
 1721                .diagnostics_max_severity
 1722                .unwrap_or(DiagnosticSeverity::Hint)
 1723        } else {
 1724            DiagnosticSeverity::Off
 1725        };
 1726        let style = window.text_style();
 1727        let font_size = style.font_size.to_pixels(window.rem_size());
 1728        let editor = cx.entity().downgrade();
 1729        let fold_placeholder = FoldPlaceholder {
 1730            constrain_width: true,
 1731            render: Arc::new(move |fold_id, fold_range, cx| {
 1732                let editor = editor.clone();
 1733                div()
 1734                    .id(fold_id)
 1735                    .bg(cx.theme().colors().ghost_element_background)
 1736                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1737                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1738                    .rounded_xs()
 1739                    .size_full()
 1740                    .cursor_pointer()
 1741                    .child("")
 1742                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1743                    .on_click(move |_, _window, cx| {
 1744                        editor
 1745                            .update(cx, |editor, cx| {
 1746                                editor.unfold_ranges(
 1747                                    &[fold_range.start..fold_range.end],
 1748                                    true,
 1749                                    false,
 1750                                    cx,
 1751                                );
 1752                                cx.stop_propagation();
 1753                            })
 1754                            .ok();
 1755                    })
 1756                    .into_any()
 1757            }),
 1758            merge_adjacent: true,
 1759            ..FoldPlaceholder::default()
 1760        };
 1761        let display_map = display_map.unwrap_or_else(|| {
 1762            cx.new(|cx| {
 1763                DisplayMap::new(
 1764                    buffer.clone(),
 1765                    style.font(),
 1766                    font_size,
 1767                    None,
 1768                    FILE_HEADER_HEIGHT,
 1769                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1770                    fold_placeholder,
 1771                    diagnostics_max_severity,
 1772                    cx,
 1773                )
 1774            })
 1775        });
 1776
 1777        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1778
 1779        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1780
 1781        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1782            .then(|| language_settings::SoftWrap::None);
 1783
 1784        let mut project_subscriptions = Vec::new();
 1785        if mode.is_full() {
 1786            if let Some(project) = project.as_ref() {
 1787                project_subscriptions.push(cx.subscribe_in(
 1788                    project,
 1789                    window,
 1790                    |editor, _, event, window, cx| match event {
 1791                        project::Event::RefreshCodeLens => {
 1792                            // we always query lens with actions, without storing them, always refreshing them
 1793                        }
 1794                        project::Event::RefreshInlayHints => {
 1795                            editor
 1796                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1797                        }
 1798                        project::Event::LanguageServerAdded(..)
 1799                        | project::Event::LanguageServerRemoved(..) => {
 1800                            if editor.tasks_update_task.is_none() {
 1801                                editor.tasks_update_task =
 1802                                    Some(editor.refresh_runnables(window, cx));
 1803                            }
 1804                            editor.pull_diagnostics(None, window, cx);
 1805                        }
 1806                        project::Event::SnippetEdit(id, snippet_edits) => {
 1807                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1808                                let focus_handle = editor.focus_handle(cx);
 1809                                if focus_handle.is_focused(window) {
 1810                                    let snapshot = buffer.read(cx).snapshot();
 1811                                    for (range, snippet) in snippet_edits {
 1812                                        let editor_range =
 1813                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1814                                        editor
 1815                                            .insert_snippet(
 1816                                                &[editor_range],
 1817                                                snippet.clone(),
 1818                                                window,
 1819                                                cx,
 1820                                            )
 1821                                            .ok();
 1822                                    }
 1823                                }
 1824                            }
 1825                        }
 1826                        _ => {}
 1827                    },
 1828                ));
 1829                if let Some(task_inventory) = project
 1830                    .read(cx)
 1831                    .task_store()
 1832                    .read(cx)
 1833                    .task_inventory()
 1834                    .cloned()
 1835                {
 1836                    project_subscriptions.push(cx.observe_in(
 1837                        &task_inventory,
 1838                        window,
 1839                        |editor, _, window, cx| {
 1840                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1841                        },
 1842                    ));
 1843                };
 1844
 1845                project_subscriptions.push(cx.subscribe_in(
 1846                    &project.read(cx).breakpoint_store(),
 1847                    window,
 1848                    |editor, _, event, window, cx| match event {
 1849                        BreakpointStoreEvent::ClearDebugLines => {
 1850                            editor.clear_row_highlights::<ActiveDebugLine>();
 1851                            editor.refresh_inline_values(cx);
 1852                        }
 1853                        BreakpointStoreEvent::SetDebugLine => {
 1854                            if editor.go_to_active_debug_line(window, cx) {
 1855                                cx.stop_propagation();
 1856                            }
 1857
 1858                            editor.refresh_inline_values(cx);
 1859                        }
 1860                        _ => {}
 1861                    },
 1862                ));
 1863            }
 1864        }
 1865
 1866        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1867
 1868        let inlay_hint_settings =
 1869            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1870        let focus_handle = cx.focus_handle();
 1871        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1872            .detach();
 1873        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1874            .detach();
 1875        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1876            .detach();
 1877        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1878            .detach();
 1879        cx.observe_pending_input(window, Self::observe_pending_input)
 1880            .detach();
 1881
 1882        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1883            Some(false)
 1884        } else {
 1885            None
 1886        };
 1887
 1888        let breakpoint_store = match (&mode, project.as_ref()) {
 1889            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1890            _ => None,
 1891        };
 1892
 1893        let mut code_action_providers = Vec::new();
 1894        let mut load_uncommitted_diff = None;
 1895        if let Some(project) = project.clone() {
 1896            load_uncommitted_diff = Some(
 1897                update_uncommitted_diff_for_buffer(
 1898                    cx.entity(),
 1899                    &project,
 1900                    buffer.read(cx).all_buffers(),
 1901                    buffer.clone(),
 1902                    cx,
 1903                )
 1904                .shared(),
 1905            );
 1906            code_action_providers.push(Rc::new(project) as Rc<_>);
 1907        }
 1908
 1909        let mut editor = Self {
 1910            focus_handle,
 1911            show_cursor_when_unfocused: false,
 1912            last_focused_descendant: None,
 1913            buffer: buffer.clone(),
 1914            display_map: display_map.clone(),
 1915            selections,
 1916            scroll_manager: ScrollManager::new(cx),
 1917            columnar_selection_state: None,
 1918            add_selections_state: None,
 1919            select_next_state: None,
 1920            select_prev_state: None,
 1921            selection_history: SelectionHistory::default(),
 1922            defer_selection_effects: false,
 1923            deferred_selection_effects_state: None,
 1924            autoclose_regions: Vec::new(),
 1925            snippet_stack: InvalidationStack::default(),
 1926            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1927            ime_transaction: None,
 1928            active_diagnostics: ActiveDiagnostic::None,
 1929            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1930            inline_diagnostics_update: Task::ready(()),
 1931            inline_diagnostics: Vec::new(),
 1932            soft_wrap_mode_override,
 1933            diagnostics_max_severity,
 1934            hard_wrap: None,
 1935            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1936            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1937            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1938            project,
 1939            blink_manager: blink_manager.clone(),
 1940            show_local_selections: true,
 1941            show_scrollbars: ScrollbarAxes {
 1942                horizontal: full_mode,
 1943                vertical: full_mode,
 1944            },
 1945            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1946            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1947            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1948            show_gutter: mode.is_full(),
 1949            show_line_numbers: None,
 1950            use_relative_line_numbers: None,
 1951            disable_expand_excerpt_buttons: false,
 1952            show_git_diff_gutter: None,
 1953            show_code_actions: None,
 1954            show_runnables: None,
 1955            show_breakpoints: None,
 1956            show_wrap_guides: None,
 1957            show_indent_guides,
 1958            placeholder_text: None,
 1959            highlight_order: 0,
 1960            highlighted_rows: HashMap::default(),
 1961            background_highlights: TreeMap::default(),
 1962            gutter_highlights: TreeMap::default(),
 1963            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1964            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1965            nav_history: None,
 1966            context_menu: RefCell::new(None),
 1967            context_menu_options: None,
 1968            mouse_context_menu: None,
 1969            completion_tasks: Vec::new(),
 1970            inline_blame_popover: None,
 1971            inline_blame_popover_show_task: None,
 1972            signature_help_state: SignatureHelpState::default(),
 1973            auto_signature_help: None,
 1974            find_all_references_task_sources: Vec::new(),
 1975            next_completion_id: 0,
 1976            next_inlay_id: 0,
 1977            code_action_providers,
 1978            available_code_actions: None,
 1979            code_actions_task: None,
 1980            quick_selection_highlight_task: None,
 1981            debounced_selection_highlight_task: None,
 1982            document_highlights_task: None,
 1983            linked_editing_range_task: None,
 1984            pending_rename: None,
 1985            searchable: true,
 1986            cursor_shape: EditorSettings::get_global(cx)
 1987                .cursor_shape
 1988                .unwrap_or_default(),
 1989            current_line_highlight: None,
 1990            autoindent_mode: Some(AutoindentMode::EachLine),
 1991            collapse_matches: false,
 1992            workspace: None,
 1993            input_enabled: true,
 1994            use_modal_editing: mode.is_full(),
 1995            read_only: mode.is_minimap(),
 1996            use_autoclose: true,
 1997            use_auto_surround: true,
 1998            auto_replace_emoji_shortcode: false,
 1999            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2000            leader_id: None,
 2001            remote_id: None,
 2002            hover_state: HoverState::default(),
 2003            pending_mouse_down: None,
 2004            hovered_link_state: None,
 2005            edit_prediction_provider: None,
 2006            active_inline_completion: None,
 2007            stale_inline_completion_in_menu: None,
 2008            edit_prediction_preview: EditPredictionPreview::Inactive {
 2009                released_too_fast: false,
 2010            },
 2011            inline_diagnostics_enabled: mode.is_full(),
 2012            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2013            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2014
 2015            gutter_hovered: false,
 2016            pixel_position_of_newest_cursor: None,
 2017            last_bounds: None,
 2018            last_position_map: None,
 2019            expect_bounds_change: None,
 2020            gutter_dimensions: GutterDimensions::default(),
 2021            style: None,
 2022            show_cursor_names: false,
 2023            hovered_cursors: HashMap::default(),
 2024            next_editor_action_id: EditorActionId::default(),
 2025            editor_actions: Rc::default(),
 2026            inline_completions_hidden_for_vim_mode: false,
 2027            show_inline_completions_override: None,
 2028            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2029            edit_prediction_settings: EditPredictionSettings::Disabled,
 2030            edit_prediction_indent_conflict: false,
 2031            edit_prediction_requires_modifier_in_indent_conflict: true,
 2032            custom_context_menu: None,
 2033            show_git_blame_gutter: false,
 2034            show_git_blame_inline: false,
 2035            show_selection_menu: None,
 2036            show_git_blame_inline_delay_task: None,
 2037            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2038            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2039            serialize_dirty_buffers: !mode.is_minimap()
 2040                && ProjectSettings::get_global(cx)
 2041                    .session
 2042                    .restore_unsaved_buffers,
 2043            blame: None,
 2044            blame_subscription: None,
 2045            tasks: BTreeMap::default(),
 2046
 2047            breakpoint_store,
 2048            gutter_breakpoint_indicator: (None, None),
 2049            hovered_diff_hunk_row: None,
 2050            _subscriptions: vec![
 2051                cx.observe(&buffer, Self::on_buffer_changed),
 2052                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2053                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2054                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2055                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2056                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2057                cx.observe_window_activation(window, |editor, window, cx| {
 2058                    let active = window.is_window_active();
 2059                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2060                        if active {
 2061                            blink_manager.enable(cx);
 2062                        } else {
 2063                            blink_manager.disable(cx);
 2064                        }
 2065                    });
 2066                    if active {
 2067                        editor.show_mouse_cursor(cx);
 2068                    }
 2069                }),
 2070            ],
 2071            tasks_update_task: None,
 2072            pull_diagnostics_task: Task::ready(()),
 2073            linked_edit_ranges: Default::default(),
 2074            in_project_search: false,
 2075            previous_search_ranges: None,
 2076            breadcrumb_header: None,
 2077            focused_block: None,
 2078            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2079            addons: HashMap::default(),
 2080            registered_buffers: HashMap::default(),
 2081            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2082            selection_mark_mode: false,
 2083            toggle_fold_multiple_buffers: Task::ready(()),
 2084            serialize_selections: Task::ready(()),
 2085            serialize_folds: Task::ready(()),
 2086            text_style_refinement: None,
 2087            load_diff_task: load_uncommitted_diff,
 2088            temporary_diff_override: false,
 2089            mouse_cursor_hidden: false,
 2090            minimap: None,
 2091            hide_mouse_mode: EditorSettings::get_global(cx)
 2092                .hide_mouse
 2093                .unwrap_or_default(),
 2094            change_list: ChangeList::new(),
 2095            mode,
 2096            selection_drag_state: SelectionDragState::None,
 2097            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2098        };
 2099        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2100            editor
 2101                ._subscriptions
 2102                .push(cx.observe(breakpoints, |_, _, cx| {
 2103                    cx.notify();
 2104                }));
 2105        }
 2106        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2107        editor._subscriptions.extend(project_subscriptions);
 2108
 2109        editor._subscriptions.push(cx.subscribe_in(
 2110            &cx.entity(),
 2111            window,
 2112            |editor, _, e: &EditorEvent, window, cx| match e {
 2113                EditorEvent::ScrollPositionChanged { local, .. } => {
 2114                    if *local {
 2115                        let new_anchor = editor.scroll_manager.anchor();
 2116                        let snapshot = editor.snapshot(window, cx);
 2117                        editor.update_restoration_data(cx, move |data| {
 2118                            data.scroll_position = (
 2119                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2120                                new_anchor.offset,
 2121                            );
 2122                        });
 2123                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2124                        editor.inline_blame_popover.take();
 2125                    }
 2126                }
 2127                EditorEvent::Edited { .. } => {
 2128                    if !vim_enabled(cx) {
 2129                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2130                        let pop_state = editor
 2131                            .change_list
 2132                            .last()
 2133                            .map(|previous| {
 2134                                previous.len() == selections.len()
 2135                                    && previous.iter().enumerate().all(|(ix, p)| {
 2136                                        p.to_display_point(&map).row()
 2137                                            == selections[ix].head().row()
 2138                                    })
 2139                            })
 2140                            .unwrap_or(false);
 2141                        let new_positions = selections
 2142                            .into_iter()
 2143                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2144                            .collect();
 2145                        editor
 2146                            .change_list
 2147                            .push_to_change_list(pop_state, new_positions);
 2148                    }
 2149                }
 2150                _ => (),
 2151            },
 2152        ));
 2153
 2154        if let Some(dap_store) = editor
 2155            .project
 2156            .as_ref()
 2157            .map(|project| project.read(cx).dap_store())
 2158        {
 2159            let weak_editor = cx.weak_entity();
 2160
 2161            editor
 2162                ._subscriptions
 2163                .push(
 2164                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2165                        let session_entity = cx.entity();
 2166                        weak_editor
 2167                            .update(cx, |editor, cx| {
 2168                                editor._subscriptions.push(
 2169                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2170                                );
 2171                            })
 2172                            .ok();
 2173                    }),
 2174                );
 2175
 2176            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2177                editor
 2178                    ._subscriptions
 2179                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2180            }
 2181        }
 2182
 2183        // skip adding the initial selection to selection history
 2184        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2185        editor.end_selection(window, cx);
 2186        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2187
 2188        editor.scroll_manager.show_scrollbars(window, cx);
 2189        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2190
 2191        if full_mode {
 2192            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2193            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2194
 2195            if editor.git_blame_inline_enabled {
 2196                editor.start_git_blame_inline(false, window, cx);
 2197            }
 2198
 2199            editor.go_to_active_debug_line(window, cx);
 2200
 2201            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2202                if let Some(project) = editor.project.as_ref() {
 2203                    let handle = project.update(cx, |project, cx| {
 2204                        project.register_buffer_with_language_servers(&buffer, cx)
 2205                    });
 2206                    editor
 2207                        .registered_buffers
 2208                        .insert(buffer.read(cx).remote_id(), handle);
 2209                }
 2210            }
 2211
 2212            editor.minimap =
 2213                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2214            editor.pull_diagnostics(None, window, cx);
 2215        }
 2216
 2217        editor.report_editor_event("Editor Opened", None, cx);
 2218        editor
 2219    }
 2220
 2221    pub fn deploy_mouse_context_menu(
 2222        &mut self,
 2223        position: gpui::Point<Pixels>,
 2224        context_menu: Entity<ContextMenu>,
 2225        window: &mut Window,
 2226        cx: &mut Context<Self>,
 2227    ) {
 2228        self.mouse_context_menu = Some(MouseContextMenu::new(
 2229            self,
 2230            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2231            context_menu,
 2232            window,
 2233            cx,
 2234        ));
 2235    }
 2236
 2237    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2238        self.mouse_context_menu
 2239            .as_ref()
 2240            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2241    }
 2242
 2243    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2244        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2245    }
 2246
 2247    fn key_context_internal(
 2248        &self,
 2249        has_active_edit_prediction: bool,
 2250        window: &Window,
 2251        cx: &App,
 2252    ) -> KeyContext {
 2253        let mut key_context = KeyContext::new_with_defaults();
 2254        key_context.add("Editor");
 2255        let mode = match self.mode {
 2256            EditorMode::SingleLine { .. } => "single_line",
 2257            EditorMode::AutoHeight { .. } => "auto_height",
 2258            EditorMode::Minimap { .. } => "minimap",
 2259            EditorMode::Full { .. } => "full",
 2260        };
 2261
 2262        if EditorSettings::jupyter_enabled(cx) {
 2263            key_context.add("jupyter");
 2264        }
 2265
 2266        key_context.set("mode", mode);
 2267        if self.pending_rename.is_some() {
 2268            key_context.add("renaming");
 2269        }
 2270
 2271        match self.context_menu.borrow().as_ref() {
 2272            Some(CodeContextMenu::Completions(_)) => {
 2273                key_context.add("menu");
 2274                key_context.add("showing_completions");
 2275            }
 2276            Some(CodeContextMenu::CodeActions(_)) => {
 2277                key_context.add("menu");
 2278                key_context.add("showing_code_actions")
 2279            }
 2280            None => {}
 2281        }
 2282
 2283        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2284        if !self.focus_handle(cx).contains_focused(window, cx)
 2285            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2286        {
 2287            for addon in self.addons.values() {
 2288                addon.extend_key_context(&mut key_context, cx)
 2289            }
 2290        }
 2291
 2292        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2293            if let Some(extension) = singleton_buffer
 2294                .read(cx)
 2295                .file()
 2296                .and_then(|file| file.path().extension()?.to_str())
 2297            {
 2298                key_context.set("extension", extension.to_string());
 2299            }
 2300        } else {
 2301            key_context.add("multibuffer");
 2302        }
 2303
 2304        if has_active_edit_prediction {
 2305            if self.edit_prediction_in_conflict() {
 2306                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2307            } else {
 2308                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2309                key_context.add("copilot_suggestion");
 2310            }
 2311        }
 2312
 2313        if self.selection_mark_mode {
 2314            key_context.add("selection_mode");
 2315        }
 2316
 2317        key_context
 2318    }
 2319
 2320    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2321        if self.mouse_cursor_hidden {
 2322            self.mouse_cursor_hidden = false;
 2323            cx.notify();
 2324        }
 2325    }
 2326
 2327    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2328        let hide_mouse_cursor = match origin {
 2329            HideMouseCursorOrigin::TypingAction => {
 2330                matches!(
 2331                    self.hide_mouse_mode,
 2332                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2333                )
 2334            }
 2335            HideMouseCursorOrigin::MovementAction => {
 2336                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2337            }
 2338        };
 2339        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2340            self.mouse_cursor_hidden = hide_mouse_cursor;
 2341            cx.notify();
 2342        }
 2343    }
 2344
 2345    pub fn edit_prediction_in_conflict(&self) -> bool {
 2346        if !self.show_edit_predictions_in_menu() {
 2347            return false;
 2348        }
 2349
 2350        let showing_completions = self
 2351            .context_menu
 2352            .borrow()
 2353            .as_ref()
 2354            .map_or(false, |context| {
 2355                matches!(context, CodeContextMenu::Completions(_))
 2356            });
 2357
 2358        showing_completions
 2359            || self.edit_prediction_requires_modifier()
 2360            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2361            // bindings to insert tab characters.
 2362            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2363    }
 2364
 2365    pub fn accept_edit_prediction_keybind(
 2366        &self,
 2367        accept_partial: bool,
 2368        window: &Window,
 2369        cx: &App,
 2370    ) -> AcceptEditPredictionBinding {
 2371        let key_context = self.key_context_internal(true, window, cx);
 2372        let in_conflict = self.edit_prediction_in_conflict();
 2373
 2374        let bindings = if accept_partial {
 2375            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2376        } else {
 2377            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2378        };
 2379
 2380        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2381        // just the first one.
 2382        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2383            !in_conflict
 2384                || binding
 2385                    .keystrokes()
 2386                    .first()
 2387                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2388        }))
 2389    }
 2390
 2391    pub fn new_file(
 2392        workspace: &mut Workspace,
 2393        _: &workspace::NewFile,
 2394        window: &mut Window,
 2395        cx: &mut Context<Workspace>,
 2396    ) {
 2397        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2398            "Failed to create buffer",
 2399            window,
 2400            cx,
 2401            |e, _, _| match e.error_code() {
 2402                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2403                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2404                e.error_tag("required").unwrap_or("the latest version")
 2405            )),
 2406                _ => None,
 2407            },
 2408        );
 2409    }
 2410
 2411    pub fn new_in_workspace(
 2412        workspace: &mut Workspace,
 2413        window: &mut Window,
 2414        cx: &mut Context<Workspace>,
 2415    ) -> Task<Result<Entity<Editor>>> {
 2416        let project = workspace.project().clone();
 2417        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2418
 2419        cx.spawn_in(window, async move |workspace, cx| {
 2420            let buffer = create.await?;
 2421            workspace.update_in(cx, |workspace, window, cx| {
 2422                let editor =
 2423                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2424                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2425                editor
 2426            })
 2427        })
 2428    }
 2429
 2430    fn new_file_vertical(
 2431        workspace: &mut Workspace,
 2432        _: &workspace::NewFileSplitVertical,
 2433        window: &mut Window,
 2434        cx: &mut Context<Workspace>,
 2435    ) {
 2436        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2437    }
 2438
 2439    fn new_file_horizontal(
 2440        workspace: &mut Workspace,
 2441        _: &workspace::NewFileSplitHorizontal,
 2442        window: &mut Window,
 2443        cx: &mut Context<Workspace>,
 2444    ) {
 2445        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2446    }
 2447
 2448    fn new_file_in_direction(
 2449        workspace: &mut Workspace,
 2450        direction: SplitDirection,
 2451        window: &mut Window,
 2452        cx: &mut Context<Workspace>,
 2453    ) {
 2454        let project = workspace.project().clone();
 2455        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2456
 2457        cx.spawn_in(window, async move |workspace, cx| {
 2458            let buffer = create.await?;
 2459            workspace.update_in(cx, move |workspace, window, cx| {
 2460                workspace.split_item(
 2461                    direction,
 2462                    Box::new(
 2463                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2464                    ),
 2465                    window,
 2466                    cx,
 2467                )
 2468            })?;
 2469            anyhow::Ok(())
 2470        })
 2471        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2472            match e.error_code() {
 2473                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2474                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2475                e.error_tag("required").unwrap_or("the latest version")
 2476            )),
 2477                _ => None,
 2478            }
 2479        });
 2480    }
 2481
 2482    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2483        self.leader_id
 2484    }
 2485
 2486    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2487        &self.buffer
 2488    }
 2489
 2490    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2491        self.workspace.as_ref()?.0.upgrade()
 2492    }
 2493
 2494    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2495        self.buffer().read(cx).title(cx)
 2496    }
 2497
 2498    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2499        let git_blame_gutter_max_author_length = self
 2500            .render_git_blame_gutter(cx)
 2501            .then(|| {
 2502                if let Some(blame) = self.blame.as_ref() {
 2503                    let max_author_length =
 2504                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2505                    Some(max_author_length)
 2506                } else {
 2507                    None
 2508                }
 2509            })
 2510            .flatten();
 2511
 2512        EditorSnapshot {
 2513            mode: self.mode.clone(),
 2514            show_gutter: self.show_gutter,
 2515            show_line_numbers: self.show_line_numbers,
 2516            show_git_diff_gutter: self.show_git_diff_gutter,
 2517            show_code_actions: self.show_code_actions,
 2518            show_runnables: self.show_runnables,
 2519            show_breakpoints: self.show_breakpoints,
 2520            git_blame_gutter_max_author_length,
 2521            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2522            scroll_anchor: self.scroll_manager.anchor(),
 2523            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2524            placeholder_text: self.placeholder_text.clone(),
 2525            is_focused: self.focus_handle.is_focused(window),
 2526            current_line_highlight: self
 2527                .current_line_highlight
 2528                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2529            gutter_hovered: self.gutter_hovered,
 2530        }
 2531    }
 2532
 2533    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2534        self.buffer.read(cx).language_at(point, cx)
 2535    }
 2536
 2537    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2538        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2539    }
 2540
 2541    pub fn active_excerpt(
 2542        &self,
 2543        cx: &App,
 2544    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2545        self.buffer
 2546            .read(cx)
 2547            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2548    }
 2549
 2550    pub fn mode(&self) -> &EditorMode {
 2551        &self.mode
 2552    }
 2553
 2554    pub fn set_mode(&mut self, mode: EditorMode) {
 2555        self.mode = mode;
 2556    }
 2557
 2558    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2559        self.collaboration_hub.as_deref()
 2560    }
 2561
 2562    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2563        self.collaboration_hub = Some(hub);
 2564    }
 2565
 2566    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2567        self.in_project_search = in_project_search;
 2568    }
 2569
 2570    pub fn set_custom_context_menu(
 2571        &mut self,
 2572        f: impl 'static
 2573        + Fn(
 2574            &mut Self,
 2575            DisplayPoint,
 2576            &mut Window,
 2577            &mut Context<Self>,
 2578        ) -> Option<Entity<ui::ContextMenu>>,
 2579    ) {
 2580        self.custom_context_menu = Some(Box::new(f))
 2581    }
 2582
 2583    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2584        self.completion_provider = provider;
 2585    }
 2586
 2587    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2588        self.semantics_provider.clone()
 2589    }
 2590
 2591    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2592        self.semantics_provider = provider;
 2593    }
 2594
 2595    pub fn set_edit_prediction_provider<T>(
 2596        &mut self,
 2597        provider: Option<Entity<T>>,
 2598        window: &mut Window,
 2599        cx: &mut Context<Self>,
 2600    ) where
 2601        T: EditPredictionProvider,
 2602    {
 2603        self.edit_prediction_provider =
 2604            provider.map(|provider| RegisteredInlineCompletionProvider {
 2605                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2606                    if this.focus_handle.is_focused(window) {
 2607                        this.update_visible_inline_completion(window, cx);
 2608                    }
 2609                }),
 2610                provider: Arc::new(provider),
 2611            });
 2612        self.update_edit_prediction_settings(cx);
 2613        self.refresh_inline_completion(false, false, window, cx);
 2614    }
 2615
 2616    pub fn placeholder_text(&self) -> Option<&str> {
 2617        self.placeholder_text.as_deref()
 2618    }
 2619
 2620    pub fn set_placeholder_text(
 2621        &mut self,
 2622        placeholder_text: impl Into<Arc<str>>,
 2623        cx: &mut Context<Self>,
 2624    ) {
 2625        let placeholder_text = Some(placeholder_text.into());
 2626        if self.placeholder_text != placeholder_text {
 2627            self.placeholder_text = placeholder_text;
 2628            cx.notify();
 2629        }
 2630    }
 2631
 2632    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2633        self.cursor_shape = cursor_shape;
 2634
 2635        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2636        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2637
 2638        cx.notify();
 2639    }
 2640
 2641    pub fn set_current_line_highlight(
 2642        &mut self,
 2643        current_line_highlight: Option<CurrentLineHighlight>,
 2644    ) {
 2645        self.current_line_highlight = current_line_highlight;
 2646    }
 2647
 2648    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2649        self.collapse_matches = collapse_matches;
 2650    }
 2651
 2652    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2653        let buffers = self.buffer.read(cx).all_buffers();
 2654        let Some(project) = self.project.as_ref() else {
 2655            return;
 2656        };
 2657        project.update(cx, |project, cx| {
 2658            for buffer in buffers {
 2659                self.registered_buffers
 2660                    .entry(buffer.read(cx).remote_id())
 2661                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2662            }
 2663        })
 2664    }
 2665
 2666    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2667        if self.collapse_matches {
 2668            return range.start..range.start;
 2669        }
 2670        range.clone()
 2671    }
 2672
 2673    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2674        if self.display_map.read(cx).clip_at_line_ends != clip {
 2675            self.display_map
 2676                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2677        }
 2678    }
 2679
 2680    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2681        self.input_enabled = input_enabled;
 2682    }
 2683
 2684    pub fn set_inline_completions_hidden_for_vim_mode(
 2685        &mut self,
 2686        hidden: bool,
 2687        window: &mut Window,
 2688        cx: &mut Context<Self>,
 2689    ) {
 2690        if hidden != self.inline_completions_hidden_for_vim_mode {
 2691            self.inline_completions_hidden_for_vim_mode = hidden;
 2692            if hidden {
 2693                self.update_visible_inline_completion(window, cx);
 2694            } else {
 2695                self.refresh_inline_completion(true, false, window, cx);
 2696            }
 2697        }
 2698    }
 2699
 2700    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2701        self.menu_inline_completions_policy = value;
 2702    }
 2703
 2704    pub fn set_autoindent(&mut self, autoindent: bool) {
 2705        if autoindent {
 2706            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2707        } else {
 2708            self.autoindent_mode = None;
 2709        }
 2710    }
 2711
 2712    pub fn read_only(&self, cx: &App) -> bool {
 2713        self.read_only || self.buffer.read(cx).read_only()
 2714    }
 2715
 2716    pub fn set_read_only(&mut self, read_only: bool) {
 2717        self.read_only = read_only;
 2718    }
 2719
 2720    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2721        self.use_autoclose = autoclose;
 2722    }
 2723
 2724    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2725        self.use_auto_surround = auto_surround;
 2726    }
 2727
 2728    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2729        self.auto_replace_emoji_shortcode = auto_replace;
 2730    }
 2731
 2732    pub fn toggle_edit_predictions(
 2733        &mut self,
 2734        _: &ToggleEditPrediction,
 2735        window: &mut Window,
 2736        cx: &mut Context<Self>,
 2737    ) {
 2738        if self.show_inline_completions_override.is_some() {
 2739            self.set_show_edit_predictions(None, window, cx);
 2740        } else {
 2741            let show_edit_predictions = !self.edit_predictions_enabled();
 2742            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2743        }
 2744    }
 2745
 2746    pub fn set_show_edit_predictions(
 2747        &mut self,
 2748        show_edit_predictions: Option<bool>,
 2749        window: &mut Window,
 2750        cx: &mut Context<Self>,
 2751    ) {
 2752        self.show_inline_completions_override = show_edit_predictions;
 2753        self.update_edit_prediction_settings(cx);
 2754
 2755        if let Some(false) = show_edit_predictions {
 2756            self.discard_inline_completion(false, cx);
 2757        } else {
 2758            self.refresh_inline_completion(false, true, window, cx);
 2759        }
 2760    }
 2761
 2762    fn inline_completions_disabled_in_scope(
 2763        &self,
 2764        buffer: &Entity<Buffer>,
 2765        buffer_position: language::Anchor,
 2766        cx: &App,
 2767    ) -> bool {
 2768        let snapshot = buffer.read(cx).snapshot();
 2769        let settings = snapshot.settings_at(buffer_position, cx);
 2770
 2771        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2772            return false;
 2773        };
 2774
 2775        scope.override_name().map_or(false, |scope_name| {
 2776            settings
 2777                .edit_predictions_disabled_in
 2778                .iter()
 2779                .any(|s| s == scope_name)
 2780        })
 2781    }
 2782
 2783    pub fn set_use_modal_editing(&mut self, to: bool) {
 2784        self.use_modal_editing = to;
 2785    }
 2786
 2787    pub fn use_modal_editing(&self) -> bool {
 2788        self.use_modal_editing
 2789    }
 2790
 2791    fn selections_did_change(
 2792        &mut self,
 2793        local: bool,
 2794        old_cursor_position: &Anchor,
 2795        effects: SelectionEffects,
 2796        window: &mut Window,
 2797        cx: &mut Context<Self>,
 2798    ) {
 2799        window.invalidate_character_coordinates();
 2800
 2801        // Copy selections to primary selection buffer
 2802        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2803        if local {
 2804            let selections = self.selections.all::<usize>(cx);
 2805            let buffer_handle = self.buffer.read(cx).read(cx);
 2806
 2807            let mut text = String::new();
 2808            for (index, selection) in selections.iter().enumerate() {
 2809                let text_for_selection = buffer_handle
 2810                    .text_for_range(selection.start..selection.end)
 2811                    .collect::<String>();
 2812
 2813                text.push_str(&text_for_selection);
 2814                if index != selections.len() - 1 {
 2815                    text.push('\n');
 2816                }
 2817            }
 2818
 2819            if !text.is_empty() {
 2820                cx.write_to_primary(ClipboardItem::new_string(text));
 2821            }
 2822        }
 2823
 2824        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2825            self.buffer.update(cx, |buffer, cx| {
 2826                buffer.set_active_selections(
 2827                    &self.selections.disjoint_anchors(),
 2828                    self.selections.line_mode,
 2829                    self.cursor_shape,
 2830                    cx,
 2831                )
 2832            });
 2833        }
 2834        let display_map = self
 2835            .display_map
 2836            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2837        let buffer = &display_map.buffer_snapshot;
 2838        if self.selections.count() == 1 {
 2839            self.add_selections_state = None;
 2840        }
 2841        self.select_next_state = None;
 2842        self.select_prev_state = None;
 2843        self.select_syntax_node_history.try_clear();
 2844        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2845        self.snippet_stack
 2846            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2847        self.take_rename(false, window, cx);
 2848
 2849        let newest_selection = self.selections.newest_anchor();
 2850        let new_cursor_position = newest_selection.head();
 2851        let selection_start = newest_selection.start;
 2852
 2853        if effects.nav_history {
 2854            self.push_to_nav_history(
 2855                *old_cursor_position,
 2856                Some(new_cursor_position.to_point(buffer)),
 2857                false,
 2858                cx,
 2859            );
 2860        }
 2861
 2862        if local {
 2863            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2864                if !self.registered_buffers.contains_key(&buffer_id) {
 2865                    if let Some(project) = self.project.as_ref() {
 2866                        project.update(cx, |project, cx| {
 2867                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2868                                return;
 2869                            };
 2870                            self.registered_buffers.insert(
 2871                                buffer_id,
 2872                                project.register_buffer_with_language_servers(&buffer, cx),
 2873                            );
 2874                        })
 2875                    }
 2876                }
 2877            }
 2878
 2879            let mut context_menu = self.context_menu.borrow_mut();
 2880            let completion_menu = match context_menu.as_ref() {
 2881                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2882                Some(CodeContextMenu::CodeActions(_)) => {
 2883                    *context_menu = None;
 2884                    None
 2885                }
 2886                None => None,
 2887            };
 2888            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2889            drop(context_menu);
 2890
 2891            if effects.completions {
 2892                if let Some(completion_position) = completion_position {
 2893                    let start_offset = selection_start.to_offset(buffer);
 2894                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2895                    let continue_showing = if position_matches {
 2896                        if self.snippet_stack.is_empty() {
 2897                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2898                        } else {
 2899                            // Snippet choices can be shown even when the cursor is in whitespace.
 2900                            // Dismissing the menu with actions like backspace is handled by
 2901                            // invalidation regions.
 2902                            true
 2903                        }
 2904                    } else {
 2905                        false
 2906                    };
 2907
 2908                    if continue_showing {
 2909                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2910                    } else {
 2911                        self.hide_context_menu(window, cx);
 2912                    }
 2913                }
 2914            }
 2915
 2916            hide_hover(self, cx);
 2917
 2918            if old_cursor_position.to_display_point(&display_map).row()
 2919                != new_cursor_position.to_display_point(&display_map).row()
 2920            {
 2921                self.available_code_actions.take();
 2922            }
 2923            self.refresh_code_actions(window, cx);
 2924            self.refresh_document_highlights(cx);
 2925            self.refresh_selected_text_highlights(false, window, cx);
 2926            refresh_matching_bracket_highlights(self, window, cx);
 2927            self.update_visible_inline_completion(window, cx);
 2928            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2929            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2930            self.inline_blame_popover.take();
 2931            if self.git_blame_inline_enabled {
 2932                self.start_inline_blame_timer(window, cx);
 2933            }
 2934        }
 2935
 2936        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2937        cx.emit(EditorEvent::SelectionsChanged { local });
 2938
 2939        let selections = &self.selections.disjoint;
 2940        if selections.len() == 1 {
 2941            cx.emit(SearchEvent::ActiveMatchChanged)
 2942        }
 2943        if local {
 2944            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2945                let inmemory_selections = selections
 2946                    .iter()
 2947                    .map(|s| {
 2948                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2949                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2950                    })
 2951                    .collect();
 2952                self.update_restoration_data(cx, |data| {
 2953                    data.selections = inmemory_selections;
 2954                });
 2955
 2956                if WorkspaceSettings::get(None, cx).restore_on_startup
 2957                    != RestoreOnStartupBehavior::None
 2958                {
 2959                    if let Some(workspace_id) =
 2960                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2961                    {
 2962                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2963                        let selections = selections.clone();
 2964                        let background_executor = cx.background_executor().clone();
 2965                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2966                        self.serialize_selections = cx.background_spawn(async move {
 2967                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2968                            let db_selections = selections
 2969                                .iter()
 2970                                .map(|selection| {
 2971                                    (
 2972                                        selection.start.to_offset(&snapshot),
 2973                                        selection.end.to_offset(&snapshot),
 2974                                    )
 2975                                })
 2976                                .collect();
 2977
 2978                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2979                                .await
 2980                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2981                                .log_err();
 2982                        });
 2983                    }
 2984                }
 2985            }
 2986        }
 2987
 2988        cx.notify();
 2989    }
 2990
 2991    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2992        use text::ToOffset as _;
 2993        use text::ToPoint as _;
 2994
 2995        if self.mode.is_minimap()
 2996            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2997        {
 2998            return;
 2999        }
 3000
 3001        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3002            return;
 3003        };
 3004
 3005        let snapshot = singleton.read(cx).snapshot();
 3006        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3007            let display_snapshot = display_map.snapshot(cx);
 3008
 3009            display_snapshot
 3010                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3011                .map(|fold| {
 3012                    fold.range.start.text_anchor.to_point(&snapshot)
 3013                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3014                })
 3015                .collect()
 3016        });
 3017        self.update_restoration_data(cx, |data| {
 3018            data.folds = inmemory_folds;
 3019        });
 3020
 3021        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3022            return;
 3023        };
 3024        let background_executor = cx.background_executor().clone();
 3025        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3026        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3027            display_map
 3028                .snapshot(cx)
 3029                .folds_in_range(0..snapshot.len())
 3030                .map(|fold| {
 3031                    (
 3032                        fold.range.start.text_anchor.to_offset(&snapshot),
 3033                        fold.range.end.text_anchor.to_offset(&snapshot),
 3034                    )
 3035                })
 3036                .collect()
 3037        });
 3038        self.serialize_folds = cx.background_spawn(async move {
 3039            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3040            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3041                .await
 3042                .with_context(|| {
 3043                    format!(
 3044                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3045                    )
 3046                })
 3047                .log_err();
 3048        });
 3049    }
 3050
 3051    pub fn sync_selections(
 3052        &mut self,
 3053        other: Entity<Editor>,
 3054        cx: &mut Context<Self>,
 3055    ) -> gpui::Subscription {
 3056        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3057        self.selections.change_with(cx, |selections| {
 3058            selections.select_anchors(other_selections);
 3059        });
 3060
 3061        let other_subscription =
 3062            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3063                EditorEvent::SelectionsChanged { local: true } => {
 3064                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3065                    if other_selections.is_empty() {
 3066                        return;
 3067                    }
 3068                    this.selections.change_with(cx, |selections| {
 3069                        selections.select_anchors(other_selections);
 3070                    });
 3071                }
 3072                _ => {}
 3073            });
 3074
 3075        let this_subscription =
 3076            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3077                EditorEvent::SelectionsChanged { local: true } => {
 3078                    let these_selections = this.selections.disjoint.to_vec();
 3079                    if these_selections.is_empty() {
 3080                        return;
 3081                    }
 3082                    other.update(cx, |other_editor, cx| {
 3083                        other_editor.selections.change_with(cx, |selections| {
 3084                            selections.select_anchors(these_selections);
 3085                        })
 3086                    });
 3087                }
 3088                _ => {}
 3089            });
 3090
 3091        Subscription::join(other_subscription, this_subscription)
 3092    }
 3093
 3094    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3095    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3096    /// effects of selection change occur at the end of the transaction.
 3097    pub fn change_selections<R>(
 3098        &mut self,
 3099        effects: impl Into<SelectionEffects>,
 3100        window: &mut Window,
 3101        cx: &mut Context<Self>,
 3102        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3103    ) -> R {
 3104        let effects = effects.into();
 3105        if let Some(state) = &mut self.deferred_selection_effects_state {
 3106            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3107            state.effects.completions = effects.completions;
 3108            state.effects.nav_history |= effects.nav_history;
 3109            let (changed, result) = self.selections.change_with(cx, change);
 3110            state.changed |= changed;
 3111            return result;
 3112        }
 3113        let mut state = DeferredSelectionEffectsState {
 3114            changed: false,
 3115            effects,
 3116            old_cursor_position: self.selections.newest_anchor().head(),
 3117            history_entry: SelectionHistoryEntry {
 3118                selections: self.selections.disjoint_anchors(),
 3119                select_next_state: self.select_next_state.clone(),
 3120                select_prev_state: self.select_prev_state.clone(),
 3121                add_selections_state: self.add_selections_state.clone(),
 3122            },
 3123        };
 3124        let (changed, result) = self.selections.change_with(cx, change);
 3125        state.changed = state.changed || changed;
 3126        if self.defer_selection_effects {
 3127            self.deferred_selection_effects_state = Some(state);
 3128        } else {
 3129            self.apply_selection_effects(state, window, cx);
 3130        }
 3131        result
 3132    }
 3133
 3134    /// Defers the effects of selection change, so that the effects of multiple calls to
 3135    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3136    /// to selection history and the state of popovers based on selection position aren't
 3137    /// erroneously updated.
 3138    pub fn with_selection_effects_deferred<R>(
 3139        &mut self,
 3140        window: &mut Window,
 3141        cx: &mut Context<Self>,
 3142        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3143    ) -> R {
 3144        let already_deferred = self.defer_selection_effects;
 3145        self.defer_selection_effects = true;
 3146        let result = update(self, window, cx);
 3147        if !already_deferred {
 3148            self.defer_selection_effects = false;
 3149            if let Some(state) = self.deferred_selection_effects_state.take() {
 3150                self.apply_selection_effects(state, window, cx);
 3151            }
 3152        }
 3153        result
 3154    }
 3155
 3156    fn apply_selection_effects(
 3157        &mut self,
 3158        state: DeferredSelectionEffectsState,
 3159        window: &mut Window,
 3160        cx: &mut Context<Self>,
 3161    ) {
 3162        if state.changed {
 3163            self.selection_history.push(state.history_entry);
 3164
 3165            if let Some(autoscroll) = state.effects.scroll {
 3166                self.request_autoscroll(autoscroll, cx);
 3167            }
 3168
 3169            let old_cursor_position = &state.old_cursor_position;
 3170
 3171            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3172
 3173            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3174                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3175            }
 3176        }
 3177    }
 3178
 3179    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3180    where
 3181        I: IntoIterator<Item = (Range<S>, T)>,
 3182        S: ToOffset,
 3183        T: Into<Arc<str>>,
 3184    {
 3185        if self.read_only(cx) {
 3186            return;
 3187        }
 3188
 3189        self.buffer
 3190            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3191    }
 3192
 3193    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3194    where
 3195        I: IntoIterator<Item = (Range<S>, T)>,
 3196        S: ToOffset,
 3197        T: Into<Arc<str>>,
 3198    {
 3199        if self.read_only(cx) {
 3200            return;
 3201        }
 3202
 3203        self.buffer.update(cx, |buffer, cx| {
 3204            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3205        });
 3206    }
 3207
 3208    pub fn edit_with_block_indent<I, S, T>(
 3209        &mut self,
 3210        edits: I,
 3211        original_indent_columns: Vec<Option<u32>>,
 3212        cx: &mut Context<Self>,
 3213    ) where
 3214        I: IntoIterator<Item = (Range<S>, T)>,
 3215        S: ToOffset,
 3216        T: Into<Arc<str>>,
 3217    {
 3218        if self.read_only(cx) {
 3219            return;
 3220        }
 3221
 3222        self.buffer.update(cx, |buffer, cx| {
 3223            buffer.edit(
 3224                edits,
 3225                Some(AutoindentMode::Block {
 3226                    original_indent_columns,
 3227                }),
 3228                cx,
 3229            )
 3230        });
 3231    }
 3232
 3233    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3234        self.hide_context_menu(window, cx);
 3235
 3236        match phase {
 3237            SelectPhase::Begin {
 3238                position,
 3239                add,
 3240                click_count,
 3241            } => self.begin_selection(position, add, click_count, window, cx),
 3242            SelectPhase::BeginColumnar {
 3243                position,
 3244                goal_column,
 3245                reset,
 3246                mode,
 3247            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3248            SelectPhase::Extend {
 3249                position,
 3250                click_count,
 3251            } => self.extend_selection(position, click_count, window, cx),
 3252            SelectPhase::Update {
 3253                position,
 3254                goal_column,
 3255                scroll_delta,
 3256            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3257            SelectPhase::End => self.end_selection(window, cx),
 3258        }
 3259    }
 3260
 3261    fn extend_selection(
 3262        &mut self,
 3263        position: DisplayPoint,
 3264        click_count: usize,
 3265        window: &mut Window,
 3266        cx: &mut Context<Self>,
 3267    ) {
 3268        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3269        let tail = self.selections.newest::<usize>(cx).tail();
 3270        self.begin_selection(position, false, click_count, window, cx);
 3271
 3272        let position = position.to_offset(&display_map, Bias::Left);
 3273        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3274
 3275        let mut pending_selection = self
 3276            .selections
 3277            .pending_anchor()
 3278            .expect("extend_selection not called with pending selection");
 3279        if position >= tail {
 3280            pending_selection.start = tail_anchor;
 3281        } else {
 3282            pending_selection.end = tail_anchor;
 3283            pending_selection.reversed = true;
 3284        }
 3285
 3286        let mut pending_mode = self.selections.pending_mode().unwrap();
 3287        match &mut pending_mode {
 3288            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3289            _ => {}
 3290        }
 3291
 3292        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3293            SelectionEffects::scroll(Autoscroll::fit())
 3294        } else {
 3295            SelectionEffects::no_scroll()
 3296        };
 3297
 3298        self.change_selections(effects, window, cx, |s| {
 3299            s.set_pending(pending_selection, pending_mode)
 3300        });
 3301    }
 3302
 3303    fn begin_selection(
 3304        &mut self,
 3305        position: DisplayPoint,
 3306        add: bool,
 3307        click_count: usize,
 3308        window: &mut Window,
 3309        cx: &mut Context<Self>,
 3310    ) {
 3311        if !self.focus_handle.is_focused(window) {
 3312            self.last_focused_descendant = None;
 3313            window.focus(&self.focus_handle);
 3314        }
 3315
 3316        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3317        let buffer = &display_map.buffer_snapshot;
 3318        let position = display_map.clip_point(position, Bias::Left);
 3319
 3320        let start;
 3321        let end;
 3322        let mode;
 3323        let mut auto_scroll;
 3324        match click_count {
 3325            1 => {
 3326                start = buffer.anchor_before(position.to_point(&display_map));
 3327                end = start;
 3328                mode = SelectMode::Character;
 3329                auto_scroll = true;
 3330            }
 3331            2 => {
 3332                let range = movement::surrounding_word(&display_map, position);
 3333                start = buffer.anchor_before(range.start.to_point(&display_map));
 3334                end = buffer.anchor_before(range.end.to_point(&display_map));
 3335                mode = SelectMode::Word(start..end);
 3336                auto_scroll = true;
 3337            }
 3338            3 => {
 3339                let position = display_map
 3340                    .clip_point(position, Bias::Left)
 3341                    .to_point(&display_map);
 3342                let line_start = display_map.prev_line_boundary(position).0;
 3343                let next_line_start = buffer.clip_point(
 3344                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3345                    Bias::Left,
 3346                );
 3347                start = buffer.anchor_before(line_start);
 3348                end = buffer.anchor_before(next_line_start);
 3349                mode = SelectMode::Line(start..end);
 3350                auto_scroll = true;
 3351            }
 3352            _ => {
 3353                start = buffer.anchor_before(0);
 3354                end = buffer.anchor_before(buffer.len());
 3355                mode = SelectMode::All;
 3356                auto_scroll = false;
 3357            }
 3358        }
 3359        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3360
 3361        let point_to_delete: Option<usize> = {
 3362            let selected_points: Vec<Selection<Point>> =
 3363                self.selections.disjoint_in_range(start..end, cx);
 3364
 3365            if !add || click_count > 1 {
 3366                None
 3367            } else if !selected_points.is_empty() {
 3368                Some(selected_points[0].id)
 3369            } else {
 3370                let clicked_point_already_selected =
 3371                    self.selections.disjoint.iter().find(|selection| {
 3372                        selection.start.to_point(buffer) == start.to_point(buffer)
 3373                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3374                    });
 3375
 3376                clicked_point_already_selected.map(|selection| selection.id)
 3377            }
 3378        };
 3379
 3380        let selections_count = self.selections.count();
 3381
 3382        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3383            if let Some(point_to_delete) = point_to_delete {
 3384                s.delete(point_to_delete);
 3385
 3386                if selections_count == 1 {
 3387                    s.set_pending_anchor_range(start..end, mode);
 3388                }
 3389            } else {
 3390                if !add {
 3391                    s.clear_disjoint();
 3392                }
 3393
 3394                s.set_pending_anchor_range(start..end, mode);
 3395            }
 3396        });
 3397    }
 3398
 3399    fn begin_columnar_selection(
 3400        &mut self,
 3401        position: DisplayPoint,
 3402        goal_column: u32,
 3403        reset: bool,
 3404        mode: ColumnarMode,
 3405        window: &mut Window,
 3406        cx: &mut Context<Self>,
 3407    ) {
 3408        if !self.focus_handle.is_focused(window) {
 3409            self.last_focused_descendant = None;
 3410            window.focus(&self.focus_handle);
 3411        }
 3412
 3413        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3414
 3415        if reset {
 3416            let pointer_position = display_map
 3417                .buffer_snapshot
 3418                .anchor_before(position.to_point(&display_map));
 3419
 3420            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3421                s.clear_disjoint();
 3422                s.set_pending_anchor_range(
 3423                    pointer_position..pointer_position,
 3424                    SelectMode::Character,
 3425                );
 3426            });
 3427        };
 3428
 3429        let tail = self.selections.newest::<Point>(cx).tail();
 3430        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3431        self.columnar_selection_state = match mode {
 3432            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3433                selection_tail: selection_anchor,
 3434                display_point: if reset {
 3435                    if position.column() != goal_column {
 3436                        Some(DisplayPoint::new(position.row(), goal_column))
 3437                    } else {
 3438                        None
 3439                    }
 3440                } else {
 3441                    None
 3442                },
 3443            }),
 3444            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3445                selection_tail: selection_anchor,
 3446            }),
 3447        };
 3448
 3449        if !reset {
 3450            self.select_columns(position, goal_column, &display_map, window, cx);
 3451        }
 3452    }
 3453
 3454    fn update_selection(
 3455        &mut self,
 3456        position: DisplayPoint,
 3457        goal_column: u32,
 3458        scroll_delta: gpui::Point<f32>,
 3459        window: &mut Window,
 3460        cx: &mut Context<Self>,
 3461    ) {
 3462        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3463
 3464        if self.columnar_selection_state.is_some() {
 3465            self.select_columns(position, goal_column, &display_map, window, cx);
 3466        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3467            let buffer = self.buffer.read(cx).snapshot(cx);
 3468            let head;
 3469            let tail;
 3470            let mode = self.selections.pending_mode().unwrap();
 3471            match &mode {
 3472                SelectMode::Character => {
 3473                    head = position.to_point(&display_map);
 3474                    tail = pending.tail().to_point(&buffer);
 3475                }
 3476                SelectMode::Word(original_range) => {
 3477                    let original_display_range = original_range.start.to_display_point(&display_map)
 3478                        ..original_range.end.to_display_point(&display_map);
 3479                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3480                        ..original_display_range.end.to_point(&display_map);
 3481                    if movement::is_inside_word(&display_map, position)
 3482                        || original_display_range.contains(&position)
 3483                    {
 3484                        let word_range = movement::surrounding_word(&display_map, position);
 3485                        if word_range.start < original_display_range.start {
 3486                            head = word_range.start.to_point(&display_map);
 3487                        } else {
 3488                            head = word_range.end.to_point(&display_map);
 3489                        }
 3490                    } else {
 3491                        head = position.to_point(&display_map);
 3492                    }
 3493
 3494                    if head <= original_buffer_range.start {
 3495                        tail = original_buffer_range.end;
 3496                    } else {
 3497                        tail = original_buffer_range.start;
 3498                    }
 3499                }
 3500                SelectMode::Line(original_range) => {
 3501                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3502
 3503                    let position = display_map
 3504                        .clip_point(position, Bias::Left)
 3505                        .to_point(&display_map);
 3506                    let line_start = display_map.prev_line_boundary(position).0;
 3507                    let next_line_start = buffer.clip_point(
 3508                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3509                        Bias::Left,
 3510                    );
 3511
 3512                    if line_start < original_range.start {
 3513                        head = line_start
 3514                    } else {
 3515                        head = next_line_start
 3516                    }
 3517
 3518                    if head <= original_range.start {
 3519                        tail = original_range.end;
 3520                    } else {
 3521                        tail = original_range.start;
 3522                    }
 3523                }
 3524                SelectMode::All => {
 3525                    return;
 3526                }
 3527            };
 3528
 3529            if head < tail {
 3530                pending.start = buffer.anchor_before(head);
 3531                pending.end = buffer.anchor_before(tail);
 3532                pending.reversed = true;
 3533            } else {
 3534                pending.start = buffer.anchor_before(tail);
 3535                pending.end = buffer.anchor_before(head);
 3536                pending.reversed = false;
 3537            }
 3538
 3539            self.change_selections(None, window, cx, |s| {
 3540                s.set_pending(pending, mode);
 3541            });
 3542        } else {
 3543            log::error!("update_selection dispatched with no pending selection");
 3544            return;
 3545        }
 3546
 3547        self.apply_scroll_delta(scroll_delta, window, cx);
 3548        cx.notify();
 3549    }
 3550
 3551    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3552        self.columnar_selection_state.take();
 3553        if self.selections.pending_anchor().is_some() {
 3554            let selections = self.selections.all::<usize>(cx);
 3555            self.change_selections(None, window, cx, |s| {
 3556                s.select(selections);
 3557                s.clear_pending();
 3558            });
 3559        }
 3560    }
 3561
 3562    fn select_columns(
 3563        &mut self,
 3564        head: DisplayPoint,
 3565        goal_column: u32,
 3566        display_map: &DisplaySnapshot,
 3567        window: &mut Window,
 3568        cx: &mut Context<Self>,
 3569    ) {
 3570        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3571            return;
 3572        };
 3573
 3574        let tail = match columnar_state {
 3575            ColumnarSelectionState::FromMouse {
 3576                selection_tail,
 3577                display_point,
 3578            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3579            ColumnarSelectionState::FromSelection { selection_tail } => {
 3580                selection_tail.to_display_point(&display_map)
 3581            }
 3582        };
 3583
 3584        let start_row = cmp::min(tail.row(), head.row());
 3585        let end_row = cmp::max(tail.row(), head.row());
 3586        let start_column = cmp::min(tail.column(), goal_column);
 3587        let end_column = cmp::max(tail.column(), goal_column);
 3588        let reversed = start_column < tail.column();
 3589
 3590        let selection_ranges = (start_row.0..=end_row.0)
 3591            .map(DisplayRow)
 3592            .filter_map(|row| {
 3593                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3594                    || start_column <= display_map.line_len(row))
 3595                    && !display_map.is_block_line(row)
 3596                {
 3597                    let start = display_map
 3598                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3599                        .to_point(display_map);
 3600                    let end = display_map
 3601                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3602                        .to_point(display_map);
 3603                    if reversed {
 3604                        Some(end..start)
 3605                    } else {
 3606                        Some(start..end)
 3607                    }
 3608                } else {
 3609                    None
 3610                }
 3611            })
 3612            .collect::<Vec<_>>();
 3613
 3614        let ranges = match columnar_state {
 3615            ColumnarSelectionState::FromMouse { .. } => {
 3616                let mut non_empty_ranges = selection_ranges
 3617                    .iter()
 3618                    .filter(|selection_range| selection_range.start != selection_range.end)
 3619                    .peekable();
 3620                if non_empty_ranges.peek().is_some() {
 3621                    non_empty_ranges.cloned().collect()
 3622                } else {
 3623                    selection_ranges
 3624                }
 3625            }
 3626            _ => selection_ranges,
 3627        };
 3628
 3629        self.change_selections(None, window, cx, |s| {
 3630            s.select_ranges(ranges);
 3631        });
 3632        cx.notify();
 3633    }
 3634
 3635    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3636        self.selections
 3637            .all_adjusted(cx)
 3638            .iter()
 3639            .any(|selection| !selection.is_empty())
 3640    }
 3641
 3642    pub fn has_pending_nonempty_selection(&self) -> bool {
 3643        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3644            Some(Selection { start, end, .. }) => start != end,
 3645            None => false,
 3646        };
 3647
 3648        pending_nonempty_selection
 3649            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3650    }
 3651
 3652    pub fn has_pending_selection(&self) -> bool {
 3653        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3654    }
 3655
 3656    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3657        self.selection_mark_mode = false;
 3658        self.selection_drag_state = SelectionDragState::None;
 3659
 3660        if self.clear_expanded_diff_hunks(cx) {
 3661            cx.notify();
 3662            return;
 3663        }
 3664        if self.dismiss_menus_and_popups(true, window, cx) {
 3665            return;
 3666        }
 3667
 3668        if self.mode.is_full()
 3669            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3670        {
 3671            return;
 3672        }
 3673
 3674        cx.propagate();
 3675    }
 3676
 3677    pub fn dismiss_menus_and_popups(
 3678        &mut self,
 3679        is_user_requested: bool,
 3680        window: &mut Window,
 3681        cx: &mut Context<Self>,
 3682    ) -> bool {
 3683        if self.take_rename(false, window, cx).is_some() {
 3684            return true;
 3685        }
 3686
 3687        if hide_hover(self, cx) {
 3688            return true;
 3689        }
 3690
 3691        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3692            return true;
 3693        }
 3694
 3695        if self.hide_context_menu(window, cx).is_some() {
 3696            return true;
 3697        }
 3698
 3699        if self.mouse_context_menu.take().is_some() {
 3700            return true;
 3701        }
 3702
 3703        if is_user_requested && self.discard_inline_completion(true, cx) {
 3704            return true;
 3705        }
 3706
 3707        if self.snippet_stack.pop().is_some() {
 3708            return true;
 3709        }
 3710
 3711        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3712            self.dismiss_diagnostics(cx);
 3713            return true;
 3714        }
 3715
 3716        false
 3717    }
 3718
 3719    fn linked_editing_ranges_for(
 3720        &self,
 3721        selection: Range<text::Anchor>,
 3722        cx: &App,
 3723    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3724        if self.linked_edit_ranges.is_empty() {
 3725            return None;
 3726        }
 3727        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3728            selection.end.buffer_id.and_then(|end_buffer_id| {
 3729                if selection.start.buffer_id != Some(end_buffer_id) {
 3730                    return None;
 3731                }
 3732                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3733                let snapshot = buffer.read(cx).snapshot();
 3734                self.linked_edit_ranges
 3735                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3736                    .map(|ranges| (ranges, snapshot, buffer))
 3737            })?;
 3738        use text::ToOffset as TO;
 3739        // find offset from the start of current range to current cursor position
 3740        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3741
 3742        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3743        let start_difference = start_offset - start_byte_offset;
 3744        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3745        let end_difference = end_offset - start_byte_offset;
 3746        // Current range has associated linked ranges.
 3747        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3748        for range in linked_ranges.iter() {
 3749            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3750            let end_offset = start_offset + end_difference;
 3751            let start_offset = start_offset + start_difference;
 3752            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3753                continue;
 3754            }
 3755            if self.selections.disjoint_anchor_ranges().any(|s| {
 3756                if s.start.buffer_id != selection.start.buffer_id
 3757                    || s.end.buffer_id != selection.end.buffer_id
 3758                {
 3759                    return false;
 3760                }
 3761                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3762                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3763            }) {
 3764                continue;
 3765            }
 3766            let start = buffer_snapshot.anchor_after(start_offset);
 3767            let end = buffer_snapshot.anchor_after(end_offset);
 3768            linked_edits
 3769                .entry(buffer.clone())
 3770                .or_default()
 3771                .push(start..end);
 3772        }
 3773        Some(linked_edits)
 3774    }
 3775
 3776    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3777        let text: Arc<str> = text.into();
 3778
 3779        if self.read_only(cx) {
 3780            return;
 3781        }
 3782
 3783        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3784
 3785        let selections = self.selections.all_adjusted(cx);
 3786        let mut bracket_inserted = false;
 3787        let mut edits = Vec::new();
 3788        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3789        let mut new_selections = Vec::with_capacity(selections.len());
 3790        let mut new_autoclose_regions = Vec::new();
 3791        let snapshot = self.buffer.read(cx).read(cx);
 3792        let mut clear_linked_edit_ranges = false;
 3793
 3794        for (selection, autoclose_region) in
 3795            self.selections_with_autoclose_regions(selections, &snapshot)
 3796        {
 3797            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3798                // Determine if the inserted text matches the opening or closing
 3799                // bracket of any of this language's bracket pairs.
 3800                let mut bracket_pair = None;
 3801                let mut is_bracket_pair_start = false;
 3802                let mut is_bracket_pair_end = false;
 3803                if !text.is_empty() {
 3804                    let mut bracket_pair_matching_end = None;
 3805                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3806                    //  and they are removing the character that triggered IME popup.
 3807                    for (pair, enabled) in scope.brackets() {
 3808                        if !pair.close && !pair.surround {
 3809                            continue;
 3810                        }
 3811
 3812                        if enabled && pair.start.ends_with(text.as_ref()) {
 3813                            let prefix_len = pair.start.len() - text.len();
 3814                            let preceding_text_matches_prefix = prefix_len == 0
 3815                                || (selection.start.column >= (prefix_len as u32)
 3816                                    && snapshot.contains_str_at(
 3817                                        Point::new(
 3818                                            selection.start.row,
 3819                                            selection.start.column - (prefix_len as u32),
 3820                                        ),
 3821                                        &pair.start[..prefix_len],
 3822                                    ));
 3823                            if preceding_text_matches_prefix {
 3824                                bracket_pair = Some(pair.clone());
 3825                                is_bracket_pair_start = true;
 3826                                break;
 3827                            }
 3828                        }
 3829                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3830                        {
 3831                            // take first bracket pair matching end, but don't break in case a later bracket
 3832                            // pair matches start
 3833                            bracket_pair_matching_end = Some(pair.clone());
 3834                        }
 3835                    }
 3836                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3837                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3838                        is_bracket_pair_end = true;
 3839                    }
 3840                }
 3841
 3842                if let Some(bracket_pair) = bracket_pair {
 3843                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3844                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3845                    let auto_surround =
 3846                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3847                    if selection.is_empty() {
 3848                        if is_bracket_pair_start {
 3849                            // If the inserted text is a suffix of an opening bracket and the
 3850                            // selection is preceded by the rest of the opening bracket, then
 3851                            // insert the closing bracket.
 3852                            let following_text_allows_autoclose = snapshot
 3853                                .chars_at(selection.start)
 3854                                .next()
 3855                                .map_or(true, |c| scope.should_autoclose_before(c));
 3856
 3857                            let preceding_text_allows_autoclose = selection.start.column == 0
 3858                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3859                                    true,
 3860                                    |c| {
 3861                                        bracket_pair.start != bracket_pair.end
 3862                                            || !snapshot
 3863                                                .char_classifier_at(selection.start)
 3864                                                .is_word(c)
 3865                                    },
 3866                                );
 3867
 3868                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3869                                && bracket_pair.start.len() == 1
 3870                            {
 3871                                let target = bracket_pair.start.chars().next().unwrap();
 3872                                let current_line_count = snapshot
 3873                                    .reversed_chars_at(selection.start)
 3874                                    .take_while(|&c| c != '\n')
 3875                                    .filter(|&c| c == target)
 3876                                    .count();
 3877                                current_line_count % 2 == 1
 3878                            } else {
 3879                                false
 3880                            };
 3881
 3882                            if autoclose
 3883                                && bracket_pair.close
 3884                                && following_text_allows_autoclose
 3885                                && preceding_text_allows_autoclose
 3886                                && !is_closing_quote
 3887                            {
 3888                                let anchor = snapshot.anchor_before(selection.end);
 3889                                new_selections.push((selection.map(|_| anchor), text.len()));
 3890                                new_autoclose_regions.push((
 3891                                    anchor,
 3892                                    text.len(),
 3893                                    selection.id,
 3894                                    bracket_pair.clone(),
 3895                                ));
 3896                                edits.push((
 3897                                    selection.range(),
 3898                                    format!("{}{}", text, bracket_pair.end).into(),
 3899                                ));
 3900                                bracket_inserted = true;
 3901                                continue;
 3902                            }
 3903                        }
 3904
 3905                        if let Some(region) = autoclose_region {
 3906                            // If the selection is followed by an auto-inserted closing bracket,
 3907                            // then don't insert that closing bracket again; just move the selection
 3908                            // past the closing bracket.
 3909                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3910                                && text.as_ref() == region.pair.end.as_str();
 3911                            if should_skip {
 3912                                let anchor = snapshot.anchor_after(selection.end);
 3913                                new_selections
 3914                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3915                                continue;
 3916                            }
 3917                        }
 3918
 3919                        let always_treat_brackets_as_autoclosed = snapshot
 3920                            .language_settings_at(selection.start, cx)
 3921                            .always_treat_brackets_as_autoclosed;
 3922                        if always_treat_brackets_as_autoclosed
 3923                            && is_bracket_pair_end
 3924                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3925                        {
 3926                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3927                            // and the inserted text is a closing bracket and the selection is followed
 3928                            // by the closing bracket then move the selection past the closing bracket.
 3929                            let anchor = snapshot.anchor_after(selection.end);
 3930                            new_selections.push((selection.map(|_| anchor), text.len()));
 3931                            continue;
 3932                        }
 3933                    }
 3934                    // If an opening bracket is 1 character long and is typed while
 3935                    // text is selected, then surround that text with the bracket pair.
 3936                    else if auto_surround
 3937                        && bracket_pair.surround
 3938                        && is_bracket_pair_start
 3939                        && bracket_pair.start.chars().count() == 1
 3940                    {
 3941                        edits.push((selection.start..selection.start, text.clone()));
 3942                        edits.push((
 3943                            selection.end..selection.end,
 3944                            bracket_pair.end.as_str().into(),
 3945                        ));
 3946                        bracket_inserted = true;
 3947                        new_selections.push((
 3948                            Selection {
 3949                                id: selection.id,
 3950                                start: snapshot.anchor_after(selection.start),
 3951                                end: snapshot.anchor_before(selection.end),
 3952                                reversed: selection.reversed,
 3953                                goal: selection.goal,
 3954                            },
 3955                            0,
 3956                        ));
 3957                        continue;
 3958                    }
 3959                }
 3960            }
 3961
 3962            if self.auto_replace_emoji_shortcode
 3963                && selection.is_empty()
 3964                && text.as_ref().ends_with(':')
 3965            {
 3966                if let Some(possible_emoji_short_code) =
 3967                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3968                {
 3969                    if !possible_emoji_short_code.is_empty() {
 3970                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3971                            let emoji_shortcode_start = Point::new(
 3972                                selection.start.row,
 3973                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3974                            );
 3975
 3976                            // Remove shortcode from buffer
 3977                            edits.push((
 3978                                emoji_shortcode_start..selection.start,
 3979                                "".to_string().into(),
 3980                            ));
 3981                            new_selections.push((
 3982                                Selection {
 3983                                    id: selection.id,
 3984                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3985                                    end: snapshot.anchor_before(selection.start),
 3986                                    reversed: selection.reversed,
 3987                                    goal: selection.goal,
 3988                                },
 3989                                0,
 3990                            ));
 3991
 3992                            // Insert emoji
 3993                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3994                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3995                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3996
 3997                            continue;
 3998                        }
 3999                    }
 4000                }
 4001            }
 4002
 4003            // If not handling any auto-close operation, then just replace the selected
 4004            // text with the given input and move the selection to the end of the
 4005            // newly inserted text.
 4006            let anchor = snapshot.anchor_after(selection.end);
 4007            if !self.linked_edit_ranges.is_empty() {
 4008                let start_anchor = snapshot.anchor_before(selection.start);
 4009
 4010                let is_word_char = text.chars().next().map_or(true, |char| {
 4011                    let classifier = snapshot
 4012                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4013                        .ignore_punctuation(true);
 4014                    classifier.is_word(char)
 4015                });
 4016
 4017                if is_word_char {
 4018                    if let Some(ranges) = self
 4019                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4020                    {
 4021                        for (buffer, edits) in ranges {
 4022                            linked_edits
 4023                                .entry(buffer.clone())
 4024                                .or_default()
 4025                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4026                        }
 4027                    }
 4028                } else {
 4029                    clear_linked_edit_ranges = true;
 4030                }
 4031            }
 4032
 4033            new_selections.push((selection.map(|_| anchor), 0));
 4034            edits.push((selection.start..selection.end, text.clone()));
 4035        }
 4036
 4037        drop(snapshot);
 4038
 4039        self.transact(window, cx, |this, window, cx| {
 4040            if clear_linked_edit_ranges {
 4041                this.linked_edit_ranges.clear();
 4042            }
 4043            let initial_buffer_versions =
 4044                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4045
 4046            this.buffer.update(cx, |buffer, cx| {
 4047                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4048            });
 4049            for (buffer, edits) in linked_edits {
 4050                buffer.update(cx, |buffer, cx| {
 4051                    let snapshot = buffer.snapshot();
 4052                    let edits = edits
 4053                        .into_iter()
 4054                        .map(|(range, text)| {
 4055                            use text::ToPoint as TP;
 4056                            let end_point = TP::to_point(&range.end, &snapshot);
 4057                            let start_point = TP::to_point(&range.start, &snapshot);
 4058                            (start_point..end_point, text)
 4059                        })
 4060                        .sorted_by_key(|(range, _)| range.start);
 4061                    buffer.edit(edits, None, cx);
 4062                })
 4063            }
 4064            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4065            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4066            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4067            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4068                .zip(new_selection_deltas)
 4069                .map(|(selection, delta)| Selection {
 4070                    id: selection.id,
 4071                    start: selection.start + delta,
 4072                    end: selection.end + delta,
 4073                    reversed: selection.reversed,
 4074                    goal: SelectionGoal::None,
 4075                })
 4076                .collect::<Vec<_>>();
 4077
 4078            let mut i = 0;
 4079            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4080                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4081                let start = map.buffer_snapshot.anchor_before(position);
 4082                let end = map.buffer_snapshot.anchor_after(position);
 4083                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4084                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4085                        Ordering::Less => i += 1,
 4086                        Ordering::Greater => break,
 4087                        Ordering::Equal => {
 4088                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4089                                Ordering::Less => i += 1,
 4090                                Ordering::Equal => break,
 4091                                Ordering::Greater => break,
 4092                            }
 4093                        }
 4094                    }
 4095                }
 4096                this.autoclose_regions.insert(
 4097                    i,
 4098                    AutocloseRegion {
 4099                        selection_id,
 4100                        range: start..end,
 4101                        pair,
 4102                    },
 4103                );
 4104            }
 4105
 4106            let had_active_inline_completion = this.has_active_inline_completion();
 4107            this.change_selections(
 4108                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4109                window,
 4110                cx,
 4111                |s| s.select(new_selections),
 4112            );
 4113
 4114            if !bracket_inserted {
 4115                if let Some(on_type_format_task) =
 4116                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4117                {
 4118                    on_type_format_task.detach_and_log_err(cx);
 4119                }
 4120            }
 4121
 4122            let editor_settings = EditorSettings::get_global(cx);
 4123            if bracket_inserted
 4124                && (editor_settings.auto_signature_help
 4125                    || editor_settings.show_signature_help_after_edits)
 4126            {
 4127                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4128            }
 4129
 4130            let trigger_in_words =
 4131                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4132            if this.hard_wrap.is_some() {
 4133                let latest: Range<Point> = this.selections.newest(cx).range();
 4134                if latest.is_empty()
 4135                    && this
 4136                        .buffer()
 4137                        .read(cx)
 4138                        .snapshot(cx)
 4139                        .line_len(MultiBufferRow(latest.start.row))
 4140                        == latest.start.column
 4141                {
 4142                    this.rewrap_impl(
 4143                        RewrapOptions {
 4144                            override_language_settings: true,
 4145                            preserve_existing_whitespace: true,
 4146                        },
 4147                        cx,
 4148                    )
 4149                }
 4150            }
 4151            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4152            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4153            this.refresh_inline_completion(true, false, window, cx);
 4154            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4155        });
 4156    }
 4157
 4158    fn find_possible_emoji_shortcode_at_position(
 4159        snapshot: &MultiBufferSnapshot,
 4160        position: Point,
 4161    ) -> Option<String> {
 4162        let mut chars = Vec::new();
 4163        let mut found_colon = false;
 4164        for char in snapshot.reversed_chars_at(position).take(100) {
 4165            // Found a possible emoji shortcode in the middle of the buffer
 4166            if found_colon {
 4167                if char.is_whitespace() {
 4168                    chars.reverse();
 4169                    return Some(chars.iter().collect());
 4170                }
 4171                // If the previous character is not a whitespace, we are in the middle of a word
 4172                // and we only want to complete the shortcode if the word is made up of other emojis
 4173                let mut containing_word = String::new();
 4174                for ch in snapshot
 4175                    .reversed_chars_at(position)
 4176                    .skip(chars.len() + 1)
 4177                    .take(100)
 4178                {
 4179                    if ch.is_whitespace() {
 4180                        break;
 4181                    }
 4182                    containing_word.push(ch);
 4183                }
 4184                let containing_word = containing_word.chars().rev().collect::<String>();
 4185                if util::word_consists_of_emojis(containing_word.as_str()) {
 4186                    chars.reverse();
 4187                    return Some(chars.iter().collect());
 4188                }
 4189            }
 4190
 4191            if char.is_whitespace() || !char.is_ascii() {
 4192                return None;
 4193            }
 4194            if char == ':' {
 4195                found_colon = true;
 4196            } else {
 4197                chars.push(char);
 4198            }
 4199        }
 4200        // Found a possible emoji shortcode at the beginning of the buffer
 4201        chars.reverse();
 4202        Some(chars.iter().collect())
 4203    }
 4204
 4205    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4206        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4207        self.transact(window, cx, |this, window, cx| {
 4208            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4209                let selections = this.selections.all::<usize>(cx);
 4210                let multi_buffer = this.buffer.read(cx);
 4211                let buffer = multi_buffer.snapshot(cx);
 4212                selections
 4213                    .iter()
 4214                    .map(|selection| {
 4215                        let start_point = selection.start.to_point(&buffer);
 4216                        let mut existing_indent =
 4217                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4218                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4219                        let start = selection.start;
 4220                        let end = selection.end;
 4221                        let selection_is_empty = start == end;
 4222                        let language_scope = buffer.language_scope_at(start);
 4223                        let (
 4224                            comment_delimiter,
 4225                            doc_delimiter,
 4226                            insert_extra_newline,
 4227                            indent_on_newline,
 4228                            indent_on_extra_newline,
 4229                        ) = if let Some(language) = &language_scope {
 4230                            let mut insert_extra_newline =
 4231                                insert_extra_newline_brackets(&buffer, start..end, language)
 4232                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4233
 4234                            // Comment extension on newline is allowed only for cursor selections
 4235                            let comment_delimiter = maybe!({
 4236                                if !selection_is_empty {
 4237                                    return None;
 4238                                }
 4239
 4240                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4241                                    return None;
 4242                                }
 4243
 4244                                let delimiters = language.line_comment_prefixes();
 4245                                let max_len_of_delimiter =
 4246                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4247                                let (snapshot, range) =
 4248                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4249
 4250                                let num_of_whitespaces = snapshot
 4251                                    .chars_for_range(range.clone())
 4252                                    .take_while(|c| c.is_whitespace())
 4253                                    .count();
 4254                                let comment_candidate = snapshot
 4255                                    .chars_for_range(range)
 4256                                    .skip(num_of_whitespaces)
 4257                                    .take(max_len_of_delimiter)
 4258                                    .collect::<String>();
 4259                                let (delimiter, trimmed_len) = delimiters
 4260                                    .iter()
 4261                                    .filter_map(|delimiter| {
 4262                                        let prefix = delimiter.trim_end();
 4263                                        if comment_candidate.starts_with(prefix) {
 4264                                            Some((delimiter, prefix.len()))
 4265                                        } else {
 4266                                            None
 4267                                        }
 4268                                    })
 4269                                    .max_by_key(|(_, len)| *len)?;
 4270
 4271                                let cursor_is_placed_after_comment_marker =
 4272                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4273                                if cursor_is_placed_after_comment_marker {
 4274                                    Some(delimiter.clone())
 4275                                } else {
 4276                                    None
 4277                                }
 4278                            });
 4279
 4280                            let mut indent_on_newline = IndentSize::spaces(0);
 4281                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4282
 4283                            let doc_delimiter = maybe!({
 4284                                if !selection_is_empty {
 4285                                    return None;
 4286                                }
 4287
 4288                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4289                                    return None;
 4290                                }
 4291
 4292                                let DocumentationConfig {
 4293                                    start: start_tag,
 4294                                    end: end_tag,
 4295                                    prefix: delimiter,
 4296                                    tab_size: len,
 4297                                } = language.documentation()?;
 4298
 4299                                let is_within_block_comment = buffer
 4300                                    .language_scope_at(start_point)
 4301                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4302                                if !is_within_block_comment {
 4303                                    return None;
 4304                                }
 4305
 4306                                let (snapshot, range) =
 4307                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4308
 4309                                let num_of_whitespaces = snapshot
 4310                                    .chars_for_range(range.clone())
 4311                                    .take_while(|c| c.is_whitespace())
 4312                                    .count();
 4313
 4314                                // 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.
 4315                                let column = start_point.column;
 4316                                let cursor_is_after_start_tag = {
 4317                                    let start_tag_len = start_tag.len();
 4318                                    let start_tag_line = snapshot
 4319                                        .chars_for_range(range.clone())
 4320                                        .skip(num_of_whitespaces)
 4321                                        .take(start_tag_len)
 4322                                        .collect::<String>();
 4323                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4324                                        num_of_whitespaces + start_tag_len <= column as usize
 4325                                    } else {
 4326                                        false
 4327                                    }
 4328                                };
 4329
 4330                                let cursor_is_after_delimiter = {
 4331                                    let delimiter_trim = delimiter.trim_end();
 4332                                    let delimiter_line = snapshot
 4333                                        .chars_for_range(range.clone())
 4334                                        .skip(num_of_whitespaces)
 4335                                        .take(delimiter_trim.len())
 4336                                        .collect::<String>();
 4337                                    if delimiter_line.starts_with(delimiter_trim) {
 4338                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4339                                    } else {
 4340                                        false
 4341                                    }
 4342                                };
 4343
 4344                                let cursor_is_before_end_tag_if_exists = {
 4345                                    let mut char_position = 0u32;
 4346                                    let mut end_tag_offset = None;
 4347
 4348                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4349                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4350                                            let chars_before_match =
 4351                                                chunk[..byte_pos].chars().count() as u32;
 4352                                            end_tag_offset =
 4353                                                Some(char_position + chars_before_match);
 4354                                            break 'outer;
 4355                                        }
 4356                                        char_position += chunk.chars().count() as u32;
 4357                                    }
 4358
 4359                                    if let Some(end_tag_offset) = end_tag_offset {
 4360                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4361                                        if cursor_is_after_start_tag {
 4362                                            if cursor_is_before_end_tag {
 4363                                                insert_extra_newline = true;
 4364                                            }
 4365                                            let cursor_is_at_start_of_end_tag =
 4366                                                column == end_tag_offset;
 4367                                            if cursor_is_at_start_of_end_tag {
 4368                                                indent_on_extra_newline.len = (*len).into();
 4369                                            }
 4370                                        }
 4371                                        cursor_is_before_end_tag
 4372                                    } else {
 4373                                        true
 4374                                    }
 4375                                };
 4376
 4377                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4378                                    && cursor_is_before_end_tag_if_exists
 4379                                {
 4380                                    if cursor_is_after_start_tag {
 4381                                        indent_on_newline.len = (*len).into();
 4382                                    }
 4383                                    Some(delimiter.clone())
 4384                                } else {
 4385                                    None
 4386                                }
 4387                            });
 4388
 4389                            (
 4390                                comment_delimiter,
 4391                                doc_delimiter,
 4392                                insert_extra_newline,
 4393                                indent_on_newline,
 4394                                indent_on_extra_newline,
 4395                            )
 4396                        } else {
 4397                            (
 4398                                None,
 4399                                None,
 4400                                false,
 4401                                IndentSize::default(),
 4402                                IndentSize::default(),
 4403                            )
 4404                        };
 4405
 4406                        let prevent_auto_indent = doc_delimiter.is_some();
 4407                        let delimiter = comment_delimiter.or(doc_delimiter);
 4408
 4409                        let capacity_for_delimiter =
 4410                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4411                        let mut new_text = String::with_capacity(
 4412                            1 + capacity_for_delimiter
 4413                                + existing_indent.len as usize
 4414                                + indent_on_newline.len as usize
 4415                                + indent_on_extra_newline.len as usize,
 4416                        );
 4417                        new_text.push('\n');
 4418                        new_text.extend(existing_indent.chars());
 4419                        new_text.extend(indent_on_newline.chars());
 4420
 4421                        if let Some(delimiter) = &delimiter {
 4422                            new_text.push_str(delimiter);
 4423                        }
 4424
 4425                        if insert_extra_newline {
 4426                            new_text.push('\n');
 4427                            new_text.extend(existing_indent.chars());
 4428                            new_text.extend(indent_on_extra_newline.chars());
 4429                        }
 4430
 4431                        let anchor = buffer.anchor_after(end);
 4432                        let new_selection = selection.map(|_| anchor);
 4433                        (
 4434                            ((start..end, new_text), prevent_auto_indent),
 4435                            (insert_extra_newline, new_selection),
 4436                        )
 4437                    })
 4438                    .unzip()
 4439            };
 4440
 4441            let mut auto_indent_edits = Vec::new();
 4442            let mut edits = Vec::new();
 4443            for (edit, prevent_auto_indent) in edits_with_flags {
 4444                if prevent_auto_indent {
 4445                    edits.push(edit);
 4446                } else {
 4447                    auto_indent_edits.push(edit);
 4448                }
 4449            }
 4450            if !edits.is_empty() {
 4451                this.edit(edits, cx);
 4452            }
 4453            if !auto_indent_edits.is_empty() {
 4454                this.edit_with_autoindent(auto_indent_edits, cx);
 4455            }
 4456
 4457            let buffer = this.buffer.read(cx).snapshot(cx);
 4458            let new_selections = selection_info
 4459                .into_iter()
 4460                .map(|(extra_newline_inserted, new_selection)| {
 4461                    let mut cursor = new_selection.end.to_point(&buffer);
 4462                    if extra_newline_inserted {
 4463                        cursor.row -= 1;
 4464                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4465                    }
 4466                    new_selection.map(|_| cursor)
 4467                })
 4468                .collect();
 4469
 4470            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4471                s.select(new_selections)
 4472            });
 4473            this.refresh_inline_completion(true, false, window, cx);
 4474        });
 4475    }
 4476
 4477    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4478        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4479
 4480        let buffer = self.buffer.read(cx);
 4481        let snapshot = buffer.snapshot(cx);
 4482
 4483        let mut edits = Vec::new();
 4484        let mut rows = Vec::new();
 4485
 4486        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4487            let cursor = selection.head();
 4488            let row = cursor.row;
 4489
 4490            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4491
 4492            let newline = "\n".to_string();
 4493            edits.push((start_of_line..start_of_line, newline));
 4494
 4495            rows.push(row + rows_inserted as u32);
 4496        }
 4497
 4498        self.transact(window, cx, |editor, window, cx| {
 4499            editor.edit(edits, cx);
 4500
 4501            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4502                let mut index = 0;
 4503                s.move_cursors_with(|map, _, _| {
 4504                    let row = rows[index];
 4505                    index += 1;
 4506
 4507                    let point = Point::new(row, 0);
 4508                    let boundary = map.next_line_boundary(point).1;
 4509                    let clipped = map.clip_point(boundary, Bias::Left);
 4510
 4511                    (clipped, SelectionGoal::None)
 4512                });
 4513            });
 4514
 4515            let mut indent_edits = Vec::new();
 4516            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4517            for row in rows {
 4518                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4519                for (row, indent) in indents {
 4520                    if indent.len == 0 {
 4521                        continue;
 4522                    }
 4523
 4524                    let text = match indent.kind {
 4525                        IndentKind::Space => " ".repeat(indent.len as usize),
 4526                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4527                    };
 4528                    let point = Point::new(row.0, 0);
 4529                    indent_edits.push((point..point, text));
 4530                }
 4531            }
 4532            editor.edit(indent_edits, cx);
 4533        });
 4534    }
 4535
 4536    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4538
 4539        let buffer = self.buffer.read(cx);
 4540        let snapshot = buffer.snapshot(cx);
 4541
 4542        let mut edits = Vec::new();
 4543        let mut rows = Vec::new();
 4544        let mut rows_inserted = 0;
 4545
 4546        for selection in self.selections.all_adjusted(cx) {
 4547            let cursor = selection.head();
 4548            let row = cursor.row;
 4549
 4550            let point = Point::new(row + 1, 0);
 4551            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4552
 4553            let newline = "\n".to_string();
 4554            edits.push((start_of_line..start_of_line, newline));
 4555
 4556            rows_inserted += 1;
 4557            rows.push(row + rows_inserted);
 4558        }
 4559
 4560        self.transact(window, cx, |editor, window, cx| {
 4561            editor.edit(edits, cx);
 4562
 4563            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4564                let mut index = 0;
 4565                s.move_cursors_with(|map, _, _| {
 4566                    let row = rows[index];
 4567                    index += 1;
 4568
 4569                    let point = Point::new(row, 0);
 4570                    let boundary = map.next_line_boundary(point).1;
 4571                    let clipped = map.clip_point(boundary, Bias::Left);
 4572
 4573                    (clipped, SelectionGoal::None)
 4574                });
 4575            });
 4576
 4577            let mut indent_edits = Vec::new();
 4578            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4579            for row in rows {
 4580                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4581                for (row, indent) in indents {
 4582                    if indent.len == 0 {
 4583                        continue;
 4584                    }
 4585
 4586                    let text = match indent.kind {
 4587                        IndentKind::Space => " ".repeat(indent.len as usize),
 4588                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4589                    };
 4590                    let point = Point::new(row.0, 0);
 4591                    indent_edits.push((point..point, text));
 4592                }
 4593            }
 4594            editor.edit(indent_edits, cx);
 4595        });
 4596    }
 4597
 4598    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4599        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4600            original_indent_columns: Vec::new(),
 4601        });
 4602        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4603    }
 4604
 4605    fn insert_with_autoindent_mode(
 4606        &mut self,
 4607        text: &str,
 4608        autoindent_mode: Option<AutoindentMode>,
 4609        window: &mut Window,
 4610        cx: &mut Context<Self>,
 4611    ) {
 4612        if self.read_only(cx) {
 4613            return;
 4614        }
 4615
 4616        let text: Arc<str> = text.into();
 4617        self.transact(window, cx, |this, window, cx| {
 4618            let old_selections = this.selections.all_adjusted(cx);
 4619            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4620                let anchors = {
 4621                    let snapshot = buffer.read(cx);
 4622                    old_selections
 4623                        .iter()
 4624                        .map(|s| {
 4625                            let anchor = snapshot.anchor_after(s.head());
 4626                            s.map(|_| anchor)
 4627                        })
 4628                        .collect::<Vec<_>>()
 4629                };
 4630                buffer.edit(
 4631                    old_selections
 4632                        .iter()
 4633                        .map(|s| (s.start..s.end, text.clone())),
 4634                    autoindent_mode,
 4635                    cx,
 4636                );
 4637                anchors
 4638            });
 4639
 4640            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4641                s.select_anchors(selection_anchors);
 4642            });
 4643
 4644            cx.notify();
 4645        });
 4646    }
 4647
 4648    fn trigger_completion_on_input(
 4649        &mut self,
 4650        text: &str,
 4651        trigger_in_words: bool,
 4652        window: &mut Window,
 4653        cx: &mut Context<Self>,
 4654    ) {
 4655        let completions_source = self
 4656            .context_menu
 4657            .borrow()
 4658            .as_ref()
 4659            .and_then(|menu| match menu {
 4660                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4661                CodeContextMenu::CodeActions(_) => None,
 4662            });
 4663
 4664        match completions_source {
 4665            Some(CompletionsMenuSource::Words) => {
 4666                self.show_word_completions(&ShowWordCompletions, window, cx)
 4667            }
 4668            Some(CompletionsMenuSource::Normal)
 4669            | Some(CompletionsMenuSource::SnippetChoices)
 4670            | None
 4671                if self.is_completion_trigger(
 4672                    text,
 4673                    trigger_in_words,
 4674                    completions_source.is_some(),
 4675                    cx,
 4676                ) =>
 4677            {
 4678                self.show_completions(
 4679                    &ShowCompletions {
 4680                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4681                    },
 4682                    window,
 4683                    cx,
 4684                )
 4685            }
 4686            _ => {
 4687                self.hide_context_menu(window, cx);
 4688            }
 4689        }
 4690    }
 4691
 4692    fn is_completion_trigger(
 4693        &self,
 4694        text: &str,
 4695        trigger_in_words: bool,
 4696        menu_is_open: bool,
 4697        cx: &mut Context<Self>,
 4698    ) -> bool {
 4699        let position = self.selections.newest_anchor().head();
 4700        let multibuffer = self.buffer.read(cx);
 4701        let Some(buffer) = position
 4702            .buffer_id
 4703            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4704        else {
 4705            return false;
 4706        };
 4707
 4708        if let Some(completion_provider) = &self.completion_provider {
 4709            completion_provider.is_completion_trigger(
 4710                &buffer,
 4711                position.text_anchor,
 4712                text,
 4713                trigger_in_words,
 4714                menu_is_open,
 4715                cx,
 4716            )
 4717        } else {
 4718            false
 4719        }
 4720    }
 4721
 4722    /// If any empty selections is touching the start of its innermost containing autoclose
 4723    /// region, expand it to select the brackets.
 4724    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4725        let selections = self.selections.all::<usize>(cx);
 4726        let buffer = self.buffer.read(cx).read(cx);
 4727        let new_selections = self
 4728            .selections_with_autoclose_regions(selections, &buffer)
 4729            .map(|(mut selection, region)| {
 4730                if !selection.is_empty() {
 4731                    return selection;
 4732                }
 4733
 4734                if let Some(region) = region {
 4735                    let mut range = region.range.to_offset(&buffer);
 4736                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4737                        range.start -= region.pair.start.len();
 4738                        if buffer.contains_str_at(range.start, &region.pair.start)
 4739                            && buffer.contains_str_at(range.end, &region.pair.end)
 4740                        {
 4741                            range.end += region.pair.end.len();
 4742                            selection.start = range.start;
 4743                            selection.end = range.end;
 4744
 4745                            return selection;
 4746                        }
 4747                    }
 4748                }
 4749
 4750                let always_treat_brackets_as_autoclosed = buffer
 4751                    .language_settings_at(selection.start, cx)
 4752                    .always_treat_brackets_as_autoclosed;
 4753
 4754                if !always_treat_brackets_as_autoclosed {
 4755                    return selection;
 4756                }
 4757
 4758                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4759                    for (pair, enabled) in scope.brackets() {
 4760                        if !enabled || !pair.close {
 4761                            continue;
 4762                        }
 4763
 4764                        if buffer.contains_str_at(selection.start, &pair.end) {
 4765                            let pair_start_len = pair.start.len();
 4766                            if buffer.contains_str_at(
 4767                                selection.start.saturating_sub(pair_start_len),
 4768                                &pair.start,
 4769                            ) {
 4770                                selection.start -= pair_start_len;
 4771                                selection.end += pair.end.len();
 4772
 4773                                return selection;
 4774                            }
 4775                        }
 4776                    }
 4777                }
 4778
 4779                selection
 4780            })
 4781            .collect();
 4782
 4783        drop(buffer);
 4784        self.change_selections(None, window, cx, |selections| {
 4785            selections.select(new_selections)
 4786        });
 4787    }
 4788
 4789    /// Iterate the given selections, and for each one, find the smallest surrounding
 4790    /// autoclose region. This uses the ordering of the selections and the autoclose
 4791    /// regions to avoid repeated comparisons.
 4792    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4793        &'a self,
 4794        selections: impl IntoIterator<Item = Selection<D>>,
 4795        buffer: &'a MultiBufferSnapshot,
 4796    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4797        let mut i = 0;
 4798        let mut regions = self.autoclose_regions.as_slice();
 4799        selections.into_iter().map(move |selection| {
 4800            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4801
 4802            let mut enclosing = None;
 4803            while let Some(pair_state) = regions.get(i) {
 4804                if pair_state.range.end.to_offset(buffer) < range.start {
 4805                    regions = &regions[i + 1..];
 4806                    i = 0;
 4807                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4808                    break;
 4809                } else {
 4810                    if pair_state.selection_id == selection.id {
 4811                        enclosing = Some(pair_state);
 4812                    }
 4813                    i += 1;
 4814                }
 4815            }
 4816
 4817            (selection, enclosing)
 4818        })
 4819    }
 4820
 4821    /// Remove any autoclose regions that no longer contain their selection.
 4822    fn invalidate_autoclose_regions(
 4823        &mut self,
 4824        mut selections: &[Selection<Anchor>],
 4825        buffer: &MultiBufferSnapshot,
 4826    ) {
 4827        self.autoclose_regions.retain(|state| {
 4828            let mut i = 0;
 4829            while let Some(selection) = selections.get(i) {
 4830                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4831                    selections = &selections[1..];
 4832                    continue;
 4833                }
 4834                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4835                    break;
 4836                }
 4837                if selection.id == state.selection_id {
 4838                    return true;
 4839                } else {
 4840                    i += 1;
 4841                }
 4842            }
 4843            false
 4844        });
 4845    }
 4846
 4847    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4848        let offset = position.to_offset(buffer);
 4849        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4850        if offset > word_range.start && kind == Some(CharKind::Word) {
 4851            Some(
 4852                buffer
 4853                    .text_for_range(word_range.start..offset)
 4854                    .collect::<String>(),
 4855            )
 4856        } else {
 4857            None
 4858        }
 4859    }
 4860
 4861    pub fn toggle_inline_values(
 4862        &mut self,
 4863        _: &ToggleInlineValues,
 4864        _: &mut Window,
 4865        cx: &mut Context<Self>,
 4866    ) {
 4867        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4868
 4869        self.refresh_inline_values(cx);
 4870    }
 4871
 4872    pub fn toggle_inlay_hints(
 4873        &mut self,
 4874        _: &ToggleInlayHints,
 4875        _: &mut Window,
 4876        cx: &mut Context<Self>,
 4877    ) {
 4878        self.refresh_inlay_hints(
 4879            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4880            cx,
 4881        );
 4882    }
 4883
 4884    pub fn inlay_hints_enabled(&self) -> bool {
 4885        self.inlay_hint_cache.enabled
 4886    }
 4887
 4888    pub fn inline_values_enabled(&self) -> bool {
 4889        self.inline_value_cache.enabled
 4890    }
 4891
 4892    #[cfg(any(test, feature = "test-support"))]
 4893    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4894        self.display_map
 4895            .read(cx)
 4896            .current_inlays()
 4897            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4898            .cloned()
 4899            .collect()
 4900    }
 4901
 4902    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4903        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4904            return;
 4905        }
 4906
 4907        let reason_description = reason.description();
 4908        let ignore_debounce = matches!(
 4909            reason,
 4910            InlayHintRefreshReason::SettingsChange(_)
 4911                | InlayHintRefreshReason::Toggle(_)
 4912                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4913                | InlayHintRefreshReason::ModifiersChanged(_)
 4914        );
 4915        let (invalidate_cache, required_languages) = match reason {
 4916            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4917                match self.inlay_hint_cache.modifiers_override(enabled) {
 4918                    Some(enabled) => {
 4919                        if enabled {
 4920                            (InvalidationStrategy::RefreshRequested, None)
 4921                        } else {
 4922                            self.splice_inlays(
 4923                                &self
 4924                                    .visible_inlay_hints(cx)
 4925                                    .iter()
 4926                                    .map(|inlay| inlay.id)
 4927                                    .collect::<Vec<InlayId>>(),
 4928                                Vec::new(),
 4929                                cx,
 4930                            );
 4931                            return;
 4932                        }
 4933                    }
 4934                    None => return,
 4935                }
 4936            }
 4937            InlayHintRefreshReason::Toggle(enabled) => {
 4938                if self.inlay_hint_cache.toggle(enabled) {
 4939                    if enabled {
 4940                        (InvalidationStrategy::RefreshRequested, None)
 4941                    } else {
 4942                        self.splice_inlays(
 4943                            &self
 4944                                .visible_inlay_hints(cx)
 4945                                .iter()
 4946                                .map(|inlay| inlay.id)
 4947                                .collect::<Vec<InlayId>>(),
 4948                            Vec::new(),
 4949                            cx,
 4950                        );
 4951                        return;
 4952                    }
 4953                } else {
 4954                    return;
 4955                }
 4956            }
 4957            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4958                match self.inlay_hint_cache.update_settings(
 4959                    &self.buffer,
 4960                    new_settings,
 4961                    self.visible_inlay_hints(cx),
 4962                    cx,
 4963                ) {
 4964                    ControlFlow::Break(Some(InlaySplice {
 4965                        to_remove,
 4966                        to_insert,
 4967                    })) => {
 4968                        self.splice_inlays(&to_remove, to_insert, cx);
 4969                        return;
 4970                    }
 4971                    ControlFlow::Break(None) => return,
 4972                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4973                }
 4974            }
 4975            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4976                if let Some(InlaySplice {
 4977                    to_remove,
 4978                    to_insert,
 4979                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4980                {
 4981                    self.splice_inlays(&to_remove, to_insert, cx);
 4982                }
 4983                self.display_map.update(cx, |display_map, _| {
 4984                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4985                });
 4986                return;
 4987            }
 4988            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4989            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4990                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4991            }
 4992            InlayHintRefreshReason::RefreshRequested => {
 4993                (InvalidationStrategy::RefreshRequested, None)
 4994            }
 4995        };
 4996
 4997        if let Some(InlaySplice {
 4998            to_remove,
 4999            to_insert,
 5000        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5001            reason_description,
 5002            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 5003            invalidate_cache,
 5004            ignore_debounce,
 5005            cx,
 5006        ) {
 5007            self.splice_inlays(&to_remove, to_insert, cx);
 5008        }
 5009    }
 5010
 5011    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5012        self.display_map
 5013            .read(cx)
 5014            .current_inlays()
 5015            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5016            .cloned()
 5017            .collect()
 5018    }
 5019
 5020    pub fn excerpts_for_inlay_hints_query(
 5021        &self,
 5022        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5023        cx: &mut Context<Editor>,
 5024    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5025        let Some(project) = self.project.as_ref() else {
 5026            return HashMap::default();
 5027        };
 5028        let project = project.read(cx);
 5029        let multi_buffer = self.buffer().read(cx);
 5030        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5031        let multi_buffer_visible_start = self
 5032            .scroll_manager
 5033            .anchor()
 5034            .anchor
 5035            .to_point(&multi_buffer_snapshot);
 5036        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5037            multi_buffer_visible_start
 5038                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5039            Bias::Left,
 5040        );
 5041        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5042        multi_buffer_snapshot
 5043            .range_to_buffer_ranges(multi_buffer_visible_range)
 5044            .into_iter()
 5045            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5046            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5047                let buffer_file = project::File::from_dyn(buffer.file())?;
 5048                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5049                let worktree_entry = buffer_worktree
 5050                    .read(cx)
 5051                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5052                if worktree_entry.is_ignored {
 5053                    return None;
 5054                }
 5055
 5056                let language = buffer.language()?;
 5057                if let Some(restrict_to_languages) = restrict_to_languages {
 5058                    if !restrict_to_languages.contains(language) {
 5059                        return None;
 5060                    }
 5061                }
 5062                Some((
 5063                    excerpt_id,
 5064                    (
 5065                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5066                        buffer.version().clone(),
 5067                        excerpt_visible_range,
 5068                    ),
 5069                ))
 5070            })
 5071            .collect()
 5072    }
 5073
 5074    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5075        TextLayoutDetails {
 5076            text_system: window.text_system().clone(),
 5077            editor_style: self.style.clone().unwrap(),
 5078            rem_size: window.rem_size(),
 5079            scroll_anchor: self.scroll_manager.anchor(),
 5080            visible_rows: self.visible_line_count(),
 5081            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5082        }
 5083    }
 5084
 5085    pub fn splice_inlays(
 5086        &self,
 5087        to_remove: &[InlayId],
 5088        to_insert: Vec<Inlay>,
 5089        cx: &mut Context<Self>,
 5090    ) {
 5091        self.display_map.update(cx, |display_map, cx| {
 5092            display_map.splice_inlays(to_remove, to_insert, cx)
 5093        });
 5094        cx.notify();
 5095    }
 5096
 5097    fn trigger_on_type_formatting(
 5098        &self,
 5099        input: String,
 5100        window: &mut Window,
 5101        cx: &mut Context<Self>,
 5102    ) -> Option<Task<Result<()>>> {
 5103        if input.len() != 1 {
 5104            return None;
 5105        }
 5106
 5107        let project = self.project.as_ref()?;
 5108        let position = self.selections.newest_anchor().head();
 5109        let (buffer, buffer_position) = self
 5110            .buffer
 5111            .read(cx)
 5112            .text_anchor_for_position(position, cx)?;
 5113
 5114        let settings = language_settings::language_settings(
 5115            buffer
 5116                .read(cx)
 5117                .language_at(buffer_position)
 5118                .map(|l| l.name()),
 5119            buffer.read(cx).file(),
 5120            cx,
 5121        );
 5122        if !settings.use_on_type_format {
 5123            return None;
 5124        }
 5125
 5126        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5127        // hence we do LSP request & edit on host side only — add formats to host's history.
 5128        let push_to_lsp_host_history = true;
 5129        // If this is not the host, append its history with new edits.
 5130        let push_to_client_history = project.read(cx).is_via_collab();
 5131
 5132        let on_type_formatting = project.update(cx, |project, cx| {
 5133            project.on_type_format(
 5134                buffer.clone(),
 5135                buffer_position,
 5136                input,
 5137                push_to_lsp_host_history,
 5138                cx,
 5139            )
 5140        });
 5141        Some(cx.spawn_in(window, async move |editor, cx| {
 5142            if let Some(transaction) = on_type_formatting.await? {
 5143                if push_to_client_history {
 5144                    buffer
 5145                        .update(cx, |buffer, _| {
 5146                            buffer.push_transaction(transaction, Instant::now());
 5147                            buffer.finalize_last_transaction();
 5148                        })
 5149                        .ok();
 5150                }
 5151                editor.update(cx, |editor, cx| {
 5152                    editor.refresh_document_highlights(cx);
 5153                })?;
 5154            }
 5155            Ok(())
 5156        }))
 5157    }
 5158
 5159    pub fn show_word_completions(
 5160        &mut self,
 5161        _: &ShowWordCompletions,
 5162        window: &mut Window,
 5163        cx: &mut Context<Self>,
 5164    ) {
 5165        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5166    }
 5167
 5168    pub fn show_completions(
 5169        &mut self,
 5170        options: &ShowCompletions,
 5171        window: &mut Window,
 5172        cx: &mut Context<Self>,
 5173    ) {
 5174        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5175    }
 5176
 5177    fn open_or_update_completions_menu(
 5178        &mut self,
 5179        requested_source: Option<CompletionsMenuSource>,
 5180        trigger: Option<&str>,
 5181        window: &mut Window,
 5182        cx: &mut Context<Self>,
 5183    ) {
 5184        if self.pending_rename.is_some() {
 5185            return;
 5186        }
 5187
 5188        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5189
 5190        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5191        // inserted and selected. To handle that case, the start of the selection is used so that
 5192        // the menu starts with all choices.
 5193        let position = self
 5194            .selections
 5195            .newest_anchor()
 5196            .start
 5197            .bias_right(&multibuffer_snapshot);
 5198        if position.diff_base_anchor.is_some() {
 5199            return;
 5200        }
 5201        let (buffer, buffer_position) =
 5202            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5203                output
 5204            } else {
 5205                return;
 5206            };
 5207        let buffer_snapshot = buffer.read(cx).snapshot();
 5208
 5209        let query: Option<Arc<String>> =
 5210            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5211
 5212        drop(multibuffer_snapshot);
 5213
 5214        let provider = match requested_source {
 5215            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5216            Some(CompletionsMenuSource::Words) => None,
 5217            Some(CompletionsMenuSource::SnippetChoices) => {
 5218                log::error!("bug: SnippetChoices requested_source is not handled");
 5219                None
 5220            }
 5221        };
 5222
 5223        let sort_completions = provider
 5224            .as_ref()
 5225            .map_or(false, |provider| provider.sort_completions());
 5226
 5227        let filter_completions = provider
 5228            .as_ref()
 5229            .map_or(true, |provider| provider.filter_completions());
 5230
 5231        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5232            if filter_completions {
 5233                menu.filter(query.clone(), provider.clone(), window, cx);
 5234            }
 5235            // When `is_incomplete` is false, no need to re-query completions when the current query
 5236            // is a suffix of the initial query.
 5237            if !menu.is_incomplete {
 5238                // If the new query is a suffix of the old query (typing more characters) and
 5239                // the previous result was complete, the existing completions can be filtered.
 5240                //
 5241                // Note that this is always true for snippet completions.
 5242                let query_matches = match (&menu.initial_query, &query) {
 5243                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5244                    (None, _) => true,
 5245                    _ => false,
 5246                };
 5247                if query_matches {
 5248                    let position_matches = if menu.initial_position == position {
 5249                        true
 5250                    } else {
 5251                        let snapshot = self.buffer.read(cx).read(cx);
 5252                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5253                    };
 5254                    if position_matches {
 5255                        return;
 5256                    }
 5257                }
 5258            }
 5259        };
 5260
 5261        let trigger_kind = match trigger {
 5262            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5263                CompletionTriggerKind::TRIGGER_CHARACTER
 5264            }
 5265            _ => CompletionTriggerKind::INVOKED,
 5266        };
 5267        let completion_context = CompletionContext {
 5268            trigger_character: trigger.and_then(|trigger| {
 5269                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5270                    Some(String::from(trigger))
 5271                } else {
 5272                    None
 5273                }
 5274            }),
 5275            trigger_kind,
 5276        };
 5277
 5278        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5279            buffer_snapshot.surrounding_word(buffer_position)
 5280        {
 5281            let word_to_exclude = buffer_snapshot
 5282                .text_for_range(word_range.clone())
 5283                .collect::<String>();
 5284            (
 5285                buffer_snapshot.anchor_before(word_range.start)
 5286                    ..buffer_snapshot.anchor_after(buffer_position),
 5287                Some(word_to_exclude),
 5288            )
 5289        } else {
 5290            (buffer_position..buffer_position, None)
 5291        };
 5292
 5293        let language = buffer_snapshot
 5294            .language_at(buffer_position)
 5295            .map(|language| language.name());
 5296
 5297        let completion_settings =
 5298            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5299
 5300        let show_completion_documentation = buffer_snapshot
 5301            .settings_at(buffer_position, cx)
 5302            .show_completion_documentation;
 5303
 5304        // The document can be large, so stay in reasonable bounds when searching for words,
 5305        // otherwise completion pop-up might be slow to appear.
 5306        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5307        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5308        let min_word_search = buffer_snapshot.clip_point(
 5309            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5310            Bias::Left,
 5311        );
 5312        let max_word_search = buffer_snapshot.clip_point(
 5313            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5314            Bias::Right,
 5315        );
 5316        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5317            ..buffer_snapshot.point_to_offset(max_word_search);
 5318
 5319        let skip_digits = query
 5320            .as_ref()
 5321            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5322
 5323        let (mut words, provider_responses) = match &provider {
 5324            Some(provider) => {
 5325                let provider_responses = provider.completions(
 5326                    position.excerpt_id,
 5327                    &buffer,
 5328                    buffer_position,
 5329                    completion_context,
 5330                    window,
 5331                    cx,
 5332                );
 5333
 5334                let words = match completion_settings.words {
 5335                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5336                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5337                        .background_spawn(async move {
 5338                            buffer_snapshot.words_in_range(WordsQuery {
 5339                                fuzzy_contents: None,
 5340                                range: word_search_range,
 5341                                skip_digits,
 5342                            })
 5343                        }),
 5344                };
 5345
 5346                (words, provider_responses)
 5347            }
 5348            None => (
 5349                cx.background_spawn(async move {
 5350                    buffer_snapshot.words_in_range(WordsQuery {
 5351                        fuzzy_contents: None,
 5352                        range: word_search_range,
 5353                        skip_digits,
 5354                    })
 5355                }),
 5356                Task::ready(Ok(Vec::new())),
 5357            ),
 5358        };
 5359
 5360        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5361
 5362        let id = post_inc(&mut self.next_completion_id);
 5363        let task = cx.spawn_in(window, async move |editor, cx| {
 5364            let Ok(()) = editor.update(cx, |this, _| {
 5365                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5366            }) else {
 5367                return;
 5368            };
 5369
 5370            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5371            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5372            let mut completions = Vec::new();
 5373            let mut is_incomplete = false;
 5374            if let Some(provider_responses) = provider_responses.await.log_err() {
 5375                if !provider_responses.is_empty() {
 5376                    for response in provider_responses {
 5377                        completions.extend(response.completions);
 5378                        is_incomplete = is_incomplete || response.is_incomplete;
 5379                    }
 5380                    if completion_settings.words == WordsCompletionMode::Fallback {
 5381                        words = Task::ready(BTreeMap::default());
 5382                    }
 5383                }
 5384            }
 5385
 5386            let mut words = words.await;
 5387            if let Some(word_to_exclude) = &word_to_exclude {
 5388                words.remove(word_to_exclude);
 5389            }
 5390            for lsp_completion in &completions {
 5391                words.remove(&lsp_completion.new_text);
 5392            }
 5393            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5394                replace_range: word_replace_range.clone(),
 5395                new_text: word.clone(),
 5396                label: CodeLabel::plain(word, None),
 5397                icon_path: None,
 5398                documentation: None,
 5399                source: CompletionSource::BufferWord {
 5400                    word_range,
 5401                    resolved: false,
 5402                },
 5403                insert_text_mode: Some(InsertTextMode::AS_IS),
 5404                confirm: None,
 5405            }));
 5406
 5407            let menu = if completions.is_empty() {
 5408                None
 5409            } else {
 5410                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5411                    let languages = editor
 5412                        .workspace
 5413                        .as_ref()
 5414                        .and_then(|(workspace, _)| workspace.upgrade())
 5415                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5416                    let menu = CompletionsMenu::new(
 5417                        id,
 5418                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5419                        sort_completions,
 5420                        show_completion_documentation,
 5421                        position,
 5422                        query.clone(),
 5423                        is_incomplete,
 5424                        buffer.clone(),
 5425                        completions.into(),
 5426                        snippet_sort_order,
 5427                        languages,
 5428                        language,
 5429                        cx,
 5430                    );
 5431
 5432                    let query = if filter_completions { query } else { None };
 5433                    let matches_task = if let Some(query) = query {
 5434                        menu.do_async_filtering(query, cx)
 5435                    } else {
 5436                        Task::ready(menu.unfiltered_matches())
 5437                    };
 5438                    (menu, matches_task)
 5439                }) else {
 5440                    return;
 5441                };
 5442
 5443                let matches = matches_task.await;
 5444
 5445                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5446                    // Newer menu already set, so exit.
 5447                    match editor.context_menu.borrow().as_ref() {
 5448                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5449                            if prev_menu.id > id {
 5450                                return;
 5451                            }
 5452                        }
 5453                        _ => {}
 5454                    };
 5455
 5456                    // Only valid to take prev_menu because it the new menu is immediately set
 5457                    // below, or the menu is hidden.
 5458                    match editor.context_menu.borrow_mut().take() {
 5459                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5460                            let position_matches =
 5461                                if prev_menu.initial_position == menu.initial_position {
 5462                                    true
 5463                                } else {
 5464                                    let snapshot = editor.buffer.read(cx).read(cx);
 5465                                    prev_menu.initial_position.to_offset(&snapshot)
 5466                                        == menu.initial_position.to_offset(&snapshot)
 5467                                };
 5468                            if position_matches {
 5469                                // Preserve markdown cache before `set_filter_results` because it will
 5470                                // try to populate the documentation cache.
 5471                                menu.preserve_markdown_cache(prev_menu);
 5472                            }
 5473                        }
 5474                        _ => {}
 5475                    };
 5476
 5477                    menu.set_filter_results(matches, provider, window, cx);
 5478                }) else {
 5479                    return;
 5480                };
 5481
 5482                menu.visible().then_some(menu)
 5483            };
 5484
 5485            editor
 5486                .update_in(cx, |editor, window, cx| {
 5487                    if editor.focus_handle.is_focused(window) {
 5488                        if let Some(menu) = menu {
 5489                            *editor.context_menu.borrow_mut() =
 5490                                Some(CodeContextMenu::Completions(menu));
 5491
 5492                            crate::hover_popover::hide_hover(editor, cx);
 5493                            if editor.show_edit_predictions_in_menu() {
 5494                                editor.update_visible_inline_completion(window, cx);
 5495                            } else {
 5496                                editor.discard_inline_completion(false, cx);
 5497                            }
 5498
 5499                            cx.notify();
 5500                            return;
 5501                        }
 5502                    }
 5503
 5504                    if editor.completion_tasks.len() <= 1 {
 5505                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5506                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5507                        // If it was already hidden and we don't show inline completions in the menu, we should
 5508                        // also show the inline-completion when available.
 5509                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5510                            editor.update_visible_inline_completion(window, cx);
 5511                        }
 5512                    }
 5513                })
 5514                .ok();
 5515        });
 5516
 5517        self.completion_tasks.push((id, task));
 5518    }
 5519
 5520    #[cfg(feature = "test-support")]
 5521    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5522        let menu = self.context_menu.borrow();
 5523        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5524            let completions = menu.completions.borrow();
 5525            Some(completions.to_vec())
 5526        } else {
 5527            None
 5528        }
 5529    }
 5530
 5531    pub fn with_completions_menu_matching_id<R>(
 5532        &self,
 5533        id: CompletionId,
 5534        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5535    ) -> R {
 5536        let mut context_menu = self.context_menu.borrow_mut();
 5537        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5538            return f(None);
 5539        };
 5540        if completions_menu.id != id {
 5541            return f(None);
 5542        }
 5543        f(Some(completions_menu))
 5544    }
 5545
 5546    pub fn confirm_completion(
 5547        &mut self,
 5548        action: &ConfirmCompletion,
 5549        window: &mut Window,
 5550        cx: &mut Context<Self>,
 5551    ) -> Option<Task<Result<()>>> {
 5552        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5553        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5554    }
 5555
 5556    pub fn confirm_completion_insert(
 5557        &mut self,
 5558        _: &ConfirmCompletionInsert,
 5559        window: &mut Window,
 5560        cx: &mut Context<Self>,
 5561    ) -> Option<Task<Result<()>>> {
 5562        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5563        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5564    }
 5565
 5566    pub fn confirm_completion_replace(
 5567        &mut self,
 5568        _: &ConfirmCompletionReplace,
 5569        window: &mut Window,
 5570        cx: &mut Context<Self>,
 5571    ) -> Option<Task<Result<()>>> {
 5572        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5573        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5574    }
 5575
 5576    pub fn compose_completion(
 5577        &mut self,
 5578        action: &ComposeCompletion,
 5579        window: &mut Window,
 5580        cx: &mut Context<Self>,
 5581    ) -> Option<Task<Result<()>>> {
 5582        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5583        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5584    }
 5585
 5586    fn do_completion(
 5587        &mut self,
 5588        item_ix: Option<usize>,
 5589        intent: CompletionIntent,
 5590        window: &mut Window,
 5591        cx: &mut Context<Editor>,
 5592    ) -> Option<Task<Result<()>>> {
 5593        use language::ToOffset as _;
 5594
 5595        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5596        else {
 5597            return None;
 5598        };
 5599
 5600        let candidate_id = {
 5601            let entries = completions_menu.entries.borrow();
 5602            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5603            if self.show_edit_predictions_in_menu() {
 5604                self.discard_inline_completion(true, cx);
 5605            }
 5606            mat.candidate_id
 5607        };
 5608
 5609        let completion = completions_menu
 5610            .completions
 5611            .borrow()
 5612            .get(candidate_id)?
 5613            .clone();
 5614        cx.stop_propagation();
 5615
 5616        let buffer_handle = completions_menu.buffer.clone();
 5617
 5618        let CompletionEdit {
 5619            new_text,
 5620            snippet,
 5621            replace_range,
 5622        } = process_completion_for_edit(
 5623            &completion,
 5624            intent,
 5625            &buffer_handle,
 5626            &completions_menu.initial_position.text_anchor,
 5627            cx,
 5628        );
 5629
 5630        let buffer = buffer_handle.read(cx);
 5631        let snapshot = self.buffer.read(cx).snapshot(cx);
 5632        let newest_anchor = self.selections.newest_anchor();
 5633        let replace_range_multibuffer = {
 5634            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5635            let multibuffer_anchor = snapshot
 5636                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5637                .unwrap()
 5638                ..snapshot
 5639                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5640                    .unwrap();
 5641            multibuffer_anchor.start.to_offset(&snapshot)
 5642                ..multibuffer_anchor.end.to_offset(&snapshot)
 5643        };
 5644        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5645            return None;
 5646        }
 5647
 5648        let old_text = buffer
 5649            .text_for_range(replace_range.clone())
 5650            .collect::<String>();
 5651        let lookbehind = newest_anchor
 5652            .start
 5653            .text_anchor
 5654            .to_offset(buffer)
 5655            .saturating_sub(replace_range.start);
 5656        let lookahead = replace_range
 5657            .end
 5658            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5659        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5660        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5661
 5662        let selections = self.selections.all::<usize>(cx);
 5663        let mut ranges = Vec::new();
 5664        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5665
 5666        for selection in &selections {
 5667            let range = if selection.id == newest_anchor.id {
 5668                replace_range_multibuffer.clone()
 5669            } else {
 5670                let mut range = selection.range();
 5671
 5672                // if prefix is present, don't duplicate it
 5673                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5674                    range.start = range.start.saturating_sub(lookbehind);
 5675
 5676                    // if suffix is also present, mimic the newest cursor and replace it
 5677                    if selection.id != newest_anchor.id
 5678                        && snapshot.contains_str_at(range.end, suffix)
 5679                    {
 5680                        range.end += lookahead;
 5681                    }
 5682                }
 5683                range
 5684            };
 5685
 5686            ranges.push(range.clone());
 5687
 5688            if !self.linked_edit_ranges.is_empty() {
 5689                let start_anchor = snapshot.anchor_before(range.start);
 5690                let end_anchor = snapshot.anchor_after(range.end);
 5691                if let Some(ranges) = self
 5692                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5693                {
 5694                    for (buffer, edits) in ranges {
 5695                        linked_edits
 5696                            .entry(buffer.clone())
 5697                            .or_default()
 5698                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5699                    }
 5700                }
 5701            }
 5702        }
 5703
 5704        let common_prefix_len = old_text
 5705            .chars()
 5706            .zip(new_text.chars())
 5707            .take_while(|(a, b)| a == b)
 5708            .map(|(a, _)| a.len_utf8())
 5709            .sum::<usize>();
 5710
 5711        cx.emit(EditorEvent::InputHandled {
 5712            utf16_range_to_replace: None,
 5713            text: new_text[common_prefix_len..].into(),
 5714        });
 5715
 5716        self.transact(window, cx, |this, window, cx| {
 5717            if let Some(mut snippet) = snippet {
 5718                snippet.text = new_text.to_string();
 5719                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5720            } else {
 5721                this.buffer.update(cx, |buffer, cx| {
 5722                    let auto_indent = match completion.insert_text_mode {
 5723                        Some(InsertTextMode::AS_IS) => None,
 5724                        _ => this.autoindent_mode.clone(),
 5725                    };
 5726                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5727                    buffer.edit(edits, auto_indent, cx);
 5728                });
 5729            }
 5730            for (buffer, edits) in linked_edits {
 5731                buffer.update(cx, |buffer, cx| {
 5732                    let snapshot = buffer.snapshot();
 5733                    let edits = edits
 5734                        .into_iter()
 5735                        .map(|(range, text)| {
 5736                            use text::ToPoint as TP;
 5737                            let end_point = TP::to_point(&range.end, &snapshot);
 5738                            let start_point = TP::to_point(&range.start, &snapshot);
 5739                            (start_point..end_point, text)
 5740                        })
 5741                        .sorted_by_key(|(range, _)| range.start);
 5742                    buffer.edit(edits, None, cx);
 5743                })
 5744            }
 5745
 5746            this.refresh_inline_completion(true, false, window, cx);
 5747        });
 5748
 5749        let show_new_completions_on_confirm = completion
 5750            .confirm
 5751            .as_ref()
 5752            .map_or(false, |confirm| confirm(intent, window, cx));
 5753        if show_new_completions_on_confirm {
 5754            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5755        }
 5756
 5757        let provider = self.completion_provider.as_ref()?;
 5758        drop(completion);
 5759        let apply_edits = provider.apply_additional_edits_for_completion(
 5760            buffer_handle,
 5761            completions_menu.completions.clone(),
 5762            candidate_id,
 5763            true,
 5764            cx,
 5765        );
 5766
 5767        let editor_settings = EditorSettings::get_global(cx);
 5768        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5769            // After the code completion is finished, users often want to know what signatures are needed.
 5770            // so we should automatically call signature_help
 5771            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5772        }
 5773
 5774        Some(cx.foreground_executor().spawn(async move {
 5775            apply_edits.await?;
 5776            Ok(())
 5777        }))
 5778    }
 5779
 5780    pub fn toggle_code_actions(
 5781        &mut self,
 5782        action: &ToggleCodeActions,
 5783        window: &mut Window,
 5784        cx: &mut Context<Self>,
 5785    ) {
 5786        let quick_launch = action.quick_launch;
 5787        let mut context_menu = self.context_menu.borrow_mut();
 5788        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5789            if code_actions.deployed_from == action.deployed_from {
 5790                // Toggle if we're selecting the same one
 5791                *context_menu = None;
 5792                cx.notify();
 5793                return;
 5794            } else {
 5795                // Otherwise, clear it and start a new one
 5796                *context_menu = None;
 5797                cx.notify();
 5798            }
 5799        }
 5800        drop(context_menu);
 5801        let snapshot = self.snapshot(window, cx);
 5802        let deployed_from = action.deployed_from.clone();
 5803        let action = action.clone();
 5804        self.completion_tasks.clear();
 5805        self.discard_inline_completion(false, cx);
 5806
 5807        let multibuffer_point = match &action.deployed_from {
 5808            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5809                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5810            }
 5811            _ => self.selections.newest::<Point>(cx).head(),
 5812        };
 5813        let Some((buffer, buffer_row)) = snapshot
 5814            .buffer_snapshot
 5815            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5816            .and_then(|(buffer_snapshot, range)| {
 5817                self.buffer()
 5818                    .read(cx)
 5819                    .buffer(buffer_snapshot.remote_id())
 5820                    .map(|buffer| (buffer, range.start.row))
 5821            })
 5822        else {
 5823            return;
 5824        };
 5825        let buffer_id = buffer.read(cx).remote_id();
 5826        let tasks = self
 5827            .tasks
 5828            .get(&(buffer_id, buffer_row))
 5829            .map(|t| Arc::new(t.to_owned()));
 5830
 5831        if !self.focus_handle.is_focused(window) {
 5832            return;
 5833        }
 5834        let project = self.project.clone();
 5835
 5836        let code_actions_task = match deployed_from {
 5837            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5838            _ => self.code_actions(buffer_row, window, cx),
 5839        };
 5840
 5841        let runnable_task = match deployed_from {
 5842            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5843            _ => {
 5844                let mut task_context_task = Task::ready(None);
 5845                if let Some(tasks) = &tasks {
 5846                    if let Some(project) = project {
 5847                        task_context_task =
 5848                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5849                    }
 5850                }
 5851
 5852                cx.spawn_in(window, {
 5853                    let buffer = buffer.clone();
 5854                    async move |editor, cx| {
 5855                        let task_context = task_context_task.await;
 5856
 5857                        let resolved_tasks =
 5858                            tasks
 5859                                .zip(task_context.clone())
 5860                                .map(|(tasks, task_context)| ResolvedTasks {
 5861                                    templates: tasks.resolve(&task_context).collect(),
 5862                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5863                                        multibuffer_point.row,
 5864                                        tasks.column,
 5865                                    )),
 5866                                });
 5867                        let debug_scenarios = editor
 5868                            .update(cx, |editor, cx| {
 5869                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5870                            })?
 5871                            .await;
 5872                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5873                    }
 5874                })
 5875            }
 5876        };
 5877
 5878        cx.spawn_in(window, async move |editor, cx| {
 5879            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5880            let code_actions = code_actions_task.await;
 5881            let spawn_straight_away = quick_launch
 5882                && resolved_tasks
 5883                    .as_ref()
 5884                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5885                && code_actions
 5886                    .as_ref()
 5887                    .map_or(true, |actions| actions.is_empty())
 5888                && debug_scenarios.is_empty();
 5889
 5890            editor.update_in(cx, |editor, window, cx| {
 5891                crate::hover_popover::hide_hover(editor, cx);
 5892                *editor.context_menu.borrow_mut() =
 5893                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5894                        buffer,
 5895                        actions: CodeActionContents::new(
 5896                            resolved_tasks,
 5897                            code_actions,
 5898                            debug_scenarios,
 5899                            task_context.unwrap_or_default(),
 5900                        ),
 5901                        selected_item: Default::default(),
 5902                        scroll_handle: UniformListScrollHandle::default(),
 5903                        deployed_from,
 5904                    }));
 5905                cx.notify();
 5906                if spawn_straight_away {
 5907                    if let Some(task) = editor.confirm_code_action(
 5908                        &ConfirmCodeAction { item_ix: Some(0) },
 5909                        window,
 5910                        cx,
 5911                    ) {
 5912                        return task;
 5913                    }
 5914                }
 5915
 5916                Task::ready(Ok(()))
 5917            })
 5918        })
 5919        .detach_and_log_err(cx);
 5920    }
 5921
 5922    fn debug_scenarios(
 5923        &mut self,
 5924        resolved_tasks: &Option<ResolvedTasks>,
 5925        buffer: &Entity<Buffer>,
 5926        cx: &mut App,
 5927    ) -> Task<Vec<task::DebugScenario>> {
 5928        if cx.has_flag::<DebuggerFeatureFlag>() {
 5929            maybe!({
 5930                let project = self.project.as_ref()?;
 5931                let dap_store = project.read(cx).dap_store();
 5932                let mut scenarios = vec![];
 5933                let resolved_tasks = resolved_tasks.as_ref()?;
 5934                let buffer = buffer.read(cx);
 5935                let language = buffer.language()?;
 5936                let file = buffer.file();
 5937                let debug_adapter = language_settings(language.name().into(), file, cx)
 5938                    .debuggers
 5939                    .first()
 5940                    .map(SharedString::from)
 5941                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5942
 5943                dap_store.update(cx, |dap_store, cx| {
 5944                    for (_, task) in &resolved_tasks.templates {
 5945                        let maybe_scenario = dap_store.debug_scenario_for_build_task(
 5946                            task.original_task().clone(),
 5947                            debug_adapter.clone().into(),
 5948                            task.display_label().to_owned().into(),
 5949                            cx,
 5950                        );
 5951                        scenarios.push(maybe_scenario);
 5952                    }
 5953                });
 5954                Some(cx.background_spawn(async move {
 5955                    let scenarios = futures::future::join_all(scenarios)
 5956                        .await
 5957                        .into_iter()
 5958                        .flatten()
 5959                        .collect::<Vec<_>>();
 5960                    scenarios
 5961                }))
 5962            })
 5963            .unwrap_or_else(|| Task::ready(vec![]))
 5964        } else {
 5965            Task::ready(vec![])
 5966        }
 5967    }
 5968
 5969    fn code_actions(
 5970        &mut self,
 5971        buffer_row: u32,
 5972        window: &mut Window,
 5973        cx: &mut Context<Self>,
 5974    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5975        let mut task = self.code_actions_task.take();
 5976        cx.spawn_in(window, async move |editor, cx| {
 5977            while let Some(prev_task) = task {
 5978                prev_task.await.log_err();
 5979                task = editor
 5980                    .update(cx, |this, _| this.code_actions_task.take())
 5981                    .ok()?;
 5982            }
 5983
 5984            editor
 5985                .update(cx, |editor, cx| {
 5986                    editor
 5987                        .available_code_actions
 5988                        .clone()
 5989                        .and_then(|(location, code_actions)| {
 5990                            let snapshot = location.buffer.read(cx).snapshot();
 5991                            let point_range = location.range.to_point(&snapshot);
 5992                            let point_range = point_range.start.row..=point_range.end.row;
 5993                            if point_range.contains(&buffer_row) {
 5994                                Some(code_actions)
 5995                            } else {
 5996                                None
 5997                            }
 5998                        })
 5999                })
 6000                .ok()
 6001                .flatten()
 6002        })
 6003    }
 6004
 6005    pub fn confirm_code_action(
 6006        &mut self,
 6007        action: &ConfirmCodeAction,
 6008        window: &mut Window,
 6009        cx: &mut Context<Self>,
 6010    ) -> Option<Task<Result<()>>> {
 6011        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6012
 6013        let actions_menu =
 6014            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6015                menu
 6016            } else {
 6017                return None;
 6018            };
 6019
 6020        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6021        let action = actions_menu.actions.get(action_ix)?;
 6022        let title = action.label();
 6023        let buffer = actions_menu.buffer;
 6024        let workspace = self.workspace()?;
 6025
 6026        match action {
 6027            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6028                workspace.update(cx, |workspace, cx| {
 6029                    workspace.schedule_resolved_task(
 6030                        task_source_kind,
 6031                        resolved_task,
 6032                        false,
 6033                        window,
 6034                        cx,
 6035                    );
 6036
 6037                    Some(Task::ready(Ok(())))
 6038                })
 6039            }
 6040            CodeActionsItem::CodeAction {
 6041                excerpt_id,
 6042                action,
 6043                provider,
 6044            } => {
 6045                let apply_code_action =
 6046                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6047                let workspace = workspace.downgrade();
 6048                Some(cx.spawn_in(window, async move |editor, cx| {
 6049                    let project_transaction = apply_code_action.await?;
 6050                    Self::open_project_transaction(
 6051                        &editor,
 6052                        workspace,
 6053                        project_transaction,
 6054                        title,
 6055                        cx,
 6056                    )
 6057                    .await
 6058                }))
 6059            }
 6060            CodeActionsItem::DebugScenario(scenario) => {
 6061                let context = actions_menu.actions.context.clone();
 6062
 6063                workspace.update(cx, |workspace, cx| {
 6064                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6065                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6066                });
 6067                Some(Task::ready(Ok(())))
 6068            }
 6069        }
 6070    }
 6071
 6072    pub async fn open_project_transaction(
 6073        this: &WeakEntity<Editor>,
 6074        workspace: WeakEntity<Workspace>,
 6075        transaction: ProjectTransaction,
 6076        title: String,
 6077        cx: &mut AsyncWindowContext,
 6078    ) -> Result<()> {
 6079        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6080        cx.update(|_, cx| {
 6081            entries.sort_unstable_by_key(|(buffer, _)| {
 6082                buffer.read(cx).file().map(|f| f.path().clone())
 6083            });
 6084        })?;
 6085
 6086        // If the project transaction's edits are all contained within this editor, then
 6087        // avoid opening a new editor to display them.
 6088
 6089        if let Some((buffer, transaction)) = entries.first() {
 6090            if entries.len() == 1 {
 6091                let excerpt = this.update(cx, |editor, cx| {
 6092                    editor
 6093                        .buffer()
 6094                        .read(cx)
 6095                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6096                })?;
 6097                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6098                    if excerpted_buffer == *buffer {
 6099                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6100                            let excerpt_range = excerpt_range.to_offset(buffer);
 6101                            buffer
 6102                                .edited_ranges_for_transaction::<usize>(transaction)
 6103                                .all(|range| {
 6104                                    excerpt_range.start <= range.start
 6105                                        && excerpt_range.end >= range.end
 6106                                })
 6107                        })?;
 6108
 6109                        if all_edits_within_excerpt {
 6110                            return Ok(());
 6111                        }
 6112                    }
 6113                }
 6114            }
 6115        } else {
 6116            return Ok(());
 6117        }
 6118
 6119        let mut ranges_to_highlight = Vec::new();
 6120        let excerpt_buffer = cx.new(|cx| {
 6121            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6122            for (buffer_handle, transaction) in &entries {
 6123                let edited_ranges = buffer_handle
 6124                    .read(cx)
 6125                    .edited_ranges_for_transaction::<Point>(transaction)
 6126                    .collect::<Vec<_>>();
 6127                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6128                    PathKey::for_buffer(buffer_handle, cx),
 6129                    buffer_handle.clone(),
 6130                    edited_ranges,
 6131                    DEFAULT_MULTIBUFFER_CONTEXT,
 6132                    cx,
 6133                );
 6134
 6135                ranges_to_highlight.extend(ranges);
 6136            }
 6137            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6138            multibuffer
 6139        })?;
 6140
 6141        workspace.update_in(cx, |workspace, window, cx| {
 6142            let project = workspace.project().clone();
 6143            let editor =
 6144                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6145            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6146            editor.update(cx, |editor, cx| {
 6147                editor.highlight_background::<Self>(
 6148                    &ranges_to_highlight,
 6149                    |theme| theme.colors().editor_highlighted_line_background,
 6150                    cx,
 6151                );
 6152            });
 6153        })?;
 6154
 6155        Ok(())
 6156    }
 6157
 6158    pub fn clear_code_action_providers(&mut self) {
 6159        self.code_action_providers.clear();
 6160        self.available_code_actions.take();
 6161    }
 6162
 6163    pub fn add_code_action_provider(
 6164        &mut self,
 6165        provider: Rc<dyn CodeActionProvider>,
 6166        window: &mut Window,
 6167        cx: &mut Context<Self>,
 6168    ) {
 6169        if self
 6170            .code_action_providers
 6171            .iter()
 6172            .any(|existing_provider| existing_provider.id() == provider.id())
 6173        {
 6174            return;
 6175        }
 6176
 6177        self.code_action_providers.push(provider);
 6178        self.refresh_code_actions(window, cx);
 6179    }
 6180
 6181    pub fn remove_code_action_provider(
 6182        &mut self,
 6183        id: Arc<str>,
 6184        window: &mut Window,
 6185        cx: &mut Context<Self>,
 6186    ) {
 6187        self.code_action_providers
 6188            .retain(|provider| provider.id() != id);
 6189        self.refresh_code_actions(window, cx);
 6190    }
 6191
 6192    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6193        !self.code_action_providers.is_empty()
 6194            && EditorSettings::get_global(cx).toolbar.code_actions
 6195    }
 6196
 6197    pub fn has_available_code_actions(&self) -> bool {
 6198        self.available_code_actions
 6199            .as_ref()
 6200            .is_some_and(|(_, actions)| !actions.is_empty())
 6201    }
 6202
 6203    fn render_inline_code_actions(
 6204        &self,
 6205        icon_size: ui::IconSize,
 6206        display_row: DisplayRow,
 6207        is_active: bool,
 6208        cx: &mut Context<Self>,
 6209    ) -> AnyElement {
 6210        let show_tooltip = !self.context_menu_visible();
 6211        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6212            .icon_size(icon_size)
 6213            .shape(ui::IconButtonShape::Square)
 6214            .style(ButtonStyle::Transparent)
 6215            .icon_color(ui::Color::Hidden)
 6216            .toggle_state(is_active)
 6217            .when(show_tooltip, |this| {
 6218                this.tooltip({
 6219                    let focus_handle = self.focus_handle.clone();
 6220                    move |window, cx| {
 6221                        Tooltip::for_action_in(
 6222                            "Toggle Code Actions",
 6223                            &ToggleCodeActions {
 6224                                deployed_from: None,
 6225                                quick_launch: false,
 6226                            },
 6227                            &focus_handle,
 6228                            window,
 6229                            cx,
 6230                        )
 6231                    }
 6232                })
 6233            })
 6234            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6235                window.focus(&editor.focus_handle(cx));
 6236                editor.toggle_code_actions(
 6237                    &crate::actions::ToggleCodeActions {
 6238                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6239                            display_row,
 6240                        )),
 6241                        quick_launch: false,
 6242                    },
 6243                    window,
 6244                    cx,
 6245                );
 6246            }))
 6247            .into_any_element()
 6248    }
 6249
 6250    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6251        &self.context_menu
 6252    }
 6253
 6254    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6255        let newest_selection = self.selections.newest_anchor().clone();
 6256        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6257        let buffer = self.buffer.read(cx);
 6258        if newest_selection.head().diff_base_anchor.is_some() {
 6259            return None;
 6260        }
 6261        let (start_buffer, start) =
 6262            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6263        let (end_buffer, end) =
 6264            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6265        if start_buffer != end_buffer {
 6266            return None;
 6267        }
 6268
 6269        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6270            cx.background_executor()
 6271                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6272                .await;
 6273
 6274            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6275                let providers = this.code_action_providers.clone();
 6276                let tasks = this
 6277                    .code_action_providers
 6278                    .iter()
 6279                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6280                    .collect::<Vec<_>>();
 6281                (providers, tasks)
 6282            })?;
 6283
 6284            let mut actions = Vec::new();
 6285            for (provider, provider_actions) in
 6286                providers.into_iter().zip(future::join_all(tasks).await)
 6287            {
 6288                if let Some(provider_actions) = provider_actions.log_err() {
 6289                    actions.extend(provider_actions.into_iter().map(|action| {
 6290                        AvailableCodeAction {
 6291                            excerpt_id: newest_selection.start.excerpt_id,
 6292                            action,
 6293                            provider: provider.clone(),
 6294                        }
 6295                    }));
 6296                }
 6297            }
 6298
 6299            this.update(cx, |this, cx| {
 6300                this.available_code_actions = if actions.is_empty() {
 6301                    None
 6302                } else {
 6303                    Some((
 6304                        Location {
 6305                            buffer: start_buffer,
 6306                            range: start..end,
 6307                        },
 6308                        actions.into(),
 6309                    ))
 6310                };
 6311                cx.notify();
 6312            })
 6313        }));
 6314        None
 6315    }
 6316
 6317    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6318        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6319            self.show_git_blame_inline = false;
 6320
 6321            self.show_git_blame_inline_delay_task =
 6322                Some(cx.spawn_in(window, async move |this, cx| {
 6323                    cx.background_executor().timer(delay).await;
 6324
 6325                    this.update(cx, |this, cx| {
 6326                        this.show_git_blame_inline = true;
 6327                        cx.notify();
 6328                    })
 6329                    .log_err();
 6330                }));
 6331        }
 6332    }
 6333
 6334    fn show_blame_popover(
 6335        &mut self,
 6336        blame_entry: &BlameEntry,
 6337        position: gpui::Point<Pixels>,
 6338        cx: &mut Context<Self>,
 6339    ) {
 6340        if let Some(state) = &mut self.inline_blame_popover {
 6341            state.hide_task.take();
 6342        } else {
 6343            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6344            let blame_entry = blame_entry.clone();
 6345            let show_task = cx.spawn(async move |editor, cx| {
 6346                cx.background_executor()
 6347                    .timer(std::time::Duration::from_millis(delay))
 6348                    .await;
 6349                editor
 6350                    .update(cx, |editor, cx| {
 6351                        editor.inline_blame_popover_show_task.take();
 6352                        let Some(blame) = editor.blame.as_ref() else {
 6353                            return;
 6354                        };
 6355                        let blame = blame.read(cx);
 6356                        let details = blame.details_for_entry(&blame_entry);
 6357                        let markdown = cx.new(|cx| {
 6358                            Markdown::new(
 6359                                details
 6360                                    .as_ref()
 6361                                    .map(|message| message.message.clone())
 6362                                    .unwrap_or_default(),
 6363                                None,
 6364                                None,
 6365                                cx,
 6366                            )
 6367                        });
 6368                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6369                            position,
 6370                            hide_task: None,
 6371                            popover_bounds: None,
 6372                            popover_state: InlineBlamePopoverState {
 6373                                scroll_handle: ScrollHandle::new(),
 6374                                commit_message: details,
 6375                                markdown,
 6376                            },
 6377                        });
 6378                        cx.notify();
 6379                    })
 6380                    .ok();
 6381            });
 6382            self.inline_blame_popover_show_task = Some(show_task);
 6383        }
 6384    }
 6385
 6386    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6387        self.inline_blame_popover_show_task.take();
 6388        if let Some(state) = &mut self.inline_blame_popover {
 6389            let hide_task = cx.spawn(async move |editor, cx| {
 6390                cx.background_executor()
 6391                    .timer(std::time::Duration::from_millis(100))
 6392                    .await;
 6393                editor
 6394                    .update(cx, |editor, cx| {
 6395                        editor.inline_blame_popover.take();
 6396                        cx.notify();
 6397                    })
 6398                    .ok();
 6399            });
 6400            state.hide_task = Some(hide_task);
 6401        }
 6402    }
 6403
 6404    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6405        if self.pending_rename.is_some() {
 6406            return None;
 6407        }
 6408
 6409        let provider = self.semantics_provider.clone()?;
 6410        let buffer = self.buffer.read(cx);
 6411        let newest_selection = self.selections.newest_anchor().clone();
 6412        let cursor_position = newest_selection.head();
 6413        let (cursor_buffer, cursor_buffer_position) =
 6414            buffer.text_anchor_for_position(cursor_position, cx)?;
 6415        let (tail_buffer, tail_buffer_position) =
 6416            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6417        if cursor_buffer != tail_buffer {
 6418            return None;
 6419        }
 6420
 6421        let snapshot = cursor_buffer.read(cx).snapshot();
 6422        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6423        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6424        if start_word_range != end_word_range {
 6425            self.document_highlights_task.take();
 6426            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6427            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6428            return None;
 6429        }
 6430
 6431        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6432        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6433            cx.background_executor()
 6434                .timer(Duration::from_millis(debounce))
 6435                .await;
 6436
 6437            let highlights = if let Some(highlights) = cx
 6438                .update(|cx| {
 6439                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6440                })
 6441                .ok()
 6442                .flatten()
 6443            {
 6444                highlights.await.log_err()
 6445            } else {
 6446                None
 6447            };
 6448
 6449            if let Some(highlights) = highlights {
 6450                this.update(cx, |this, cx| {
 6451                    if this.pending_rename.is_some() {
 6452                        return;
 6453                    }
 6454
 6455                    let buffer_id = cursor_position.buffer_id;
 6456                    let buffer = this.buffer.read(cx);
 6457                    if !buffer
 6458                        .text_anchor_for_position(cursor_position, cx)
 6459                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6460                    {
 6461                        return;
 6462                    }
 6463
 6464                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6465                    let mut write_ranges = Vec::new();
 6466                    let mut read_ranges = Vec::new();
 6467                    for highlight in highlights {
 6468                        for (excerpt_id, excerpt_range) in
 6469                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6470                        {
 6471                            let start = highlight
 6472                                .range
 6473                                .start
 6474                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6475                            let end = highlight
 6476                                .range
 6477                                .end
 6478                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6479                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6480                                continue;
 6481                            }
 6482
 6483                            let range = Anchor {
 6484                                buffer_id,
 6485                                excerpt_id,
 6486                                text_anchor: start,
 6487                                diff_base_anchor: None,
 6488                            }..Anchor {
 6489                                buffer_id,
 6490                                excerpt_id,
 6491                                text_anchor: end,
 6492                                diff_base_anchor: None,
 6493                            };
 6494                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6495                                write_ranges.push(range);
 6496                            } else {
 6497                                read_ranges.push(range);
 6498                            }
 6499                        }
 6500                    }
 6501
 6502                    this.highlight_background::<DocumentHighlightRead>(
 6503                        &read_ranges,
 6504                        |theme| theme.colors().editor_document_highlight_read_background,
 6505                        cx,
 6506                    );
 6507                    this.highlight_background::<DocumentHighlightWrite>(
 6508                        &write_ranges,
 6509                        |theme| theme.colors().editor_document_highlight_write_background,
 6510                        cx,
 6511                    );
 6512                    cx.notify();
 6513                })
 6514                .log_err();
 6515            }
 6516        }));
 6517        None
 6518    }
 6519
 6520    fn prepare_highlight_query_from_selection(
 6521        &mut self,
 6522        cx: &mut Context<Editor>,
 6523    ) -> Option<(String, Range<Anchor>)> {
 6524        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6525            return None;
 6526        }
 6527        if !EditorSettings::get_global(cx).selection_highlight {
 6528            return None;
 6529        }
 6530        if self.selections.count() != 1 || self.selections.line_mode {
 6531            return None;
 6532        }
 6533        let selection = self.selections.newest::<Point>(cx);
 6534        if selection.is_empty() || selection.start.row != selection.end.row {
 6535            return None;
 6536        }
 6537        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6538        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6539        let query = multi_buffer_snapshot
 6540            .text_for_range(selection_anchor_range.clone())
 6541            .collect::<String>();
 6542        if query.trim().is_empty() {
 6543            return None;
 6544        }
 6545        Some((query, selection_anchor_range))
 6546    }
 6547
 6548    fn update_selection_occurrence_highlights(
 6549        &mut self,
 6550        query_text: String,
 6551        query_range: Range<Anchor>,
 6552        multi_buffer_range_to_query: Range<Point>,
 6553        use_debounce: bool,
 6554        window: &mut Window,
 6555        cx: &mut Context<Editor>,
 6556    ) -> Task<()> {
 6557        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6558        cx.spawn_in(window, async move |editor, cx| {
 6559            if use_debounce {
 6560                cx.background_executor()
 6561                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6562                    .await;
 6563            }
 6564            let match_task = cx.background_spawn(async move {
 6565                let buffer_ranges = multi_buffer_snapshot
 6566                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6567                    .into_iter()
 6568                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6569                let mut match_ranges = Vec::new();
 6570                let Ok(regex) = project::search::SearchQuery::text(
 6571                    query_text.clone(),
 6572                    false,
 6573                    false,
 6574                    false,
 6575                    Default::default(),
 6576                    Default::default(),
 6577                    false,
 6578                    None,
 6579                ) else {
 6580                    return Vec::default();
 6581                };
 6582                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6583                    match_ranges.extend(
 6584                        regex
 6585                            .search(&buffer_snapshot, Some(search_range.clone()))
 6586                            .await
 6587                            .into_iter()
 6588                            .filter_map(|match_range| {
 6589                                let match_start = buffer_snapshot
 6590                                    .anchor_after(search_range.start + match_range.start);
 6591                                let match_end = buffer_snapshot
 6592                                    .anchor_before(search_range.start + match_range.end);
 6593                                let match_anchor_range = Anchor::range_in_buffer(
 6594                                    excerpt_id,
 6595                                    buffer_snapshot.remote_id(),
 6596                                    match_start..match_end,
 6597                                );
 6598                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6599                            }),
 6600                    );
 6601                }
 6602                match_ranges
 6603            });
 6604            let match_ranges = match_task.await;
 6605            editor
 6606                .update_in(cx, |editor, _, cx| {
 6607                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6608                    if !match_ranges.is_empty() {
 6609                        editor.highlight_background::<SelectedTextHighlight>(
 6610                            &match_ranges,
 6611                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6612                            cx,
 6613                        )
 6614                    }
 6615                })
 6616                .log_err();
 6617        })
 6618    }
 6619
 6620    fn refresh_selected_text_highlights(
 6621        &mut self,
 6622        on_buffer_edit: bool,
 6623        window: &mut Window,
 6624        cx: &mut Context<Editor>,
 6625    ) {
 6626        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6627        else {
 6628            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6629            self.quick_selection_highlight_task.take();
 6630            self.debounced_selection_highlight_task.take();
 6631            return;
 6632        };
 6633        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6634        if on_buffer_edit
 6635            || self
 6636                .quick_selection_highlight_task
 6637                .as_ref()
 6638                .map_or(true, |(prev_anchor_range, _)| {
 6639                    prev_anchor_range != &query_range
 6640                })
 6641        {
 6642            let multi_buffer_visible_start = self
 6643                .scroll_manager
 6644                .anchor()
 6645                .anchor
 6646                .to_point(&multi_buffer_snapshot);
 6647            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6648                multi_buffer_visible_start
 6649                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6650                Bias::Left,
 6651            );
 6652            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6653            self.quick_selection_highlight_task = Some((
 6654                query_range.clone(),
 6655                self.update_selection_occurrence_highlights(
 6656                    query_text.clone(),
 6657                    query_range.clone(),
 6658                    multi_buffer_visible_range,
 6659                    false,
 6660                    window,
 6661                    cx,
 6662                ),
 6663            ));
 6664        }
 6665        if on_buffer_edit
 6666            || self
 6667                .debounced_selection_highlight_task
 6668                .as_ref()
 6669                .map_or(true, |(prev_anchor_range, _)| {
 6670                    prev_anchor_range != &query_range
 6671                })
 6672        {
 6673            let multi_buffer_start = multi_buffer_snapshot
 6674                .anchor_before(0)
 6675                .to_point(&multi_buffer_snapshot);
 6676            let multi_buffer_end = multi_buffer_snapshot
 6677                .anchor_after(multi_buffer_snapshot.len())
 6678                .to_point(&multi_buffer_snapshot);
 6679            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6680            self.debounced_selection_highlight_task = Some((
 6681                query_range.clone(),
 6682                self.update_selection_occurrence_highlights(
 6683                    query_text,
 6684                    query_range,
 6685                    multi_buffer_full_range,
 6686                    true,
 6687                    window,
 6688                    cx,
 6689                ),
 6690            ));
 6691        }
 6692    }
 6693
 6694    pub fn refresh_inline_completion(
 6695        &mut self,
 6696        debounce: bool,
 6697        user_requested: bool,
 6698        window: &mut Window,
 6699        cx: &mut Context<Self>,
 6700    ) -> Option<()> {
 6701        let provider = self.edit_prediction_provider()?;
 6702        let cursor = self.selections.newest_anchor().head();
 6703        let (buffer, cursor_buffer_position) =
 6704            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6705
 6706        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6707            self.discard_inline_completion(false, cx);
 6708            return None;
 6709        }
 6710
 6711        if !user_requested
 6712            && (!self.should_show_edit_predictions()
 6713                || !self.is_focused(window)
 6714                || buffer.read(cx).is_empty())
 6715        {
 6716            self.discard_inline_completion(false, cx);
 6717            return None;
 6718        }
 6719
 6720        self.update_visible_inline_completion(window, cx);
 6721        provider.refresh(
 6722            self.project.clone(),
 6723            buffer,
 6724            cursor_buffer_position,
 6725            debounce,
 6726            cx,
 6727        );
 6728        Some(())
 6729    }
 6730
 6731    fn show_edit_predictions_in_menu(&self) -> bool {
 6732        match self.edit_prediction_settings {
 6733            EditPredictionSettings::Disabled => false,
 6734            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6735        }
 6736    }
 6737
 6738    pub fn edit_predictions_enabled(&self) -> bool {
 6739        match self.edit_prediction_settings {
 6740            EditPredictionSettings::Disabled => false,
 6741            EditPredictionSettings::Enabled { .. } => true,
 6742        }
 6743    }
 6744
 6745    fn edit_prediction_requires_modifier(&self) -> bool {
 6746        match self.edit_prediction_settings {
 6747            EditPredictionSettings::Disabled => false,
 6748            EditPredictionSettings::Enabled {
 6749                preview_requires_modifier,
 6750                ..
 6751            } => preview_requires_modifier,
 6752        }
 6753    }
 6754
 6755    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6756        if self.edit_prediction_provider.is_none() {
 6757            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6758        } else {
 6759            let selection = self.selections.newest_anchor();
 6760            let cursor = selection.head();
 6761
 6762            if let Some((buffer, cursor_buffer_position)) =
 6763                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6764            {
 6765                self.edit_prediction_settings =
 6766                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6767            }
 6768        }
 6769    }
 6770
 6771    fn edit_prediction_settings_at_position(
 6772        &self,
 6773        buffer: &Entity<Buffer>,
 6774        buffer_position: language::Anchor,
 6775        cx: &App,
 6776    ) -> EditPredictionSettings {
 6777        if !self.mode.is_full()
 6778            || !self.show_inline_completions_override.unwrap_or(true)
 6779            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6780        {
 6781            return EditPredictionSettings::Disabled;
 6782        }
 6783
 6784        let buffer = buffer.read(cx);
 6785
 6786        let file = buffer.file();
 6787
 6788        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6789            return EditPredictionSettings::Disabled;
 6790        };
 6791
 6792        let by_provider = matches!(
 6793            self.menu_inline_completions_policy,
 6794            MenuInlineCompletionsPolicy::ByProvider
 6795        );
 6796
 6797        let show_in_menu = by_provider
 6798            && self
 6799                .edit_prediction_provider
 6800                .as_ref()
 6801                .map_or(false, |provider| {
 6802                    provider.provider.show_completions_in_menu()
 6803                });
 6804
 6805        let preview_requires_modifier =
 6806            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6807
 6808        EditPredictionSettings::Enabled {
 6809            show_in_menu,
 6810            preview_requires_modifier,
 6811        }
 6812    }
 6813
 6814    fn should_show_edit_predictions(&self) -> bool {
 6815        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6816    }
 6817
 6818    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6819        matches!(
 6820            self.edit_prediction_preview,
 6821            EditPredictionPreview::Active { .. }
 6822        )
 6823    }
 6824
 6825    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6826        let cursor = self.selections.newest_anchor().head();
 6827        if let Some((buffer, cursor_position)) =
 6828            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6829        {
 6830            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6831        } else {
 6832            false
 6833        }
 6834    }
 6835
 6836    pub fn supports_minimap(&self, cx: &App) -> bool {
 6837        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6838    }
 6839
 6840    fn edit_predictions_enabled_in_buffer(
 6841        &self,
 6842        buffer: &Entity<Buffer>,
 6843        buffer_position: language::Anchor,
 6844        cx: &App,
 6845    ) -> bool {
 6846        maybe!({
 6847            if self.read_only(cx) {
 6848                return Some(false);
 6849            }
 6850            let provider = self.edit_prediction_provider()?;
 6851            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6852                return Some(false);
 6853            }
 6854            let buffer = buffer.read(cx);
 6855            let Some(file) = buffer.file() else {
 6856                return Some(true);
 6857            };
 6858            let settings = all_language_settings(Some(file), cx);
 6859            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6860        })
 6861        .unwrap_or(false)
 6862    }
 6863
 6864    fn cycle_inline_completion(
 6865        &mut self,
 6866        direction: Direction,
 6867        window: &mut Window,
 6868        cx: &mut Context<Self>,
 6869    ) -> Option<()> {
 6870        let provider = self.edit_prediction_provider()?;
 6871        let cursor = self.selections.newest_anchor().head();
 6872        let (buffer, cursor_buffer_position) =
 6873            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6874        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6875            return None;
 6876        }
 6877
 6878        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6879        self.update_visible_inline_completion(window, cx);
 6880
 6881        Some(())
 6882    }
 6883
 6884    pub fn show_inline_completion(
 6885        &mut self,
 6886        _: &ShowEditPrediction,
 6887        window: &mut Window,
 6888        cx: &mut Context<Self>,
 6889    ) {
 6890        if !self.has_active_inline_completion() {
 6891            self.refresh_inline_completion(false, true, window, cx);
 6892            return;
 6893        }
 6894
 6895        self.update_visible_inline_completion(window, cx);
 6896    }
 6897
 6898    pub fn display_cursor_names(
 6899        &mut self,
 6900        _: &DisplayCursorNames,
 6901        window: &mut Window,
 6902        cx: &mut Context<Self>,
 6903    ) {
 6904        self.show_cursor_names(window, cx);
 6905    }
 6906
 6907    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6908        self.show_cursor_names = true;
 6909        cx.notify();
 6910        cx.spawn_in(window, async move |this, cx| {
 6911            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6912            this.update(cx, |this, cx| {
 6913                this.show_cursor_names = false;
 6914                cx.notify()
 6915            })
 6916            .ok()
 6917        })
 6918        .detach();
 6919    }
 6920
 6921    pub fn next_edit_prediction(
 6922        &mut self,
 6923        _: &NextEditPrediction,
 6924        window: &mut Window,
 6925        cx: &mut Context<Self>,
 6926    ) {
 6927        if self.has_active_inline_completion() {
 6928            self.cycle_inline_completion(Direction::Next, window, cx);
 6929        } else {
 6930            let is_copilot_disabled = self
 6931                .refresh_inline_completion(false, true, window, cx)
 6932                .is_none();
 6933            if is_copilot_disabled {
 6934                cx.propagate();
 6935            }
 6936        }
 6937    }
 6938
 6939    pub fn previous_edit_prediction(
 6940        &mut self,
 6941        _: &PreviousEditPrediction,
 6942        window: &mut Window,
 6943        cx: &mut Context<Self>,
 6944    ) {
 6945        if self.has_active_inline_completion() {
 6946            self.cycle_inline_completion(Direction::Prev, window, cx);
 6947        } else {
 6948            let is_copilot_disabled = self
 6949                .refresh_inline_completion(false, true, window, cx)
 6950                .is_none();
 6951            if is_copilot_disabled {
 6952                cx.propagate();
 6953            }
 6954        }
 6955    }
 6956
 6957    pub fn accept_edit_prediction(
 6958        &mut self,
 6959        _: &AcceptEditPrediction,
 6960        window: &mut Window,
 6961        cx: &mut Context<Self>,
 6962    ) {
 6963        if self.show_edit_predictions_in_menu() {
 6964            self.hide_context_menu(window, cx);
 6965        }
 6966
 6967        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6968            return;
 6969        };
 6970
 6971        self.report_inline_completion_event(
 6972            active_inline_completion.completion_id.clone(),
 6973            true,
 6974            cx,
 6975        );
 6976
 6977        match &active_inline_completion.completion {
 6978            InlineCompletion::Move { target, .. } => {
 6979                let target = *target;
 6980
 6981                if let Some(position_map) = &self.last_position_map {
 6982                    if position_map
 6983                        .visible_row_range
 6984                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6985                        || !self.edit_prediction_requires_modifier()
 6986                    {
 6987                        self.unfold_ranges(&[target..target], true, false, cx);
 6988                        // Note that this is also done in vim's handler of the Tab action.
 6989                        self.change_selections(
 6990                            Some(Autoscroll::newest()),
 6991                            window,
 6992                            cx,
 6993                            |selections| {
 6994                                selections.select_anchor_ranges([target..target]);
 6995                            },
 6996                        );
 6997                        self.clear_row_highlights::<EditPredictionPreview>();
 6998
 6999                        self.edit_prediction_preview
 7000                            .set_previous_scroll_position(None);
 7001                    } else {
 7002                        self.edit_prediction_preview
 7003                            .set_previous_scroll_position(Some(
 7004                                position_map.snapshot.scroll_anchor,
 7005                            ));
 7006
 7007                        self.highlight_rows::<EditPredictionPreview>(
 7008                            target..target,
 7009                            cx.theme().colors().editor_highlighted_line_background,
 7010                            RowHighlightOptions {
 7011                                autoscroll: true,
 7012                                ..Default::default()
 7013                            },
 7014                            cx,
 7015                        );
 7016                        self.request_autoscroll(Autoscroll::fit(), cx);
 7017                    }
 7018                }
 7019            }
 7020            InlineCompletion::Edit { edits, .. } => {
 7021                if let Some(provider) = self.edit_prediction_provider() {
 7022                    provider.accept(cx);
 7023                }
 7024
 7025                // Store the transaction ID and selections before applying the edit
 7026                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7027
 7028                let snapshot = self.buffer.read(cx).snapshot(cx);
 7029                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7030
 7031                self.buffer.update(cx, |buffer, cx| {
 7032                    buffer.edit(edits.iter().cloned(), None, cx)
 7033                });
 7034
 7035                self.change_selections(None, window, cx, |s| {
 7036                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7037                });
 7038
 7039                let selections = self.selections.disjoint_anchors();
 7040                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7041                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7042                    if has_new_transaction {
 7043                        self.selection_history
 7044                            .insert_transaction(transaction_id_now, selections);
 7045                    }
 7046                }
 7047
 7048                self.update_visible_inline_completion(window, cx);
 7049                if self.active_inline_completion.is_none() {
 7050                    self.refresh_inline_completion(true, true, window, cx);
 7051                }
 7052
 7053                cx.notify();
 7054            }
 7055        }
 7056
 7057        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7058    }
 7059
 7060    pub fn accept_partial_inline_completion(
 7061        &mut self,
 7062        _: &AcceptPartialEditPrediction,
 7063        window: &mut Window,
 7064        cx: &mut Context<Self>,
 7065    ) {
 7066        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7067            return;
 7068        };
 7069        if self.selections.count() != 1 {
 7070            return;
 7071        }
 7072
 7073        self.report_inline_completion_event(
 7074            active_inline_completion.completion_id.clone(),
 7075            true,
 7076            cx,
 7077        );
 7078
 7079        match &active_inline_completion.completion {
 7080            InlineCompletion::Move { target, .. } => {
 7081                let target = *target;
 7082                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7083                    selections.select_anchor_ranges([target..target]);
 7084                });
 7085            }
 7086            InlineCompletion::Edit { edits, .. } => {
 7087                // Find an insertion that starts at the cursor position.
 7088                let snapshot = self.buffer.read(cx).snapshot(cx);
 7089                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7090                let insertion = edits.iter().find_map(|(range, text)| {
 7091                    let range = range.to_offset(&snapshot);
 7092                    if range.is_empty() && range.start == cursor_offset {
 7093                        Some(text)
 7094                    } else {
 7095                        None
 7096                    }
 7097                });
 7098
 7099                if let Some(text) = insertion {
 7100                    let mut partial_completion = text
 7101                        .chars()
 7102                        .by_ref()
 7103                        .take_while(|c| c.is_alphabetic())
 7104                        .collect::<String>();
 7105                    if partial_completion.is_empty() {
 7106                        partial_completion = text
 7107                            .chars()
 7108                            .by_ref()
 7109                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7110                            .collect::<String>();
 7111                    }
 7112
 7113                    cx.emit(EditorEvent::InputHandled {
 7114                        utf16_range_to_replace: None,
 7115                        text: partial_completion.clone().into(),
 7116                    });
 7117
 7118                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7119
 7120                    self.refresh_inline_completion(true, true, window, cx);
 7121                    cx.notify();
 7122                } else {
 7123                    self.accept_edit_prediction(&Default::default(), window, cx);
 7124                }
 7125            }
 7126        }
 7127    }
 7128
 7129    fn discard_inline_completion(
 7130        &mut self,
 7131        should_report_inline_completion_event: bool,
 7132        cx: &mut Context<Self>,
 7133    ) -> bool {
 7134        if should_report_inline_completion_event {
 7135            let completion_id = self
 7136                .active_inline_completion
 7137                .as_ref()
 7138                .and_then(|active_completion| active_completion.completion_id.clone());
 7139
 7140            self.report_inline_completion_event(completion_id, false, cx);
 7141        }
 7142
 7143        if let Some(provider) = self.edit_prediction_provider() {
 7144            provider.discard(cx);
 7145        }
 7146
 7147        self.take_active_inline_completion(cx)
 7148    }
 7149
 7150    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7151        let Some(provider) = self.edit_prediction_provider() else {
 7152            return;
 7153        };
 7154
 7155        let Some((_, buffer, _)) = self
 7156            .buffer
 7157            .read(cx)
 7158            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7159        else {
 7160            return;
 7161        };
 7162
 7163        let extension = buffer
 7164            .read(cx)
 7165            .file()
 7166            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7167
 7168        let event_type = match accepted {
 7169            true => "Edit Prediction Accepted",
 7170            false => "Edit Prediction Discarded",
 7171        };
 7172        telemetry::event!(
 7173            event_type,
 7174            provider = provider.name(),
 7175            prediction_id = id,
 7176            suggestion_accepted = accepted,
 7177            file_extension = extension,
 7178        );
 7179    }
 7180
 7181    pub fn has_active_inline_completion(&self) -> bool {
 7182        self.active_inline_completion.is_some()
 7183    }
 7184
 7185    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7186        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7187            return false;
 7188        };
 7189
 7190        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7191        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7192        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7193        true
 7194    }
 7195
 7196    /// Returns true when we're displaying the edit prediction popover below the cursor
 7197    /// like we are not previewing and the LSP autocomplete menu is visible
 7198    /// or we are in `when_holding_modifier` mode.
 7199    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7200        if self.edit_prediction_preview_is_active()
 7201            || !self.show_edit_predictions_in_menu()
 7202            || !self.edit_predictions_enabled()
 7203        {
 7204            return false;
 7205        }
 7206
 7207        if self.has_visible_completions_menu() {
 7208            return true;
 7209        }
 7210
 7211        has_completion && self.edit_prediction_requires_modifier()
 7212    }
 7213
 7214    fn handle_modifiers_changed(
 7215        &mut self,
 7216        modifiers: Modifiers,
 7217        position_map: &PositionMap,
 7218        window: &mut Window,
 7219        cx: &mut Context<Self>,
 7220    ) {
 7221        if self.show_edit_predictions_in_menu() {
 7222            self.update_edit_prediction_preview(&modifiers, window, cx);
 7223        }
 7224
 7225        self.update_selection_mode(&modifiers, position_map, window, cx);
 7226
 7227        let mouse_position = window.mouse_position();
 7228        if !position_map.text_hitbox.is_hovered(window) {
 7229            return;
 7230        }
 7231
 7232        self.update_hovered_link(
 7233            position_map.point_for_position(mouse_position),
 7234            &position_map.snapshot,
 7235            modifiers,
 7236            window,
 7237            cx,
 7238        )
 7239    }
 7240
 7241    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7242        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7243        if invert {
 7244            match multi_cursor_setting {
 7245                MultiCursorModifier::Alt => modifiers.alt,
 7246                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7247            }
 7248        } else {
 7249            match multi_cursor_setting {
 7250                MultiCursorModifier::Alt => modifiers.secondary(),
 7251                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7252            }
 7253        }
 7254    }
 7255
 7256    fn columnar_selection_mode(
 7257        modifiers: &Modifiers,
 7258        cx: &mut Context<Self>,
 7259    ) -> Option<ColumnarMode> {
 7260        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7261            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7262                Some(ColumnarMode::FromMouse)
 7263            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7264                Some(ColumnarMode::FromSelection)
 7265            } else {
 7266                None
 7267            }
 7268        } else {
 7269            None
 7270        }
 7271    }
 7272
 7273    fn update_selection_mode(
 7274        &mut self,
 7275        modifiers: &Modifiers,
 7276        position_map: &PositionMap,
 7277        window: &mut Window,
 7278        cx: &mut Context<Self>,
 7279    ) {
 7280        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7281            return;
 7282        };
 7283        if self.selections.pending.is_none() {
 7284            return;
 7285        }
 7286
 7287        let mouse_position = window.mouse_position();
 7288        let point_for_position = position_map.point_for_position(mouse_position);
 7289        let position = point_for_position.previous_valid;
 7290
 7291        self.select(
 7292            SelectPhase::BeginColumnar {
 7293                position,
 7294                reset: false,
 7295                mode,
 7296                goal_column: point_for_position.exact_unclipped.column(),
 7297            },
 7298            window,
 7299            cx,
 7300        );
 7301    }
 7302
 7303    fn update_edit_prediction_preview(
 7304        &mut self,
 7305        modifiers: &Modifiers,
 7306        window: &mut Window,
 7307        cx: &mut Context<Self>,
 7308    ) {
 7309        let mut modifiers_held = false;
 7310        if let Some(accept_keystroke) = self
 7311            .accept_edit_prediction_keybind(false, window, cx)
 7312            .keystroke()
 7313        {
 7314            modifiers_held = modifiers_held
 7315                || (&accept_keystroke.modifiers == modifiers
 7316                    && accept_keystroke.modifiers.modified());
 7317        };
 7318        if let Some(accept_partial_keystroke) = self
 7319            .accept_edit_prediction_keybind(true, window, cx)
 7320            .keystroke()
 7321        {
 7322            modifiers_held = modifiers_held
 7323                || (&accept_partial_keystroke.modifiers == modifiers
 7324                    && accept_partial_keystroke.modifiers.modified());
 7325        }
 7326
 7327        if modifiers_held {
 7328            if matches!(
 7329                self.edit_prediction_preview,
 7330                EditPredictionPreview::Inactive { .. }
 7331            ) {
 7332                self.edit_prediction_preview = EditPredictionPreview::Active {
 7333                    previous_scroll_position: None,
 7334                    since: Instant::now(),
 7335                };
 7336
 7337                self.update_visible_inline_completion(window, cx);
 7338                cx.notify();
 7339            }
 7340        } else if let EditPredictionPreview::Active {
 7341            previous_scroll_position,
 7342            since,
 7343        } = self.edit_prediction_preview
 7344        {
 7345            if let (Some(previous_scroll_position), Some(position_map)) =
 7346                (previous_scroll_position, self.last_position_map.as_ref())
 7347            {
 7348                self.set_scroll_position(
 7349                    previous_scroll_position
 7350                        .scroll_position(&position_map.snapshot.display_snapshot),
 7351                    window,
 7352                    cx,
 7353                );
 7354            }
 7355
 7356            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7357                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7358            };
 7359            self.clear_row_highlights::<EditPredictionPreview>();
 7360            self.update_visible_inline_completion(window, cx);
 7361            cx.notify();
 7362        }
 7363    }
 7364
 7365    fn update_visible_inline_completion(
 7366        &mut self,
 7367        _window: &mut Window,
 7368        cx: &mut Context<Self>,
 7369    ) -> Option<()> {
 7370        let selection = self.selections.newest_anchor();
 7371        let cursor = selection.head();
 7372        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7373        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7374        let excerpt_id = cursor.excerpt_id;
 7375
 7376        let show_in_menu = self.show_edit_predictions_in_menu();
 7377        let completions_menu_has_precedence = !show_in_menu
 7378            && (self.context_menu.borrow().is_some()
 7379                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7380
 7381        if completions_menu_has_precedence
 7382            || !offset_selection.is_empty()
 7383            || self
 7384                .active_inline_completion
 7385                .as_ref()
 7386                .map_or(false, |completion| {
 7387                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7388                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7389                    !invalidation_range.contains(&offset_selection.head())
 7390                })
 7391        {
 7392            self.discard_inline_completion(false, cx);
 7393            return None;
 7394        }
 7395
 7396        self.take_active_inline_completion(cx);
 7397        let Some(provider) = self.edit_prediction_provider() else {
 7398            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7399            return None;
 7400        };
 7401
 7402        let (buffer, cursor_buffer_position) =
 7403            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7404
 7405        self.edit_prediction_settings =
 7406            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7407
 7408        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7409
 7410        if self.edit_prediction_indent_conflict {
 7411            let cursor_point = cursor.to_point(&multibuffer);
 7412
 7413            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7414
 7415            if let Some((_, indent)) = indents.iter().next() {
 7416                if indent.len == cursor_point.column {
 7417                    self.edit_prediction_indent_conflict = false;
 7418                }
 7419            }
 7420        }
 7421
 7422        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7423        let edits = inline_completion
 7424            .edits
 7425            .into_iter()
 7426            .flat_map(|(range, new_text)| {
 7427                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7428                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7429                Some((start..end, new_text))
 7430            })
 7431            .collect::<Vec<_>>();
 7432        if edits.is_empty() {
 7433            return None;
 7434        }
 7435
 7436        let first_edit_start = edits.first().unwrap().0.start;
 7437        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7438        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7439
 7440        let last_edit_end = edits.last().unwrap().0.end;
 7441        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7442        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7443
 7444        let cursor_row = cursor.to_point(&multibuffer).row;
 7445
 7446        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7447
 7448        let mut inlay_ids = Vec::new();
 7449        let invalidation_row_range;
 7450        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7451            Some(cursor_row..edit_end_row)
 7452        } else if cursor_row > edit_end_row {
 7453            Some(edit_start_row..cursor_row)
 7454        } else {
 7455            None
 7456        };
 7457        let is_move =
 7458            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7459        let completion = if is_move {
 7460            invalidation_row_range =
 7461                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7462            let target = first_edit_start;
 7463            InlineCompletion::Move { target, snapshot }
 7464        } else {
 7465            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7466                && !self.inline_completions_hidden_for_vim_mode;
 7467
 7468            if show_completions_in_buffer {
 7469                if edits
 7470                    .iter()
 7471                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7472                {
 7473                    let mut inlays = Vec::new();
 7474                    for (range, new_text) in &edits {
 7475                        let inlay = Inlay::inline_completion(
 7476                            post_inc(&mut self.next_inlay_id),
 7477                            range.start,
 7478                            new_text.as_str(),
 7479                        );
 7480                        inlay_ids.push(inlay.id);
 7481                        inlays.push(inlay);
 7482                    }
 7483
 7484                    self.splice_inlays(&[], inlays, cx);
 7485                } else {
 7486                    let background_color = cx.theme().status().deleted_background;
 7487                    let style = HighlightStyle {
 7488                        background_color: Some(background_color),
 7489                        ..Default::default()
 7490                    };
 7491                    self.highlight_text::<InlineCompletionHighlight>(
 7492                        edits
 7493                            .iter()
 7494                            .map(|(range, _)| (range.clone(), style))
 7495                            .collect(),
 7496                        cx,
 7497                    );
 7498                }
 7499            }
 7500
 7501            invalidation_row_range = edit_start_row..edit_end_row;
 7502
 7503            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7504                if provider.show_tab_accept_marker() {
 7505                    EditDisplayMode::TabAccept
 7506                } else {
 7507                    EditDisplayMode::Inline
 7508                }
 7509            } else {
 7510                EditDisplayMode::DiffPopover
 7511            };
 7512
 7513            InlineCompletion::Edit {
 7514                edits,
 7515                edit_preview: inline_completion.edit_preview,
 7516                display_mode,
 7517                snapshot,
 7518            }
 7519        };
 7520
 7521        let invalidation_range = multibuffer
 7522            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7523            ..multibuffer.anchor_after(Point::new(
 7524                invalidation_row_range.end,
 7525                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7526            ));
 7527
 7528        self.stale_inline_completion_in_menu = None;
 7529        self.active_inline_completion = Some(InlineCompletionState {
 7530            inlay_ids,
 7531            completion,
 7532            completion_id: inline_completion.id,
 7533            invalidation_range,
 7534        });
 7535
 7536        cx.notify();
 7537
 7538        Some(())
 7539    }
 7540
 7541    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7542        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7543    }
 7544
 7545    fn clear_tasks(&mut self) {
 7546        self.tasks.clear()
 7547    }
 7548
 7549    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7550        if self.tasks.insert(key, value).is_some() {
 7551            // This case should hopefully be rare, but just in case...
 7552            log::error!(
 7553                "multiple different run targets found on a single line, only the last target will be rendered"
 7554            )
 7555        }
 7556    }
 7557
 7558    /// Get all display points of breakpoints that will be rendered within editor
 7559    ///
 7560    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7561    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7562    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7563    fn active_breakpoints(
 7564        &self,
 7565        range: Range<DisplayRow>,
 7566        window: &mut Window,
 7567        cx: &mut Context<Self>,
 7568    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7569        let mut breakpoint_display_points = HashMap::default();
 7570
 7571        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7572            return breakpoint_display_points;
 7573        };
 7574
 7575        let snapshot = self.snapshot(window, cx);
 7576
 7577        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7578        let Some(project) = self.project.as_ref() else {
 7579            return breakpoint_display_points;
 7580        };
 7581
 7582        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7583            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7584
 7585        for (buffer_snapshot, range, excerpt_id) in
 7586            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7587        {
 7588            let Some(buffer) = project
 7589                .read(cx)
 7590                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7591            else {
 7592                continue;
 7593            };
 7594            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7595                &buffer,
 7596                Some(
 7597                    buffer_snapshot.anchor_before(range.start)
 7598                        ..buffer_snapshot.anchor_after(range.end),
 7599                ),
 7600                buffer_snapshot,
 7601                cx,
 7602            );
 7603            for (breakpoint, state) in breakpoints {
 7604                let multi_buffer_anchor =
 7605                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7606                let position = multi_buffer_anchor
 7607                    .to_point(&multi_buffer_snapshot)
 7608                    .to_display_point(&snapshot);
 7609
 7610                breakpoint_display_points.insert(
 7611                    position.row(),
 7612                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7613                );
 7614            }
 7615        }
 7616
 7617        breakpoint_display_points
 7618    }
 7619
 7620    fn breakpoint_context_menu(
 7621        &self,
 7622        anchor: Anchor,
 7623        window: &mut Window,
 7624        cx: &mut Context<Self>,
 7625    ) -> Entity<ui::ContextMenu> {
 7626        let weak_editor = cx.weak_entity();
 7627        let focus_handle = self.focus_handle(cx);
 7628
 7629        let row = self
 7630            .buffer
 7631            .read(cx)
 7632            .snapshot(cx)
 7633            .summary_for_anchor::<Point>(&anchor)
 7634            .row;
 7635
 7636        let breakpoint = self
 7637            .breakpoint_at_row(row, window, cx)
 7638            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7639
 7640        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7641            "Edit Log Breakpoint"
 7642        } else {
 7643            "Set Log Breakpoint"
 7644        };
 7645
 7646        let condition_breakpoint_msg = if breakpoint
 7647            .as_ref()
 7648            .is_some_and(|bp| bp.1.condition.is_some())
 7649        {
 7650            "Edit Condition Breakpoint"
 7651        } else {
 7652            "Set Condition Breakpoint"
 7653        };
 7654
 7655        let hit_condition_breakpoint_msg = if breakpoint
 7656            .as_ref()
 7657            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7658        {
 7659            "Edit Hit Condition Breakpoint"
 7660        } else {
 7661            "Set Hit Condition Breakpoint"
 7662        };
 7663
 7664        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7665            "Unset Breakpoint"
 7666        } else {
 7667            "Set Breakpoint"
 7668        };
 7669
 7670        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7671
 7672        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7673            BreakpointState::Enabled => Some("Disable"),
 7674            BreakpointState::Disabled => Some("Enable"),
 7675        });
 7676
 7677        let (anchor, breakpoint) =
 7678            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7679
 7680        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7681            menu.on_blur_subscription(Subscription::new(|| {}))
 7682                .context(focus_handle)
 7683                .when(run_to_cursor, |this| {
 7684                    let weak_editor = weak_editor.clone();
 7685                    this.entry("Run to cursor", None, move |window, cx| {
 7686                        weak_editor
 7687                            .update(cx, |editor, cx| {
 7688                                editor.change_selections(None, window, cx, |s| {
 7689                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7690                                });
 7691                            })
 7692                            .ok();
 7693
 7694                        window.dispatch_action(Box::new(RunToCursor), cx);
 7695                    })
 7696                    .separator()
 7697                })
 7698                .when_some(toggle_state_msg, |this, msg| {
 7699                    this.entry(msg, None, {
 7700                        let weak_editor = weak_editor.clone();
 7701                        let breakpoint = breakpoint.clone();
 7702                        move |_window, cx| {
 7703                            weak_editor
 7704                                .update(cx, |this, cx| {
 7705                                    this.edit_breakpoint_at_anchor(
 7706                                        anchor,
 7707                                        breakpoint.as_ref().clone(),
 7708                                        BreakpointEditAction::InvertState,
 7709                                        cx,
 7710                                    );
 7711                                })
 7712                                .log_err();
 7713                        }
 7714                    })
 7715                })
 7716                .entry(set_breakpoint_msg, None, {
 7717                    let weak_editor = weak_editor.clone();
 7718                    let breakpoint = breakpoint.clone();
 7719                    move |_window, cx| {
 7720                        weak_editor
 7721                            .update(cx, |this, cx| {
 7722                                this.edit_breakpoint_at_anchor(
 7723                                    anchor,
 7724                                    breakpoint.as_ref().clone(),
 7725                                    BreakpointEditAction::Toggle,
 7726                                    cx,
 7727                                );
 7728                            })
 7729                            .log_err();
 7730                    }
 7731                })
 7732                .entry(log_breakpoint_msg, None, {
 7733                    let breakpoint = breakpoint.clone();
 7734                    let weak_editor = weak_editor.clone();
 7735                    move |window, cx| {
 7736                        weak_editor
 7737                            .update(cx, |this, cx| {
 7738                                this.add_edit_breakpoint_block(
 7739                                    anchor,
 7740                                    breakpoint.as_ref(),
 7741                                    BreakpointPromptEditAction::Log,
 7742                                    window,
 7743                                    cx,
 7744                                );
 7745                            })
 7746                            .log_err();
 7747                    }
 7748                })
 7749                .entry(condition_breakpoint_msg, None, {
 7750                    let breakpoint = breakpoint.clone();
 7751                    let weak_editor = weak_editor.clone();
 7752                    move |window, cx| {
 7753                        weak_editor
 7754                            .update(cx, |this, cx| {
 7755                                this.add_edit_breakpoint_block(
 7756                                    anchor,
 7757                                    breakpoint.as_ref(),
 7758                                    BreakpointPromptEditAction::Condition,
 7759                                    window,
 7760                                    cx,
 7761                                );
 7762                            })
 7763                            .log_err();
 7764                    }
 7765                })
 7766                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7767                    weak_editor
 7768                        .update(cx, |this, cx| {
 7769                            this.add_edit_breakpoint_block(
 7770                                anchor,
 7771                                breakpoint.as_ref(),
 7772                                BreakpointPromptEditAction::HitCondition,
 7773                                window,
 7774                                cx,
 7775                            );
 7776                        })
 7777                        .log_err();
 7778                })
 7779        })
 7780    }
 7781
 7782    fn render_breakpoint(
 7783        &self,
 7784        position: Anchor,
 7785        row: DisplayRow,
 7786        breakpoint: &Breakpoint,
 7787        state: Option<BreakpointSessionState>,
 7788        cx: &mut Context<Self>,
 7789    ) -> IconButton {
 7790        let is_rejected = state.is_some_and(|s| !s.verified);
 7791        // Is it a breakpoint that shows up when hovering over gutter?
 7792        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7793            (false, false),
 7794            |PhantomBreakpointIndicator {
 7795                 is_active,
 7796                 display_row,
 7797                 collides_with_existing_breakpoint,
 7798             }| {
 7799                (
 7800                    is_active && display_row == row,
 7801                    collides_with_existing_breakpoint,
 7802                )
 7803            },
 7804        );
 7805
 7806        let (color, icon) = {
 7807            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7808                (false, false) => ui::IconName::DebugBreakpoint,
 7809                (true, false) => ui::IconName::DebugLogBreakpoint,
 7810                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7811                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7812            };
 7813
 7814            let color = if is_phantom {
 7815                Color::Hint
 7816            } else if is_rejected {
 7817                Color::Disabled
 7818            } else {
 7819                Color::Debugger
 7820            };
 7821
 7822            (color, icon)
 7823        };
 7824
 7825        let breakpoint = Arc::from(breakpoint.clone());
 7826
 7827        let alt_as_text = gpui::Keystroke {
 7828            modifiers: Modifiers::secondary_key(),
 7829            ..Default::default()
 7830        };
 7831        let primary_action_text = if breakpoint.is_disabled() {
 7832            "Enable breakpoint"
 7833        } else if is_phantom && !collides_with_existing {
 7834            "Set breakpoint"
 7835        } else {
 7836            "Unset breakpoint"
 7837        };
 7838        let focus_handle = self.focus_handle.clone();
 7839
 7840        let meta = if is_rejected {
 7841            SharedString::from("No executable code is associated with this line.")
 7842        } else if collides_with_existing && !breakpoint.is_disabled() {
 7843            SharedString::from(format!(
 7844                "{alt_as_text}-click to disable,\nright-click for more options."
 7845            ))
 7846        } else {
 7847            SharedString::from("Right-click for more options.")
 7848        };
 7849        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7850            .icon_size(IconSize::XSmall)
 7851            .size(ui::ButtonSize::None)
 7852            .when(is_rejected, |this| {
 7853                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7854            })
 7855            .icon_color(color)
 7856            .style(ButtonStyle::Transparent)
 7857            .on_click(cx.listener({
 7858                let breakpoint = breakpoint.clone();
 7859
 7860                move |editor, event: &ClickEvent, window, cx| {
 7861                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7862                        BreakpointEditAction::InvertState
 7863                    } else {
 7864                        BreakpointEditAction::Toggle
 7865                    };
 7866
 7867                    window.focus(&editor.focus_handle(cx));
 7868                    editor.edit_breakpoint_at_anchor(
 7869                        position,
 7870                        breakpoint.as_ref().clone(),
 7871                        edit_action,
 7872                        cx,
 7873                    );
 7874                }
 7875            }))
 7876            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7877                editor.set_breakpoint_context_menu(
 7878                    row,
 7879                    Some(position),
 7880                    event.down.position,
 7881                    window,
 7882                    cx,
 7883                );
 7884            }))
 7885            .tooltip(move |window, cx| {
 7886                Tooltip::with_meta_in(
 7887                    primary_action_text,
 7888                    Some(&ToggleBreakpoint),
 7889                    meta.clone(),
 7890                    &focus_handle,
 7891                    window,
 7892                    cx,
 7893                )
 7894            })
 7895    }
 7896
 7897    fn build_tasks_context(
 7898        project: &Entity<Project>,
 7899        buffer: &Entity<Buffer>,
 7900        buffer_row: u32,
 7901        tasks: &Arc<RunnableTasks>,
 7902        cx: &mut Context<Self>,
 7903    ) -> Task<Option<task::TaskContext>> {
 7904        let position = Point::new(buffer_row, tasks.column);
 7905        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7906        let location = Location {
 7907            buffer: buffer.clone(),
 7908            range: range_start..range_start,
 7909        };
 7910        // Fill in the environmental variables from the tree-sitter captures
 7911        let mut captured_task_variables = TaskVariables::default();
 7912        for (capture_name, value) in tasks.extra_variables.clone() {
 7913            captured_task_variables.insert(
 7914                task::VariableName::Custom(capture_name.into()),
 7915                value.clone(),
 7916            );
 7917        }
 7918        project.update(cx, |project, cx| {
 7919            project.task_store().update(cx, |task_store, cx| {
 7920                task_store.task_context_for_location(captured_task_variables, location, cx)
 7921            })
 7922        })
 7923    }
 7924
 7925    pub fn spawn_nearest_task(
 7926        &mut self,
 7927        action: &SpawnNearestTask,
 7928        window: &mut Window,
 7929        cx: &mut Context<Self>,
 7930    ) {
 7931        let Some((workspace, _)) = self.workspace.clone() else {
 7932            return;
 7933        };
 7934        let Some(project) = self.project.clone() else {
 7935            return;
 7936        };
 7937
 7938        // Try to find a closest, enclosing node using tree-sitter that has a
 7939        // task
 7940        let Some((buffer, buffer_row, tasks)) = self
 7941            .find_enclosing_node_task(cx)
 7942            // Or find the task that's closest in row-distance.
 7943            .or_else(|| self.find_closest_task(cx))
 7944        else {
 7945            return;
 7946        };
 7947
 7948        let reveal_strategy = action.reveal;
 7949        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7950        cx.spawn_in(window, async move |_, cx| {
 7951            let context = task_context.await?;
 7952            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7953
 7954            let resolved = &mut resolved_task.resolved;
 7955            resolved.reveal = reveal_strategy;
 7956
 7957            workspace
 7958                .update_in(cx, |workspace, window, cx| {
 7959                    workspace.schedule_resolved_task(
 7960                        task_source_kind,
 7961                        resolved_task,
 7962                        false,
 7963                        window,
 7964                        cx,
 7965                    );
 7966                })
 7967                .ok()
 7968        })
 7969        .detach();
 7970    }
 7971
 7972    fn find_closest_task(
 7973        &mut self,
 7974        cx: &mut Context<Self>,
 7975    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7976        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7977
 7978        let ((buffer_id, row), tasks) = self
 7979            .tasks
 7980            .iter()
 7981            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7982
 7983        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7984        let tasks = Arc::new(tasks.to_owned());
 7985        Some((buffer, *row, tasks))
 7986    }
 7987
 7988    fn find_enclosing_node_task(
 7989        &mut self,
 7990        cx: &mut Context<Self>,
 7991    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7992        let snapshot = self.buffer.read(cx).snapshot(cx);
 7993        let offset = self.selections.newest::<usize>(cx).head();
 7994        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7995        let buffer_id = excerpt.buffer().remote_id();
 7996
 7997        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7998        let mut cursor = layer.node().walk();
 7999
 8000        while cursor.goto_first_child_for_byte(offset).is_some() {
 8001            if cursor.node().end_byte() == offset {
 8002                cursor.goto_next_sibling();
 8003            }
 8004        }
 8005
 8006        // Ascend to the smallest ancestor that contains the range and has a task.
 8007        loop {
 8008            let node = cursor.node();
 8009            let node_range = node.byte_range();
 8010            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8011
 8012            // Check if this node contains our offset
 8013            if node_range.start <= offset && node_range.end >= offset {
 8014                // If it contains offset, check for task
 8015                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8016                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8017                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8018                }
 8019            }
 8020
 8021            if !cursor.goto_parent() {
 8022                break;
 8023            }
 8024        }
 8025        None
 8026    }
 8027
 8028    fn render_run_indicator(
 8029        &self,
 8030        _style: &EditorStyle,
 8031        is_active: bool,
 8032        row: DisplayRow,
 8033        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8034        cx: &mut Context<Self>,
 8035    ) -> IconButton {
 8036        let color = Color::Muted;
 8037        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8038
 8039        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8040            .shape(ui::IconButtonShape::Square)
 8041            .icon_size(IconSize::XSmall)
 8042            .icon_color(color)
 8043            .toggle_state(is_active)
 8044            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8045                let quick_launch = e.down.button == MouseButton::Left;
 8046                window.focus(&editor.focus_handle(cx));
 8047                editor.toggle_code_actions(
 8048                    &ToggleCodeActions {
 8049                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8050                        quick_launch,
 8051                    },
 8052                    window,
 8053                    cx,
 8054                );
 8055            }))
 8056            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8057                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8058            }))
 8059    }
 8060
 8061    pub fn context_menu_visible(&self) -> bool {
 8062        !self.edit_prediction_preview_is_active()
 8063            && self
 8064                .context_menu
 8065                .borrow()
 8066                .as_ref()
 8067                .map_or(false, |menu| menu.visible())
 8068    }
 8069
 8070    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8071        self.context_menu
 8072            .borrow()
 8073            .as_ref()
 8074            .map(|menu| menu.origin())
 8075    }
 8076
 8077    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8078        self.context_menu_options = Some(options);
 8079    }
 8080
 8081    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8082    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8083
 8084    fn render_edit_prediction_popover(
 8085        &mut self,
 8086        text_bounds: &Bounds<Pixels>,
 8087        content_origin: gpui::Point<Pixels>,
 8088        right_margin: Pixels,
 8089        editor_snapshot: &EditorSnapshot,
 8090        visible_row_range: Range<DisplayRow>,
 8091        scroll_top: f32,
 8092        scroll_bottom: f32,
 8093        line_layouts: &[LineWithInvisibles],
 8094        line_height: Pixels,
 8095        scroll_pixel_position: gpui::Point<Pixels>,
 8096        newest_selection_head: Option<DisplayPoint>,
 8097        editor_width: Pixels,
 8098        style: &EditorStyle,
 8099        window: &mut Window,
 8100        cx: &mut App,
 8101    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8102        if self.mode().is_minimap() {
 8103            return None;
 8104        }
 8105        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8106
 8107        if self.edit_prediction_visible_in_cursor_popover(true) {
 8108            return None;
 8109        }
 8110
 8111        match &active_inline_completion.completion {
 8112            InlineCompletion::Move { target, .. } => {
 8113                let target_display_point = target.to_display_point(editor_snapshot);
 8114
 8115                if self.edit_prediction_requires_modifier() {
 8116                    if !self.edit_prediction_preview_is_active() {
 8117                        return None;
 8118                    }
 8119
 8120                    self.render_edit_prediction_modifier_jump_popover(
 8121                        text_bounds,
 8122                        content_origin,
 8123                        visible_row_range,
 8124                        line_layouts,
 8125                        line_height,
 8126                        scroll_pixel_position,
 8127                        newest_selection_head,
 8128                        target_display_point,
 8129                        window,
 8130                        cx,
 8131                    )
 8132                } else {
 8133                    self.render_edit_prediction_eager_jump_popover(
 8134                        text_bounds,
 8135                        content_origin,
 8136                        editor_snapshot,
 8137                        visible_row_range,
 8138                        scroll_top,
 8139                        scroll_bottom,
 8140                        line_height,
 8141                        scroll_pixel_position,
 8142                        target_display_point,
 8143                        editor_width,
 8144                        window,
 8145                        cx,
 8146                    )
 8147                }
 8148            }
 8149            InlineCompletion::Edit {
 8150                display_mode: EditDisplayMode::Inline,
 8151                ..
 8152            } => None,
 8153            InlineCompletion::Edit {
 8154                display_mode: EditDisplayMode::TabAccept,
 8155                edits,
 8156                ..
 8157            } => {
 8158                let range = &edits.first()?.0;
 8159                let target_display_point = range.end.to_display_point(editor_snapshot);
 8160
 8161                self.render_edit_prediction_end_of_line_popover(
 8162                    "Accept",
 8163                    editor_snapshot,
 8164                    visible_row_range,
 8165                    target_display_point,
 8166                    line_height,
 8167                    scroll_pixel_position,
 8168                    content_origin,
 8169                    editor_width,
 8170                    window,
 8171                    cx,
 8172                )
 8173            }
 8174            InlineCompletion::Edit {
 8175                edits,
 8176                edit_preview,
 8177                display_mode: EditDisplayMode::DiffPopover,
 8178                snapshot,
 8179            } => self.render_edit_prediction_diff_popover(
 8180                text_bounds,
 8181                content_origin,
 8182                right_margin,
 8183                editor_snapshot,
 8184                visible_row_range,
 8185                line_layouts,
 8186                line_height,
 8187                scroll_pixel_position,
 8188                newest_selection_head,
 8189                editor_width,
 8190                style,
 8191                edits,
 8192                edit_preview,
 8193                snapshot,
 8194                window,
 8195                cx,
 8196            ),
 8197        }
 8198    }
 8199
 8200    fn render_edit_prediction_modifier_jump_popover(
 8201        &mut self,
 8202        text_bounds: &Bounds<Pixels>,
 8203        content_origin: gpui::Point<Pixels>,
 8204        visible_row_range: Range<DisplayRow>,
 8205        line_layouts: &[LineWithInvisibles],
 8206        line_height: Pixels,
 8207        scroll_pixel_position: gpui::Point<Pixels>,
 8208        newest_selection_head: Option<DisplayPoint>,
 8209        target_display_point: DisplayPoint,
 8210        window: &mut Window,
 8211        cx: &mut App,
 8212    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8213        let scrolled_content_origin =
 8214            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8215
 8216        const SCROLL_PADDING_Y: Pixels = px(12.);
 8217
 8218        if target_display_point.row() < visible_row_range.start {
 8219            return self.render_edit_prediction_scroll_popover(
 8220                |_| SCROLL_PADDING_Y,
 8221                IconName::ArrowUp,
 8222                visible_row_range,
 8223                line_layouts,
 8224                newest_selection_head,
 8225                scrolled_content_origin,
 8226                window,
 8227                cx,
 8228            );
 8229        } else if target_display_point.row() >= visible_row_range.end {
 8230            return self.render_edit_prediction_scroll_popover(
 8231                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8232                IconName::ArrowDown,
 8233                visible_row_range,
 8234                line_layouts,
 8235                newest_selection_head,
 8236                scrolled_content_origin,
 8237                window,
 8238                cx,
 8239            );
 8240        }
 8241
 8242        const POLE_WIDTH: Pixels = px(2.);
 8243
 8244        let line_layout =
 8245            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8246        let target_column = target_display_point.column() as usize;
 8247
 8248        let target_x = line_layout.x_for_index(target_column);
 8249        let target_y =
 8250            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8251
 8252        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8253
 8254        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8255        border_color.l += 0.001;
 8256
 8257        let mut element = v_flex()
 8258            .items_end()
 8259            .when(flag_on_right, |el| el.items_start())
 8260            .child(if flag_on_right {
 8261                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8262                    .rounded_bl(px(0.))
 8263                    .rounded_tl(px(0.))
 8264                    .border_l_2()
 8265                    .border_color(border_color)
 8266            } else {
 8267                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8268                    .rounded_br(px(0.))
 8269                    .rounded_tr(px(0.))
 8270                    .border_r_2()
 8271                    .border_color(border_color)
 8272            })
 8273            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8274            .into_any();
 8275
 8276        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8277
 8278        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8279            - point(
 8280                if flag_on_right {
 8281                    POLE_WIDTH
 8282                } else {
 8283                    size.width - POLE_WIDTH
 8284                },
 8285                size.height - line_height,
 8286            );
 8287
 8288        origin.x = origin.x.max(content_origin.x);
 8289
 8290        element.prepaint_at(origin, window, cx);
 8291
 8292        Some((element, origin))
 8293    }
 8294
 8295    fn render_edit_prediction_scroll_popover(
 8296        &mut self,
 8297        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8298        scroll_icon: IconName,
 8299        visible_row_range: Range<DisplayRow>,
 8300        line_layouts: &[LineWithInvisibles],
 8301        newest_selection_head: Option<DisplayPoint>,
 8302        scrolled_content_origin: gpui::Point<Pixels>,
 8303        window: &mut Window,
 8304        cx: &mut App,
 8305    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8306        let mut element = self
 8307            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8308            .into_any();
 8309
 8310        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8311
 8312        let cursor = newest_selection_head?;
 8313        let cursor_row_layout =
 8314            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8315        let cursor_column = cursor.column() as usize;
 8316
 8317        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8318
 8319        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8320
 8321        element.prepaint_at(origin, window, cx);
 8322        Some((element, origin))
 8323    }
 8324
 8325    fn render_edit_prediction_eager_jump_popover(
 8326        &mut self,
 8327        text_bounds: &Bounds<Pixels>,
 8328        content_origin: gpui::Point<Pixels>,
 8329        editor_snapshot: &EditorSnapshot,
 8330        visible_row_range: Range<DisplayRow>,
 8331        scroll_top: f32,
 8332        scroll_bottom: f32,
 8333        line_height: Pixels,
 8334        scroll_pixel_position: gpui::Point<Pixels>,
 8335        target_display_point: DisplayPoint,
 8336        editor_width: Pixels,
 8337        window: &mut Window,
 8338        cx: &mut App,
 8339    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8340        if target_display_point.row().as_f32() < scroll_top {
 8341            let mut element = self
 8342                .render_edit_prediction_line_popover(
 8343                    "Jump to Edit",
 8344                    Some(IconName::ArrowUp),
 8345                    window,
 8346                    cx,
 8347                )?
 8348                .into_any();
 8349
 8350            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8351            let offset = point(
 8352                (text_bounds.size.width - size.width) / 2.,
 8353                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8354            );
 8355
 8356            let origin = text_bounds.origin + offset;
 8357            element.prepaint_at(origin, window, cx);
 8358            Some((element, origin))
 8359        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8360            let mut element = self
 8361                .render_edit_prediction_line_popover(
 8362                    "Jump to Edit",
 8363                    Some(IconName::ArrowDown),
 8364                    window,
 8365                    cx,
 8366                )?
 8367                .into_any();
 8368
 8369            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8370            let offset = point(
 8371                (text_bounds.size.width - size.width) / 2.,
 8372                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8373            );
 8374
 8375            let origin = text_bounds.origin + offset;
 8376            element.prepaint_at(origin, window, cx);
 8377            Some((element, origin))
 8378        } else {
 8379            self.render_edit_prediction_end_of_line_popover(
 8380                "Jump to Edit",
 8381                editor_snapshot,
 8382                visible_row_range,
 8383                target_display_point,
 8384                line_height,
 8385                scroll_pixel_position,
 8386                content_origin,
 8387                editor_width,
 8388                window,
 8389                cx,
 8390            )
 8391        }
 8392    }
 8393
 8394    fn render_edit_prediction_end_of_line_popover(
 8395        self: &mut Editor,
 8396        label: &'static str,
 8397        editor_snapshot: &EditorSnapshot,
 8398        visible_row_range: Range<DisplayRow>,
 8399        target_display_point: DisplayPoint,
 8400        line_height: Pixels,
 8401        scroll_pixel_position: gpui::Point<Pixels>,
 8402        content_origin: gpui::Point<Pixels>,
 8403        editor_width: Pixels,
 8404        window: &mut Window,
 8405        cx: &mut App,
 8406    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8407        let target_line_end = DisplayPoint::new(
 8408            target_display_point.row(),
 8409            editor_snapshot.line_len(target_display_point.row()),
 8410        );
 8411
 8412        let mut element = self
 8413            .render_edit_prediction_line_popover(label, None, window, cx)?
 8414            .into_any();
 8415
 8416        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8417
 8418        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8419
 8420        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8421        let mut origin = start_point
 8422            + line_origin
 8423            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8424        origin.x = origin.x.max(content_origin.x);
 8425
 8426        let max_x = content_origin.x + editor_width - size.width;
 8427
 8428        if origin.x > max_x {
 8429            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8430
 8431            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8432                origin.y += offset;
 8433                IconName::ArrowUp
 8434            } else {
 8435                origin.y -= offset;
 8436                IconName::ArrowDown
 8437            };
 8438
 8439            element = self
 8440                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8441                .into_any();
 8442
 8443            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8444
 8445            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8446        }
 8447
 8448        element.prepaint_at(origin, window, cx);
 8449        Some((element, origin))
 8450    }
 8451
 8452    fn render_edit_prediction_diff_popover(
 8453        self: &Editor,
 8454        text_bounds: &Bounds<Pixels>,
 8455        content_origin: gpui::Point<Pixels>,
 8456        right_margin: Pixels,
 8457        editor_snapshot: &EditorSnapshot,
 8458        visible_row_range: Range<DisplayRow>,
 8459        line_layouts: &[LineWithInvisibles],
 8460        line_height: Pixels,
 8461        scroll_pixel_position: gpui::Point<Pixels>,
 8462        newest_selection_head: Option<DisplayPoint>,
 8463        editor_width: Pixels,
 8464        style: &EditorStyle,
 8465        edits: &Vec<(Range<Anchor>, String)>,
 8466        edit_preview: &Option<language::EditPreview>,
 8467        snapshot: &language::BufferSnapshot,
 8468        window: &mut Window,
 8469        cx: &mut App,
 8470    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8471        let edit_start = edits
 8472            .first()
 8473            .unwrap()
 8474            .0
 8475            .start
 8476            .to_display_point(editor_snapshot);
 8477        let edit_end = edits
 8478            .last()
 8479            .unwrap()
 8480            .0
 8481            .end
 8482            .to_display_point(editor_snapshot);
 8483
 8484        let is_visible = visible_row_range.contains(&edit_start.row())
 8485            || visible_row_range.contains(&edit_end.row());
 8486        if !is_visible {
 8487            return None;
 8488        }
 8489
 8490        let highlighted_edits =
 8491            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8492
 8493        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8494        let line_count = highlighted_edits.text.lines().count();
 8495
 8496        const BORDER_WIDTH: Pixels = px(1.);
 8497
 8498        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8499        let has_keybind = keybind.is_some();
 8500
 8501        let mut element = h_flex()
 8502            .items_start()
 8503            .child(
 8504                h_flex()
 8505                    .bg(cx.theme().colors().editor_background)
 8506                    .border(BORDER_WIDTH)
 8507                    .shadow_sm()
 8508                    .border_color(cx.theme().colors().border)
 8509                    .rounded_l_lg()
 8510                    .when(line_count > 1, |el| el.rounded_br_lg())
 8511                    .pr_1()
 8512                    .child(styled_text),
 8513            )
 8514            .child(
 8515                h_flex()
 8516                    .h(line_height + BORDER_WIDTH * 2.)
 8517                    .px_1p5()
 8518                    .gap_1()
 8519                    // Workaround: For some reason, there's a gap if we don't do this
 8520                    .ml(-BORDER_WIDTH)
 8521                    .shadow(vec![gpui::BoxShadow {
 8522                        color: gpui::black().opacity(0.05),
 8523                        offset: point(px(1.), px(1.)),
 8524                        blur_radius: px(2.),
 8525                        spread_radius: px(0.),
 8526                    }])
 8527                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8528                    .border(BORDER_WIDTH)
 8529                    .border_color(cx.theme().colors().border)
 8530                    .rounded_r_lg()
 8531                    .id("edit_prediction_diff_popover_keybind")
 8532                    .when(!has_keybind, |el| {
 8533                        let status_colors = cx.theme().status();
 8534
 8535                        el.bg(status_colors.error_background)
 8536                            .border_color(status_colors.error.opacity(0.6))
 8537                            .child(Icon::new(IconName::Info).color(Color::Error))
 8538                            .cursor_default()
 8539                            .hoverable_tooltip(move |_window, cx| {
 8540                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8541                            })
 8542                    })
 8543                    .children(keybind),
 8544            )
 8545            .into_any();
 8546
 8547        let longest_row =
 8548            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8549        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8550            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8551        } else {
 8552            layout_line(
 8553                longest_row,
 8554                editor_snapshot,
 8555                style,
 8556                editor_width,
 8557                |_| false,
 8558                window,
 8559                cx,
 8560            )
 8561            .width
 8562        };
 8563
 8564        let viewport_bounds =
 8565            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8566                right: -right_margin,
 8567                ..Default::default()
 8568            });
 8569
 8570        let x_after_longest =
 8571            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8572                - scroll_pixel_position.x;
 8573
 8574        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8575
 8576        // Fully visible if it can be displayed within the window (allow overlapping other
 8577        // panes). However, this is only allowed if the popover starts within text_bounds.
 8578        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8579            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8580
 8581        let mut origin = if can_position_to_the_right {
 8582            point(
 8583                x_after_longest,
 8584                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8585                    - scroll_pixel_position.y,
 8586            )
 8587        } else {
 8588            let cursor_row = newest_selection_head.map(|head| head.row());
 8589            let above_edit = edit_start
 8590                .row()
 8591                .0
 8592                .checked_sub(line_count as u32)
 8593                .map(DisplayRow);
 8594            let below_edit = Some(edit_end.row() + 1);
 8595            let above_cursor =
 8596                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8597            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8598
 8599            // Place the edit popover adjacent to the edit if there is a location
 8600            // available that is onscreen and does not obscure the cursor. Otherwise,
 8601            // place it adjacent to the cursor.
 8602            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8603                .into_iter()
 8604                .flatten()
 8605                .find(|&start_row| {
 8606                    let end_row = start_row + line_count as u32;
 8607                    visible_row_range.contains(&start_row)
 8608                        && visible_row_range.contains(&end_row)
 8609                        && cursor_row.map_or(true, |cursor_row| {
 8610                            !((start_row..end_row).contains(&cursor_row))
 8611                        })
 8612                })?;
 8613
 8614            content_origin
 8615                + point(
 8616                    -scroll_pixel_position.x,
 8617                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8618                )
 8619        };
 8620
 8621        origin.x -= BORDER_WIDTH;
 8622
 8623        window.defer_draw(element, origin, 1);
 8624
 8625        // Do not return an element, since it will already be drawn due to defer_draw.
 8626        None
 8627    }
 8628
 8629    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8630        px(30.)
 8631    }
 8632
 8633    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8634        if self.read_only(cx) {
 8635            cx.theme().players().read_only()
 8636        } else {
 8637            self.style.as_ref().unwrap().local_player
 8638        }
 8639    }
 8640
 8641    fn render_edit_prediction_accept_keybind(
 8642        &self,
 8643        window: &mut Window,
 8644        cx: &App,
 8645    ) -> Option<AnyElement> {
 8646        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8647        let accept_keystroke = accept_binding.keystroke()?;
 8648
 8649        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8650
 8651        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8652            Color::Accent
 8653        } else {
 8654            Color::Muted
 8655        };
 8656
 8657        h_flex()
 8658            .px_0p5()
 8659            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8660            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8661            .text_size(TextSize::XSmall.rems(cx))
 8662            .child(h_flex().children(ui::render_modifiers(
 8663                &accept_keystroke.modifiers,
 8664                PlatformStyle::platform(),
 8665                Some(modifiers_color),
 8666                Some(IconSize::XSmall.rems().into()),
 8667                true,
 8668            )))
 8669            .when(is_platform_style_mac, |parent| {
 8670                parent.child(accept_keystroke.key.clone())
 8671            })
 8672            .when(!is_platform_style_mac, |parent| {
 8673                parent.child(
 8674                    Key::new(
 8675                        util::capitalize(&accept_keystroke.key),
 8676                        Some(Color::Default),
 8677                    )
 8678                    .size(Some(IconSize::XSmall.rems().into())),
 8679                )
 8680            })
 8681            .into_any()
 8682            .into()
 8683    }
 8684
 8685    fn render_edit_prediction_line_popover(
 8686        &self,
 8687        label: impl Into<SharedString>,
 8688        icon: Option<IconName>,
 8689        window: &mut Window,
 8690        cx: &App,
 8691    ) -> Option<Stateful<Div>> {
 8692        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8693
 8694        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8695        let has_keybind = keybind.is_some();
 8696
 8697        let result = h_flex()
 8698            .id("ep-line-popover")
 8699            .py_0p5()
 8700            .pl_1()
 8701            .pr(padding_right)
 8702            .gap_1()
 8703            .rounded_md()
 8704            .border_1()
 8705            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8706            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8707            .shadow_sm()
 8708            .when(!has_keybind, |el| {
 8709                let status_colors = cx.theme().status();
 8710
 8711                el.bg(status_colors.error_background)
 8712                    .border_color(status_colors.error.opacity(0.6))
 8713                    .pl_2()
 8714                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8715                    .cursor_default()
 8716                    .hoverable_tooltip(move |_window, cx| {
 8717                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8718                    })
 8719            })
 8720            .children(keybind)
 8721            .child(
 8722                Label::new(label)
 8723                    .size(LabelSize::Small)
 8724                    .when(!has_keybind, |el| {
 8725                        el.color(cx.theme().status().error.into()).strikethrough()
 8726                    }),
 8727            )
 8728            .when(!has_keybind, |el| {
 8729                el.child(
 8730                    h_flex().ml_1().child(
 8731                        Icon::new(IconName::Info)
 8732                            .size(IconSize::Small)
 8733                            .color(cx.theme().status().error.into()),
 8734                    ),
 8735                )
 8736            })
 8737            .when_some(icon, |element, icon| {
 8738                element.child(
 8739                    div()
 8740                        .mt(px(1.5))
 8741                        .child(Icon::new(icon).size(IconSize::Small)),
 8742                )
 8743            });
 8744
 8745        Some(result)
 8746    }
 8747
 8748    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8749        let accent_color = cx.theme().colors().text_accent;
 8750        let editor_bg_color = cx.theme().colors().editor_background;
 8751        editor_bg_color.blend(accent_color.opacity(0.1))
 8752    }
 8753
 8754    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8755        let accent_color = cx.theme().colors().text_accent;
 8756        let editor_bg_color = cx.theme().colors().editor_background;
 8757        editor_bg_color.blend(accent_color.opacity(0.6))
 8758    }
 8759
 8760    fn render_edit_prediction_cursor_popover(
 8761        &self,
 8762        min_width: Pixels,
 8763        max_width: Pixels,
 8764        cursor_point: Point,
 8765        style: &EditorStyle,
 8766        accept_keystroke: Option<&gpui::Keystroke>,
 8767        _window: &Window,
 8768        cx: &mut Context<Editor>,
 8769    ) -> Option<AnyElement> {
 8770        let provider = self.edit_prediction_provider.as_ref()?;
 8771
 8772        if provider.provider.needs_terms_acceptance(cx) {
 8773            return Some(
 8774                h_flex()
 8775                    .min_w(min_width)
 8776                    .flex_1()
 8777                    .px_2()
 8778                    .py_1()
 8779                    .gap_3()
 8780                    .elevation_2(cx)
 8781                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8782                    .id("accept-terms")
 8783                    .cursor_pointer()
 8784                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8785                    .on_click(cx.listener(|this, _event, window, cx| {
 8786                        cx.stop_propagation();
 8787                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8788                        window.dispatch_action(
 8789                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8790                            cx,
 8791                        );
 8792                    }))
 8793                    .child(
 8794                        h_flex()
 8795                            .flex_1()
 8796                            .gap_2()
 8797                            .child(Icon::new(IconName::ZedPredict))
 8798                            .child(Label::new("Accept Terms of Service"))
 8799                            .child(div().w_full())
 8800                            .child(
 8801                                Icon::new(IconName::ArrowUpRight)
 8802                                    .color(Color::Muted)
 8803                                    .size(IconSize::Small),
 8804                            )
 8805                            .into_any_element(),
 8806                    )
 8807                    .into_any(),
 8808            );
 8809        }
 8810
 8811        let is_refreshing = provider.provider.is_refreshing(cx);
 8812
 8813        fn pending_completion_container() -> Div {
 8814            h_flex()
 8815                .h_full()
 8816                .flex_1()
 8817                .gap_2()
 8818                .child(Icon::new(IconName::ZedPredict))
 8819        }
 8820
 8821        let completion = match &self.active_inline_completion {
 8822            Some(prediction) => {
 8823                if !self.has_visible_completions_menu() {
 8824                    const RADIUS: Pixels = px(6.);
 8825                    const BORDER_WIDTH: Pixels = px(1.);
 8826
 8827                    return Some(
 8828                        h_flex()
 8829                            .elevation_2(cx)
 8830                            .border(BORDER_WIDTH)
 8831                            .border_color(cx.theme().colors().border)
 8832                            .when(accept_keystroke.is_none(), |el| {
 8833                                el.border_color(cx.theme().status().error)
 8834                            })
 8835                            .rounded(RADIUS)
 8836                            .rounded_tl(px(0.))
 8837                            .overflow_hidden()
 8838                            .child(div().px_1p5().child(match &prediction.completion {
 8839                                InlineCompletion::Move { target, snapshot } => {
 8840                                    use text::ToPoint as _;
 8841                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8842                                    {
 8843                                        Icon::new(IconName::ZedPredictDown)
 8844                                    } else {
 8845                                        Icon::new(IconName::ZedPredictUp)
 8846                                    }
 8847                                }
 8848                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8849                            }))
 8850                            .child(
 8851                                h_flex()
 8852                                    .gap_1()
 8853                                    .py_1()
 8854                                    .px_2()
 8855                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8856                                    .border_l_1()
 8857                                    .border_color(cx.theme().colors().border)
 8858                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8859                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8860                                        el.child(
 8861                                            Label::new("Hold")
 8862                                                .size(LabelSize::Small)
 8863                                                .when(accept_keystroke.is_none(), |el| {
 8864                                                    el.strikethrough()
 8865                                                })
 8866                                                .line_height_style(LineHeightStyle::UiLabel),
 8867                                        )
 8868                                    })
 8869                                    .id("edit_prediction_cursor_popover_keybind")
 8870                                    .when(accept_keystroke.is_none(), |el| {
 8871                                        let status_colors = cx.theme().status();
 8872
 8873                                        el.bg(status_colors.error_background)
 8874                                            .border_color(status_colors.error.opacity(0.6))
 8875                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8876                                            .cursor_default()
 8877                                            .hoverable_tooltip(move |_window, cx| {
 8878                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8879                                                    .into()
 8880                                            })
 8881                                    })
 8882                                    .when_some(
 8883                                        accept_keystroke.as_ref(),
 8884                                        |el, accept_keystroke| {
 8885                                            el.child(h_flex().children(ui::render_modifiers(
 8886                                                &accept_keystroke.modifiers,
 8887                                                PlatformStyle::platform(),
 8888                                                Some(Color::Default),
 8889                                                Some(IconSize::XSmall.rems().into()),
 8890                                                false,
 8891                                            )))
 8892                                        },
 8893                                    ),
 8894                            )
 8895                            .into_any(),
 8896                    );
 8897                }
 8898
 8899                self.render_edit_prediction_cursor_popover_preview(
 8900                    prediction,
 8901                    cursor_point,
 8902                    style,
 8903                    cx,
 8904                )?
 8905            }
 8906
 8907            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8908                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8909                    stale_completion,
 8910                    cursor_point,
 8911                    style,
 8912                    cx,
 8913                )?,
 8914
 8915                None => {
 8916                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8917                }
 8918            },
 8919
 8920            None => pending_completion_container().child(Label::new("No Prediction")),
 8921        };
 8922
 8923        let completion = if is_refreshing {
 8924            completion
 8925                .with_animation(
 8926                    "loading-completion",
 8927                    Animation::new(Duration::from_secs(2))
 8928                        .repeat()
 8929                        .with_easing(pulsating_between(0.4, 0.8)),
 8930                    |label, delta| label.opacity(delta),
 8931                )
 8932                .into_any_element()
 8933        } else {
 8934            completion.into_any_element()
 8935        };
 8936
 8937        let has_completion = self.active_inline_completion.is_some();
 8938
 8939        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8940        Some(
 8941            h_flex()
 8942                .min_w(min_width)
 8943                .max_w(max_width)
 8944                .flex_1()
 8945                .elevation_2(cx)
 8946                .border_color(cx.theme().colors().border)
 8947                .child(
 8948                    div()
 8949                        .flex_1()
 8950                        .py_1()
 8951                        .px_2()
 8952                        .overflow_hidden()
 8953                        .child(completion),
 8954                )
 8955                .when_some(accept_keystroke, |el, accept_keystroke| {
 8956                    if !accept_keystroke.modifiers.modified() {
 8957                        return el;
 8958                    }
 8959
 8960                    el.child(
 8961                        h_flex()
 8962                            .h_full()
 8963                            .border_l_1()
 8964                            .rounded_r_lg()
 8965                            .border_color(cx.theme().colors().border)
 8966                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8967                            .gap_1()
 8968                            .py_1()
 8969                            .px_2()
 8970                            .child(
 8971                                h_flex()
 8972                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8973                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8974                                    .child(h_flex().children(ui::render_modifiers(
 8975                                        &accept_keystroke.modifiers,
 8976                                        PlatformStyle::platform(),
 8977                                        Some(if !has_completion {
 8978                                            Color::Muted
 8979                                        } else {
 8980                                            Color::Default
 8981                                        }),
 8982                                        None,
 8983                                        false,
 8984                                    ))),
 8985                            )
 8986                            .child(Label::new("Preview").into_any_element())
 8987                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8988                    )
 8989                })
 8990                .into_any(),
 8991        )
 8992    }
 8993
 8994    fn render_edit_prediction_cursor_popover_preview(
 8995        &self,
 8996        completion: &InlineCompletionState,
 8997        cursor_point: Point,
 8998        style: &EditorStyle,
 8999        cx: &mut Context<Editor>,
 9000    ) -> Option<Div> {
 9001        use text::ToPoint as _;
 9002
 9003        fn render_relative_row_jump(
 9004            prefix: impl Into<String>,
 9005            current_row: u32,
 9006            target_row: u32,
 9007        ) -> Div {
 9008            let (row_diff, arrow) = if target_row < current_row {
 9009                (current_row - target_row, IconName::ArrowUp)
 9010            } else {
 9011                (target_row - current_row, IconName::ArrowDown)
 9012            };
 9013
 9014            h_flex()
 9015                .child(
 9016                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9017                        .color(Color::Muted)
 9018                        .size(LabelSize::Small),
 9019                )
 9020                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9021        }
 9022
 9023        match &completion.completion {
 9024            InlineCompletion::Move {
 9025                target, snapshot, ..
 9026            } => Some(
 9027                h_flex()
 9028                    .px_2()
 9029                    .gap_2()
 9030                    .flex_1()
 9031                    .child(
 9032                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9033                            Icon::new(IconName::ZedPredictDown)
 9034                        } else {
 9035                            Icon::new(IconName::ZedPredictUp)
 9036                        },
 9037                    )
 9038                    .child(Label::new("Jump to Edit")),
 9039            ),
 9040
 9041            InlineCompletion::Edit {
 9042                edits,
 9043                edit_preview,
 9044                snapshot,
 9045                display_mode: _,
 9046            } => {
 9047                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9048
 9049                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9050                    &snapshot,
 9051                    &edits,
 9052                    edit_preview.as_ref()?,
 9053                    true,
 9054                    cx,
 9055                )
 9056                .first_line_preview();
 9057
 9058                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9059                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9060
 9061                let preview = h_flex()
 9062                    .gap_1()
 9063                    .min_w_16()
 9064                    .child(styled_text)
 9065                    .when(has_more_lines, |parent| parent.child(""));
 9066
 9067                let left = if first_edit_row != cursor_point.row {
 9068                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9069                        .into_any_element()
 9070                } else {
 9071                    Icon::new(IconName::ZedPredict).into_any_element()
 9072                };
 9073
 9074                Some(
 9075                    h_flex()
 9076                        .h_full()
 9077                        .flex_1()
 9078                        .gap_2()
 9079                        .pr_1()
 9080                        .overflow_x_hidden()
 9081                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9082                        .child(left)
 9083                        .child(preview),
 9084                )
 9085            }
 9086        }
 9087    }
 9088
 9089    pub fn render_context_menu(
 9090        &self,
 9091        style: &EditorStyle,
 9092        max_height_in_lines: u32,
 9093        window: &mut Window,
 9094        cx: &mut Context<Editor>,
 9095    ) -> Option<AnyElement> {
 9096        let menu = self.context_menu.borrow();
 9097        let menu = menu.as_ref()?;
 9098        if !menu.visible() {
 9099            return None;
 9100        };
 9101        Some(menu.render(style, max_height_in_lines, window, cx))
 9102    }
 9103
 9104    fn render_context_menu_aside(
 9105        &mut self,
 9106        max_size: Size<Pixels>,
 9107        window: &mut Window,
 9108        cx: &mut Context<Editor>,
 9109    ) -> Option<AnyElement> {
 9110        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9111            if menu.visible() {
 9112                menu.render_aside(max_size, window, cx)
 9113            } else {
 9114                None
 9115            }
 9116        })
 9117    }
 9118
 9119    fn hide_context_menu(
 9120        &mut self,
 9121        window: &mut Window,
 9122        cx: &mut Context<Self>,
 9123    ) -> Option<CodeContextMenu> {
 9124        cx.notify();
 9125        self.completion_tasks.clear();
 9126        let context_menu = self.context_menu.borrow_mut().take();
 9127        self.stale_inline_completion_in_menu.take();
 9128        self.update_visible_inline_completion(window, cx);
 9129        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9130            if let Some(completion_provider) = &self.completion_provider {
 9131                completion_provider.selection_changed(None, window, cx);
 9132            }
 9133        }
 9134        context_menu
 9135    }
 9136
 9137    fn show_snippet_choices(
 9138        &mut self,
 9139        choices: &Vec<String>,
 9140        selection: Range<Anchor>,
 9141        cx: &mut Context<Self>,
 9142    ) {
 9143        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9144            (Some(a), Some(b)) if a == b => a,
 9145            _ => {
 9146                log::error!("expected anchor range to have matching buffer IDs");
 9147                return;
 9148            }
 9149        };
 9150        let multi_buffer = self.buffer().read(cx);
 9151        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9152            return;
 9153        };
 9154
 9155        let id = post_inc(&mut self.next_completion_id);
 9156        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9157        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9158            CompletionsMenu::new_snippet_choices(
 9159                id,
 9160                true,
 9161                choices,
 9162                selection,
 9163                buffer,
 9164                snippet_sort_order,
 9165            ),
 9166        ));
 9167    }
 9168
 9169    pub fn insert_snippet(
 9170        &mut self,
 9171        insertion_ranges: &[Range<usize>],
 9172        snippet: Snippet,
 9173        window: &mut Window,
 9174        cx: &mut Context<Self>,
 9175    ) -> Result<()> {
 9176        struct Tabstop<T> {
 9177            is_end_tabstop: bool,
 9178            ranges: Vec<Range<T>>,
 9179            choices: Option<Vec<String>>,
 9180        }
 9181
 9182        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9183            let snippet_text: Arc<str> = snippet.text.clone().into();
 9184            let edits = insertion_ranges
 9185                .iter()
 9186                .cloned()
 9187                .map(|range| (range, snippet_text.clone()));
 9188            let autoindent_mode = AutoindentMode::Block {
 9189                original_indent_columns: Vec::new(),
 9190            };
 9191            buffer.edit(edits, Some(autoindent_mode), cx);
 9192
 9193            let snapshot = &*buffer.read(cx);
 9194            let snippet = &snippet;
 9195            snippet
 9196                .tabstops
 9197                .iter()
 9198                .map(|tabstop| {
 9199                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9200                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9201                    });
 9202                    let mut tabstop_ranges = tabstop
 9203                        .ranges
 9204                        .iter()
 9205                        .flat_map(|tabstop_range| {
 9206                            let mut delta = 0_isize;
 9207                            insertion_ranges.iter().map(move |insertion_range| {
 9208                                let insertion_start = insertion_range.start as isize + delta;
 9209                                delta +=
 9210                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9211
 9212                                let start = ((insertion_start + tabstop_range.start) as usize)
 9213                                    .min(snapshot.len());
 9214                                let end = ((insertion_start + tabstop_range.end) as usize)
 9215                                    .min(snapshot.len());
 9216                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9217                            })
 9218                        })
 9219                        .collect::<Vec<_>>();
 9220                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9221
 9222                    Tabstop {
 9223                        is_end_tabstop,
 9224                        ranges: tabstop_ranges,
 9225                        choices: tabstop.choices.clone(),
 9226                    }
 9227                })
 9228                .collect::<Vec<_>>()
 9229        });
 9230        if let Some(tabstop) = tabstops.first() {
 9231            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9232                // Reverse order so that the first range is the newest created selection.
 9233                // Completions will use it and autoscroll will prioritize it.
 9234                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9235            });
 9236
 9237            if let Some(choices) = &tabstop.choices {
 9238                if let Some(selection) = tabstop.ranges.first() {
 9239                    self.show_snippet_choices(choices, selection.clone(), cx)
 9240                }
 9241            }
 9242
 9243            // If we're already at the last tabstop and it's at the end of the snippet,
 9244            // we're done, we don't need to keep the state around.
 9245            if !tabstop.is_end_tabstop {
 9246                let choices = tabstops
 9247                    .iter()
 9248                    .map(|tabstop| tabstop.choices.clone())
 9249                    .collect();
 9250
 9251                let ranges = tabstops
 9252                    .into_iter()
 9253                    .map(|tabstop| tabstop.ranges)
 9254                    .collect::<Vec<_>>();
 9255
 9256                self.snippet_stack.push(SnippetState {
 9257                    active_index: 0,
 9258                    ranges,
 9259                    choices,
 9260                });
 9261            }
 9262
 9263            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9264            if self.autoclose_regions.is_empty() {
 9265                let snapshot = self.buffer.read(cx).snapshot(cx);
 9266                for selection in &mut self.selections.all::<Point>(cx) {
 9267                    let selection_head = selection.head();
 9268                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9269                        continue;
 9270                    };
 9271
 9272                    let mut bracket_pair = None;
 9273                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9274                    let prev_chars = snapshot
 9275                        .reversed_chars_at(selection_head)
 9276                        .collect::<String>();
 9277                    for (pair, enabled) in scope.brackets() {
 9278                        if enabled
 9279                            && pair.close
 9280                            && prev_chars.starts_with(pair.start.as_str())
 9281                            && next_chars.starts_with(pair.end.as_str())
 9282                        {
 9283                            bracket_pair = Some(pair.clone());
 9284                            break;
 9285                        }
 9286                    }
 9287                    if let Some(pair) = bracket_pair {
 9288                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9289                        let autoclose_enabled =
 9290                            self.use_autoclose && snapshot_settings.use_autoclose;
 9291                        if autoclose_enabled {
 9292                            let start = snapshot.anchor_after(selection_head);
 9293                            let end = snapshot.anchor_after(selection_head);
 9294                            self.autoclose_regions.push(AutocloseRegion {
 9295                                selection_id: selection.id,
 9296                                range: start..end,
 9297                                pair,
 9298                            });
 9299                        }
 9300                    }
 9301                }
 9302            }
 9303        }
 9304        Ok(())
 9305    }
 9306
 9307    pub fn move_to_next_snippet_tabstop(
 9308        &mut self,
 9309        window: &mut Window,
 9310        cx: &mut Context<Self>,
 9311    ) -> bool {
 9312        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9313    }
 9314
 9315    pub fn move_to_prev_snippet_tabstop(
 9316        &mut self,
 9317        window: &mut Window,
 9318        cx: &mut Context<Self>,
 9319    ) -> bool {
 9320        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9321    }
 9322
 9323    pub fn move_to_snippet_tabstop(
 9324        &mut self,
 9325        bias: Bias,
 9326        window: &mut Window,
 9327        cx: &mut Context<Self>,
 9328    ) -> bool {
 9329        if let Some(mut snippet) = self.snippet_stack.pop() {
 9330            match bias {
 9331                Bias::Left => {
 9332                    if snippet.active_index > 0 {
 9333                        snippet.active_index -= 1;
 9334                    } else {
 9335                        self.snippet_stack.push(snippet);
 9336                        return false;
 9337                    }
 9338                }
 9339                Bias::Right => {
 9340                    if snippet.active_index + 1 < snippet.ranges.len() {
 9341                        snippet.active_index += 1;
 9342                    } else {
 9343                        self.snippet_stack.push(snippet);
 9344                        return false;
 9345                    }
 9346                }
 9347            }
 9348            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9349                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9350                    // Reverse order so that the first range is the newest created selection.
 9351                    // Completions will use it and autoscroll will prioritize it.
 9352                    s.select_ranges(current_ranges.iter().rev().cloned())
 9353                });
 9354
 9355                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9356                    if let Some(selection) = current_ranges.first() {
 9357                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9358                    }
 9359                }
 9360
 9361                // If snippet state is not at the last tabstop, push it back on the stack
 9362                if snippet.active_index + 1 < snippet.ranges.len() {
 9363                    self.snippet_stack.push(snippet);
 9364                }
 9365                return true;
 9366            }
 9367        }
 9368
 9369        false
 9370    }
 9371
 9372    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9373        self.transact(window, cx, |this, window, cx| {
 9374            this.select_all(&SelectAll, window, cx);
 9375            this.insert("", window, cx);
 9376        });
 9377    }
 9378
 9379    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9381        self.transact(window, cx, |this, window, cx| {
 9382            this.select_autoclose_pair(window, cx);
 9383            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9384            if !this.linked_edit_ranges.is_empty() {
 9385                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9386                let snapshot = this.buffer.read(cx).snapshot(cx);
 9387
 9388                for selection in selections.iter() {
 9389                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9390                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9391                    if selection_start.buffer_id != selection_end.buffer_id {
 9392                        continue;
 9393                    }
 9394                    if let Some(ranges) =
 9395                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9396                    {
 9397                        for (buffer, entries) in ranges {
 9398                            linked_ranges.entry(buffer).or_default().extend(entries);
 9399                        }
 9400                    }
 9401                }
 9402            }
 9403
 9404            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9405            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9406            for selection in &mut selections {
 9407                if selection.is_empty() {
 9408                    let old_head = selection.head();
 9409                    let mut new_head =
 9410                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9411                            .to_point(&display_map);
 9412                    if let Some((buffer, line_buffer_range)) = display_map
 9413                        .buffer_snapshot
 9414                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9415                    {
 9416                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9417                        let indent_len = match indent_size.kind {
 9418                            IndentKind::Space => {
 9419                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9420                            }
 9421                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9422                        };
 9423                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9424                            let indent_len = indent_len.get();
 9425                            new_head = cmp::min(
 9426                                new_head,
 9427                                MultiBufferPoint::new(
 9428                                    old_head.row,
 9429                                    ((old_head.column - 1) / indent_len) * indent_len,
 9430                                ),
 9431                            );
 9432                        }
 9433                    }
 9434
 9435                    selection.set_head(new_head, SelectionGoal::None);
 9436                }
 9437            }
 9438
 9439            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9440                s.select(selections)
 9441            });
 9442            this.insert("", window, cx);
 9443            let empty_str: Arc<str> = Arc::from("");
 9444            for (buffer, edits) in linked_ranges {
 9445                let snapshot = buffer.read(cx).snapshot();
 9446                use text::ToPoint as TP;
 9447
 9448                let edits = edits
 9449                    .into_iter()
 9450                    .map(|range| {
 9451                        let end_point = TP::to_point(&range.end, &snapshot);
 9452                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9453
 9454                        if end_point == start_point {
 9455                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9456                                .saturating_sub(1);
 9457                            start_point =
 9458                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9459                        };
 9460
 9461                        (start_point..end_point, empty_str.clone())
 9462                    })
 9463                    .sorted_by_key(|(range, _)| range.start)
 9464                    .collect::<Vec<_>>();
 9465                buffer.update(cx, |this, cx| {
 9466                    this.edit(edits, None, cx);
 9467                })
 9468            }
 9469            this.refresh_inline_completion(true, false, window, cx);
 9470            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9471        });
 9472    }
 9473
 9474    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9475        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9476        self.transact(window, cx, |this, window, cx| {
 9477            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9478                s.move_with(|map, selection| {
 9479                    if selection.is_empty() {
 9480                        let cursor = movement::right(map, selection.head());
 9481                        selection.end = cursor;
 9482                        selection.reversed = true;
 9483                        selection.goal = SelectionGoal::None;
 9484                    }
 9485                })
 9486            });
 9487            this.insert("", window, cx);
 9488            this.refresh_inline_completion(true, false, window, cx);
 9489        });
 9490    }
 9491
 9492    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9493        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9494        if self.move_to_prev_snippet_tabstop(window, cx) {
 9495            return;
 9496        }
 9497        self.outdent(&Outdent, window, cx);
 9498    }
 9499
 9500    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9501        if self.move_to_next_snippet_tabstop(window, cx) {
 9502            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9503            return;
 9504        }
 9505        if self.read_only(cx) {
 9506            return;
 9507        }
 9508        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9509        let mut selections = self.selections.all_adjusted(cx);
 9510        let buffer = self.buffer.read(cx);
 9511        let snapshot = buffer.snapshot(cx);
 9512        let rows_iter = selections.iter().map(|s| s.head().row);
 9513        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9514
 9515        let has_some_cursor_in_whitespace = selections
 9516            .iter()
 9517            .filter(|selection| selection.is_empty())
 9518            .any(|selection| {
 9519                let cursor = selection.head();
 9520                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9521                cursor.column < current_indent.len
 9522            });
 9523
 9524        let mut edits = Vec::new();
 9525        let mut prev_edited_row = 0;
 9526        let mut row_delta = 0;
 9527        for selection in &mut selections {
 9528            if selection.start.row != prev_edited_row {
 9529                row_delta = 0;
 9530            }
 9531            prev_edited_row = selection.end.row;
 9532
 9533            // If the selection is non-empty, then increase the indentation of the selected lines.
 9534            if !selection.is_empty() {
 9535                row_delta =
 9536                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9537                continue;
 9538            }
 9539
 9540            let cursor = selection.head();
 9541            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9542            if let Some(suggested_indent) =
 9543                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9544            {
 9545                // Don't do anything if already at suggested indent
 9546                // and there is any other cursor which is not
 9547                if has_some_cursor_in_whitespace
 9548                    && cursor.column == current_indent.len
 9549                    && current_indent.len == suggested_indent.len
 9550                {
 9551                    continue;
 9552                }
 9553
 9554                // Adjust line and move cursor to suggested indent
 9555                // if cursor is not at suggested indent
 9556                if cursor.column < suggested_indent.len
 9557                    && cursor.column <= current_indent.len
 9558                    && current_indent.len <= suggested_indent.len
 9559                {
 9560                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9561                    selection.end = selection.start;
 9562                    if row_delta == 0 {
 9563                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9564                            cursor.row,
 9565                            current_indent,
 9566                            suggested_indent,
 9567                        ));
 9568                        row_delta = suggested_indent.len - current_indent.len;
 9569                    }
 9570                    continue;
 9571                }
 9572
 9573                // If current indent is more than suggested indent
 9574                // only move cursor to current indent and skip indent
 9575                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9576                    selection.start = Point::new(cursor.row, current_indent.len);
 9577                    selection.end = selection.start;
 9578                    continue;
 9579                }
 9580            }
 9581
 9582            // Otherwise, insert a hard or soft tab.
 9583            let settings = buffer.language_settings_at(cursor, cx);
 9584            let tab_size = if settings.hard_tabs {
 9585                IndentSize::tab()
 9586            } else {
 9587                let tab_size = settings.tab_size.get();
 9588                let indent_remainder = snapshot
 9589                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9590                    .flat_map(str::chars)
 9591                    .fold(row_delta % tab_size, |counter: u32, c| {
 9592                        if c == '\t' {
 9593                            0
 9594                        } else {
 9595                            (counter + 1) % tab_size
 9596                        }
 9597                    });
 9598
 9599                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9600                IndentSize::spaces(chars_to_next_tab_stop)
 9601            };
 9602            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9603            selection.end = selection.start;
 9604            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9605            row_delta += tab_size.len;
 9606        }
 9607
 9608        self.transact(window, cx, |this, window, cx| {
 9609            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9610            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9611                s.select(selections)
 9612            });
 9613            this.refresh_inline_completion(true, false, window, cx);
 9614        });
 9615    }
 9616
 9617    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9618        if self.read_only(cx) {
 9619            return;
 9620        }
 9621        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9622        let mut selections = self.selections.all::<Point>(cx);
 9623        let mut prev_edited_row = 0;
 9624        let mut row_delta = 0;
 9625        let mut edits = Vec::new();
 9626        let buffer = self.buffer.read(cx);
 9627        let snapshot = buffer.snapshot(cx);
 9628        for selection in &mut selections {
 9629            if selection.start.row != prev_edited_row {
 9630                row_delta = 0;
 9631            }
 9632            prev_edited_row = selection.end.row;
 9633
 9634            row_delta =
 9635                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9636        }
 9637
 9638        self.transact(window, cx, |this, window, cx| {
 9639            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9640            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9641                s.select(selections)
 9642            });
 9643        });
 9644    }
 9645
 9646    fn indent_selection(
 9647        buffer: &MultiBuffer,
 9648        snapshot: &MultiBufferSnapshot,
 9649        selection: &mut Selection<Point>,
 9650        edits: &mut Vec<(Range<Point>, String)>,
 9651        delta_for_start_row: u32,
 9652        cx: &App,
 9653    ) -> u32 {
 9654        let settings = buffer.language_settings_at(selection.start, cx);
 9655        let tab_size = settings.tab_size.get();
 9656        let indent_kind = if settings.hard_tabs {
 9657            IndentKind::Tab
 9658        } else {
 9659            IndentKind::Space
 9660        };
 9661        let mut start_row = selection.start.row;
 9662        let mut end_row = selection.end.row + 1;
 9663
 9664        // If a selection ends at the beginning of a line, don't indent
 9665        // that last line.
 9666        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9667            end_row -= 1;
 9668        }
 9669
 9670        // Avoid re-indenting a row that has already been indented by a
 9671        // previous selection, but still update this selection's column
 9672        // to reflect that indentation.
 9673        if delta_for_start_row > 0 {
 9674            start_row += 1;
 9675            selection.start.column += delta_for_start_row;
 9676            if selection.end.row == selection.start.row {
 9677                selection.end.column += delta_for_start_row;
 9678            }
 9679        }
 9680
 9681        let mut delta_for_end_row = 0;
 9682        let has_multiple_rows = start_row + 1 != end_row;
 9683        for row in start_row..end_row {
 9684            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9685            let indent_delta = match (current_indent.kind, indent_kind) {
 9686                (IndentKind::Space, IndentKind::Space) => {
 9687                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9688                    IndentSize::spaces(columns_to_next_tab_stop)
 9689                }
 9690                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9691                (_, IndentKind::Tab) => IndentSize::tab(),
 9692            };
 9693
 9694            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9695                0
 9696            } else {
 9697                selection.start.column
 9698            };
 9699            let row_start = Point::new(row, start);
 9700            edits.push((
 9701                row_start..row_start,
 9702                indent_delta.chars().collect::<String>(),
 9703            ));
 9704
 9705            // Update this selection's endpoints to reflect the indentation.
 9706            if row == selection.start.row {
 9707                selection.start.column += indent_delta.len;
 9708            }
 9709            if row == selection.end.row {
 9710                selection.end.column += indent_delta.len;
 9711                delta_for_end_row = indent_delta.len;
 9712            }
 9713        }
 9714
 9715        if selection.start.row == selection.end.row {
 9716            delta_for_start_row + delta_for_end_row
 9717        } else {
 9718            delta_for_end_row
 9719        }
 9720    }
 9721
 9722    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9723        if self.read_only(cx) {
 9724            return;
 9725        }
 9726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9727        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9728        let selections = self.selections.all::<Point>(cx);
 9729        let mut deletion_ranges = Vec::new();
 9730        let mut last_outdent = None;
 9731        {
 9732            let buffer = self.buffer.read(cx);
 9733            let snapshot = buffer.snapshot(cx);
 9734            for selection in &selections {
 9735                let settings = buffer.language_settings_at(selection.start, cx);
 9736                let tab_size = settings.tab_size.get();
 9737                let mut rows = selection.spanned_rows(false, &display_map);
 9738
 9739                // Avoid re-outdenting a row that has already been outdented by a
 9740                // previous selection.
 9741                if let Some(last_row) = last_outdent {
 9742                    if last_row == rows.start {
 9743                        rows.start = rows.start.next_row();
 9744                    }
 9745                }
 9746                let has_multiple_rows = rows.len() > 1;
 9747                for row in rows.iter_rows() {
 9748                    let indent_size = snapshot.indent_size_for_line(row);
 9749                    if indent_size.len > 0 {
 9750                        let deletion_len = match indent_size.kind {
 9751                            IndentKind::Space => {
 9752                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9753                                if columns_to_prev_tab_stop == 0 {
 9754                                    tab_size
 9755                                } else {
 9756                                    columns_to_prev_tab_stop
 9757                                }
 9758                            }
 9759                            IndentKind::Tab => 1,
 9760                        };
 9761                        let start = if has_multiple_rows
 9762                            || deletion_len > selection.start.column
 9763                            || indent_size.len < selection.start.column
 9764                        {
 9765                            0
 9766                        } else {
 9767                            selection.start.column - deletion_len
 9768                        };
 9769                        deletion_ranges.push(
 9770                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9771                        );
 9772                        last_outdent = Some(row);
 9773                    }
 9774                }
 9775            }
 9776        }
 9777
 9778        self.transact(window, cx, |this, window, cx| {
 9779            this.buffer.update(cx, |buffer, cx| {
 9780                let empty_str: Arc<str> = Arc::default();
 9781                buffer.edit(
 9782                    deletion_ranges
 9783                        .into_iter()
 9784                        .map(|range| (range, empty_str.clone())),
 9785                    None,
 9786                    cx,
 9787                );
 9788            });
 9789            let selections = this.selections.all::<usize>(cx);
 9790            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9791                s.select(selections)
 9792            });
 9793        });
 9794    }
 9795
 9796    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9797        if self.read_only(cx) {
 9798            return;
 9799        }
 9800        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9801        let selections = self
 9802            .selections
 9803            .all::<usize>(cx)
 9804            .into_iter()
 9805            .map(|s| s.range());
 9806
 9807        self.transact(window, cx, |this, window, cx| {
 9808            this.buffer.update(cx, |buffer, cx| {
 9809                buffer.autoindent_ranges(selections, cx);
 9810            });
 9811            let selections = this.selections.all::<usize>(cx);
 9812            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9813                s.select(selections)
 9814            });
 9815        });
 9816    }
 9817
 9818    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9819        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9820        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9821        let selections = self.selections.all::<Point>(cx);
 9822
 9823        let mut new_cursors = Vec::new();
 9824        let mut edit_ranges = Vec::new();
 9825        let mut selections = selections.iter().peekable();
 9826        while let Some(selection) = selections.next() {
 9827            let mut rows = selection.spanned_rows(false, &display_map);
 9828            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9829
 9830            // Accumulate contiguous regions of rows that we want to delete.
 9831            while let Some(next_selection) = selections.peek() {
 9832                let next_rows = next_selection.spanned_rows(false, &display_map);
 9833                if next_rows.start <= rows.end {
 9834                    rows.end = next_rows.end;
 9835                    selections.next().unwrap();
 9836                } else {
 9837                    break;
 9838                }
 9839            }
 9840
 9841            let buffer = &display_map.buffer_snapshot;
 9842            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9843            let edit_end;
 9844            let cursor_buffer_row;
 9845            if buffer.max_point().row >= rows.end.0 {
 9846                // If there's a line after the range, delete the \n from the end of the row range
 9847                // and position the cursor on the next line.
 9848                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9849                cursor_buffer_row = rows.end;
 9850            } else {
 9851                // If there isn't a line after the range, delete the \n from the line before the
 9852                // start of the row range and position the cursor there.
 9853                edit_start = edit_start.saturating_sub(1);
 9854                edit_end = buffer.len();
 9855                cursor_buffer_row = rows.start.previous_row();
 9856            }
 9857
 9858            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9859            *cursor.column_mut() =
 9860                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9861
 9862            new_cursors.push((
 9863                selection.id,
 9864                buffer.anchor_after(cursor.to_point(&display_map)),
 9865            ));
 9866            edit_ranges.push(edit_start..edit_end);
 9867        }
 9868
 9869        self.transact(window, cx, |this, window, cx| {
 9870            let buffer = this.buffer.update(cx, |buffer, cx| {
 9871                let empty_str: Arc<str> = Arc::default();
 9872                buffer.edit(
 9873                    edit_ranges
 9874                        .into_iter()
 9875                        .map(|range| (range, empty_str.clone())),
 9876                    None,
 9877                    cx,
 9878                );
 9879                buffer.snapshot(cx)
 9880            });
 9881            let new_selections = new_cursors
 9882                .into_iter()
 9883                .map(|(id, cursor)| {
 9884                    let cursor = cursor.to_point(&buffer);
 9885                    Selection {
 9886                        id,
 9887                        start: cursor,
 9888                        end: cursor,
 9889                        reversed: false,
 9890                        goal: SelectionGoal::None,
 9891                    }
 9892                })
 9893                .collect();
 9894
 9895            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9896                s.select(new_selections);
 9897            });
 9898        });
 9899    }
 9900
 9901    pub fn join_lines_impl(
 9902        &mut self,
 9903        insert_whitespace: bool,
 9904        window: &mut Window,
 9905        cx: &mut Context<Self>,
 9906    ) {
 9907        if self.read_only(cx) {
 9908            return;
 9909        }
 9910        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9911        for selection in self.selections.all::<Point>(cx) {
 9912            let start = MultiBufferRow(selection.start.row);
 9913            // Treat single line selections as if they include the next line. Otherwise this action
 9914            // would do nothing for single line selections individual cursors.
 9915            let end = if selection.start.row == selection.end.row {
 9916                MultiBufferRow(selection.start.row + 1)
 9917            } else {
 9918                MultiBufferRow(selection.end.row)
 9919            };
 9920
 9921            if let Some(last_row_range) = row_ranges.last_mut() {
 9922                if start <= last_row_range.end {
 9923                    last_row_range.end = end;
 9924                    continue;
 9925                }
 9926            }
 9927            row_ranges.push(start..end);
 9928        }
 9929
 9930        let snapshot = self.buffer.read(cx).snapshot(cx);
 9931        let mut cursor_positions = Vec::new();
 9932        for row_range in &row_ranges {
 9933            let anchor = snapshot.anchor_before(Point::new(
 9934                row_range.end.previous_row().0,
 9935                snapshot.line_len(row_range.end.previous_row()),
 9936            ));
 9937            cursor_positions.push(anchor..anchor);
 9938        }
 9939
 9940        self.transact(window, cx, |this, window, cx| {
 9941            for row_range in row_ranges.into_iter().rev() {
 9942                for row in row_range.iter_rows().rev() {
 9943                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9944                    let next_line_row = row.next_row();
 9945                    let indent = snapshot.indent_size_for_line(next_line_row);
 9946                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9947
 9948                    let replace =
 9949                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9950                            " "
 9951                        } else {
 9952                            ""
 9953                        };
 9954
 9955                    this.buffer.update(cx, |buffer, cx| {
 9956                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9957                    });
 9958                }
 9959            }
 9960
 9961            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9962                s.select_anchor_ranges(cursor_positions)
 9963            });
 9964        });
 9965    }
 9966
 9967    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9968        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9969        self.join_lines_impl(true, window, cx);
 9970    }
 9971
 9972    pub fn sort_lines_case_sensitive(
 9973        &mut self,
 9974        _: &SortLinesCaseSensitive,
 9975        window: &mut Window,
 9976        cx: &mut Context<Self>,
 9977    ) {
 9978        self.manipulate_lines(window, cx, |lines| lines.sort())
 9979    }
 9980
 9981    pub fn sort_lines_case_insensitive(
 9982        &mut self,
 9983        _: &SortLinesCaseInsensitive,
 9984        window: &mut Window,
 9985        cx: &mut Context<Self>,
 9986    ) {
 9987        self.manipulate_lines(window, cx, |lines| {
 9988            lines.sort_by_key(|line| line.to_lowercase())
 9989        })
 9990    }
 9991
 9992    pub fn unique_lines_case_insensitive(
 9993        &mut self,
 9994        _: &UniqueLinesCaseInsensitive,
 9995        window: &mut Window,
 9996        cx: &mut Context<Self>,
 9997    ) {
 9998        self.manipulate_lines(window, cx, |lines| {
 9999            let mut seen = HashSet::default();
10000            lines.retain(|line| seen.insert(line.to_lowercase()));
10001        })
10002    }
10003
10004    pub fn unique_lines_case_sensitive(
10005        &mut self,
10006        _: &UniqueLinesCaseSensitive,
10007        window: &mut Window,
10008        cx: &mut Context<Self>,
10009    ) {
10010        self.manipulate_lines(window, cx, |lines| {
10011            let mut seen = HashSet::default();
10012            lines.retain(|line| seen.insert(*line));
10013        })
10014    }
10015
10016    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10017        let Some(project) = self.project.clone() else {
10018            return;
10019        };
10020        self.reload(project, window, cx)
10021            .detach_and_notify_err(window, cx);
10022    }
10023
10024    pub fn restore_file(
10025        &mut self,
10026        _: &::git::RestoreFile,
10027        window: &mut Window,
10028        cx: &mut Context<Self>,
10029    ) {
10030        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10031        let mut buffer_ids = HashSet::default();
10032        let snapshot = self.buffer().read(cx).snapshot(cx);
10033        for selection in self.selections.all::<usize>(cx) {
10034            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10035        }
10036
10037        let buffer = self.buffer().read(cx);
10038        let ranges = buffer_ids
10039            .into_iter()
10040            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10041            .collect::<Vec<_>>();
10042
10043        self.restore_hunks_in_ranges(ranges, window, cx);
10044    }
10045
10046    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10048        let selections = self
10049            .selections
10050            .all(cx)
10051            .into_iter()
10052            .map(|s| s.range())
10053            .collect();
10054        self.restore_hunks_in_ranges(selections, window, cx);
10055    }
10056
10057    pub fn restore_hunks_in_ranges(
10058        &mut self,
10059        ranges: Vec<Range<Point>>,
10060        window: &mut Window,
10061        cx: &mut Context<Editor>,
10062    ) {
10063        let mut revert_changes = HashMap::default();
10064        let chunk_by = self
10065            .snapshot(window, cx)
10066            .hunks_for_ranges(ranges)
10067            .into_iter()
10068            .chunk_by(|hunk| hunk.buffer_id);
10069        for (buffer_id, hunks) in &chunk_by {
10070            let hunks = hunks.collect::<Vec<_>>();
10071            for hunk in &hunks {
10072                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10073            }
10074            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10075        }
10076        drop(chunk_by);
10077        if !revert_changes.is_empty() {
10078            self.transact(window, cx, |editor, window, cx| {
10079                editor.restore(revert_changes, window, cx);
10080            });
10081        }
10082    }
10083
10084    pub fn open_active_item_in_terminal(
10085        &mut self,
10086        _: &OpenInTerminal,
10087        window: &mut Window,
10088        cx: &mut Context<Self>,
10089    ) {
10090        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10091            let project_path = buffer.read(cx).project_path(cx)?;
10092            let project = self.project.as_ref()?.read(cx);
10093            let entry = project.entry_for_path(&project_path, cx)?;
10094            let parent = match &entry.canonical_path {
10095                Some(canonical_path) => canonical_path.to_path_buf(),
10096                None => project.absolute_path(&project_path, cx)?,
10097            }
10098            .parent()?
10099            .to_path_buf();
10100            Some(parent)
10101        }) {
10102            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10103        }
10104    }
10105
10106    fn set_breakpoint_context_menu(
10107        &mut self,
10108        display_row: DisplayRow,
10109        position: Option<Anchor>,
10110        clicked_point: gpui::Point<Pixels>,
10111        window: &mut Window,
10112        cx: &mut Context<Self>,
10113    ) {
10114        if !cx.has_flag::<DebuggerFeatureFlag>() {
10115            return;
10116        }
10117        let source = self
10118            .buffer
10119            .read(cx)
10120            .snapshot(cx)
10121            .anchor_before(Point::new(display_row.0, 0u32));
10122
10123        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10124
10125        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10126            self,
10127            source,
10128            clicked_point,
10129            context_menu,
10130            window,
10131            cx,
10132        );
10133    }
10134
10135    fn add_edit_breakpoint_block(
10136        &mut self,
10137        anchor: Anchor,
10138        breakpoint: &Breakpoint,
10139        edit_action: BreakpointPromptEditAction,
10140        window: &mut Window,
10141        cx: &mut Context<Self>,
10142    ) {
10143        let weak_editor = cx.weak_entity();
10144        let bp_prompt = cx.new(|cx| {
10145            BreakpointPromptEditor::new(
10146                weak_editor,
10147                anchor,
10148                breakpoint.clone(),
10149                edit_action,
10150                window,
10151                cx,
10152            )
10153        });
10154
10155        let height = bp_prompt.update(cx, |this, cx| {
10156            this.prompt
10157                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10158        });
10159        let cloned_prompt = bp_prompt.clone();
10160        let blocks = vec![BlockProperties {
10161            style: BlockStyle::Sticky,
10162            placement: BlockPlacement::Above(anchor),
10163            height: Some(height),
10164            render: Arc::new(move |cx| {
10165                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10166                cloned_prompt.clone().into_any_element()
10167            }),
10168            priority: 0,
10169            render_in_minimap: true,
10170        }];
10171
10172        let focus_handle = bp_prompt.focus_handle(cx);
10173        window.focus(&focus_handle);
10174
10175        let block_ids = self.insert_blocks(blocks, None, cx);
10176        bp_prompt.update(cx, |prompt, _| {
10177            prompt.add_block_ids(block_ids);
10178        });
10179    }
10180
10181    pub(crate) fn breakpoint_at_row(
10182        &self,
10183        row: u32,
10184        window: &mut Window,
10185        cx: &mut Context<Self>,
10186    ) -> Option<(Anchor, Breakpoint)> {
10187        let snapshot = self.snapshot(window, cx);
10188        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10189
10190        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10191    }
10192
10193    pub(crate) fn breakpoint_at_anchor(
10194        &self,
10195        breakpoint_position: Anchor,
10196        snapshot: &EditorSnapshot,
10197        cx: &mut Context<Self>,
10198    ) -> Option<(Anchor, Breakpoint)> {
10199        let project = self.project.clone()?;
10200
10201        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10202            snapshot
10203                .buffer_snapshot
10204                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10205        })?;
10206
10207        let enclosing_excerpt = breakpoint_position.excerpt_id;
10208        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10209        let buffer_snapshot = buffer.read(cx).snapshot();
10210
10211        let row = buffer_snapshot
10212            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10213            .row;
10214
10215        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10216        let anchor_end = snapshot
10217            .buffer_snapshot
10218            .anchor_after(Point::new(row, line_len));
10219
10220        let bp = self
10221            .breakpoint_store
10222            .as_ref()?
10223            .read_with(cx, |breakpoint_store, cx| {
10224                breakpoint_store
10225                    .breakpoints(
10226                        &buffer,
10227                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10228                        &buffer_snapshot,
10229                        cx,
10230                    )
10231                    .next()
10232                    .and_then(|(bp, _)| {
10233                        let breakpoint_row = buffer_snapshot
10234                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10235                            .row;
10236
10237                        if breakpoint_row == row {
10238                            snapshot
10239                                .buffer_snapshot
10240                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10241                                .map(|position| (position, bp.bp.clone()))
10242                        } else {
10243                            None
10244                        }
10245                    })
10246            });
10247        bp
10248    }
10249
10250    pub fn edit_log_breakpoint(
10251        &mut self,
10252        _: &EditLogBreakpoint,
10253        window: &mut Window,
10254        cx: &mut Context<Self>,
10255    ) {
10256        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10257            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10258                message: None,
10259                state: BreakpointState::Enabled,
10260                condition: None,
10261                hit_condition: None,
10262            });
10263
10264            self.add_edit_breakpoint_block(
10265                anchor,
10266                &breakpoint,
10267                BreakpointPromptEditAction::Log,
10268                window,
10269                cx,
10270            );
10271        }
10272    }
10273
10274    fn breakpoints_at_cursors(
10275        &self,
10276        window: &mut Window,
10277        cx: &mut Context<Self>,
10278    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10279        let snapshot = self.snapshot(window, cx);
10280        let cursors = self
10281            .selections
10282            .disjoint_anchors()
10283            .into_iter()
10284            .map(|selection| {
10285                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10286
10287                let breakpoint_position = self
10288                    .breakpoint_at_row(cursor_position.row, window, cx)
10289                    .map(|bp| bp.0)
10290                    .unwrap_or_else(|| {
10291                        snapshot
10292                            .display_snapshot
10293                            .buffer_snapshot
10294                            .anchor_after(Point::new(cursor_position.row, 0))
10295                    });
10296
10297                let breakpoint = self
10298                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10299                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10300
10301                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10302            })
10303            // 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.
10304            .collect::<HashMap<Anchor, _>>();
10305
10306        cursors.into_iter().collect()
10307    }
10308
10309    pub fn enable_breakpoint(
10310        &mut self,
10311        _: &crate::actions::EnableBreakpoint,
10312        window: &mut Window,
10313        cx: &mut Context<Self>,
10314    ) {
10315        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10316            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10317                continue;
10318            };
10319            self.edit_breakpoint_at_anchor(
10320                anchor,
10321                breakpoint,
10322                BreakpointEditAction::InvertState,
10323                cx,
10324            );
10325        }
10326    }
10327
10328    pub fn disable_breakpoint(
10329        &mut self,
10330        _: &crate::actions::DisableBreakpoint,
10331        window: &mut Window,
10332        cx: &mut Context<Self>,
10333    ) {
10334        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10335            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10336                continue;
10337            };
10338            self.edit_breakpoint_at_anchor(
10339                anchor,
10340                breakpoint,
10341                BreakpointEditAction::InvertState,
10342                cx,
10343            );
10344        }
10345    }
10346
10347    pub fn toggle_breakpoint(
10348        &mut self,
10349        _: &crate::actions::ToggleBreakpoint,
10350        window: &mut Window,
10351        cx: &mut Context<Self>,
10352    ) {
10353        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10354            if let Some(breakpoint) = breakpoint {
10355                self.edit_breakpoint_at_anchor(
10356                    anchor,
10357                    breakpoint,
10358                    BreakpointEditAction::Toggle,
10359                    cx,
10360                );
10361            } else {
10362                self.edit_breakpoint_at_anchor(
10363                    anchor,
10364                    Breakpoint::new_standard(),
10365                    BreakpointEditAction::Toggle,
10366                    cx,
10367                );
10368            }
10369        }
10370    }
10371
10372    pub fn edit_breakpoint_at_anchor(
10373        &mut self,
10374        breakpoint_position: Anchor,
10375        breakpoint: Breakpoint,
10376        edit_action: BreakpointEditAction,
10377        cx: &mut Context<Self>,
10378    ) {
10379        let Some(breakpoint_store) = &self.breakpoint_store else {
10380            return;
10381        };
10382
10383        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10384            if breakpoint_position == Anchor::min() {
10385                self.buffer()
10386                    .read(cx)
10387                    .excerpt_buffer_ids()
10388                    .into_iter()
10389                    .next()
10390            } else {
10391                None
10392            }
10393        }) else {
10394            return;
10395        };
10396
10397        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10398            return;
10399        };
10400
10401        breakpoint_store.update(cx, |breakpoint_store, cx| {
10402            breakpoint_store.toggle_breakpoint(
10403                buffer,
10404                BreakpointWithPosition {
10405                    position: breakpoint_position.text_anchor,
10406                    bp: breakpoint,
10407                },
10408                edit_action,
10409                cx,
10410            );
10411        });
10412
10413        cx.notify();
10414    }
10415
10416    #[cfg(any(test, feature = "test-support"))]
10417    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10418        self.breakpoint_store.clone()
10419    }
10420
10421    pub fn prepare_restore_change(
10422        &self,
10423        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10424        hunk: &MultiBufferDiffHunk,
10425        cx: &mut App,
10426    ) -> Option<()> {
10427        if hunk.is_created_file() {
10428            return None;
10429        }
10430        let buffer = self.buffer.read(cx);
10431        let diff = buffer.diff_for(hunk.buffer_id)?;
10432        let buffer = buffer.buffer(hunk.buffer_id)?;
10433        let buffer = buffer.read(cx);
10434        let original_text = diff
10435            .read(cx)
10436            .base_text()
10437            .as_rope()
10438            .slice(hunk.diff_base_byte_range.clone());
10439        let buffer_snapshot = buffer.snapshot();
10440        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10441        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10442            probe
10443                .0
10444                .start
10445                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10446                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10447        }) {
10448            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10449            Some(())
10450        } else {
10451            None
10452        }
10453    }
10454
10455    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10456        self.manipulate_lines(window, cx, |lines| lines.reverse())
10457    }
10458
10459    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10460        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10461    }
10462
10463    fn manipulate_lines<Fn>(
10464        &mut self,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467        mut callback: Fn,
10468    ) where
10469        Fn: FnMut(&mut Vec<&str>),
10470    {
10471        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10472
10473        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10474        let buffer = self.buffer.read(cx).snapshot(cx);
10475
10476        let mut edits = Vec::new();
10477
10478        let selections = self.selections.all::<Point>(cx);
10479        let mut selections = selections.iter().peekable();
10480        let mut contiguous_row_selections = Vec::new();
10481        let mut new_selections = Vec::new();
10482        let mut added_lines = 0;
10483        let mut removed_lines = 0;
10484
10485        while let Some(selection) = selections.next() {
10486            let (start_row, end_row) = consume_contiguous_rows(
10487                &mut contiguous_row_selections,
10488                selection,
10489                &display_map,
10490                &mut selections,
10491            );
10492
10493            let start_point = Point::new(start_row.0, 0);
10494            let end_point = Point::new(
10495                end_row.previous_row().0,
10496                buffer.line_len(end_row.previous_row()),
10497            );
10498            let text = buffer
10499                .text_for_range(start_point..end_point)
10500                .collect::<String>();
10501
10502            let mut lines = text.split('\n').collect_vec();
10503
10504            let lines_before = lines.len();
10505            callback(&mut lines);
10506            let lines_after = lines.len();
10507
10508            edits.push((start_point..end_point, lines.join("\n")));
10509
10510            // Selections must change based on added and removed line count
10511            let start_row =
10512                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10513            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10514            new_selections.push(Selection {
10515                id: selection.id,
10516                start: start_row,
10517                end: end_row,
10518                goal: SelectionGoal::None,
10519                reversed: selection.reversed,
10520            });
10521
10522            if lines_after > lines_before {
10523                added_lines += lines_after - lines_before;
10524            } else if lines_before > lines_after {
10525                removed_lines += lines_before - lines_after;
10526            }
10527        }
10528
10529        self.transact(window, cx, |this, window, cx| {
10530            let buffer = this.buffer.update(cx, |buffer, cx| {
10531                buffer.edit(edits, None, cx);
10532                buffer.snapshot(cx)
10533            });
10534
10535            // Recalculate offsets on newly edited buffer
10536            let new_selections = new_selections
10537                .iter()
10538                .map(|s| {
10539                    let start_point = Point::new(s.start.0, 0);
10540                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10541                    Selection {
10542                        id: s.id,
10543                        start: buffer.point_to_offset(start_point),
10544                        end: buffer.point_to_offset(end_point),
10545                        goal: s.goal,
10546                        reversed: s.reversed,
10547                    }
10548                })
10549                .collect();
10550
10551            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10552                s.select(new_selections);
10553            });
10554
10555            this.request_autoscroll(Autoscroll::fit(), cx);
10556        });
10557    }
10558
10559    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10560        self.manipulate_text(window, cx, |text| {
10561            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10562            if has_upper_case_characters {
10563                text.to_lowercase()
10564            } else {
10565                text.to_uppercase()
10566            }
10567        })
10568    }
10569
10570    pub fn convert_to_upper_case(
10571        &mut self,
10572        _: &ConvertToUpperCase,
10573        window: &mut Window,
10574        cx: &mut Context<Self>,
10575    ) {
10576        self.manipulate_text(window, cx, |text| text.to_uppercase())
10577    }
10578
10579    pub fn convert_to_lower_case(
10580        &mut self,
10581        _: &ConvertToLowerCase,
10582        window: &mut Window,
10583        cx: &mut Context<Self>,
10584    ) {
10585        self.manipulate_text(window, cx, |text| text.to_lowercase())
10586    }
10587
10588    pub fn convert_to_title_case(
10589        &mut self,
10590        _: &ConvertToTitleCase,
10591        window: &mut Window,
10592        cx: &mut Context<Self>,
10593    ) {
10594        self.manipulate_text(window, cx, |text| {
10595            text.split('\n')
10596                .map(|line| line.to_case(Case::Title))
10597                .join("\n")
10598        })
10599    }
10600
10601    pub fn convert_to_snake_case(
10602        &mut self,
10603        _: &ConvertToSnakeCase,
10604        window: &mut Window,
10605        cx: &mut Context<Self>,
10606    ) {
10607        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10608    }
10609
10610    pub fn convert_to_kebab_case(
10611        &mut self,
10612        _: &ConvertToKebabCase,
10613        window: &mut Window,
10614        cx: &mut Context<Self>,
10615    ) {
10616        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10617    }
10618
10619    pub fn convert_to_upper_camel_case(
10620        &mut self,
10621        _: &ConvertToUpperCamelCase,
10622        window: &mut Window,
10623        cx: &mut Context<Self>,
10624    ) {
10625        self.manipulate_text(window, cx, |text| {
10626            text.split('\n')
10627                .map(|line| line.to_case(Case::UpperCamel))
10628                .join("\n")
10629        })
10630    }
10631
10632    pub fn convert_to_lower_camel_case(
10633        &mut self,
10634        _: &ConvertToLowerCamelCase,
10635        window: &mut Window,
10636        cx: &mut Context<Self>,
10637    ) {
10638        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10639    }
10640
10641    pub fn convert_to_opposite_case(
10642        &mut self,
10643        _: &ConvertToOppositeCase,
10644        window: &mut Window,
10645        cx: &mut Context<Self>,
10646    ) {
10647        self.manipulate_text(window, cx, |text| {
10648            text.chars()
10649                .fold(String::with_capacity(text.len()), |mut t, c| {
10650                    if c.is_uppercase() {
10651                        t.extend(c.to_lowercase());
10652                    } else {
10653                        t.extend(c.to_uppercase());
10654                    }
10655                    t
10656                })
10657        })
10658    }
10659
10660    pub fn convert_to_rot13(
10661        &mut self,
10662        _: &ConvertToRot13,
10663        window: &mut Window,
10664        cx: &mut Context<Self>,
10665    ) {
10666        self.manipulate_text(window, cx, |text| {
10667            text.chars()
10668                .map(|c| match c {
10669                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10670                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10671                    _ => c,
10672                })
10673                .collect()
10674        })
10675    }
10676
10677    pub fn convert_to_rot47(
10678        &mut self,
10679        _: &ConvertToRot47,
10680        window: &mut Window,
10681        cx: &mut Context<Self>,
10682    ) {
10683        self.manipulate_text(window, cx, |text| {
10684            text.chars()
10685                .map(|c| {
10686                    let code_point = c as u32;
10687                    if code_point >= 33 && code_point <= 126 {
10688                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10689                    }
10690                    c
10691                })
10692                .collect()
10693        })
10694    }
10695
10696    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10697    where
10698        Fn: FnMut(&str) -> String,
10699    {
10700        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10701        let buffer = self.buffer.read(cx).snapshot(cx);
10702
10703        let mut new_selections = Vec::new();
10704        let mut edits = Vec::new();
10705        let mut selection_adjustment = 0i32;
10706
10707        for selection in self.selections.all::<usize>(cx) {
10708            let selection_is_empty = selection.is_empty();
10709
10710            let (start, end) = if selection_is_empty {
10711                let word_range = movement::surrounding_word(
10712                    &display_map,
10713                    selection.start.to_display_point(&display_map),
10714                );
10715                let start = word_range.start.to_offset(&display_map, Bias::Left);
10716                let end = word_range.end.to_offset(&display_map, Bias::Left);
10717                (start, end)
10718            } else {
10719                (selection.start, selection.end)
10720            };
10721
10722            let text = buffer.text_for_range(start..end).collect::<String>();
10723            let old_length = text.len() as i32;
10724            let text = callback(&text);
10725
10726            new_selections.push(Selection {
10727                start: (start as i32 - selection_adjustment) as usize,
10728                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10729                goal: SelectionGoal::None,
10730                ..selection
10731            });
10732
10733            selection_adjustment += old_length - text.len() as i32;
10734
10735            edits.push((start..end, text));
10736        }
10737
10738        self.transact(window, cx, |this, window, cx| {
10739            this.buffer.update(cx, |buffer, cx| {
10740                buffer.edit(edits, None, cx);
10741            });
10742
10743            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10744                s.select(new_selections);
10745            });
10746
10747            this.request_autoscroll(Autoscroll::fit(), cx);
10748        });
10749    }
10750
10751    pub fn move_selection_on_drop(
10752        &mut self,
10753        selection: &Selection<Anchor>,
10754        target: DisplayPoint,
10755        is_cut: bool,
10756        window: &mut Window,
10757        cx: &mut Context<Self>,
10758    ) {
10759        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10760        let buffer = &display_map.buffer_snapshot;
10761        let mut edits = Vec::new();
10762        let insert_point = display_map
10763            .clip_point(target, Bias::Left)
10764            .to_point(&display_map);
10765        let text = buffer
10766            .text_for_range(selection.start..selection.end)
10767            .collect::<String>();
10768        if is_cut {
10769            edits.push(((selection.start..selection.end), String::new()));
10770        }
10771        let insert_anchor = buffer.anchor_before(insert_point);
10772        edits.push(((insert_anchor..insert_anchor), text));
10773        let last_edit_start = insert_anchor.bias_left(buffer);
10774        let last_edit_end = insert_anchor.bias_right(buffer);
10775        self.transact(window, cx, |this, window, cx| {
10776            this.buffer.update(cx, |buffer, cx| {
10777                buffer.edit(edits, None, cx);
10778            });
10779            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10780                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10781            });
10782        });
10783    }
10784
10785    pub fn clear_selection_drag_state(&mut self) {
10786        self.selection_drag_state = SelectionDragState::None;
10787    }
10788
10789    pub fn duplicate(
10790        &mut self,
10791        upwards: bool,
10792        whole_lines: bool,
10793        window: &mut Window,
10794        cx: &mut Context<Self>,
10795    ) {
10796        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10797
10798        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10799        let buffer = &display_map.buffer_snapshot;
10800        let selections = self.selections.all::<Point>(cx);
10801
10802        let mut edits = Vec::new();
10803        let mut selections_iter = selections.iter().peekable();
10804        while let Some(selection) = selections_iter.next() {
10805            let mut rows = selection.spanned_rows(false, &display_map);
10806            // duplicate line-wise
10807            if whole_lines || selection.start == selection.end {
10808                // Avoid duplicating the same lines twice.
10809                while let Some(next_selection) = selections_iter.peek() {
10810                    let next_rows = next_selection.spanned_rows(false, &display_map);
10811                    if next_rows.start < rows.end {
10812                        rows.end = next_rows.end;
10813                        selections_iter.next().unwrap();
10814                    } else {
10815                        break;
10816                    }
10817                }
10818
10819                // Copy the text from the selected row region and splice it either at the start
10820                // or end of the region.
10821                let start = Point::new(rows.start.0, 0);
10822                let end = Point::new(
10823                    rows.end.previous_row().0,
10824                    buffer.line_len(rows.end.previous_row()),
10825                );
10826                let text = buffer
10827                    .text_for_range(start..end)
10828                    .chain(Some("\n"))
10829                    .collect::<String>();
10830                let insert_location = if upwards {
10831                    Point::new(rows.end.0, 0)
10832                } else {
10833                    start
10834                };
10835                edits.push((insert_location..insert_location, text));
10836            } else {
10837                // duplicate character-wise
10838                let start = selection.start;
10839                let end = selection.end;
10840                let text = buffer.text_for_range(start..end).collect::<String>();
10841                edits.push((selection.end..selection.end, text));
10842            }
10843        }
10844
10845        self.transact(window, cx, |this, _, cx| {
10846            this.buffer.update(cx, |buffer, cx| {
10847                buffer.edit(edits, None, cx);
10848            });
10849
10850            this.request_autoscroll(Autoscroll::fit(), cx);
10851        });
10852    }
10853
10854    pub fn duplicate_line_up(
10855        &mut self,
10856        _: &DuplicateLineUp,
10857        window: &mut Window,
10858        cx: &mut Context<Self>,
10859    ) {
10860        self.duplicate(true, true, window, cx);
10861    }
10862
10863    pub fn duplicate_line_down(
10864        &mut self,
10865        _: &DuplicateLineDown,
10866        window: &mut Window,
10867        cx: &mut Context<Self>,
10868    ) {
10869        self.duplicate(false, true, window, cx);
10870    }
10871
10872    pub fn duplicate_selection(
10873        &mut self,
10874        _: &DuplicateSelection,
10875        window: &mut Window,
10876        cx: &mut Context<Self>,
10877    ) {
10878        self.duplicate(false, false, window, cx);
10879    }
10880
10881    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10882        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10883
10884        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10885        let buffer = self.buffer.read(cx).snapshot(cx);
10886
10887        let mut edits = Vec::new();
10888        let mut unfold_ranges = Vec::new();
10889        let mut refold_creases = Vec::new();
10890
10891        let selections = self.selections.all::<Point>(cx);
10892        let mut selections = selections.iter().peekable();
10893        let mut contiguous_row_selections = Vec::new();
10894        let mut new_selections = Vec::new();
10895
10896        while let Some(selection) = selections.next() {
10897            // Find all the selections that span a contiguous row range
10898            let (start_row, end_row) = consume_contiguous_rows(
10899                &mut contiguous_row_selections,
10900                selection,
10901                &display_map,
10902                &mut selections,
10903            );
10904
10905            // Move the text spanned by the row range to be before the line preceding the row range
10906            if start_row.0 > 0 {
10907                let range_to_move = Point::new(
10908                    start_row.previous_row().0,
10909                    buffer.line_len(start_row.previous_row()),
10910                )
10911                    ..Point::new(
10912                        end_row.previous_row().0,
10913                        buffer.line_len(end_row.previous_row()),
10914                    );
10915                let insertion_point = display_map
10916                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10917                    .0;
10918
10919                // Don't move lines across excerpts
10920                if buffer
10921                    .excerpt_containing(insertion_point..range_to_move.end)
10922                    .is_some()
10923                {
10924                    let text = buffer
10925                        .text_for_range(range_to_move.clone())
10926                        .flat_map(|s| s.chars())
10927                        .skip(1)
10928                        .chain(['\n'])
10929                        .collect::<String>();
10930
10931                    edits.push((
10932                        buffer.anchor_after(range_to_move.start)
10933                            ..buffer.anchor_before(range_to_move.end),
10934                        String::new(),
10935                    ));
10936                    let insertion_anchor = buffer.anchor_after(insertion_point);
10937                    edits.push((insertion_anchor..insertion_anchor, text));
10938
10939                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10940
10941                    // Move selections up
10942                    new_selections.extend(contiguous_row_selections.drain(..).map(
10943                        |mut selection| {
10944                            selection.start.row -= row_delta;
10945                            selection.end.row -= row_delta;
10946                            selection
10947                        },
10948                    ));
10949
10950                    // Move folds up
10951                    unfold_ranges.push(range_to_move.clone());
10952                    for fold in display_map.folds_in_range(
10953                        buffer.anchor_before(range_to_move.start)
10954                            ..buffer.anchor_after(range_to_move.end),
10955                    ) {
10956                        let mut start = fold.range.start.to_point(&buffer);
10957                        let mut end = fold.range.end.to_point(&buffer);
10958                        start.row -= row_delta;
10959                        end.row -= row_delta;
10960                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10961                    }
10962                }
10963            }
10964
10965            // If we didn't move line(s), preserve the existing selections
10966            new_selections.append(&mut contiguous_row_selections);
10967        }
10968
10969        self.transact(window, cx, |this, window, cx| {
10970            this.unfold_ranges(&unfold_ranges, true, true, cx);
10971            this.buffer.update(cx, |buffer, cx| {
10972                for (range, text) in edits {
10973                    buffer.edit([(range, text)], None, cx);
10974                }
10975            });
10976            this.fold_creases(refold_creases, true, window, cx);
10977            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10978                s.select(new_selections);
10979            })
10980        });
10981    }
10982
10983    pub fn move_line_down(
10984        &mut self,
10985        _: &MoveLineDown,
10986        window: &mut Window,
10987        cx: &mut Context<Self>,
10988    ) {
10989        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10990
10991        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10992        let buffer = self.buffer.read(cx).snapshot(cx);
10993
10994        let mut edits = Vec::new();
10995        let mut unfold_ranges = Vec::new();
10996        let mut refold_creases = Vec::new();
10997
10998        let selections = self.selections.all::<Point>(cx);
10999        let mut selections = selections.iter().peekable();
11000        let mut contiguous_row_selections = Vec::new();
11001        let mut new_selections = Vec::new();
11002
11003        while let Some(selection) = selections.next() {
11004            // Find all the selections that span a contiguous row range
11005            let (start_row, end_row) = consume_contiguous_rows(
11006                &mut contiguous_row_selections,
11007                selection,
11008                &display_map,
11009                &mut selections,
11010            );
11011
11012            // Move the text spanned by the row range to be after the last line of the row range
11013            if end_row.0 <= buffer.max_point().row {
11014                let range_to_move =
11015                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11016                let insertion_point = display_map
11017                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11018                    .0;
11019
11020                // Don't move lines across excerpt boundaries
11021                if buffer
11022                    .excerpt_containing(range_to_move.start..insertion_point)
11023                    .is_some()
11024                {
11025                    let mut text = String::from("\n");
11026                    text.extend(buffer.text_for_range(range_to_move.clone()));
11027                    text.pop(); // Drop trailing newline
11028                    edits.push((
11029                        buffer.anchor_after(range_to_move.start)
11030                            ..buffer.anchor_before(range_to_move.end),
11031                        String::new(),
11032                    ));
11033                    let insertion_anchor = buffer.anchor_after(insertion_point);
11034                    edits.push((insertion_anchor..insertion_anchor, text));
11035
11036                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11037
11038                    // Move selections down
11039                    new_selections.extend(contiguous_row_selections.drain(..).map(
11040                        |mut selection| {
11041                            selection.start.row += row_delta;
11042                            selection.end.row += row_delta;
11043                            selection
11044                        },
11045                    ));
11046
11047                    // Move folds down
11048                    unfold_ranges.push(range_to_move.clone());
11049                    for fold in display_map.folds_in_range(
11050                        buffer.anchor_before(range_to_move.start)
11051                            ..buffer.anchor_after(range_to_move.end),
11052                    ) {
11053                        let mut start = fold.range.start.to_point(&buffer);
11054                        let mut end = fold.range.end.to_point(&buffer);
11055                        start.row += row_delta;
11056                        end.row += row_delta;
11057                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11058                    }
11059                }
11060            }
11061
11062            // If we didn't move line(s), preserve the existing selections
11063            new_selections.append(&mut contiguous_row_selections);
11064        }
11065
11066        self.transact(window, cx, |this, window, cx| {
11067            this.unfold_ranges(&unfold_ranges, true, true, cx);
11068            this.buffer.update(cx, |buffer, cx| {
11069                for (range, text) in edits {
11070                    buffer.edit([(range, text)], None, cx);
11071                }
11072            });
11073            this.fold_creases(refold_creases, true, window, cx);
11074            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11075                s.select(new_selections)
11076            });
11077        });
11078    }
11079
11080    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11081        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11082        let text_layout_details = &self.text_layout_details(window);
11083        self.transact(window, cx, |this, window, cx| {
11084            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11085                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11086                s.move_with(|display_map, selection| {
11087                    if !selection.is_empty() {
11088                        return;
11089                    }
11090
11091                    let mut head = selection.head();
11092                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11093                    if head.column() == display_map.line_len(head.row()) {
11094                        transpose_offset = display_map
11095                            .buffer_snapshot
11096                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11097                    }
11098
11099                    if transpose_offset == 0 {
11100                        return;
11101                    }
11102
11103                    *head.column_mut() += 1;
11104                    head = display_map.clip_point(head, Bias::Right);
11105                    let goal = SelectionGoal::HorizontalPosition(
11106                        display_map
11107                            .x_for_display_point(head, text_layout_details)
11108                            .into(),
11109                    );
11110                    selection.collapse_to(head, goal);
11111
11112                    let transpose_start = display_map
11113                        .buffer_snapshot
11114                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11115                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11116                        let transpose_end = display_map
11117                            .buffer_snapshot
11118                            .clip_offset(transpose_offset + 1, Bias::Right);
11119                        if let Some(ch) =
11120                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11121                        {
11122                            edits.push((transpose_start..transpose_offset, String::new()));
11123                            edits.push((transpose_end..transpose_end, ch.to_string()));
11124                        }
11125                    }
11126                });
11127                edits
11128            });
11129            this.buffer
11130                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11131            let selections = this.selections.all::<usize>(cx);
11132            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11133                s.select(selections);
11134            });
11135        });
11136    }
11137
11138    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11139        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11140        self.rewrap_impl(RewrapOptions::default(), cx)
11141    }
11142
11143    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11144        let buffer = self.buffer.read(cx).snapshot(cx);
11145        let selections = self.selections.all::<Point>(cx);
11146
11147        // Shrink and split selections to respect paragraph boundaries.
11148        let ranges = selections.into_iter().flat_map(|selection| {
11149            let language_settings = buffer.language_settings_at(selection.head(), cx);
11150            let language_scope = buffer.language_scope_at(selection.head());
11151
11152            let Some(start_row) = (selection.start.row..=selection.end.row)
11153                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11154            else {
11155                return vec![];
11156            };
11157            let Some(end_row) = (selection.start.row..=selection.end.row)
11158                .rev()
11159                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11160            else {
11161                return vec![];
11162            };
11163
11164            let mut row = start_row;
11165            let mut ranges = Vec::new();
11166            while let Some(blank_row) =
11167                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11168            {
11169                let next_paragraph_start = (blank_row + 1..=end_row)
11170                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11171                    .unwrap();
11172                ranges.push((
11173                    language_settings.clone(),
11174                    language_scope.clone(),
11175                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11176                ));
11177                row = next_paragraph_start;
11178            }
11179            ranges.push((
11180                language_settings.clone(),
11181                language_scope.clone(),
11182                Point::new(row, 0)..Point::new(end_row, 0),
11183            ));
11184
11185            ranges
11186        });
11187
11188        let mut edits = Vec::new();
11189        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11190
11191        for (language_settings, language_scope, range) in ranges {
11192            let mut start_row = range.start.row;
11193            let mut end_row = range.end.row;
11194
11195            // Skip selections that overlap with a range that has already been rewrapped.
11196            let selection_range = start_row..end_row;
11197            if rewrapped_row_ranges
11198                .iter()
11199                .any(|range| range.overlaps(&selection_range))
11200            {
11201                continue;
11202            }
11203
11204            let tab_size = language_settings.tab_size;
11205
11206            // Since not all lines in the selection may be at the same indent
11207            // level, choose the indent size that is the most common between all
11208            // of the lines.
11209            //
11210            // If there is a tie, we use the deepest indent.
11211            let (indent_size, indent_end) = {
11212                let mut indent_size_occurrences = HashMap::default();
11213                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11214
11215                for row in start_row..=end_row {
11216                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11217                    rows_by_indent_size.entry(indent).or_default().push(row);
11218                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11219                }
11220
11221                let indent_size = indent_size_occurrences
11222                    .into_iter()
11223                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11224                    .map(|(indent, _)| indent)
11225                    .unwrap_or_default();
11226                let row = rows_by_indent_size[&indent_size][0];
11227                let indent_end = Point::new(row, indent_size.len);
11228
11229                (indent_size, indent_end)
11230            };
11231
11232            let mut line_prefix = indent_size.chars().collect::<String>();
11233
11234            let mut inside_comment = false;
11235            if let Some(comment_prefix) = language_scope.and_then(|language| {
11236                language
11237                    .line_comment_prefixes()
11238                    .iter()
11239                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11240                    .cloned()
11241            }) {
11242                line_prefix.push_str(&comment_prefix);
11243                inside_comment = true;
11244            }
11245
11246            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11247                RewrapBehavior::InComments => inside_comment,
11248                RewrapBehavior::InSelections => !range.is_empty(),
11249                RewrapBehavior::Anywhere => true,
11250            };
11251
11252            let should_rewrap = options.override_language_settings
11253                || allow_rewrap_based_on_language
11254                || self.hard_wrap.is_some();
11255            if !should_rewrap {
11256                continue;
11257            }
11258
11259            if range.is_empty() {
11260                'expand_upwards: while start_row > 0 {
11261                    let prev_row = start_row - 1;
11262                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11263                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11264                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11265                    {
11266                        start_row = prev_row;
11267                    } else {
11268                        break 'expand_upwards;
11269                    }
11270                }
11271
11272                'expand_downwards: while end_row < buffer.max_point().row {
11273                    let next_row = end_row + 1;
11274                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11275                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11276                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11277                    {
11278                        end_row = next_row;
11279                    } else {
11280                        break 'expand_downwards;
11281                    }
11282                }
11283            }
11284
11285            let start = Point::new(start_row, 0);
11286            let start_offset = start.to_offset(&buffer);
11287            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11288            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11289            let Some(lines_without_prefixes) = selection_text
11290                .lines()
11291                .map(|line| {
11292                    line.strip_prefix(&line_prefix)
11293                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11294                        .with_context(|| {
11295                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11296                        })
11297                })
11298                .collect::<Result<Vec<_>, _>>()
11299                .log_err()
11300            else {
11301                continue;
11302            };
11303
11304            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11305                buffer
11306                    .language_settings_at(Point::new(start_row, 0), cx)
11307                    .preferred_line_length as usize
11308            });
11309            let wrapped_text = wrap_with_prefix(
11310                line_prefix,
11311                lines_without_prefixes.join("\n"),
11312                wrap_column,
11313                tab_size,
11314                options.preserve_existing_whitespace,
11315            );
11316
11317            // TODO: should always use char-based diff while still supporting cursor behavior that
11318            // matches vim.
11319            let mut diff_options = DiffOptions::default();
11320            if options.override_language_settings {
11321                diff_options.max_word_diff_len = 0;
11322                diff_options.max_word_diff_line_count = 0;
11323            } else {
11324                diff_options.max_word_diff_len = usize::MAX;
11325                diff_options.max_word_diff_line_count = usize::MAX;
11326            }
11327
11328            for (old_range, new_text) in
11329                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11330            {
11331                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11332                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11333                edits.push((edit_start..edit_end, new_text));
11334            }
11335
11336            rewrapped_row_ranges.push(start_row..=end_row);
11337        }
11338
11339        self.buffer
11340            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11341    }
11342
11343    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11344        let mut text = String::new();
11345        let buffer = self.buffer.read(cx).snapshot(cx);
11346        let mut selections = self.selections.all::<Point>(cx);
11347        let mut clipboard_selections = Vec::with_capacity(selections.len());
11348        {
11349            let max_point = buffer.max_point();
11350            let mut is_first = true;
11351            for selection in &mut selections {
11352                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11353                if is_entire_line {
11354                    selection.start = Point::new(selection.start.row, 0);
11355                    if !selection.is_empty() && selection.end.column == 0 {
11356                        selection.end = cmp::min(max_point, selection.end);
11357                    } else {
11358                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11359                    }
11360                    selection.goal = SelectionGoal::None;
11361                }
11362                if is_first {
11363                    is_first = false;
11364                } else {
11365                    text += "\n";
11366                }
11367                let mut len = 0;
11368                for chunk in buffer.text_for_range(selection.start..selection.end) {
11369                    text.push_str(chunk);
11370                    len += chunk.len();
11371                }
11372                clipboard_selections.push(ClipboardSelection {
11373                    len,
11374                    is_entire_line,
11375                    first_line_indent: buffer
11376                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11377                        .len,
11378                });
11379            }
11380        }
11381
11382        self.transact(window, cx, |this, window, cx| {
11383            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11384                s.select(selections);
11385            });
11386            this.insert("", window, cx);
11387        });
11388        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11389    }
11390
11391    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11392        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11393        let item = self.cut_common(window, cx);
11394        cx.write_to_clipboard(item);
11395    }
11396
11397    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11398        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11399        self.change_selections(None, window, cx, |s| {
11400            s.move_with(|snapshot, sel| {
11401                if sel.is_empty() {
11402                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11403                }
11404            });
11405        });
11406        let item = self.cut_common(window, cx);
11407        cx.set_global(KillRing(item))
11408    }
11409
11410    pub fn kill_ring_yank(
11411        &mut self,
11412        _: &KillRingYank,
11413        window: &mut Window,
11414        cx: &mut Context<Self>,
11415    ) {
11416        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11417        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11418            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11419                (kill_ring.text().to_string(), kill_ring.metadata_json())
11420            } else {
11421                return;
11422            }
11423        } else {
11424            return;
11425        };
11426        self.do_paste(&text, metadata, false, window, cx);
11427    }
11428
11429    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11430        self.do_copy(true, cx);
11431    }
11432
11433    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11434        self.do_copy(false, cx);
11435    }
11436
11437    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11438        let selections = self.selections.all::<Point>(cx);
11439        let buffer = self.buffer.read(cx).read(cx);
11440        let mut text = String::new();
11441
11442        let mut clipboard_selections = Vec::with_capacity(selections.len());
11443        {
11444            let max_point = buffer.max_point();
11445            let mut is_first = true;
11446            for selection in &selections {
11447                let mut start = selection.start;
11448                let mut end = selection.end;
11449                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11450                if is_entire_line {
11451                    start = Point::new(start.row, 0);
11452                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11453                }
11454
11455                let mut trimmed_selections = Vec::new();
11456                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11457                    let row = MultiBufferRow(start.row);
11458                    let first_indent = buffer.indent_size_for_line(row);
11459                    if first_indent.len == 0 || start.column > first_indent.len {
11460                        trimmed_selections.push(start..end);
11461                    } else {
11462                        trimmed_selections.push(
11463                            Point::new(row.0, first_indent.len)
11464                                ..Point::new(row.0, buffer.line_len(row)),
11465                        );
11466                        for row in start.row + 1..=end.row {
11467                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11468                            if row == end.row {
11469                                line_len = end.column;
11470                            }
11471                            if line_len == 0 {
11472                                trimmed_selections
11473                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11474                                continue;
11475                            }
11476                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11477                            if row_indent_size.len >= first_indent.len {
11478                                trimmed_selections.push(
11479                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11480                                );
11481                            } else {
11482                                trimmed_selections.clear();
11483                                trimmed_selections.push(start..end);
11484                                break;
11485                            }
11486                        }
11487                    }
11488                } else {
11489                    trimmed_selections.push(start..end);
11490                }
11491
11492                for trimmed_range in trimmed_selections {
11493                    if is_first {
11494                        is_first = false;
11495                    } else {
11496                        text += "\n";
11497                    }
11498                    let mut len = 0;
11499                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11500                        text.push_str(chunk);
11501                        len += chunk.len();
11502                    }
11503                    clipboard_selections.push(ClipboardSelection {
11504                        len,
11505                        is_entire_line,
11506                        first_line_indent: buffer
11507                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11508                            .len,
11509                    });
11510                }
11511            }
11512        }
11513
11514        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11515            text,
11516            clipboard_selections,
11517        ));
11518    }
11519
11520    pub fn do_paste(
11521        &mut self,
11522        text: &String,
11523        clipboard_selections: Option<Vec<ClipboardSelection>>,
11524        handle_entire_lines: bool,
11525        window: &mut Window,
11526        cx: &mut Context<Self>,
11527    ) {
11528        if self.read_only(cx) {
11529            return;
11530        }
11531
11532        let clipboard_text = Cow::Borrowed(text);
11533
11534        self.transact(window, cx, |this, window, cx| {
11535            if let Some(mut clipboard_selections) = clipboard_selections {
11536                let old_selections = this.selections.all::<usize>(cx);
11537                let all_selections_were_entire_line =
11538                    clipboard_selections.iter().all(|s| s.is_entire_line);
11539                let first_selection_indent_column =
11540                    clipboard_selections.first().map(|s| s.first_line_indent);
11541                if clipboard_selections.len() != old_selections.len() {
11542                    clipboard_selections.drain(..);
11543                }
11544                let cursor_offset = this.selections.last::<usize>(cx).head();
11545                let mut auto_indent_on_paste = true;
11546
11547                this.buffer.update(cx, |buffer, cx| {
11548                    let snapshot = buffer.read(cx);
11549                    auto_indent_on_paste = snapshot
11550                        .language_settings_at(cursor_offset, cx)
11551                        .auto_indent_on_paste;
11552
11553                    let mut start_offset = 0;
11554                    let mut edits = Vec::new();
11555                    let mut original_indent_columns = Vec::new();
11556                    for (ix, selection) in old_selections.iter().enumerate() {
11557                        let to_insert;
11558                        let entire_line;
11559                        let original_indent_column;
11560                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11561                            let end_offset = start_offset + clipboard_selection.len;
11562                            to_insert = &clipboard_text[start_offset..end_offset];
11563                            entire_line = clipboard_selection.is_entire_line;
11564                            start_offset = end_offset + 1;
11565                            original_indent_column = Some(clipboard_selection.first_line_indent);
11566                        } else {
11567                            to_insert = clipboard_text.as_str();
11568                            entire_line = all_selections_were_entire_line;
11569                            original_indent_column = first_selection_indent_column
11570                        }
11571
11572                        // If the corresponding selection was empty when this slice of the
11573                        // clipboard text was written, then the entire line containing the
11574                        // selection was copied. If this selection is also currently empty,
11575                        // then paste the line before the current line of the buffer.
11576                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11577                            let column = selection.start.to_point(&snapshot).column as usize;
11578                            let line_start = selection.start - column;
11579                            line_start..line_start
11580                        } else {
11581                            selection.range()
11582                        };
11583
11584                        edits.push((range, to_insert));
11585                        original_indent_columns.push(original_indent_column);
11586                    }
11587                    drop(snapshot);
11588
11589                    buffer.edit(
11590                        edits,
11591                        if auto_indent_on_paste {
11592                            Some(AutoindentMode::Block {
11593                                original_indent_columns,
11594                            })
11595                        } else {
11596                            None
11597                        },
11598                        cx,
11599                    );
11600                });
11601
11602                let selections = this.selections.all::<usize>(cx);
11603                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11604                    s.select(selections)
11605                });
11606            } else {
11607                this.insert(&clipboard_text, window, cx);
11608            }
11609        });
11610    }
11611
11612    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11613        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11614        if let Some(item) = cx.read_from_clipboard() {
11615            let entries = item.entries();
11616
11617            match entries.first() {
11618                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11619                // of all the pasted entries.
11620                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11621                    .do_paste(
11622                        clipboard_string.text(),
11623                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11624                        true,
11625                        window,
11626                        cx,
11627                    ),
11628                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11629            }
11630        }
11631    }
11632
11633    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11634        if self.read_only(cx) {
11635            return;
11636        }
11637
11638        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11639
11640        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11641            if let Some((selections, _)) =
11642                self.selection_history.transaction(transaction_id).cloned()
11643            {
11644                self.change_selections(None, window, cx, |s| {
11645                    s.select_anchors(selections.to_vec());
11646                });
11647            } else {
11648                log::error!(
11649                    "No entry in selection_history found for undo. \
11650                     This may correspond to a bug where undo does not update the selection. \
11651                     If this is occurring, please add details to \
11652                     https://github.com/zed-industries/zed/issues/22692"
11653                );
11654            }
11655            self.request_autoscroll(Autoscroll::fit(), cx);
11656            self.unmark_text(window, cx);
11657            self.refresh_inline_completion(true, false, window, cx);
11658            cx.emit(EditorEvent::Edited { transaction_id });
11659            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11660        }
11661    }
11662
11663    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11664        if self.read_only(cx) {
11665            return;
11666        }
11667
11668        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11669
11670        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11671            if let Some((_, Some(selections))) =
11672                self.selection_history.transaction(transaction_id).cloned()
11673            {
11674                self.change_selections(None, window, cx, |s| {
11675                    s.select_anchors(selections.to_vec());
11676                });
11677            } else {
11678                log::error!(
11679                    "No entry in selection_history found for redo. \
11680                     This may correspond to a bug where undo does not update the selection. \
11681                     If this is occurring, please add details to \
11682                     https://github.com/zed-industries/zed/issues/22692"
11683                );
11684            }
11685            self.request_autoscroll(Autoscroll::fit(), cx);
11686            self.unmark_text(window, cx);
11687            self.refresh_inline_completion(true, false, window, cx);
11688            cx.emit(EditorEvent::Edited { transaction_id });
11689        }
11690    }
11691
11692    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11693        self.buffer
11694            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11695    }
11696
11697    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11698        self.buffer
11699            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11700    }
11701
11702    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11703        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11704        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11705            s.move_with(|map, selection| {
11706                let cursor = if selection.is_empty() {
11707                    movement::left(map, selection.start)
11708                } else {
11709                    selection.start
11710                };
11711                selection.collapse_to(cursor, SelectionGoal::None);
11712            });
11713        })
11714    }
11715
11716    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11717        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11718        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11719            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11720        })
11721    }
11722
11723    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11724        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11725        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11726            s.move_with(|map, selection| {
11727                let cursor = if selection.is_empty() {
11728                    movement::right(map, selection.end)
11729                } else {
11730                    selection.end
11731                };
11732                selection.collapse_to(cursor, SelectionGoal::None)
11733            });
11734        })
11735    }
11736
11737    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11738        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11739        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11740            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11741        })
11742    }
11743
11744    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11745        if self.take_rename(true, window, cx).is_some() {
11746            return;
11747        }
11748
11749        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11750            cx.propagate();
11751            return;
11752        }
11753
11754        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11755
11756        let text_layout_details = &self.text_layout_details(window);
11757        let selection_count = self.selections.count();
11758        let first_selection = self.selections.first_anchor();
11759
11760        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11761            s.move_with(|map, selection| {
11762                if !selection.is_empty() {
11763                    selection.goal = SelectionGoal::None;
11764                }
11765                let (cursor, goal) = movement::up(
11766                    map,
11767                    selection.start,
11768                    selection.goal,
11769                    false,
11770                    text_layout_details,
11771                );
11772                selection.collapse_to(cursor, goal);
11773            });
11774        });
11775
11776        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11777        {
11778            cx.propagate();
11779        }
11780    }
11781
11782    pub fn move_up_by_lines(
11783        &mut self,
11784        action: &MoveUpByLines,
11785        window: &mut Window,
11786        cx: &mut Context<Self>,
11787    ) {
11788        if self.take_rename(true, window, cx).is_some() {
11789            return;
11790        }
11791
11792        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11793            cx.propagate();
11794            return;
11795        }
11796
11797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11798
11799        let text_layout_details = &self.text_layout_details(window);
11800
11801        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11802            s.move_with(|map, selection| {
11803                if !selection.is_empty() {
11804                    selection.goal = SelectionGoal::None;
11805                }
11806                let (cursor, goal) = movement::up_by_rows(
11807                    map,
11808                    selection.start,
11809                    action.lines,
11810                    selection.goal,
11811                    false,
11812                    text_layout_details,
11813                );
11814                selection.collapse_to(cursor, goal);
11815            });
11816        })
11817    }
11818
11819    pub fn move_down_by_lines(
11820        &mut self,
11821        action: &MoveDownByLines,
11822        window: &mut Window,
11823        cx: &mut Context<Self>,
11824    ) {
11825        if self.take_rename(true, window, cx).is_some() {
11826            return;
11827        }
11828
11829        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11830            cx.propagate();
11831            return;
11832        }
11833
11834        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11835
11836        let text_layout_details = &self.text_layout_details(window);
11837
11838        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11839            s.move_with(|map, selection| {
11840                if !selection.is_empty() {
11841                    selection.goal = SelectionGoal::None;
11842                }
11843                let (cursor, goal) = movement::down_by_rows(
11844                    map,
11845                    selection.start,
11846                    action.lines,
11847                    selection.goal,
11848                    false,
11849                    text_layout_details,
11850                );
11851                selection.collapse_to(cursor, goal);
11852            });
11853        })
11854    }
11855
11856    pub fn select_down_by_lines(
11857        &mut self,
11858        action: &SelectDownByLines,
11859        window: &mut Window,
11860        cx: &mut Context<Self>,
11861    ) {
11862        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11863        let text_layout_details = &self.text_layout_details(window);
11864        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11865            s.move_heads_with(|map, head, goal| {
11866                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11867            })
11868        })
11869    }
11870
11871    pub fn select_up_by_lines(
11872        &mut self,
11873        action: &SelectUpByLines,
11874        window: &mut Window,
11875        cx: &mut Context<Self>,
11876    ) {
11877        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11878        let text_layout_details = &self.text_layout_details(window);
11879        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11880            s.move_heads_with(|map, head, goal| {
11881                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11882            })
11883        })
11884    }
11885
11886    pub fn select_page_up(
11887        &mut self,
11888        _: &SelectPageUp,
11889        window: &mut Window,
11890        cx: &mut Context<Self>,
11891    ) {
11892        let Some(row_count) = self.visible_row_count() else {
11893            return;
11894        };
11895
11896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11897
11898        let text_layout_details = &self.text_layout_details(window);
11899
11900        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11901            s.move_heads_with(|map, head, goal| {
11902                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11903            })
11904        })
11905    }
11906
11907    pub fn move_page_up(
11908        &mut self,
11909        action: &MovePageUp,
11910        window: &mut Window,
11911        cx: &mut Context<Self>,
11912    ) {
11913        if self.take_rename(true, window, cx).is_some() {
11914            return;
11915        }
11916
11917        if self
11918            .context_menu
11919            .borrow_mut()
11920            .as_mut()
11921            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11922            .unwrap_or(false)
11923        {
11924            return;
11925        }
11926
11927        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11928            cx.propagate();
11929            return;
11930        }
11931
11932        let Some(row_count) = self.visible_row_count() else {
11933            return;
11934        };
11935
11936        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11937
11938        let autoscroll = if action.center_cursor {
11939            Autoscroll::center()
11940        } else {
11941            Autoscroll::fit()
11942        };
11943
11944        let text_layout_details = &self.text_layout_details(window);
11945
11946        self.change_selections(Some(autoscroll), window, cx, |s| {
11947            s.move_with(|map, selection| {
11948                if !selection.is_empty() {
11949                    selection.goal = SelectionGoal::None;
11950                }
11951                let (cursor, goal) = movement::up_by_rows(
11952                    map,
11953                    selection.end,
11954                    row_count,
11955                    selection.goal,
11956                    false,
11957                    text_layout_details,
11958                );
11959                selection.collapse_to(cursor, goal);
11960            });
11961        });
11962    }
11963
11964    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11965        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11966        let text_layout_details = &self.text_layout_details(window);
11967        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11968            s.move_heads_with(|map, head, goal| {
11969                movement::up(map, head, goal, false, text_layout_details)
11970            })
11971        })
11972    }
11973
11974    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11975        self.take_rename(true, window, cx);
11976
11977        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11978            cx.propagate();
11979            return;
11980        }
11981
11982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11983
11984        let text_layout_details = &self.text_layout_details(window);
11985        let selection_count = self.selections.count();
11986        let first_selection = self.selections.first_anchor();
11987
11988        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11989            s.move_with(|map, selection| {
11990                if !selection.is_empty() {
11991                    selection.goal = SelectionGoal::None;
11992                }
11993                let (cursor, goal) = movement::down(
11994                    map,
11995                    selection.end,
11996                    selection.goal,
11997                    false,
11998                    text_layout_details,
11999                );
12000                selection.collapse_to(cursor, goal);
12001            });
12002        });
12003
12004        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12005        {
12006            cx.propagate();
12007        }
12008    }
12009
12010    pub fn select_page_down(
12011        &mut self,
12012        _: &SelectPageDown,
12013        window: &mut Window,
12014        cx: &mut Context<Self>,
12015    ) {
12016        let Some(row_count) = self.visible_row_count() else {
12017            return;
12018        };
12019
12020        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12021
12022        let text_layout_details = &self.text_layout_details(window);
12023
12024        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12025            s.move_heads_with(|map, head, goal| {
12026                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12027            })
12028        })
12029    }
12030
12031    pub fn move_page_down(
12032        &mut self,
12033        action: &MovePageDown,
12034        window: &mut Window,
12035        cx: &mut Context<Self>,
12036    ) {
12037        if self.take_rename(true, window, cx).is_some() {
12038            return;
12039        }
12040
12041        if self
12042            .context_menu
12043            .borrow_mut()
12044            .as_mut()
12045            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12046            .unwrap_or(false)
12047        {
12048            return;
12049        }
12050
12051        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12052            cx.propagate();
12053            return;
12054        }
12055
12056        let Some(row_count) = self.visible_row_count() else {
12057            return;
12058        };
12059
12060        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12061
12062        let autoscroll = if action.center_cursor {
12063            Autoscroll::center()
12064        } else {
12065            Autoscroll::fit()
12066        };
12067
12068        let text_layout_details = &self.text_layout_details(window);
12069        self.change_selections(Some(autoscroll), window, cx, |s| {
12070            s.move_with(|map, selection| {
12071                if !selection.is_empty() {
12072                    selection.goal = SelectionGoal::None;
12073                }
12074                let (cursor, goal) = movement::down_by_rows(
12075                    map,
12076                    selection.end,
12077                    row_count,
12078                    selection.goal,
12079                    false,
12080                    text_layout_details,
12081                );
12082                selection.collapse_to(cursor, goal);
12083            });
12084        });
12085    }
12086
12087    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12089        let text_layout_details = &self.text_layout_details(window);
12090        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12091            s.move_heads_with(|map, head, goal| {
12092                movement::down(map, head, goal, false, text_layout_details)
12093            })
12094        });
12095    }
12096
12097    pub fn context_menu_first(
12098        &mut self,
12099        _: &ContextMenuFirst,
12100        window: &mut Window,
12101        cx: &mut Context<Self>,
12102    ) {
12103        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12104            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12105        }
12106    }
12107
12108    pub fn context_menu_prev(
12109        &mut self,
12110        _: &ContextMenuPrevious,
12111        window: &mut Window,
12112        cx: &mut Context<Self>,
12113    ) {
12114        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12115            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12116        }
12117    }
12118
12119    pub fn context_menu_next(
12120        &mut self,
12121        _: &ContextMenuNext,
12122        window: &mut Window,
12123        cx: &mut Context<Self>,
12124    ) {
12125        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12126            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12127        }
12128    }
12129
12130    pub fn context_menu_last(
12131        &mut self,
12132        _: &ContextMenuLast,
12133        window: &mut Window,
12134        cx: &mut Context<Self>,
12135    ) {
12136        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12137            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12138        }
12139    }
12140
12141    pub fn move_to_previous_word_start(
12142        &mut self,
12143        _: &MoveToPreviousWordStart,
12144        window: &mut Window,
12145        cx: &mut Context<Self>,
12146    ) {
12147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12148        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12149            s.move_cursors_with(|map, head, _| {
12150                (
12151                    movement::previous_word_start(map, head),
12152                    SelectionGoal::None,
12153                )
12154            });
12155        })
12156    }
12157
12158    pub fn move_to_previous_subword_start(
12159        &mut self,
12160        _: &MoveToPreviousSubwordStart,
12161        window: &mut Window,
12162        cx: &mut Context<Self>,
12163    ) {
12164        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12165        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12166            s.move_cursors_with(|map, head, _| {
12167                (
12168                    movement::previous_subword_start(map, head),
12169                    SelectionGoal::None,
12170                )
12171            });
12172        })
12173    }
12174
12175    pub fn select_to_previous_word_start(
12176        &mut self,
12177        _: &SelectToPreviousWordStart,
12178        window: &mut Window,
12179        cx: &mut Context<Self>,
12180    ) {
12181        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12182        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12183            s.move_heads_with(|map, head, _| {
12184                (
12185                    movement::previous_word_start(map, head),
12186                    SelectionGoal::None,
12187                )
12188            });
12189        })
12190    }
12191
12192    pub fn select_to_previous_subword_start(
12193        &mut self,
12194        _: &SelectToPreviousSubwordStart,
12195        window: &mut Window,
12196        cx: &mut Context<Self>,
12197    ) {
12198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12199        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12200            s.move_heads_with(|map, head, _| {
12201                (
12202                    movement::previous_subword_start(map, head),
12203                    SelectionGoal::None,
12204                )
12205            });
12206        })
12207    }
12208
12209    pub fn delete_to_previous_word_start(
12210        &mut self,
12211        action: &DeleteToPreviousWordStart,
12212        window: &mut Window,
12213        cx: &mut Context<Self>,
12214    ) {
12215        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12216        self.transact(window, cx, |this, window, cx| {
12217            this.select_autoclose_pair(window, cx);
12218            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12219                s.move_with(|map, selection| {
12220                    if selection.is_empty() {
12221                        let cursor = if action.ignore_newlines {
12222                            movement::previous_word_start(map, selection.head())
12223                        } else {
12224                            movement::previous_word_start_or_newline(map, selection.head())
12225                        };
12226                        selection.set_head(cursor, SelectionGoal::None);
12227                    }
12228                });
12229            });
12230            this.insert("", window, cx);
12231        });
12232    }
12233
12234    pub fn delete_to_previous_subword_start(
12235        &mut self,
12236        _: &DeleteToPreviousSubwordStart,
12237        window: &mut Window,
12238        cx: &mut Context<Self>,
12239    ) {
12240        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12241        self.transact(window, cx, |this, window, cx| {
12242            this.select_autoclose_pair(window, cx);
12243            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12244                s.move_with(|map, selection| {
12245                    if selection.is_empty() {
12246                        let cursor = movement::previous_subword_start(map, selection.head());
12247                        selection.set_head(cursor, SelectionGoal::None);
12248                    }
12249                });
12250            });
12251            this.insert("", window, cx);
12252        });
12253    }
12254
12255    pub fn move_to_next_word_end(
12256        &mut self,
12257        _: &MoveToNextWordEnd,
12258        window: &mut Window,
12259        cx: &mut Context<Self>,
12260    ) {
12261        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12262        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12263            s.move_cursors_with(|map, head, _| {
12264                (movement::next_word_end(map, head), SelectionGoal::None)
12265            });
12266        })
12267    }
12268
12269    pub fn move_to_next_subword_end(
12270        &mut self,
12271        _: &MoveToNextSubwordEnd,
12272        window: &mut Window,
12273        cx: &mut Context<Self>,
12274    ) {
12275        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12276        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12277            s.move_cursors_with(|map, head, _| {
12278                (movement::next_subword_end(map, head), SelectionGoal::None)
12279            });
12280        })
12281    }
12282
12283    pub fn select_to_next_word_end(
12284        &mut self,
12285        _: &SelectToNextWordEnd,
12286        window: &mut Window,
12287        cx: &mut Context<Self>,
12288    ) {
12289        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12290        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12291            s.move_heads_with(|map, head, _| {
12292                (movement::next_word_end(map, head), SelectionGoal::None)
12293            });
12294        })
12295    }
12296
12297    pub fn select_to_next_subword_end(
12298        &mut self,
12299        _: &SelectToNextSubwordEnd,
12300        window: &mut Window,
12301        cx: &mut Context<Self>,
12302    ) {
12303        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12304        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12305            s.move_heads_with(|map, head, _| {
12306                (movement::next_subword_end(map, head), SelectionGoal::None)
12307            });
12308        })
12309    }
12310
12311    pub fn delete_to_next_word_end(
12312        &mut self,
12313        action: &DeleteToNextWordEnd,
12314        window: &mut Window,
12315        cx: &mut Context<Self>,
12316    ) {
12317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12318        self.transact(window, cx, |this, window, cx| {
12319            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12320                s.move_with(|map, selection| {
12321                    if selection.is_empty() {
12322                        let cursor = if action.ignore_newlines {
12323                            movement::next_word_end(map, selection.head())
12324                        } else {
12325                            movement::next_word_end_or_newline(map, selection.head())
12326                        };
12327                        selection.set_head(cursor, SelectionGoal::None);
12328                    }
12329                });
12330            });
12331            this.insert("", window, cx);
12332        });
12333    }
12334
12335    pub fn delete_to_next_subword_end(
12336        &mut self,
12337        _: &DeleteToNextSubwordEnd,
12338        window: &mut Window,
12339        cx: &mut Context<Self>,
12340    ) {
12341        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12342        self.transact(window, cx, |this, window, cx| {
12343            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12344                s.move_with(|map, selection| {
12345                    if selection.is_empty() {
12346                        let cursor = movement::next_subword_end(map, selection.head());
12347                        selection.set_head(cursor, SelectionGoal::None);
12348                    }
12349                });
12350            });
12351            this.insert("", window, cx);
12352        });
12353    }
12354
12355    pub fn move_to_beginning_of_line(
12356        &mut self,
12357        action: &MoveToBeginningOfLine,
12358        window: &mut Window,
12359        cx: &mut Context<Self>,
12360    ) {
12361        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12362        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12363            s.move_cursors_with(|map, head, _| {
12364                (
12365                    movement::indented_line_beginning(
12366                        map,
12367                        head,
12368                        action.stop_at_soft_wraps,
12369                        action.stop_at_indent,
12370                    ),
12371                    SelectionGoal::None,
12372                )
12373            });
12374        })
12375    }
12376
12377    pub fn select_to_beginning_of_line(
12378        &mut self,
12379        action: &SelectToBeginningOfLine,
12380        window: &mut Window,
12381        cx: &mut Context<Self>,
12382    ) {
12383        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12384        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12385            s.move_heads_with(|map, head, _| {
12386                (
12387                    movement::indented_line_beginning(
12388                        map,
12389                        head,
12390                        action.stop_at_soft_wraps,
12391                        action.stop_at_indent,
12392                    ),
12393                    SelectionGoal::None,
12394                )
12395            });
12396        });
12397    }
12398
12399    pub fn delete_to_beginning_of_line(
12400        &mut self,
12401        action: &DeleteToBeginningOfLine,
12402        window: &mut Window,
12403        cx: &mut Context<Self>,
12404    ) {
12405        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12406        self.transact(window, cx, |this, window, cx| {
12407            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12408                s.move_with(|_, selection| {
12409                    selection.reversed = true;
12410                });
12411            });
12412
12413            this.select_to_beginning_of_line(
12414                &SelectToBeginningOfLine {
12415                    stop_at_soft_wraps: false,
12416                    stop_at_indent: action.stop_at_indent,
12417                },
12418                window,
12419                cx,
12420            );
12421            this.backspace(&Backspace, window, cx);
12422        });
12423    }
12424
12425    pub fn move_to_end_of_line(
12426        &mut self,
12427        action: &MoveToEndOfLine,
12428        window: &mut Window,
12429        cx: &mut Context<Self>,
12430    ) {
12431        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12432        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12433            s.move_cursors_with(|map, head, _| {
12434                (
12435                    movement::line_end(map, head, action.stop_at_soft_wraps),
12436                    SelectionGoal::None,
12437                )
12438            });
12439        })
12440    }
12441
12442    pub fn select_to_end_of_line(
12443        &mut self,
12444        action: &SelectToEndOfLine,
12445        window: &mut Window,
12446        cx: &mut Context<Self>,
12447    ) {
12448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12449        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12450            s.move_heads_with(|map, head, _| {
12451                (
12452                    movement::line_end(map, head, action.stop_at_soft_wraps),
12453                    SelectionGoal::None,
12454                )
12455            });
12456        })
12457    }
12458
12459    pub fn delete_to_end_of_line(
12460        &mut self,
12461        _: &DeleteToEndOfLine,
12462        window: &mut Window,
12463        cx: &mut Context<Self>,
12464    ) {
12465        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12466        self.transact(window, cx, |this, window, cx| {
12467            this.select_to_end_of_line(
12468                &SelectToEndOfLine {
12469                    stop_at_soft_wraps: false,
12470                },
12471                window,
12472                cx,
12473            );
12474            this.delete(&Delete, window, cx);
12475        });
12476    }
12477
12478    pub fn cut_to_end_of_line(
12479        &mut self,
12480        _: &CutToEndOfLine,
12481        window: &mut Window,
12482        cx: &mut Context<Self>,
12483    ) {
12484        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12485        self.transact(window, cx, |this, window, cx| {
12486            this.select_to_end_of_line(
12487                &SelectToEndOfLine {
12488                    stop_at_soft_wraps: false,
12489                },
12490                window,
12491                cx,
12492            );
12493            this.cut(&Cut, window, cx);
12494        });
12495    }
12496
12497    pub fn move_to_start_of_paragraph(
12498        &mut self,
12499        _: &MoveToStartOfParagraph,
12500        window: &mut Window,
12501        cx: &mut Context<Self>,
12502    ) {
12503        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12504            cx.propagate();
12505            return;
12506        }
12507        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12508        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12509            s.move_with(|map, selection| {
12510                selection.collapse_to(
12511                    movement::start_of_paragraph(map, selection.head(), 1),
12512                    SelectionGoal::None,
12513                )
12514            });
12515        })
12516    }
12517
12518    pub fn move_to_end_of_paragraph(
12519        &mut self,
12520        _: &MoveToEndOfParagraph,
12521        window: &mut Window,
12522        cx: &mut Context<Self>,
12523    ) {
12524        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12525            cx.propagate();
12526            return;
12527        }
12528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12529        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12530            s.move_with(|map, selection| {
12531                selection.collapse_to(
12532                    movement::end_of_paragraph(map, selection.head(), 1),
12533                    SelectionGoal::None,
12534                )
12535            });
12536        })
12537    }
12538
12539    pub fn select_to_start_of_paragraph(
12540        &mut self,
12541        _: &SelectToStartOfParagraph,
12542        window: &mut Window,
12543        cx: &mut Context<Self>,
12544    ) {
12545        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12546            cx.propagate();
12547            return;
12548        }
12549        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12550        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12551            s.move_heads_with(|map, head, _| {
12552                (
12553                    movement::start_of_paragraph(map, head, 1),
12554                    SelectionGoal::None,
12555                )
12556            });
12557        })
12558    }
12559
12560    pub fn select_to_end_of_paragraph(
12561        &mut self,
12562        _: &SelectToEndOfParagraph,
12563        window: &mut Window,
12564        cx: &mut Context<Self>,
12565    ) {
12566        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12567            cx.propagate();
12568            return;
12569        }
12570        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12571        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12572            s.move_heads_with(|map, head, _| {
12573                (
12574                    movement::end_of_paragraph(map, head, 1),
12575                    SelectionGoal::None,
12576                )
12577            });
12578        })
12579    }
12580
12581    pub fn move_to_start_of_excerpt(
12582        &mut self,
12583        _: &MoveToStartOfExcerpt,
12584        window: &mut Window,
12585        cx: &mut Context<Self>,
12586    ) {
12587        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12588            cx.propagate();
12589            return;
12590        }
12591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12592        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12593            s.move_with(|map, selection| {
12594                selection.collapse_to(
12595                    movement::start_of_excerpt(
12596                        map,
12597                        selection.head(),
12598                        workspace::searchable::Direction::Prev,
12599                    ),
12600                    SelectionGoal::None,
12601                )
12602            });
12603        })
12604    }
12605
12606    pub fn move_to_start_of_next_excerpt(
12607        &mut self,
12608        _: &MoveToStartOfNextExcerpt,
12609        window: &mut Window,
12610        cx: &mut Context<Self>,
12611    ) {
12612        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12613            cx.propagate();
12614            return;
12615        }
12616
12617        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12618            s.move_with(|map, selection| {
12619                selection.collapse_to(
12620                    movement::start_of_excerpt(
12621                        map,
12622                        selection.head(),
12623                        workspace::searchable::Direction::Next,
12624                    ),
12625                    SelectionGoal::None,
12626                )
12627            });
12628        })
12629    }
12630
12631    pub fn move_to_end_of_excerpt(
12632        &mut self,
12633        _: &MoveToEndOfExcerpt,
12634        window: &mut Window,
12635        cx: &mut Context<Self>,
12636    ) {
12637        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12638            cx.propagate();
12639            return;
12640        }
12641        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12642        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12643            s.move_with(|map, selection| {
12644                selection.collapse_to(
12645                    movement::end_of_excerpt(
12646                        map,
12647                        selection.head(),
12648                        workspace::searchable::Direction::Next,
12649                    ),
12650                    SelectionGoal::None,
12651                )
12652            });
12653        })
12654    }
12655
12656    pub fn move_to_end_of_previous_excerpt(
12657        &mut self,
12658        _: &MoveToEndOfPreviousExcerpt,
12659        window: &mut Window,
12660        cx: &mut Context<Self>,
12661    ) {
12662        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12663            cx.propagate();
12664            return;
12665        }
12666        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12667        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12668            s.move_with(|map, selection| {
12669                selection.collapse_to(
12670                    movement::end_of_excerpt(
12671                        map,
12672                        selection.head(),
12673                        workspace::searchable::Direction::Prev,
12674                    ),
12675                    SelectionGoal::None,
12676                )
12677            });
12678        })
12679    }
12680
12681    pub fn select_to_start_of_excerpt(
12682        &mut self,
12683        _: &SelectToStartOfExcerpt,
12684        window: &mut Window,
12685        cx: &mut Context<Self>,
12686    ) {
12687        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12688            cx.propagate();
12689            return;
12690        }
12691        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12692        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12693            s.move_heads_with(|map, head, _| {
12694                (
12695                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12696                    SelectionGoal::None,
12697                )
12698            });
12699        })
12700    }
12701
12702    pub fn select_to_start_of_next_excerpt(
12703        &mut self,
12704        _: &SelectToStartOfNextExcerpt,
12705        window: &mut Window,
12706        cx: &mut Context<Self>,
12707    ) {
12708        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12709            cx.propagate();
12710            return;
12711        }
12712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12713        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12714            s.move_heads_with(|map, head, _| {
12715                (
12716                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12717                    SelectionGoal::None,
12718                )
12719            });
12720        })
12721    }
12722
12723    pub fn select_to_end_of_excerpt(
12724        &mut self,
12725        _: &SelectToEndOfExcerpt,
12726        window: &mut Window,
12727        cx: &mut Context<Self>,
12728    ) {
12729        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12730            cx.propagate();
12731            return;
12732        }
12733        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12734        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12735            s.move_heads_with(|map, head, _| {
12736                (
12737                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12738                    SelectionGoal::None,
12739                )
12740            });
12741        })
12742    }
12743
12744    pub fn select_to_end_of_previous_excerpt(
12745        &mut self,
12746        _: &SelectToEndOfPreviousExcerpt,
12747        window: &mut Window,
12748        cx: &mut Context<Self>,
12749    ) {
12750        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12751            cx.propagate();
12752            return;
12753        }
12754        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12755        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12756            s.move_heads_with(|map, head, _| {
12757                (
12758                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12759                    SelectionGoal::None,
12760                )
12761            });
12762        })
12763    }
12764
12765    pub fn move_to_beginning(
12766        &mut self,
12767        _: &MoveToBeginning,
12768        window: &mut Window,
12769        cx: &mut Context<Self>,
12770    ) {
12771        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12772            cx.propagate();
12773            return;
12774        }
12775        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12776        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12777            s.select_ranges(vec![0..0]);
12778        });
12779    }
12780
12781    pub fn select_to_beginning(
12782        &mut self,
12783        _: &SelectToBeginning,
12784        window: &mut Window,
12785        cx: &mut Context<Self>,
12786    ) {
12787        let mut selection = self.selections.last::<Point>(cx);
12788        selection.set_head(Point::zero(), SelectionGoal::None);
12789        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12790        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12791            s.select(vec![selection]);
12792        });
12793    }
12794
12795    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12796        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12797            cx.propagate();
12798            return;
12799        }
12800        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12801        let cursor = self.buffer.read(cx).read(cx).len();
12802        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12803            s.select_ranges(vec![cursor..cursor])
12804        });
12805    }
12806
12807    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12808        self.nav_history = nav_history;
12809    }
12810
12811    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12812        self.nav_history.as_ref()
12813    }
12814
12815    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12816        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12817    }
12818
12819    fn push_to_nav_history(
12820        &mut self,
12821        cursor_anchor: Anchor,
12822        new_position: Option<Point>,
12823        is_deactivate: bool,
12824        cx: &mut Context<Self>,
12825    ) {
12826        if let Some(nav_history) = self.nav_history.as_mut() {
12827            let buffer = self.buffer.read(cx).read(cx);
12828            let cursor_position = cursor_anchor.to_point(&buffer);
12829            let scroll_state = self.scroll_manager.anchor();
12830            let scroll_top_row = scroll_state.top_row(&buffer);
12831            drop(buffer);
12832
12833            if let Some(new_position) = new_position {
12834                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12835                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12836                    return;
12837                }
12838            }
12839
12840            nav_history.push(
12841                Some(NavigationData {
12842                    cursor_anchor,
12843                    cursor_position,
12844                    scroll_anchor: scroll_state,
12845                    scroll_top_row,
12846                }),
12847                cx,
12848            );
12849            cx.emit(EditorEvent::PushedToNavHistory {
12850                anchor: cursor_anchor,
12851                is_deactivate,
12852            })
12853        }
12854    }
12855
12856    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12858        let buffer = self.buffer.read(cx).snapshot(cx);
12859        let mut selection = self.selections.first::<usize>(cx);
12860        selection.set_head(buffer.len(), SelectionGoal::None);
12861        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12862            s.select(vec![selection]);
12863        });
12864    }
12865
12866    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12868        let end = self.buffer.read(cx).read(cx).len();
12869        self.change_selections(None, window, cx, |s| {
12870            s.select_ranges(vec![0..end]);
12871        });
12872    }
12873
12874    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12876        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12877        let mut selections = self.selections.all::<Point>(cx);
12878        let max_point = display_map.buffer_snapshot.max_point();
12879        for selection in &mut selections {
12880            let rows = selection.spanned_rows(true, &display_map);
12881            selection.start = Point::new(rows.start.0, 0);
12882            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12883            selection.reversed = false;
12884        }
12885        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12886            s.select(selections);
12887        });
12888    }
12889
12890    pub fn split_selection_into_lines(
12891        &mut self,
12892        _: &SplitSelectionIntoLines,
12893        window: &mut Window,
12894        cx: &mut Context<Self>,
12895    ) {
12896        let selections = self
12897            .selections
12898            .all::<Point>(cx)
12899            .into_iter()
12900            .map(|selection| selection.start..selection.end)
12901            .collect::<Vec<_>>();
12902        self.unfold_ranges(&selections, true, true, cx);
12903
12904        let mut new_selection_ranges = Vec::new();
12905        {
12906            let buffer = self.buffer.read(cx).read(cx);
12907            for selection in selections {
12908                for row in selection.start.row..selection.end.row {
12909                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12910                    new_selection_ranges.push(cursor..cursor);
12911                }
12912
12913                let is_multiline_selection = selection.start.row != selection.end.row;
12914                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12915                // so this action feels more ergonomic when paired with other selection operations
12916                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12917                if !should_skip_last {
12918                    new_selection_ranges.push(selection.end..selection.end);
12919                }
12920            }
12921        }
12922        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12923            s.select_ranges(new_selection_ranges);
12924        });
12925    }
12926
12927    pub fn add_selection_above(
12928        &mut self,
12929        _: &AddSelectionAbove,
12930        window: &mut Window,
12931        cx: &mut Context<Self>,
12932    ) {
12933        self.add_selection(true, window, cx);
12934    }
12935
12936    pub fn add_selection_below(
12937        &mut self,
12938        _: &AddSelectionBelow,
12939        window: &mut Window,
12940        cx: &mut Context<Self>,
12941    ) {
12942        self.add_selection(false, window, cx);
12943    }
12944
12945    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12947
12948        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12949        let all_selections = self.selections.all::<Point>(cx);
12950        let text_layout_details = self.text_layout_details(window);
12951
12952        let (mut columnar_selections, new_selections_to_columnarize) = {
12953            if let Some(state) = self.add_selections_state.as_ref() {
12954                let columnar_selection_ids: HashSet<_> = state
12955                    .groups
12956                    .iter()
12957                    .flat_map(|group| group.stack.iter())
12958                    .copied()
12959                    .collect();
12960
12961                all_selections
12962                    .into_iter()
12963                    .partition(|s| columnar_selection_ids.contains(&s.id))
12964            } else {
12965                (Vec::new(), all_selections)
12966            }
12967        };
12968
12969        let mut state = self
12970            .add_selections_state
12971            .take()
12972            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12973
12974        for selection in new_selections_to_columnarize {
12975            let range = selection.display_range(&display_map).sorted();
12976            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12977            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12978            let positions = start_x.min(end_x)..start_x.max(end_x);
12979            let mut stack = Vec::new();
12980            for row in range.start.row().0..=range.end.row().0 {
12981                if let Some(selection) = self.selections.build_columnar_selection(
12982                    &display_map,
12983                    DisplayRow(row),
12984                    &positions,
12985                    selection.reversed,
12986                    &text_layout_details,
12987                ) {
12988                    stack.push(selection.id);
12989                    columnar_selections.push(selection);
12990                }
12991            }
12992            if !stack.is_empty() {
12993                if above {
12994                    stack.reverse();
12995                }
12996                state.groups.push(AddSelectionsGroup { above, stack });
12997            }
12998        }
12999
13000        let mut final_selections = Vec::new();
13001        let end_row = if above {
13002            DisplayRow(0)
13003        } else {
13004            display_map.max_point().row()
13005        };
13006
13007        let mut last_added_item_per_group = HashMap::default();
13008        for group in state.groups.iter_mut() {
13009            if let Some(last_id) = group.stack.last() {
13010                last_added_item_per_group.insert(*last_id, group);
13011            }
13012        }
13013
13014        for selection in columnar_selections {
13015            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13016                if above == group.above {
13017                    let range = selection.display_range(&display_map).sorted();
13018                    debug_assert_eq!(range.start.row(), range.end.row());
13019                    let mut row = range.start.row();
13020                    let positions =
13021                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13022                            px(start)..px(end)
13023                        } else {
13024                            let start_x =
13025                                display_map.x_for_display_point(range.start, &text_layout_details);
13026                            let end_x =
13027                                display_map.x_for_display_point(range.end, &text_layout_details);
13028                            start_x.min(end_x)..start_x.max(end_x)
13029                        };
13030
13031                    let mut maybe_new_selection = None;
13032                    while row != end_row {
13033                        if above {
13034                            row.0 -= 1;
13035                        } else {
13036                            row.0 += 1;
13037                        }
13038                        if let Some(new_selection) = self.selections.build_columnar_selection(
13039                            &display_map,
13040                            row,
13041                            &positions,
13042                            selection.reversed,
13043                            &text_layout_details,
13044                        ) {
13045                            maybe_new_selection = Some(new_selection);
13046                            break;
13047                        }
13048                    }
13049
13050                    if let Some(new_selection) = maybe_new_selection {
13051                        group.stack.push(new_selection.id);
13052                        if above {
13053                            final_selections.push(new_selection);
13054                            final_selections.push(selection);
13055                        } else {
13056                            final_selections.push(selection);
13057                            final_selections.push(new_selection);
13058                        }
13059                    } else {
13060                        final_selections.push(selection);
13061                    }
13062                } else {
13063                    group.stack.pop();
13064                }
13065            } else {
13066                final_selections.push(selection);
13067            }
13068        }
13069
13070        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13071            s.select(final_selections);
13072        });
13073
13074        let final_selection_ids: HashSet<_> = self
13075            .selections
13076            .all::<Point>(cx)
13077            .iter()
13078            .map(|s| s.id)
13079            .collect();
13080        state.groups.retain_mut(|group| {
13081            // selections might get merged above so we remove invalid items from stacks
13082            group.stack.retain(|id| final_selection_ids.contains(id));
13083
13084            // single selection in stack can be treated as initial state
13085            group.stack.len() > 1
13086        });
13087
13088        if !state.groups.is_empty() {
13089            self.add_selections_state = Some(state);
13090        }
13091    }
13092
13093    fn select_match_ranges(
13094        &mut self,
13095        range: Range<usize>,
13096        reversed: bool,
13097        replace_newest: bool,
13098        auto_scroll: Option<Autoscroll>,
13099        window: &mut Window,
13100        cx: &mut Context<Editor>,
13101    ) {
13102        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13103        self.change_selections(auto_scroll, window, cx, |s| {
13104            if replace_newest {
13105                s.delete(s.newest_anchor().id);
13106            }
13107            if reversed {
13108                s.insert_range(range.end..range.start);
13109            } else {
13110                s.insert_range(range);
13111            }
13112        });
13113    }
13114
13115    pub fn select_next_match_internal(
13116        &mut self,
13117        display_map: &DisplaySnapshot,
13118        replace_newest: bool,
13119        autoscroll: Option<Autoscroll>,
13120        window: &mut Window,
13121        cx: &mut Context<Self>,
13122    ) -> Result<()> {
13123        let buffer = &display_map.buffer_snapshot;
13124        let mut selections = self.selections.all::<usize>(cx);
13125        if let Some(mut select_next_state) = self.select_next_state.take() {
13126            let query = &select_next_state.query;
13127            if !select_next_state.done {
13128                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13129                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13130                let mut next_selected_range = None;
13131
13132                let bytes_after_last_selection =
13133                    buffer.bytes_in_range(last_selection.end..buffer.len());
13134                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13135                let query_matches = query
13136                    .stream_find_iter(bytes_after_last_selection)
13137                    .map(|result| (last_selection.end, result))
13138                    .chain(
13139                        query
13140                            .stream_find_iter(bytes_before_first_selection)
13141                            .map(|result| (0, result)),
13142                    );
13143
13144                for (start_offset, query_match) in query_matches {
13145                    let query_match = query_match.unwrap(); // can only fail due to I/O
13146                    let offset_range =
13147                        start_offset + query_match.start()..start_offset + query_match.end();
13148                    let display_range = offset_range.start.to_display_point(display_map)
13149                        ..offset_range.end.to_display_point(display_map);
13150
13151                    if !select_next_state.wordwise
13152                        || (!movement::is_inside_word(display_map, display_range.start)
13153                            && !movement::is_inside_word(display_map, display_range.end))
13154                    {
13155                        // TODO: This is n^2, because we might check all the selections
13156                        if !selections
13157                            .iter()
13158                            .any(|selection| selection.range().overlaps(&offset_range))
13159                        {
13160                            next_selected_range = Some(offset_range);
13161                            break;
13162                        }
13163                    }
13164                }
13165
13166                if let Some(next_selected_range) = next_selected_range {
13167                    self.select_match_ranges(
13168                        next_selected_range,
13169                        last_selection.reversed,
13170                        replace_newest,
13171                        autoscroll,
13172                        window,
13173                        cx,
13174                    );
13175                } else {
13176                    select_next_state.done = true;
13177                }
13178            }
13179
13180            self.select_next_state = Some(select_next_state);
13181        } else {
13182            let mut only_carets = true;
13183            let mut same_text_selected = true;
13184            let mut selected_text = None;
13185
13186            let mut selections_iter = selections.iter().peekable();
13187            while let Some(selection) = selections_iter.next() {
13188                if selection.start != selection.end {
13189                    only_carets = false;
13190                }
13191
13192                if same_text_selected {
13193                    if selected_text.is_none() {
13194                        selected_text =
13195                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13196                    }
13197
13198                    if let Some(next_selection) = selections_iter.peek() {
13199                        if next_selection.range().len() == selection.range().len() {
13200                            let next_selected_text = buffer
13201                                .text_for_range(next_selection.range())
13202                                .collect::<String>();
13203                            if Some(next_selected_text) != selected_text {
13204                                same_text_selected = false;
13205                                selected_text = None;
13206                            }
13207                        } else {
13208                            same_text_selected = false;
13209                            selected_text = None;
13210                        }
13211                    }
13212                }
13213            }
13214
13215            if only_carets {
13216                for selection in &mut selections {
13217                    let word_range = movement::surrounding_word(
13218                        display_map,
13219                        selection.start.to_display_point(display_map),
13220                    );
13221                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13222                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13223                    selection.goal = SelectionGoal::None;
13224                    selection.reversed = false;
13225                    self.select_match_ranges(
13226                        selection.start..selection.end,
13227                        selection.reversed,
13228                        replace_newest,
13229                        autoscroll,
13230                        window,
13231                        cx,
13232                    );
13233                }
13234
13235                if selections.len() == 1 {
13236                    let selection = selections
13237                        .last()
13238                        .expect("ensured that there's only one selection");
13239                    let query = buffer
13240                        .text_for_range(selection.start..selection.end)
13241                        .collect::<String>();
13242                    let is_empty = query.is_empty();
13243                    let select_state = SelectNextState {
13244                        query: AhoCorasick::new(&[query])?,
13245                        wordwise: true,
13246                        done: is_empty,
13247                    };
13248                    self.select_next_state = Some(select_state);
13249                } else {
13250                    self.select_next_state = None;
13251                }
13252            } else if let Some(selected_text) = selected_text {
13253                self.select_next_state = Some(SelectNextState {
13254                    query: AhoCorasick::new(&[selected_text])?,
13255                    wordwise: false,
13256                    done: false,
13257                });
13258                self.select_next_match_internal(
13259                    display_map,
13260                    replace_newest,
13261                    autoscroll,
13262                    window,
13263                    cx,
13264                )?;
13265            }
13266        }
13267        Ok(())
13268    }
13269
13270    pub fn select_all_matches(
13271        &mut self,
13272        _action: &SelectAllMatches,
13273        window: &mut Window,
13274        cx: &mut Context<Self>,
13275    ) -> Result<()> {
13276        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13277
13278        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13279
13280        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13281        let Some(select_next_state) = self.select_next_state.as_mut() else {
13282            return Ok(());
13283        };
13284        if select_next_state.done {
13285            return Ok(());
13286        }
13287
13288        let mut new_selections = Vec::new();
13289
13290        let reversed = self.selections.oldest::<usize>(cx).reversed;
13291        let buffer = &display_map.buffer_snapshot;
13292        let query_matches = select_next_state
13293            .query
13294            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13295
13296        for query_match in query_matches.into_iter() {
13297            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13298            let offset_range = if reversed {
13299                query_match.end()..query_match.start()
13300            } else {
13301                query_match.start()..query_match.end()
13302            };
13303            let display_range = offset_range.start.to_display_point(&display_map)
13304                ..offset_range.end.to_display_point(&display_map);
13305
13306            if !select_next_state.wordwise
13307                || (!movement::is_inside_word(&display_map, display_range.start)
13308                    && !movement::is_inside_word(&display_map, display_range.end))
13309            {
13310                new_selections.push(offset_range.start..offset_range.end);
13311            }
13312        }
13313
13314        select_next_state.done = true;
13315        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13316        self.change_selections(None, window, cx, |selections| {
13317            selections.select_ranges(new_selections)
13318        });
13319
13320        Ok(())
13321    }
13322
13323    pub fn select_next(
13324        &mut self,
13325        action: &SelectNext,
13326        window: &mut Window,
13327        cx: &mut Context<Self>,
13328    ) -> Result<()> {
13329        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13330        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13331        self.select_next_match_internal(
13332            &display_map,
13333            action.replace_newest,
13334            Some(Autoscroll::newest()),
13335            window,
13336            cx,
13337        )?;
13338        Ok(())
13339    }
13340
13341    pub fn select_previous(
13342        &mut self,
13343        action: &SelectPrevious,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) -> Result<()> {
13347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13348        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13349        let buffer = &display_map.buffer_snapshot;
13350        let mut selections = self.selections.all::<usize>(cx);
13351        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13352            let query = &select_prev_state.query;
13353            if !select_prev_state.done {
13354                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13355                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13356                let mut next_selected_range = None;
13357                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13358                let bytes_before_last_selection =
13359                    buffer.reversed_bytes_in_range(0..last_selection.start);
13360                let bytes_after_first_selection =
13361                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13362                let query_matches = query
13363                    .stream_find_iter(bytes_before_last_selection)
13364                    .map(|result| (last_selection.start, result))
13365                    .chain(
13366                        query
13367                            .stream_find_iter(bytes_after_first_selection)
13368                            .map(|result| (buffer.len(), result)),
13369                    );
13370                for (end_offset, query_match) in query_matches {
13371                    let query_match = query_match.unwrap(); // can only fail due to I/O
13372                    let offset_range =
13373                        end_offset - query_match.end()..end_offset - query_match.start();
13374                    let display_range = offset_range.start.to_display_point(&display_map)
13375                        ..offset_range.end.to_display_point(&display_map);
13376
13377                    if !select_prev_state.wordwise
13378                        || (!movement::is_inside_word(&display_map, display_range.start)
13379                            && !movement::is_inside_word(&display_map, display_range.end))
13380                    {
13381                        next_selected_range = Some(offset_range);
13382                        break;
13383                    }
13384                }
13385
13386                if let Some(next_selected_range) = next_selected_range {
13387                    self.select_match_ranges(
13388                        next_selected_range,
13389                        last_selection.reversed,
13390                        action.replace_newest,
13391                        Some(Autoscroll::newest()),
13392                        window,
13393                        cx,
13394                    );
13395                } else {
13396                    select_prev_state.done = true;
13397                }
13398            }
13399
13400            self.select_prev_state = Some(select_prev_state);
13401        } else {
13402            let mut only_carets = true;
13403            let mut same_text_selected = true;
13404            let mut selected_text = None;
13405
13406            let mut selections_iter = selections.iter().peekable();
13407            while let Some(selection) = selections_iter.next() {
13408                if selection.start != selection.end {
13409                    only_carets = false;
13410                }
13411
13412                if same_text_selected {
13413                    if selected_text.is_none() {
13414                        selected_text =
13415                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13416                    }
13417
13418                    if let Some(next_selection) = selections_iter.peek() {
13419                        if next_selection.range().len() == selection.range().len() {
13420                            let next_selected_text = buffer
13421                                .text_for_range(next_selection.range())
13422                                .collect::<String>();
13423                            if Some(next_selected_text) != selected_text {
13424                                same_text_selected = false;
13425                                selected_text = None;
13426                            }
13427                        } else {
13428                            same_text_selected = false;
13429                            selected_text = None;
13430                        }
13431                    }
13432                }
13433            }
13434
13435            if only_carets {
13436                for selection in &mut selections {
13437                    let word_range = movement::surrounding_word(
13438                        &display_map,
13439                        selection.start.to_display_point(&display_map),
13440                    );
13441                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13442                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13443                    selection.goal = SelectionGoal::None;
13444                    selection.reversed = false;
13445                    self.select_match_ranges(
13446                        selection.start..selection.end,
13447                        selection.reversed,
13448                        action.replace_newest,
13449                        Some(Autoscroll::newest()),
13450                        window,
13451                        cx,
13452                    );
13453                }
13454                if selections.len() == 1 {
13455                    let selection = selections
13456                        .last()
13457                        .expect("ensured that there's only one selection");
13458                    let query = buffer
13459                        .text_for_range(selection.start..selection.end)
13460                        .collect::<String>();
13461                    let is_empty = query.is_empty();
13462                    let select_state = SelectNextState {
13463                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13464                        wordwise: true,
13465                        done: is_empty,
13466                    };
13467                    self.select_prev_state = Some(select_state);
13468                } else {
13469                    self.select_prev_state = None;
13470                }
13471            } else if let Some(selected_text) = selected_text {
13472                self.select_prev_state = Some(SelectNextState {
13473                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13474                    wordwise: false,
13475                    done: false,
13476                });
13477                self.select_previous(action, window, cx)?;
13478            }
13479        }
13480        Ok(())
13481    }
13482
13483    pub fn find_next_match(
13484        &mut self,
13485        _: &FindNextMatch,
13486        window: &mut Window,
13487        cx: &mut Context<Self>,
13488    ) -> Result<()> {
13489        let selections = self.selections.disjoint_anchors();
13490        match selections.first() {
13491            Some(first) if selections.len() >= 2 => {
13492                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13493                    s.select_ranges([first.range()]);
13494                });
13495            }
13496            _ => self.select_next(
13497                &SelectNext {
13498                    replace_newest: true,
13499                },
13500                window,
13501                cx,
13502            )?,
13503        }
13504        Ok(())
13505    }
13506
13507    pub fn find_previous_match(
13508        &mut self,
13509        _: &FindPreviousMatch,
13510        window: &mut Window,
13511        cx: &mut Context<Self>,
13512    ) -> Result<()> {
13513        let selections = self.selections.disjoint_anchors();
13514        match selections.last() {
13515            Some(last) if selections.len() >= 2 => {
13516                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13517                    s.select_ranges([last.range()]);
13518                });
13519            }
13520            _ => self.select_previous(
13521                &SelectPrevious {
13522                    replace_newest: true,
13523                },
13524                window,
13525                cx,
13526            )?,
13527        }
13528        Ok(())
13529    }
13530
13531    pub fn toggle_comments(
13532        &mut self,
13533        action: &ToggleComments,
13534        window: &mut Window,
13535        cx: &mut Context<Self>,
13536    ) {
13537        if self.read_only(cx) {
13538            return;
13539        }
13540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13541        let text_layout_details = &self.text_layout_details(window);
13542        self.transact(window, cx, |this, window, cx| {
13543            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13544            let mut edits = Vec::new();
13545            let mut selection_edit_ranges = Vec::new();
13546            let mut last_toggled_row = None;
13547            let snapshot = this.buffer.read(cx).read(cx);
13548            let empty_str: Arc<str> = Arc::default();
13549            let mut suffixes_inserted = Vec::new();
13550            let ignore_indent = action.ignore_indent;
13551
13552            fn comment_prefix_range(
13553                snapshot: &MultiBufferSnapshot,
13554                row: MultiBufferRow,
13555                comment_prefix: &str,
13556                comment_prefix_whitespace: &str,
13557                ignore_indent: bool,
13558            ) -> Range<Point> {
13559                let indent_size = if ignore_indent {
13560                    0
13561                } else {
13562                    snapshot.indent_size_for_line(row).len
13563                };
13564
13565                let start = Point::new(row.0, indent_size);
13566
13567                let mut line_bytes = snapshot
13568                    .bytes_in_range(start..snapshot.max_point())
13569                    .flatten()
13570                    .copied();
13571
13572                // If this line currently begins with the line comment prefix, then record
13573                // the range containing the prefix.
13574                if line_bytes
13575                    .by_ref()
13576                    .take(comment_prefix.len())
13577                    .eq(comment_prefix.bytes())
13578                {
13579                    // Include any whitespace that matches the comment prefix.
13580                    let matching_whitespace_len = line_bytes
13581                        .zip(comment_prefix_whitespace.bytes())
13582                        .take_while(|(a, b)| a == b)
13583                        .count() as u32;
13584                    let end = Point::new(
13585                        start.row,
13586                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13587                    );
13588                    start..end
13589                } else {
13590                    start..start
13591                }
13592            }
13593
13594            fn comment_suffix_range(
13595                snapshot: &MultiBufferSnapshot,
13596                row: MultiBufferRow,
13597                comment_suffix: &str,
13598                comment_suffix_has_leading_space: bool,
13599            ) -> Range<Point> {
13600                let end = Point::new(row.0, snapshot.line_len(row));
13601                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13602
13603                let mut line_end_bytes = snapshot
13604                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13605                    .flatten()
13606                    .copied();
13607
13608                let leading_space_len = if suffix_start_column > 0
13609                    && line_end_bytes.next() == Some(b' ')
13610                    && comment_suffix_has_leading_space
13611                {
13612                    1
13613                } else {
13614                    0
13615                };
13616
13617                // If this line currently begins with the line comment prefix, then record
13618                // the range containing the prefix.
13619                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13620                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13621                    start..end
13622                } else {
13623                    end..end
13624                }
13625            }
13626
13627            // TODO: Handle selections that cross excerpts
13628            for selection in &mut selections {
13629                let start_column = snapshot
13630                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13631                    .len;
13632                let language = if let Some(language) =
13633                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13634                {
13635                    language
13636                } else {
13637                    continue;
13638                };
13639
13640                selection_edit_ranges.clear();
13641
13642                // If multiple selections contain a given row, avoid processing that
13643                // row more than once.
13644                let mut start_row = MultiBufferRow(selection.start.row);
13645                if last_toggled_row == Some(start_row) {
13646                    start_row = start_row.next_row();
13647                }
13648                let end_row =
13649                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13650                        MultiBufferRow(selection.end.row - 1)
13651                    } else {
13652                        MultiBufferRow(selection.end.row)
13653                    };
13654                last_toggled_row = Some(end_row);
13655
13656                if start_row > end_row {
13657                    continue;
13658                }
13659
13660                // If the language has line comments, toggle those.
13661                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13662
13663                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13664                if ignore_indent {
13665                    full_comment_prefixes = full_comment_prefixes
13666                        .into_iter()
13667                        .map(|s| Arc::from(s.trim_end()))
13668                        .collect();
13669                }
13670
13671                if !full_comment_prefixes.is_empty() {
13672                    let first_prefix = full_comment_prefixes
13673                        .first()
13674                        .expect("prefixes is non-empty");
13675                    let prefix_trimmed_lengths = full_comment_prefixes
13676                        .iter()
13677                        .map(|p| p.trim_end_matches(' ').len())
13678                        .collect::<SmallVec<[usize; 4]>>();
13679
13680                    let mut all_selection_lines_are_comments = true;
13681
13682                    for row in start_row.0..=end_row.0 {
13683                        let row = MultiBufferRow(row);
13684                        if start_row < end_row && snapshot.is_line_blank(row) {
13685                            continue;
13686                        }
13687
13688                        let prefix_range = full_comment_prefixes
13689                            .iter()
13690                            .zip(prefix_trimmed_lengths.iter().copied())
13691                            .map(|(prefix, trimmed_prefix_len)| {
13692                                comment_prefix_range(
13693                                    snapshot.deref(),
13694                                    row,
13695                                    &prefix[..trimmed_prefix_len],
13696                                    &prefix[trimmed_prefix_len..],
13697                                    ignore_indent,
13698                                )
13699                            })
13700                            .max_by_key(|range| range.end.column - range.start.column)
13701                            .expect("prefixes is non-empty");
13702
13703                        if prefix_range.is_empty() {
13704                            all_selection_lines_are_comments = false;
13705                        }
13706
13707                        selection_edit_ranges.push(prefix_range);
13708                    }
13709
13710                    if all_selection_lines_are_comments {
13711                        edits.extend(
13712                            selection_edit_ranges
13713                                .iter()
13714                                .cloned()
13715                                .map(|range| (range, empty_str.clone())),
13716                        );
13717                    } else {
13718                        let min_column = selection_edit_ranges
13719                            .iter()
13720                            .map(|range| range.start.column)
13721                            .min()
13722                            .unwrap_or(0);
13723                        edits.extend(selection_edit_ranges.iter().map(|range| {
13724                            let position = Point::new(range.start.row, min_column);
13725                            (position..position, first_prefix.clone())
13726                        }));
13727                    }
13728                } else if let Some((full_comment_prefix, comment_suffix)) =
13729                    language.block_comment_delimiters()
13730                {
13731                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13732                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13733                    let prefix_range = comment_prefix_range(
13734                        snapshot.deref(),
13735                        start_row,
13736                        comment_prefix,
13737                        comment_prefix_whitespace,
13738                        ignore_indent,
13739                    );
13740                    let suffix_range = comment_suffix_range(
13741                        snapshot.deref(),
13742                        end_row,
13743                        comment_suffix.trim_start_matches(' '),
13744                        comment_suffix.starts_with(' '),
13745                    );
13746
13747                    if prefix_range.is_empty() || suffix_range.is_empty() {
13748                        edits.push((
13749                            prefix_range.start..prefix_range.start,
13750                            full_comment_prefix.clone(),
13751                        ));
13752                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13753                        suffixes_inserted.push((end_row, comment_suffix.len()));
13754                    } else {
13755                        edits.push((prefix_range, empty_str.clone()));
13756                        edits.push((suffix_range, empty_str.clone()));
13757                    }
13758                } else {
13759                    continue;
13760                }
13761            }
13762
13763            drop(snapshot);
13764            this.buffer.update(cx, |buffer, cx| {
13765                buffer.edit(edits, None, cx);
13766            });
13767
13768            // Adjust selections so that they end before any comment suffixes that
13769            // were inserted.
13770            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13771            let mut selections = this.selections.all::<Point>(cx);
13772            let snapshot = this.buffer.read(cx).read(cx);
13773            for selection in &mut selections {
13774                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13775                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13776                        Ordering::Less => {
13777                            suffixes_inserted.next();
13778                            continue;
13779                        }
13780                        Ordering::Greater => break,
13781                        Ordering::Equal => {
13782                            if selection.end.column == snapshot.line_len(row) {
13783                                if selection.is_empty() {
13784                                    selection.start.column -= suffix_len as u32;
13785                                }
13786                                selection.end.column -= suffix_len as u32;
13787                            }
13788                            break;
13789                        }
13790                    }
13791                }
13792            }
13793
13794            drop(snapshot);
13795            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13796                s.select(selections)
13797            });
13798
13799            let selections = this.selections.all::<Point>(cx);
13800            let selections_on_single_row = selections.windows(2).all(|selections| {
13801                selections[0].start.row == selections[1].start.row
13802                    && selections[0].end.row == selections[1].end.row
13803                    && selections[0].start.row == selections[0].end.row
13804            });
13805            let selections_selecting = selections
13806                .iter()
13807                .any(|selection| selection.start != selection.end);
13808            let advance_downwards = action.advance_downwards
13809                && selections_on_single_row
13810                && !selections_selecting
13811                && !matches!(this.mode, EditorMode::SingleLine { .. });
13812
13813            if advance_downwards {
13814                let snapshot = this.buffer.read(cx).snapshot(cx);
13815
13816                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13817                    s.move_cursors_with(|display_snapshot, display_point, _| {
13818                        let mut point = display_point.to_point(display_snapshot);
13819                        point.row += 1;
13820                        point = snapshot.clip_point(point, Bias::Left);
13821                        let display_point = point.to_display_point(display_snapshot);
13822                        let goal = SelectionGoal::HorizontalPosition(
13823                            display_snapshot
13824                                .x_for_display_point(display_point, text_layout_details)
13825                                .into(),
13826                        );
13827                        (display_point, goal)
13828                    })
13829                });
13830            }
13831        });
13832    }
13833
13834    pub fn select_enclosing_symbol(
13835        &mut self,
13836        _: &SelectEnclosingSymbol,
13837        window: &mut Window,
13838        cx: &mut Context<Self>,
13839    ) {
13840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13841
13842        let buffer = self.buffer.read(cx).snapshot(cx);
13843        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13844
13845        fn update_selection(
13846            selection: &Selection<usize>,
13847            buffer_snap: &MultiBufferSnapshot,
13848        ) -> Option<Selection<usize>> {
13849            let cursor = selection.head();
13850            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13851            for symbol in symbols.iter().rev() {
13852                let start = symbol.range.start.to_offset(buffer_snap);
13853                let end = symbol.range.end.to_offset(buffer_snap);
13854                let new_range = start..end;
13855                if start < selection.start || end > selection.end {
13856                    return Some(Selection {
13857                        id: selection.id,
13858                        start: new_range.start,
13859                        end: new_range.end,
13860                        goal: SelectionGoal::None,
13861                        reversed: selection.reversed,
13862                    });
13863                }
13864            }
13865            None
13866        }
13867
13868        let mut selected_larger_symbol = false;
13869        let new_selections = old_selections
13870            .iter()
13871            .map(|selection| match update_selection(selection, &buffer) {
13872                Some(new_selection) => {
13873                    if new_selection.range() != selection.range() {
13874                        selected_larger_symbol = true;
13875                    }
13876                    new_selection
13877                }
13878                None => selection.clone(),
13879            })
13880            .collect::<Vec<_>>();
13881
13882        if selected_larger_symbol {
13883            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13884                s.select(new_selections);
13885            });
13886        }
13887    }
13888
13889    pub fn select_larger_syntax_node(
13890        &mut self,
13891        _: &SelectLargerSyntaxNode,
13892        window: &mut Window,
13893        cx: &mut Context<Self>,
13894    ) {
13895        let Some(visible_row_count) = self.visible_row_count() else {
13896            return;
13897        };
13898        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13899        if old_selections.is_empty() {
13900            return;
13901        }
13902
13903        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13904
13905        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13906        let buffer = self.buffer.read(cx).snapshot(cx);
13907
13908        let mut selected_larger_node = false;
13909        let mut new_selections = old_selections
13910            .iter()
13911            .map(|selection| {
13912                let old_range = selection.start..selection.end;
13913
13914                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13915                    // manually select word at selection
13916                    if ["string_content", "inline"].contains(&node.kind()) {
13917                        let word_range = {
13918                            let display_point = buffer
13919                                .offset_to_point(old_range.start)
13920                                .to_display_point(&display_map);
13921                            let Range { start, end } =
13922                                movement::surrounding_word(&display_map, display_point);
13923                            start.to_point(&display_map).to_offset(&buffer)
13924                                ..end.to_point(&display_map).to_offset(&buffer)
13925                        };
13926                        // ignore if word is already selected
13927                        if !word_range.is_empty() && old_range != word_range {
13928                            let last_word_range = {
13929                                let display_point = buffer
13930                                    .offset_to_point(old_range.end)
13931                                    .to_display_point(&display_map);
13932                                let Range { start, end } =
13933                                    movement::surrounding_word(&display_map, display_point);
13934                                start.to_point(&display_map).to_offset(&buffer)
13935                                    ..end.to_point(&display_map).to_offset(&buffer)
13936                            };
13937                            // only select word if start and end point belongs to same word
13938                            if word_range == last_word_range {
13939                                selected_larger_node = true;
13940                                return Selection {
13941                                    id: selection.id,
13942                                    start: word_range.start,
13943                                    end: word_range.end,
13944                                    goal: SelectionGoal::None,
13945                                    reversed: selection.reversed,
13946                                };
13947                            }
13948                        }
13949                    }
13950                }
13951
13952                let mut new_range = old_range.clone();
13953                while let Some((_node, containing_range)) =
13954                    buffer.syntax_ancestor(new_range.clone())
13955                {
13956                    new_range = match containing_range {
13957                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13958                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13959                    };
13960                    if !display_map.intersects_fold(new_range.start)
13961                        && !display_map.intersects_fold(new_range.end)
13962                    {
13963                        break;
13964                    }
13965                }
13966
13967                selected_larger_node |= new_range != old_range;
13968                Selection {
13969                    id: selection.id,
13970                    start: new_range.start,
13971                    end: new_range.end,
13972                    goal: SelectionGoal::None,
13973                    reversed: selection.reversed,
13974                }
13975            })
13976            .collect::<Vec<_>>();
13977
13978        if !selected_larger_node {
13979            return; // don't put this call in the history
13980        }
13981
13982        // scroll based on transformation done to the last selection created by the user
13983        let (last_old, last_new) = old_selections
13984            .last()
13985            .zip(new_selections.last().cloned())
13986            .expect("old_selections isn't empty");
13987
13988        // revert selection
13989        let is_selection_reversed = {
13990            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13991            new_selections.last_mut().expect("checked above").reversed =
13992                should_newest_selection_be_reversed;
13993            should_newest_selection_be_reversed
13994        };
13995
13996        if selected_larger_node {
13997            self.select_syntax_node_history.disable_clearing = true;
13998            self.change_selections(None, window, cx, |s| {
13999                s.select(new_selections.clone());
14000            });
14001            self.select_syntax_node_history.disable_clearing = false;
14002        }
14003
14004        let start_row = last_new.start.to_display_point(&display_map).row().0;
14005        let end_row = last_new.end.to_display_point(&display_map).row().0;
14006        let selection_height = end_row - start_row + 1;
14007        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14008
14009        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14010        let scroll_behavior = if fits_on_the_screen {
14011            self.request_autoscroll(Autoscroll::fit(), cx);
14012            SelectSyntaxNodeScrollBehavior::FitSelection
14013        } else if is_selection_reversed {
14014            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14015            SelectSyntaxNodeScrollBehavior::CursorTop
14016        } else {
14017            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14018            SelectSyntaxNodeScrollBehavior::CursorBottom
14019        };
14020
14021        self.select_syntax_node_history.push((
14022            old_selections,
14023            scroll_behavior,
14024            is_selection_reversed,
14025        ));
14026    }
14027
14028    pub fn select_smaller_syntax_node(
14029        &mut self,
14030        _: &SelectSmallerSyntaxNode,
14031        window: &mut Window,
14032        cx: &mut Context<Self>,
14033    ) {
14034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14035
14036        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14037            self.select_syntax_node_history.pop()
14038        {
14039            if let Some(selection) = selections.last_mut() {
14040                selection.reversed = is_selection_reversed;
14041            }
14042
14043            self.select_syntax_node_history.disable_clearing = true;
14044            self.change_selections(None, window, cx, |s| {
14045                s.select(selections.to_vec());
14046            });
14047            self.select_syntax_node_history.disable_clearing = false;
14048
14049            match scroll_behavior {
14050                SelectSyntaxNodeScrollBehavior::CursorTop => {
14051                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14052                }
14053                SelectSyntaxNodeScrollBehavior::FitSelection => {
14054                    self.request_autoscroll(Autoscroll::fit(), cx);
14055                }
14056                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14057                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14058                }
14059            }
14060        }
14061    }
14062
14063    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14064        if !EditorSettings::get_global(cx).gutter.runnables {
14065            self.clear_tasks();
14066            return Task::ready(());
14067        }
14068        let project = self.project.as_ref().map(Entity::downgrade);
14069        let task_sources = self.lsp_task_sources(cx);
14070        let multi_buffer = self.buffer.downgrade();
14071        cx.spawn_in(window, async move |editor, cx| {
14072            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14073            let Some(project) = project.and_then(|p| p.upgrade()) else {
14074                return;
14075            };
14076            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14077                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14078            }) else {
14079                return;
14080            };
14081
14082            let hide_runnables = project
14083                .update(cx, |project, cx| {
14084                    // Do not display any test indicators in non-dev server remote projects.
14085                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14086                })
14087                .unwrap_or(true);
14088            if hide_runnables {
14089                return;
14090            }
14091            let new_rows =
14092                cx.background_spawn({
14093                    let snapshot = display_snapshot.clone();
14094                    async move {
14095                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14096                    }
14097                })
14098                    .await;
14099            let Ok(lsp_tasks) =
14100                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14101            else {
14102                return;
14103            };
14104            let lsp_tasks = lsp_tasks.await;
14105
14106            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14107                lsp_tasks
14108                    .into_iter()
14109                    .flat_map(|(kind, tasks)| {
14110                        tasks.into_iter().filter_map(move |(location, task)| {
14111                            Some((kind.clone(), location?, task))
14112                        })
14113                    })
14114                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14115                        let buffer = location.target.buffer;
14116                        let buffer_snapshot = buffer.read(cx).snapshot();
14117                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14118                            |(excerpt_id, snapshot, _)| {
14119                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14120                                    display_snapshot
14121                                        .buffer_snapshot
14122                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14123                                } else {
14124                                    None
14125                                }
14126                            },
14127                        );
14128                        if let Some(offset) = offset {
14129                            let task_buffer_range =
14130                                location.target.range.to_point(&buffer_snapshot);
14131                            let context_buffer_range =
14132                                task_buffer_range.to_offset(&buffer_snapshot);
14133                            let context_range = BufferOffset(context_buffer_range.start)
14134                                ..BufferOffset(context_buffer_range.end);
14135
14136                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14137                                .or_insert_with(|| RunnableTasks {
14138                                    templates: Vec::new(),
14139                                    offset,
14140                                    column: task_buffer_range.start.column,
14141                                    extra_variables: HashMap::default(),
14142                                    context_range,
14143                                })
14144                                .templates
14145                                .push((kind, task.original_task().clone()));
14146                        }
14147
14148                        acc
14149                    })
14150            }) else {
14151                return;
14152            };
14153
14154            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14155                buffer.language_settings(cx).tasks.prefer_lsp
14156            }) else {
14157                return;
14158            };
14159
14160            let rows = Self::runnable_rows(
14161                project,
14162                display_snapshot,
14163                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14164                new_rows,
14165                cx.clone(),
14166            )
14167            .await;
14168            editor
14169                .update(cx, |editor, _| {
14170                    editor.clear_tasks();
14171                    for (key, mut value) in rows {
14172                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14173                            value.templates.extend(lsp_tasks.templates);
14174                        }
14175
14176                        editor.insert_tasks(key, value);
14177                    }
14178                    for (key, value) in lsp_tasks_by_rows {
14179                        editor.insert_tasks(key, value);
14180                    }
14181                })
14182                .ok();
14183        })
14184    }
14185    fn fetch_runnable_ranges(
14186        snapshot: &DisplaySnapshot,
14187        range: Range<Anchor>,
14188    ) -> Vec<language::RunnableRange> {
14189        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14190    }
14191
14192    fn runnable_rows(
14193        project: Entity<Project>,
14194        snapshot: DisplaySnapshot,
14195        prefer_lsp: bool,
14196        runnable_ranges: Vec<RunnableRange>,
14197        cx: AsyncWindowContext,
14198    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14199        cx.spawn(async move |cx| {
14200            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14201            for mut runnable in runnable_ranges {
14202                let Some(tasks) = cx
14203                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14204                    .ok()
14205                else {
14206                    continue;
14207                };
14208                let mut tasks = tasks.await;
14209
14210                if prefer_lsp {
14211                    tasks.retain(|(task_kind, _)| {
14212                        !matches!(task_kind, TaskSourceKind::Language { .. })
14213                    });
14214                }
14215                if tasks.is_empty() {
14216                    continue;
14217                }
14218
14219                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14220                let Some(row) = snapshot
14221                    .buffer_snapshot
14222                    .buffer_line_for_row(MultiBufferRow(point.row))
14223                    .map(|(_, range)| range.start.row)
14224                else {
14225                    continue;
14226                };
14227
14228                let context_range =
14229                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14230                runnable_rows.push((
14231                    (runnable.buffer_id, row),
14232                    RunnableTasks {
14233                        templates: tasks,
14234                        offset: snapshot
14235                            .buffer_snapshot
14236                            .anchor_before(runnable.run_range.start),
14237                        context_range,
14238                        column: point.column,
14239                        extra_variables: runnable.extra_captures,
14240                    },
14241                ));
14242            }
14243            runnable_rows
14244        })
14245    }
14246
14247    fn templates_with_tags(
14248        project: &Entity<Project>,
14249        runnable: &mut Runnable,
14250        cx: &mut App,
14251    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14252        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14253            let (worktree_id, file) = project
14254                .buffer_for_id(runnable.buffer, cx)
14255                .and_then(|buffer| buffer.read(cx).file())
14256                .map(|file| (file.worktree_id(cx), file.clone()))
14257                .unzip();
14258
14259            (
14260                project.task_store().read(cx).task_inventory().cloned(),
14261                worktree_id,
14262                file,
14263            )
14264        });
14265
14266        let tags = mem::take(&mut runnable.tags);
14267        let language = runnable.language.clone();
14268        cx.spawn(async move |cx| {
14269            let mut templates_with_tags = Vec::new();
14270            if let Some(inventory) = inventory {
14271                for RunnableTag(tag) in tags {
14272                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14273                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14274                    }) else {
14275                        return templates_with_tags;
14276                    };
14277                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14278                        move |(_, template)| {
14279                            template.tags.iter().any(|source_tag| source_tag == &tag)
14280                        },
14281                    ));
14282                }
14283            }
14284            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14285
14286            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14287                // Strongest source wins; if we have worktree tag binding, prefer that to
14288                // global and language bindings;
14289                // if we have a global binding, prefer that to language binding.
14290                let first_mismatch = templates_with_tags
14291                    .iter()
14292                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14293                if let Some(index) = first_mismatch {
14294                    templates_with_tags.truncate(index);
14295                }
14296            }
14297
14298            templates_with_tags
14299        })
14300    }
14301
14302    pub fn move_to_enclosing_bracket(
14303        &mut self,
14304        _: &MoveToEnclosingBracket,
14305        window: &mut Window,
14306        cx: &mut Context<Self>,
14307    ) {
14308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14309        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14310            s.move_offsets_with(|snapshot, selection| {
14311                let Some(enclosing_bracket_ranges) =
14312                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14313                else {
14314                    return;
14315                };
14316
14317                let mut best_length = usize::MAX;
14318                let mut best_inside = false;
14319                let mut best_in_bracket_range = false;
14320                let mut best_destination = None;
14321                for (open, close) in enclosing_bracket_ranges {
14322                    let close = close.to_inclusive();
14323                    let length = close.end() - open.start;
14324                    let inside = selection.start >= open.end && selection.end <= *close.start();
14325                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14326                        || close.contains(&selection.head());
14327
14328                    // If best is next to a bracket and current isn't, skip
14329                    if !in_bracket_range && best_in_bracket_range {
14330                        continue;
14331                    }
14332
14333                    // Prefer smaller lengths unless best is inside and current isn't
14334                    if length > best_length && (best_inside || !inside) {
14335                        continue;
14336                    }
14337
14338                    best_length = length;
14339                    best_inside = inside;
14340                    best_in_bracket_range = in_bracket_range;
14341                    best_destination = Some(
14342                        if close.contains(&selection.start) && close.contains(&selection.end) {
14343                            if inside { open.end } else { open.start }
14344                        } else if inside {
14345                            *close.start()
14346                        } else {
14347                            *close.end()
14348                        },
14349                    );
14350                }
14351
14352                if let Some(destination) = best_destination {
14353                    selection.collapse_to(destination, SelectionGoal::None);
14354                }
14355            })
14356        });
14357    }
14358
14359    pub fn undo_selection(
14360        &mut self,
14361        _: &UndoSelection,
14362        window: &mut Window,
14363        cx: &mut Context<Self>,
14364    ) {
14365        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14366        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14367            self.selection_history.mode = SelectionHistoryMode::Undoing;
14368            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14369                this.end_selection(window, cx);
14370                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14371                    s.select_anchors(entry.selections.to_vec())
14372                });
14373            });
14374            self.selection_history.mode = SelectionHistoryMode::Normal;
14375
14376            self.select_next_state = entry.select_next_state;
14377            self.select_prev_state = entry.select_prev_state;
14378            self.add_selections_state = entry.add_selections_state;
14379        }
14380    }
14381
14382    pub fn redo_selection(
14383        &mut self,
14384        _: &RedoSelection,
14385        window: &mut Window,
14386        cx: &mut Context<Self>,
14387    ) {
14388        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14389        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14390            self.selection_history.mode = SelectionHistoryMode::Redoing;
14391            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14392                this.end_selection(window, cx);
14393                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14394                    s.select_anchors(entry.selections.to_vec())
14395                });
14396            });
14397            self.selection_history.mode = SelectionHistoryMode::Normal;
14398
14399            self.select_next_state = entry.select_next_state;
14400            self.select_prev_state = entry.select_prev_state;
14401            self.add_selections_state = entry.add_selections_state;
14402        }
14403    }
14404
14405    pub fn expand_excerpts(
14406        &mut self,
14407        action: &ExpandExcerpts,
14408        _: &mut Window,
14409        cx: &mut Context<Self>,
14410    ) {
14411        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14412    }
14413
14414    pub fn expand_excerpts_down(
14415        &mut self,
14416        action: &ExpandExcerptsDown,
14417        _: &mut Window,
14418        cx: &mut Context<Self>,
14419    ) {
14420        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14421    }
14422
14423    pub fn expand_excerpts_up(
14424        &mut self,
14425        action: &ExpandExcerptsUp,
14426        _: &mut Window,
14427        cx: &mut Context<Self>,
14428    ) {
14429        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14430    }
14431
14432    pub fn expand_excerpts_for_direction(
14433        &mut self,
14434        lines: u32,
14435        direction: ExpandExcerptDirection,
14436
14437        cx: &mut Context<Self>,
14438    ) {
14439        let selections = self.selections.disjoint_anchors();
14440
14441        let lines = if lines == 0 {
14442            EditorSettings::get_global(cx).expand_excerpt_lines
14443        } else {
14444            lines
14445        };
14446
14447        self.buffer.update(cx, |buffer, cx| {
14448            let snapshot = buffer.snapshot(cx);
14449            let mut excerpt_ids = selections
14450                .iter()
14451                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14452                .collect::<Vec<_>>();
14453            excerpt_ids.sort();
14454            excerpt_ids.dedup();
14455            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14456        })
14457    }
14458
14459    pub fn expand_excerpt(
14460        &mut self,
14461        excerpt: ExcerptId,
14462        direction: ExpandExcerptDirection,
14463        window: &mut Window,
14464        cx: &mut Context<Self>,
14465    ) {
14466        let current_scroll_position = self.scroll_position(cx);
14467        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14468        let mut should_scroll_up = false;
14469
14470        if direction == ExpandExcerptDirection::Down {
14471            let multi_buffer = self.buffer.read(cx);
14472            let snapshot = multi_buffer.snapshot(cx);
14473            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14474                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14475                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14476                        let buffer_snapshot = buffer.read(cx).snapshot();
14477                        let excerpt_end_row =
14478                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14479                        let last_row = buffer_snapshot.max_point().row;
14480                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14481                        should_scroll_up = lines_below >= lines_to_expand;
14482                    }
14483                }
14484            }
14485        }
14486
14487        self.buffer.update(cx, |buffer, cx| {
14488            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14489        });
14490
14491        if should_scroll_up {
14492            let new_scroll_position =
14493                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14494            self.set_scroll_position(new_scroll_position, window, cx);
14495        }
14496    }
14497
14498    pub fn go_to_singleton_buffer_point(
14499        &mut self,
14500        point: Point,
14501        window: &mut Window,
14502        cx: &mut Context<Self>,
14503    ) {
14504        self.go_to_singleton_buffer_range(point..point, window, cx);
14505    }
14506
14507    pub fn go_to_singleton_buffer_range(
14508        &mut self,
14509        range: Range<Point>,
14510        window: &mut Window,
14511        cx: &mut Context<Self>,
14512    ) {
14513        let multibuffer = self.buffer().read(cx);
14514        let Some(buffer) = multibuffer.as_singleton() else {
14515            return;
14516        };
14517        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14518            return;
14519        };
14520        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14521            return;
14522        };
14523        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14524            s.select_anchor_ranges([start..end])
14525        });
14526    }
14527
14528    pub fn go_to_diagnostic(
14529        &mut self,
14530        _: &GoToDiagnostic,
14531        window: &mut Window,
14532        cx: &mut Context<Self>,
14533    ) {
14534        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14535        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14536    }
14537
14538    pub fn go_to_prev_diagnostic(
14539        &mut self,
14540        _: &GoToPreviousDiagnostic,
14541        window: &mut Window,
14542        cx: &mut Context<Self>,
14543    ) {
14544        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14545        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14546    }
14547
14548    pub fn go_to_diagnostic_impl(
14549        &mut self,
14550        direction: Direction,
14551        window: &mut Window,
14552        cx: &mut Context<Self>,
14553    ) {
14554        let buffer = self.buffer.read(cx).snapshot(cx);
14555        let selection = self.selections.newest::<usize>(cx);
14556
14557        let mut active_group_id = None;
14558        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14559            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14560                active_group_id = Some(active_group.group_id);
14561            }
14562        }
14563
14564        fn filtered(
14565            snapshot: EditorSnapshot,
14566            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14567        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14568            diagnostics
14569                .filter(|entry| entry.range.start != entry.range.end)
14570                .filter(|entry| !entry.diagnostic.is_unnecessary)
14571                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14572        }
14573
14574        let snapshot = self.snapshot(window, cx);
14575        let before = filtered(
14576            snapshot.clone(),
14577            buffer
14578                .diagnostics_in_range(0..selection.start)
14579                .filter(|entry| entry.range.start <= selection.start),
14580        );
14581        let after = filtered(
14582            snapshot,
14583            buffer
14584                .diagnostics_in_range(selection.start..buffer.len())
14585                .filter(|entry| entry.range.start >= selection.start),
14586        );
14587
14588        let mut found: Option<DiagnosticEntry<usize>> = None;
14589        if direction == Direction::Prev {
14590            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14591            {
14592                for diagnostic in prev_diagnostics.into_iter().rev() {
14593                    if diagnostic.range.start != selection.start
14594                        || active_group_id
14595                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14596                    {
14597                        found = Some(diagnostic);
14598                        break 'outer;
14599                    }
14600                }
14601            }
14602        } else {
14603            for diagnostic in after.chain(before) {
14604                if diagnostic.range.start != selection.start
14605                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14606                {
14607                    found = Some(diagnostic);
14608                    break;
14609                }
14610            }
14611        }
14612        let Some(next_diagnostic) = found else {
14613            return;
14614        };
14615
14616        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14617            return;
14618        };
14619        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14620            s.select_ranges(vec![
14621                next_diagnostic.range.start..next_diagnostic.range.start,
14622            ])
14623        });
14624        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14625        self.refresh_inline_completion(false, true, window, cx);
14626    }
14627
14628    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14629        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14630        let snapshot = self.snapshot(window, cx);
14631        let selection = self.selections.newest::<Point>(cx);
14632        self.go_to_hunk_before_or_after_position(
14633            &snapshot,
14634            selection.head(),
14635            Direction::Next,
14636            window,
14637            cx,
14638        );
14639    }
14640
14641    pub fn go_to_hunk_before_or_after_position(
14642        &mut self,
14643        snapshot: &EditorSnapshot,
14644        position: Point,
14645        direction: Direction,
14646        window: &mut Window,
14647        cx: &mut Context<Editor>,
14648    ) {
14649        let row = if direction == Direction::Next {
14650            self.hunk_after_position(snapshot, position)
14651                .map(|hunk| hunk.row_range.start)
14652        } else {
14653            self.hunk_before_position(snapshot, position)
14654        };
14655
14656        if let Some(row) = row {
14657            let destination = Point::new(row.0, 0);
14658            let autoscroll = Autoscroll::center();
14659
14660            self.unfold_ranges(&[destination..destination], false, false, cx);
14661            self.change_selections(Some(autoscroll), window, cx, |s| {
14662                s.select_ranges([destination..destination]);
14663            });
14664        }
14665    }
14666
14667    fn hunk_after_position(
14668        &mut self,
14669        snapshot: &EditorSnapshot,
14670        position: Point,
14671    ) -> Option<MultiBufferDiffHunk> {
14672        snapshot
14673            .buffer_snapshot
14674            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14675            .find(|hunk| hunk.row_range.start.0 > position.row)
14676            .or_else(|| {
14677                snapshot
14678                    .buffer_snapshot
14679                    .diff_hunks_in_range(Point::zero()..position)
14680                    .find(|hunk| hunk.row_range.end.0 < position.row)
14681            })
14682    }
14683
14684    fn go_to_prev_hunk(
14685        &mut self,
14686        _: &GoToPreviousHunk,
14687        window: &mut Window,
14688        cx: &mut Context<Self>,
14689    ) {
14690        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14691        let snapshot = self.snapshot(window, cx);
14692        let selection = self.selections.newest::<Point>(cx);
14693        self.go_to_hunk_before_or_after_position(
14694            &snapshot,
14695            selection.head(),
14696            Direction::Prev,
14697            window,
14698            cx,
14699        );
14700    }
14701
14702    fn hunk_before_position(
14703        &mut self,
14704        snapshot: &EditorSnapshot,
14705        position: Point,
14706    ) -> Option<MultiBufferRow> {
14707        snapshot
14708            .buffer_snapshot
14709            .diff_hunk_before(position)
14710            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14711    }
14712
14713    fn go_to_next_change(
14714        &mut self,
14715        _: &GoToNextChange,
14716        window: &mut Window,
14717        cx: &mut Context<Self>,
14718    ) {
14719        if let Some(selections) = self
14720            .change_list
14721            .next_change(1, Direction::Next)
14722            .map(|s| s.to_vec())
14723        {
14724            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14725                let map = s.display_map();
14726                s.select_display_ranges(selections.iter().map(|a| {
14727                    let point = a.to_display_point(&map);
14728                    point..point
14729                }))
14730            })
14731        }
14732    }
14733
14734    fn go_to_previous_change(
14735        &mut self,
14736        _: &GoToPreviousChange,
14737        window: &mut Window,
14738        cx: &mut Context<Self>,
14739    ) {
14740        if let Some(selections) = self
14741            .change_list
14742            .next_change(1, Direction::Prev)
14743            .map(|s| s.to_vec())
14744        {
14745            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14746                let map = s.display_map();
14747                s.select_display_ranges(selections.iter().map(|a| {
14748                    let point = a.to_display_point(&map);
14749                    point..point
14750                }))
14751            })
14752        }
14753    }
14754
14755    fn go_to_line<T: 'static>(
14756        &mut self,
14757        position: Anchor,
14758        highlight_color: Option<Hsla>,
14759        window: &mut Window,
14760        cx: &mut Context<Self>,
14761    ) {
14762        let snapshot = self.snapshot(window, cx).display_snapshot;
14763        let position = position.to_point(&snapshot.buffer_snapshot);
14764        let start = snapshot
14765            .buffer_snapshot
14766            .clip_point(Point::new(position.row, 0), Bias::Left);
14767        let end = start + Point::new(1, 0);
14768        let start = snapshot.buffer_snapshot.anchor_before(start);
14769        let end = snapshot.buffer_snapshot.anchor_before(end);
14770
14771        self.highlight_rows::<T>(
14772            start..end,
14773            highlight_color
14774                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14775            Default::default(),
14776            cx,
14777        );
14778
14779        if self.buffer.read(cx).is_singleton() {
14780            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14781        }
14782    }
14783
14784    pub fn go_to_definition(
14785        &mut self,
14786        _: &GoToDefinition,
14787        window: &mut Window,
14788        cx: &mut Context<Self>,
14789    ) -> Task<Result<Navigated>> {
14790        let definition =
14791            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14792        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14793        cx.spawn_in(window, async move |editor, cx| {
14794            if definition.await? == Navigated::Yes {
14795                return Ok(Navigated::Yes);
14796            }
14797            match fallback_strategy {
14798                GoToDefinitionFallback::None => Ok(Navigated::No),
14799                GoToDefinitionFallback::FindAllReferences => {
14800                    match editor.update_in(cx, |editor, window, cx| {
14801                        editor.find_all_references(&FindAllReferences, window, cx)
14802                    })? {
14803                        Some(references) => references.await,
14804                        None => Ok(Navigated::No),
14805                    }
14806                }
14807            }
14808        })
14809    }
14810
14811    pub fn go_to_declaration(
14812        &mut self,
14813        _: &GoToDeclaration,
14814        window: &mut Window,
14815        cx: &mut Context<Self>,
14816    ) -> Task<Result<Navigated>> {
14817        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14818    }
14819
14820    pub fn go_to_declaration_split(
14821        &mut self,
14822        _: &GoToDeclaration,
14823        window: &mut Window,
14824        cx: &mut Context<Self>,
14825    ) -> Task<Result<Navigated>> {
14826        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14827    }
14828
14829    pub fn go_to_implementation(
14830        &mut self,
14831        _: &GoToImplementation,
14832        window: &mut Window,
14833        cx: &mut Context<Self>,
14834    ) -> Task<Result<Navigated>> {
14835        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14836    }
14837
14838    pub fn go_to_implementation_split(
14839        &mut self,
14840        _: &GoToImplementationSplit,
14841        window: &mut Window,
14842        cx: &mut Context<Self>,
14843    ) -> Task<Result<Navigated>> {
14844        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14845    }
14846
14847    pub fn go_to_type_definition(
14848        &mut self,
14849        _: &GoToTypeDefinition,
14850        window: &mut Window,
14851        cx: &mut Context<Self>,
14852    ) -> Task<Result<Navigated>> {
14853        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14854    }
14855
14856    pub fn go_to_definition_split(
14857        &mut self,
14858        _: &GoToDefinitionSplit,
14859        window: &mut Window,
14860        cx: &mut Context<Self>,
14861    ) -> Task<Result<Navigated>> {
14862        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14863    }
14864
14865    pub fn go_to_type_definition_split(
14866        &mut self,
14867        _: &GoToTypeDefinitionSplit,
14868        window: &mut Window,
14869        cx: &mut Context<Self>,
14870    ) -> Task<Result<Navigated>> {
14871        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14872    }
14873
14874    fn go_to_definition_of_kind(
14875        &mut self,
14876        kind: GotoDefinitionKind,
14877        split: bool,
14878        window: &mut Window,
14879        cx: &mut Context<Self>,
14880    ) -> Task<Result<Navigated>> {
14881        let Some(provider) = self.semantics_provider.clone() else {
14882            return Task::ready(Ok(Navigated::No));
14883        };
14884        let head = self.selections.newest::<usize>(cx).head();
14885        let buffer = self.buffer.read(cx);
14886        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14887            text_anchor
14888        } else {
14889            return Task::ready(Ok(Navigated::No));
14890        };
14891
14892        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14893            return Task::ready(Ok(Navigated::No));
14894        };
14895
14896        cx.spawn_in(window, async move |editor, cx| {
14897            let definitions = definitions.await?;
14898            let navigated = editor
14899                .update_in(cx, |editor, window, cx| {
14900                    editor.navigate_to_hover_links(
14901                        Some(kind),
14902                        definitions
14903                            .into_iter()
14904                            .filter(|location| {
14905                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14906                            })
14907                            .map(HoverLink::Text)
14908                            .collect::<Vec<_>>(),
14909                        split,
14910                        window,
14911                        cx,
14912                    )
14913                })?
14914                .await?;
14915            anyhow::Ok(navigated)
14916        })
14917    }
14918
14919    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14920        let selection = self.selections.newest_anchor();
14921        let head = selection.head();
14922        let tail = selection.tail();
14923
14924        let Some((buffer, start_position)) =
14925            self.buffer.read(cx).text_anchor_for_position(head, cx)
14926        else {
14927            return;
14928        };
14929
14930        let end_position = if head != tail {
14931            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14932                return;
14933            };
14934            Some(pos)
14935        } else {
14936            None
14937        };
14938
14939        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14940            let url = if let Some(end_pos) = end_position {
14941                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14942            } else {
14943                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14944            };
14945
14946            if let Some(url) = url {
14947                editor.update(cx, |_, cx| {
14948                    cx.open_url(&url);
14949                })
14950            } else {
14951                Ok(())
14952            }
14953        });
14954
14955        url_finder.detach();
14956    }
14957
14958    pub fn open_selected_filename(
14959        &mut self,
14960        _: &OpenSelectedFilename,
14961        window: &mut Window,
14962        cx: &mut Context<Self>,
14963    ) {
14964        let Some(workspace) = self.workspace() else {
14965            return;
14966        };
14967
14968        let position = self.selections.newest_anchor().head();
14969
14970        let Some((buffer, buffer_position)) =
14971            self.buffer.read(cx).text_anchor_for_position(position, cx)
14972        else {
14973            return;
14974        };
14975
14976        let project = self.project.clone();
14977
14978        cx.spawn_in(window, async move |_, cx| {
14979            let result = find_file(&buffer, project, buffer_position, cx).await;
14980
14981            if let Some((_, path)) = result {
14982                workspace
14983                    .update_in(cx, |workspace, window, cx| {
14984                        workspace.open_resolved_path(path, window, cx)
14985                    })?
14986                    .await?;
14987            }
14988            anyhow::Ok(())
14989        })
14990        .detach();
14991    }
14992
14993    pub(crate) fn navigate_to_hover_links(
14994        &mut self,
14995        kind: Option<GotoDefinitionKind>,
14996        mut definitions: Vec<HoverLink>,
14997        split: bool,
14998        window: &mut Window,
14999        cx: &mut Context<Editor>,
15000    ) -> Task<Result<Navigated>> {
15001        // If there is one definition, just open it directly
15002        if definitions.len() == 1 {
15003            let definition = definitions.pop().unwrap();
15004
15005            enum TargetTaskResult {
15006                Location(Option<Location>),
15007                AlreadyNavigated,
15008            }
15009
15010            let target_task = match definition {
15011                HoverLink::Text(link) => {
15012                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15013                }
15014                HoverLink::InlayHint(lsp_location, server_id) => {
15015                    let computation =
15016                        self.compute_target_location(lsp_location, server_id, window, cx);
15017                    cx.background_spawn(async move {
15018                        let location = computation.await?;
15019                        Ok(TargetTaskResult::Location(location))
15020                    })
15021                }
15022                HoverLink::Url(url) => {
15023                    cx.open_url(&url);
15024                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15025                }
15026                HoverLink::File(path) => {
15027                    if let Some(workspace) = self.workspace() {
15028                        cx.spawn_in(window, async move |_, cx| {
15029                            workspace
15030                                .update_in(cx, |workspace, window, cx| {
15031                                    workspace.open_resolved_path(path, window, cx)
15032                                })?
15033                                .await
15034                                .map(|_| TargetTaskResult::AlreadyNavigated)
15035                        })
15036                    } else {
15037                        Task::ready(Ok(TargetTaskResult::Location(None)))
15038                    }
15039                }
15040            };
15041            cx.spawn_in(window, async move |editor, cx| {
15042                let target = match target_task.await.context("target resolution task")? {
15043                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15044                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15045                    TargetTaskResult::Location(Some(target)) => target,
15046                };
15047
15048                editor.update_in(cx, |editor, window, cx| {
15049                    let Some(workspace) = editor.workspace() else {
15050                        return Navigated::No;
15051                    };
15052                    let pane = workspace.read(cx).active_pane().clone();
15053
15054                    let range = target.range.to_point(target.buffer.read(cx));
15055                    let range = editor.range_for_match(&range);
15056                    let range = collapse_multiline_range(range);
15057
15058                    if !split
15059                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15060                    {
15061                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15062                    } else {
15063                        window.defer(cx, move |window, cx| {
15064                            let target_editor: Entity<Self> =
15065                                workspace.update(cx, |workspace, cx| {
15066                                    let pane = if split {
15067                                        workspace.adjacent_pane(window, cx)
15068                                    } else {
15069                                        workspace.active_pane().clone()
15070                                    };
15071
15072                                    workspace.open_project_item(
15073                                        pane,
15074                                        target.buffer.clone(),
15075                                        true,
15076                                        true,
15077                                        window,
15078                                        cx,
15079                                    )
15080                                });
15081                            target_editor.update(cx, |target_editor, cx| {
15082                                // When selecting a definition in a different buffer, disable the nav history
15083                                // to avoid creating a history entry at the previous cursor location.
15084                                pane.update(cx, |pane, _| pane.disable_history());
15085                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15086                                pane.update(cx, |pane, _| pane.enable_history());
15087                            });
15088                        });
15089                    }
15090                    Navigated::Yes
15091                })
15092            })
15093        } else if !definitions.is_empty() {
15094            cx.spawn_in(window, async move |editor, cx| {
15095                let (title, location_tasks, workspace) = editor
15096                    .update_in(cx, |editor, window, cx| {
15097                        let tab_kind = match kind {
15098                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15099                            _ => "Definitions",
15100                        };
15101                        let title = definitions
15102                            .iter()
15103                            .find_map(|definition| match definition {
15104                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15105                                    let buffer = origin.buffer.read(cx);
15106                                    format!(
15107                                        "{} for {}",
15108                                        tab_kind,
15109                                        buffer
15110                                            .text_for_range(origin.range.clone())
15111                                            .collect::<String>()
15112                                    )
15113                                }),
15114                                HoverLink::InlayHint(_, _) => None,
15115                                HoverLink::Url(_) => None,
15116                                HoverLink::File(_) => None,
15117                            })
15118                            .unwrap_or(tab_kind.to_string());
15119                        let location_tasks = definitions
15120                            .into_iter()
15121                            .map(|definition| match definition {
15122                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15123                                HoverLink::InlayHint(lsp_location, server_id) => editor
15124                                    .compute_target_location(lsp_location, server_id, window, cx),
15125                                HoverLink::Url(_) => Task::ready(Ok(None)),
15126                                HoverLink::File(_) => Task::ready(Ok(None)),
15127                            })
15128                            .collect::<Vec<_>>();
15129                        (title, location_tasks, editor.workspace().clone())
15130                    })
15131                    .context("location tasks preparation")?;
15132
15133                let locations = future::join_all(location_tasks)
15134                    .await
15135                    .into_iter()
15136                    .filter_map(|location| location.transpose())
15137                    .collect::<Result<_>>()
15138                    .context("location tasks")?;
15139
15140                let Some(workspace) = workspace else {
15141                    return Ok(Navigated::No);
15142                };
15143                let opened = workspace
15144                    .update_in(cx, |workspace, window, cx| {
15145                        Self::open_locations_in_multibuffer(
15146                            workspace,
15147                            locations,
15148                            title,
15149                            split,
15150                            MultibufferSelectionMode::First,
15151                            window,
15152                            cx,
15153                        )
15154                    })
15155                    .ok();
15156
15157                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15158            })
15159        } else {
15160            Task::ready(Ok(Navigated::No))
15161        }
15162    }
15163
15164    fn compute_target_location(
15165        &self,
15166        lsp_location: lsp::Location,
15167        server_id: LanguageServerId,
15168        window: &mut Window,
15169        cx: &mut Context<Self>,
15170    ) -> Task<anyhow::Result<Option<Location>>> {
15171        let Some(project) = self.project.clone() else {
15172            return Task::ready(Ok(None));
15173        };
15174
15175        cx.spawn_in(window, async move |editor, cx| {
15176            let location_task = editor.update(cx, |_, cx| {
15177                project.update(cx, |project, cx| {
15178                    let language_server_name = project
15179                        .language_server_statuses(cx)
15180                        .find(|(id, _)| server_id == *id)
15181                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15182                    language_server_name.map(|language_server_name| {
15183                        project.open_local_buffer_via_lsp(
15184                            lsp_location.uri.clone(),
15185                            server_id,
15186                            language_server_name,
15187                            cx,
15188                        )
15189                    })
15190                })
15191            })?;
15192            let location = match location_task {
15193                Some(task) => Some({
15194                    let target_buffer_handle = task.await.context("open local buffer")?;
15195                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15196                        let target_start = target_buffer
15197                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15198                        let target_end = target_buffer
15199                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15200                        target_buffer.anchor_after(target_start)
15201                            ..target_buffer.anchor_before(target_end)
15202                    })?;
15203                    Location {
15204                        buffer: target_buffer_handle,
15205                        range,
15206                    }
15207                }),
15208                None => None,
15209            };
15210            Ok(location)
15211        })
15212    }
15213
15214    pub fn find_all_references(
15215        &mut self,
15216        _: &FindAllReferences,
15217        window: &mut Window,
15218        cx: &mut Context<Self>,
15219    ) -> Option<Task<Result<Navigated>>> {
15220        let selection = self.selections.newest::<usize>(cx);
15221        let multi_buffer = self.buffer.read(cx);
15222        let head = selection.head();
15223
15224        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15225        let head_anchor = multi_buffer_snapshot.anchor_at(
15226            head,
15227            if head < selection.tail() {
15228                Bias::Right
15229            } else {
15230                Bias::Left
15231            },
15232        );
15233
15234        match self
15235            .find_all_references_task_sources
15236            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15237        {
15238            Ok(_) => {
15239                log::info!(
15240                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15241                );
15242                return None;
15243            }
15244            Err(i) => {
15245                self.find_all_references_task_sources.insert(i, head_anchor);
15246            }
15247        }
15248
15249        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15250        let workspace = self.workspace()?;
15251        let project = workspace.read(cx).project().clone();
15252        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15253        Some(cx.spawn_in(window, async move |editor, cx| {
15254            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15255                if let Ok(i) = editor
15256                    .find_all_references_task_sources
15257                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15258                {
15259                    editor.find_all_references_task_sources.remove(i);
15260                }
15261            });
15262
15263            let locations = references.await?;
15264            if locations.is_empty() {
15265                return anyhow::Ok(Navigated::No);
15266            }
15267
15268            workspace.update_in(cx, |workspace, window, cx| {
15269                let title = locations
15270                    .first()
15271                    .as_ref()
15272                    .map(|location| {
15273                        let buffer = location.buffer.read(cx);
15274                        format!(
15275                            "References to `{}`",
15276                            buffer
15277                                .text_for_range(location.range.clone())
15278                                .collect::<String>()
15279                        )
15280                    })
15281                    .unwrap();
15282                Self::open_locations_in_multibuffer(
15283                    workspace,
15284                    locations,
15285                    title,
15286                    false,
15287                    MultibufferSelectionMode::First,
15288                    window,
15289                    cx,
15290                );
15291                Navigated::Yes
15292            })
15293        }))
15294    }
15295
15296    /// Opens a multibuffer with the given project locations in it
15297    pub fn open_locations_in_multibuffer(
15298        workspace: &mut Workspace,
15299        mut locations: Vec<Location>,
15300        title: String,
15301        split: bool,
15302        multibuffer_selection_mode: MultibufferSelectionMode,
15303        window: &mut Window,
15304        cx: &mut Context<Workspace>,
15305    ) {
15306        // If there are multiple definitions, open them in a multibuffer
15307        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15308        let mut locations = locations.into_iter().peekable();
15309        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15310        let capability = workspace.project().read(cx).capability();
15311
15312        let excerpt_buffer = cx.new(|cx| {
15313            let mut multibuffer = MultiBuffer::new(capability);
15314            while let Some(location) = locations.next() {
15315                let buffer = location.buffer.read(cx);
15316                let mut ranges_for_buffer = Vec::new();
15317                let range = location.range.to_point(buffer);
15318                ranges_for_buffer.push(range.clone());
15319
15320                while let Some(next_location) = locations.peek() {
15321                    if next_location.buffer == location.buffer {
15322                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15323                        locations.next();
15324                    } else {
15325                        break;
15326                    }
15327                }
15328
15329                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15330                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15331                    PathKey::for_buffer(&location.buffer, cx),
15332                    location.buffer.clone(),
15333                    ranges_for_buffer,
15334                    DEFAULT_MULTIBUFFER_CONTEXT,
15335                    cx,
15336                );
15337                ranges.extend(new_ranges)
15338            }
15339
15340            multibuffer.with_title(title)
15341        });
15342
15343        let editor = cx.new(|cx| {
15344            Editor::for_multibuffer(
15345                excerpt_buffer,
15346                Some(workspace.project().clone()),
15347                window,
15348                cx,
15349            )
15350        });
15351        editor.update(cx, |editor, cx| {
15352            match multibuffer_selection_mode {
15353                MultibufferSelectionMode::First => {
15354                    if let Some(first_range) = ranges.first() {
15355                        editor.change_selections(None, window, cx, |selections| {
15356                            selections.clear_disjoint();
15357                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15358                        });
15359                    }
15360                    editor.highlight_background::<Self>(
15361                        &ranges,
15362                        |theme| theme.colors().editor_highlighted_line_background,
15363                        cx,
15364                    );
15365                }
15366                MultibufferSelectionMode::All => {
15367                    editor.change_selections(None, window, cx, |selections| {
15368                        selections.clear_disjoint();
15369                        selections.select_anchor_ranges(ranges);
15370                    });
15371                }
15372            }
15373            editor.register_buffers_with_language_servers(cx);
15374        });
15375
15376        let item = Box::new(editor);
15377        let item_id = item.item_id();
15378
15379        if split {
15380            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15381        } else {
15382            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15383                let (preview_item_id, preview_item_idx) =
15384                    workspace.active_pane().read_with(cx, |pane, _| {
15385                        (pane.preview_item_id(), pane.preview_item_idx())
15386                    });
15387
15388                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15389
15390                if let Some(preview_item_id) = preview_item_id {
15391                    workspace.active_pane().update(cx, |pane, cx| {
15392                        pane.remove_item(preview_item_id, false, false, window, cx);
15393                    });
15394                }
15395            } else {
15396                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15397            }
15398        }
15399        workspace.active_pane().update(cx, |pane, cx| {
15400            pane.set_preview_item_id(Some(item_id), cx);
15401        });
15402    }
15403
15404    pub fn rename(
15405        &mut self,
15406        _: &Rename,
15407        window: &mut Window,
15408        cx: &mut Context<Self>,
15409    ) -> Option<Task<Result<()>>> {
15410        use language::ToOffset as _;
15411
15412        let provider = self.semantics_provider.clone()?;
15413        let selection = self.selections.newest_anchor().clone();
15414        let (cursor_buffer, cursor_buffer_position) = self
15415            .buffer
15416            .read(cx)
15417            .text_anchor_for_position(selection.head(), cx)?;
15418        let (tail_buffer, cursor_buffer_position_end) = self
15419            .buffer
15420            .read(cx)
15421            .text_anchor_for_position(selection.tail(), cx)?;
15422        if tail_buffer != cursor_buffer {
15423            return None;
15424        }
15425
15426        let snapshot = cursor_buffer.read(cx).snapshot();
15427        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15428        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15429        let prepare_rename = provider
15430            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15431            .unwrap_or_else(|| Task::ready(Ok(None)));
15432        drop(snapshot);
15433
15434        Some(cx.spawn_in(window, async move |this, cx| {
15435            let rename_range = if let Some(range) = prepare_rename.await? {
15436                Some(range)
15437            } else {
15438                this.update(cx, |this, cx| {
15439                    let buffer = this.buffer.read(cx).snapshot(cx);
15440                    let mut buffer_highlights = this
15441                        .document_highlights_for_position(selection.head(), &buffer)
15442                        .filter(|highlight| {
15443                            highlight.start.excerpt_id == selection.head().excerpt_id
15444                                && highlight.end.excerpt_id == selection.head().excerpt_id
15445                        });
15446                    buffer_highlights
15447                        .next()
15448                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15449                })?
15450            };
15451            if let Some(rename_range) = rename_range {
15452                this.update_in(cx, |this, window, cx| {
15453                    let snapshot = cursor_buffer.read(cx).snapshot();
15454                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15455                    let cursor_offset_in_rename_range =
15456                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15457                    let cursor_offset_in_rename_range_end =
15458                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15459
15460                    this.take_rename(false, window, cx);
15461                    let buffer = this.buffer.read(cx).read(cx);
15462                    let cursor_offset = selection.head().to_offset(&buffer);
15463                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15464                    let rename_end = rename_start + rename_buffer_range.len();
15465                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15466                    let mut old_highlight_id = None;
15467                    let old_name: Arc<str> = buffer
15468                        .chunks(rename_start..rename_end, true)
15469                        .map(|chunk| {
15470                            if old_highlight_id.is_none() {
15471                                old_highlight_id = chunk.syntax_highlight_id;
15472                            }
15473                            chunk.text
15474                        })
15475                        .collect::<String>()
15476                        .into();
15477
15478                    drop(buffer);
15479
15480                    // Position the selection in the rename editor so that it matches the current selection.
15481                    this.show_local_selections = false;
15482                    let rename_editor = cx.new(|cx| {
15483                        let mut editor = Editor::single_line(window, cx);
15484                        editor.buffer.update(cx, |buffer, cx| {
15485                            buffer.edit([(0..0, old_name.clone())], None, cx)
15486                        });
15487                        let rename_selection_range = match cursor_offset_in_rename_range
15488                            .cmp(&cursor_offset_in_rename_range_end)
15489                        {
15490                            Ordering::Equal => {
15491                                editor.select_all(&SelectAll, window, cx);
15492                                return editor;
15493                            }
15494                            Ordering::Less => {
15495                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15496                            }
15497                            Ordering::Greater => {
15498                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15499                            }
15500                        };
15501                        if rename_selection_range.end > old_name.len() {
15502                            editor.select_all(&SelectAll, window, cx);
15503                        } else {
15504                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15505                                s.select_ranges([rename_selection_range]);
15506                            });
15507                        }
15508                        editor
15509                    });
15510                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15511                        if e == &EditorEvent::Focused {
15512                            cx.emit(EditorEvent::FocusedIn)
15513                        }
15514                    })
15515                    .detach();
15516
15517                    let write_highlights = this
15518                        .clear_background_highlights::<DocumentHighlightWrite>(cx)
15519                        .unwrap_or_default();
15520                    let read_highlights = this
15521                        .clear_background_highlights::<DocumentHighlightRead>(cx)
15522                        .unwrap_or_default();
15523                    let ranges = write_highlights
15524                        .iter()
15525                        .chain(read_highlights.iter())
15526                        .cloned()
15527                        .map(|highlight| {
15528                            (
15529                                highlight.range,
15530                                HighlightStyle {
15531                                    fade_out: Some(0.6),
15532                                    ..Default::default()
15533                                },
15534                            )
15535                        })
15536                        .collect();
15537
15538                    this.highlight_text::<Rename>(ranges, cx);
15539                    let rename_focus_handle = rename_editor.focus_handle(cx);
15540                    window.focus(&rename_focus_handle);
15541                    let block_id = this.insert_blocks(
15542                        [BlockProperties {
15543                            style: BlockStyle::Flex,
15544                            placement: BlockPlacement::Below(range.start),
15545                            height: Some(1),
15546                            render: Arc::new({
15547                                let rename_editor = rename_editor.clone();
15548                                move |cx: &mut BlockContext| {
15549                                    let mut text_style = cx.editor_style.text.clone();
15550                                    if let Some(highlight_style) = old_highlight_id
15551                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15552                                    {
15553                                        text_style = text_style.highlight(highlight_style);
15554                                    }
15555                                    div()
15556                                        .block_mouse_except_scroll()
15557                                        .pl(cx.anchor_x)
15558                                        .child(EditorElement::new(
15559                                            &rename_editor,
15560                                            EditorStyle {
15561                                                background: cx.theme().system().transparent,
15562                                                local_player: cx.editor_style.local_player,
15563                                                text: text_style,
15564                                                scrollbar_width: cx.editor_style.scrollbar_width,
15565                                                syntax: cx.editor_style.syntax.clone(),
15566                                                status: cx.editor_style.status.clone(),
15567                                                inlay_hints_style: HighlightStyle {
15568                                                    font_weight: Some(FontWeight::BOLD),
15569                                                    ..make_inlay_hints_style(cx.app)
15570                                                },
15571                                                inline_completion_styles: make_suggestion_styles(
15572                                                    cx.app,
15573                                                ),
15574                                                ..EditorStyle::default()
15575                                            },
15576                                        ))
15577                                        .into_any_element()
15578                                }
15579                            }),
15580                            priority: 0,
15581                            render_in_minimap: true,
15582                        }],
15583                        Some(Autoscroll::fit()),
15584                        cx,
15585                    )[0];
15586                    this.pending_rename = Some(RenameState {
15587                        range,
15588                        old_name,
15589                        editor: rename_editor,
15590                        block_id,
15591                    });
15592                })?;
15593            }
15594
15595            Ok(())
15596        }))
15597    }
15598
15599    pub fn confirm_rename(
15600        &mut self,
15601        _: &ConfirmRename,
15602        window: &mut Window,
15603        cx: &mut Context<Self>,
15604    ) -> Option<Task<Result<()>>> {
15605        let rename = self.take_rename(false, window, cx)?;
15606        let workspace = self.workspace()?.downgrade();
15607        let (buffer, start) = self
15608            .buffer
15609            .read(cx)
15610            .text_anchor_for_position(rename.range.start, cx)?;
15611        let (end_buffer, _) = self
15612            .buffer
15613            .read(cx)
15614            .text_anchor_for_position(rename.range.end, cx)?;
15615        if buffer != end_buffer {
15616            return None;
15617        }
15618
15619        let old_name = rename.old_name;
15620        let new_name = rename.editor.read(cx).text(cx);
15621
15622        let rename = self.semantics_provider.as_ref()?.perform_rename(
15623            &buffer,
15624            start,
15625            new_name.clone(),
15626            cx,
15627        )?;
15628
15629        Some(cx.spawn_in(window, async move |editor, cx| {
15630            let project_transaction = rename.await?;
15631            Self::open_project_transaction(
15632                &editor,
15633                workspace,
15634                project_transaction,
15635                format!("Rename: {}{}", old_name, new_name),
15636                cx,
15637            )
15638            .await?;
15639
15640            editor.update(cx, |editor, cx| {
15641                editor.refresh_document_highlights(cx);
15642            })?;
15643            Ok(())
15644        }))
15645    }
15646
15647    fn take_rename(
15648        &mut self,
15649        moving_cursor: bool,
15650        window: &mut Window,
15651        cx: &mut Context<Self>,
15652    ) -> Option<RenameState> {
15653        let rename = self.pending_rename.take()?;
15654        if rename.editor.focus_handle(cx).is_focused(window) {
15655            window.focus(&self.focus_handle);
15656        }
15657
15658        self.remove_blocks(
15659            [rename.block_id].into_iter().collect(),
15660            Some(Autoscroll::fit()),
15661            cx,
15662        );
15663        self.clear_highlights::<Rename>(cx);
15664        self.show_local_selections = true;
15665
15666        if moving_cursor {
15667            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15668                editor.selections.newest::<usize>(cx).head()
15669            });
15670
15671            // Update the selection to match the position of the selection inside
15672            // the rename editor.
15673            let snapshot = self.buffer.read(cx).read(cx);
15674            let rename_range = rename.range.to_offset(&snapshot);
15675            let cursor_in_editor = snapshot
15676                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15677                .min(rename_range.end);
15678            drop(snapshot);
15679
15680            self.change_selections(None, window, cx, |s| {
15681                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15682            });
15683        } else {
15684            self.refresh_document_highlights(cx);
15685        }
15686
15687        Some(rename)
15688    }
15689
15690    pub fn pending_rename(&self) -> Option<&RenameState> {
15691        self.pending_rename.as_ref()
15692    }
15693
15694    fn format(
15695        &mut self,
15696        _: &Format,
15697        window: &mut Window,
15698        cx: &mut Context<Self>,
15699    ) -> Option<Task<Result<()>>> {
15700        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15701
15702        let project = match &self.project {
15703            Some(project) => project.clone(),
15704            None => return None,
15705        };
15706
15707        Some(self.perform_format(
15708            project,
15709            FormatTrigger::Manual,
15710            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15711            window,
15712            cx,
15713        ))
15714    }
15715
15716    fn format_selections(
15717        &mut self,
15718        _: &FormatSelections,
15719        window: &mut Window,
15720        cx: &mut Context<Self>,
15721    ) -> Option<Task<Result<()>>> {
15722        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15723
15724        let project = match &self.project {
15725            Some(project) => project.clone(),
15726            None => return None,
15727        };
15728
15729        let ranges = self
15730            .selections
15731            .all_adjusted(cx)
15732            .into_iter()
15733            .map(|selection| selection.range())
15734            .collect_vec();
15735
15736        Some(self.perform_format(
15737            project,
15738            FormatTrigger::Manual,
15739            FormatTarget::Ranges(ranges),
15740            window,
15741            cx,
15742        ))
15743    }
15744
15745    fn perform_format(
15746        &mut self,
15747        project: Entity<Project>,
15748        trigger: FormatTrigger,
15749        target: FormatTarget,
15750        window: &mut Window,
15751        cx: &mut Context<Self>,
15752    ) -> Task<Result<()>> {
15753        let buffer = self.buffer.clone();
15754        let (buffers, target) = match target {
15755            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15756            FormatTarget::Ranges(selection_ranges) => {
15757                let multi_buffer = buffer.read(cx);
15758                let snapshot = multi_buffer.read(cx);
15759                let mut buffers = HashSet::default();
15760                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15761                    BTreeMap::new();
15762                for selection_range in selection_ranges {
15763                    for (buffer, buffer_range, _) in
15764                        snapshot.range_to_buffer_ranges(selection_range)
15765                    {
15766                        let buffer_id = buffer.remote_id();
15767                        let start = buffer.anchor_before(buffer_range.start);
15768                        let end = buffer.anchor_after(buffer_range.end);
15769                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15770                        buffer_id_to_ranges
15771                            .entry(buffer_id)
15772                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15773                            .or_insert_with(|| vec![start..end]);
15774                    }
15775                }
15776                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15777            }
15778        };
15779
15780        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15781        let selections_prev = transaction_id_prev
15782            .and_then(|transaction_id_prev| {
15783                // default to selections as they were after the last edit, if we have them,
15784                // instead of how they are now.
15785                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15786                // will take you back to where you made the last edit, instead of staying where you scrolled
15787                self.selection_history
15788                    .transaction(transaction_id_prev)
15789                    .map(|t| t.0.clone())
15790            })
15791            .unwrap_or_else(|| {
15792                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15793                self.selections.disjoint_anchors()
15794            });
15795
15796        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15797        let format = project.update(cx, |project, cx| {
15798            project.format(buffers, target, true, trigger, cx)
15799        });
15800
15801        cx.spawn_in(window, async move |editor, cx| {
15802            let transaction = futures::select_biased! {
15803                transaction = format.log_err().fuse() => transaction,
15804                () = timeout => {
15805                    log::warn!("timed out waiting for formatting");
15806                    None
15807                }
15808            };
15809
15810            buffer
15811                .update(cx, |buffer, cx| {
15812                    if let Some(transaction) = transaction {
15813                        if !buffer.is_singleton() {
15814                            buffer.push_transaction(&transaction.0, cx);
15815                        }
15816                    }
15817                    cx.notify();
15818                })
15819                .ok();
15820
15821            if let Some(transaction_id_now) =
15822                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15823            {
15824                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15825                if has_new_transaction {
15826                    _ = editor.update(cx, |editor, _| {
15827                        editor
15828                            .selection_history
15829                            .insert_transaction(transaction_id_now, selections_prev);
15830                    });
15831                }
15832            }
15833
15834            Ok(())
15835        })
15836    }
15837
15838    fn organize_imports(
15839        &mut self,
15840        _: &OrganizeImports,
15841        window: &mut Window,
15842        cx: &mut Context<Self>,
15843    ) -> Option<Task<Result<()>>> {
15844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15845        let project = match &self.project {
15846            Some(project) => project.clone(),
15847            None => return None,
15848        };
15849        Some(self.perform_code_action_kind(
15850            project,
15851            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15852            window,
15853            cx,
15854        ))
15855    }
15856
15857    fn perform_code_action_kind(
15858        &mut self,
15859        project: Entity<Project>,
15860        kind: CodeActionKind,
15861        window: &mut Window,
15862        cx: &mut Context<Self>,
15863    ) -> Task<Result<()>> {
15864        let buffer = self.buffer.clone();
15865        let buffers = buffer.read(cx).all_buffers();
15866        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15867        let apply_action = project.update(cx, |project, cx| {
15868            project.apply_code_action_kind(buffers, kind, true, cx)
15869        });
15870        cx.spawn_in(window, async move |_, cx| {
15871            let transaction = futures::select_biased! {
15872                () = timeout => {
15873                    log::warn!("timed out waiting for executing code action");
15874                    None
15875                }
15876                transaction = apply_action.log_err().fuse() => transaction,
15877            };
15878            buffer
15879                .update(cx, |buffer, cx| {
15880                    // check if we need this
15881                    if let Some(transaction) = transaction {
15882                        if !buffer.is_singleton() {
15883                            buffer.push_transaction(&transaction.0, cx);
15884                        }
15885                    }
15886                    cx.notify();
15887                })
15888                .ok();
15889            Ok(())
15890        })
15891    }
15892
15893    fn restart_language_server(
15894        &mut self,
15895        _: &RestartLanguageServer,
15896        _: &mut Window,
15897        cx: &mut Context<Self>,
15898    ) {
15899        if let Some(project) = self.project.clone() {
15900            self.buffer.update(cx, |multi_buffer, cx| {
15901                project.update(cx, |project, cx| {
15902                    project.restart_language_servers_for_buffers(
15903                        multi_buffer.all_buffers().into_iter().collect(),
15904                        cx,
15905                    );
15906                });
15907            })
15908        }
15909    }
15910
15911    fn stop_language_server(
15912        &mut self,
15913        _: &StopLanguageServer,
15914        _: &mut Window,
15915        cx: &mut Context<Self>,
15916    ) {
15917        if let Some(project) = self.project.clone() {
15918            self.buffer.update(cx, |multi_buffer, cx| {
15919                project.update(cx, |project, cx| {
15920                    project.stop_language_servers_for_buffers(
15921                        multi_buffer.all_buffers().into_iter().collect(),
15922                        cx,
15923                    );
15924                    cx.emit(project::Event::RefreshInlayHints);
15925                });
15926            });
15927        }
15928    }
15929
15930    fn cancel_language_server_work(
15931        workspace: &mut Workspace,
15932        _: &actions::CancelLanguageServerWork,
15933        _: &mut Window,
15934        cx: &mut Context<Workspace>,
15935    ) {
15936        let project = workspace.project();
15937        let buffers = workspace
15938            .active_item(cx)
15939            .and_then(|item| item.act_as::<Editor>(cx))
15940            .map_or(HashSet::default(), |editor| {
15941                editor.read(cx).buffer.read(cx).all_buffers()
15942            });
15943        project.update(cx, |project, cx| {
15944            project.cancel_language_server_work_for_buffers(buffers, cx);
15945        });
15946    }
15947
15948    fn show_character_palette(
15949        &mut self,
15950        _: &ShowCharacterPalette,
15951        window: &mut Window,
15952        _: &mut Context<Self>,
15953    ) {
15954        window.show_character_palette();
15955    }
15956
15957    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15958        if self.mode.is_minimap() {
15959            return;
15960        }
15961
15962        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15963            let buffer = self.buffer.read(cx).snapshot(cx);
15964            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15965            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15966            let is_valid = buffer
15967                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15968                .any(|entry| {
15969                    entry.diagnostic.is_primary
15970                        && !entry.range.is_empty()
15971                        && entry.range.start == primary_range_start
15972                        && entry.diagnostic.message == active_diagnostics.active_message
15973                });
15974
15975            if !is_valid {
15976                self.dismiss_diagnostics(cx);
15977            }
15978        }
15979    }
15980
15981    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15982        match &self.active_diagnostics {
15983            ActiveDiagnostic::Group(group) => Some(group),
15984            _ => None,
15985        }
15986    }
15987
15988    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15989        self.dismiss_diagnostics(cx);
15990        self.active_diagnostics = ActiveDiagnostic::All;
15991    }
15992
15993    fn activate_diagnostics(
15994        &mut self,
15995        buffer_id: BufferId,
15996        diagnostic: DiagnosticEntry<usize>,
15997        window: &mut Window,
15998        cx: &mut Context<Self>,
15999    ) {
16000        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16001            return;
16002        }
16003        self.dismiss_diagnostics(cx);
16004        let snapshot = self.snapshot(window, cx);
16005        let buffer = self.buffer.read(cx).snapshot(cx);
16006        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16007            return;
16008        };
16009
16010        let diagnostic_group = buffer
16011            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16012            .collect::<Vec<_>>();
16013
16014        let blocks =
16015            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16016
16017        let blocks = self.display_map.update(cx, |display_map, cx| {
16018            display_map.insert_blocks(blocks, cx).into_iter().collect()
16019        });
16020        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16021            active_range: buffer.anchor_before(diagnostic.range.start)
16022                ..buffer.anchor_after(diagnostic.range.end),
16023            active_message: diagnostic.diagnostic.message.clone(),
16024            group_id: diagnostic.diagnostic.group_id,
16025            blocks,
16026        });
16027        cx.notify();
16028    }
16029
16030    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16031        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16032            return;
16033        };
16034
16035        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16036        if let ActiveDiagnostic::Group(group) = prev {
16037            self.display_map.update(cx, |display_map, cx| {
16038                display_map.remove_blocks(group.blocks, cx);
16039            });
16040            cx.notify();
16041        }
16042    }
16043
16044    /// Disable inline diagnostics rendering for this editor.
16045    pub fn disable_inline_diagnostics(&mut self) {
16046        self.inline_diagnostics_enabled = false;
16047        self.inline_diagnostics_update = Task::ready(());
16048        self.inline_diagnostics.clear();
16049    }
16050
16051    pub fn diagnostics_enabled(&self) -> bool {
16052        self.mode.is_full()
16053    }
16054
16055    pub fn inline_diagnostics_enabled(&self) -> bool {
16056        self.diagnostics_enabled() && self.inline_diagnostics_enabled
16057    }
16058
16059    pub fn show_inline_diagnostics(&self) -> bool {
16060        self.show_inline_diagnostics
16061    }
16062
16063    pub fn toggle_inline_diagnostics(
16064        &mut self,
16065        _: &ToggleInlineDiagnostics,
16066        window: &mut Window,
16067        cx: &mut Context<Editor>,
16068    ) {
16069        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16070        self.refresh_inline_diagnostics(false, window, cx);
16071    }
16072
16073    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16074        self.diagnostics_max_severity = severity;
16075        self.display_map.update(cx, |display_map, _| {
16076            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16077        });
16078    }
16079
16080    pub fn toggle_diagnostics(
16081        &mut self,
16082        _: &ToggleDiagnostics,
16083        window: &mut Window,
16084        cx: &mut Context<Editor>,
16085    ) {
16086        if !self.diagnostics_enabled() {
16087            return;
16088        }
16089
16090        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16091            EditorSettings::get_global(cx)
16092                .diagnostics_max_severity
16093                .filter(|severity| severity != &DiagnosticSeverity::Off)
16094                .unwrap_or(DiagnosticSeverity::Hint)
16095        } else {
16096            DiagnosticSeverity::Off
16097        };
16098        self.set_max_diagnostics_severity(new_severity, cx);
16099        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16100            self.active_diagnostics = ActiveDiagnostic::None;
16101            self.inline_diagnostics_update = Task::ready(());
16102            self.inline_diagnostics.clear();
16103        } else {
16104            self.refresh_inline_diagnostics(false, window, cx);
16105        }
16106
16107        cx.notify();
16108    }
16109
16110    pub fn toggle_minimap(
16111        &mut self,
16112        _: &ToggleMinimap,
16113        window: &mut Window,
16114        cx: &mut Context<Editor>,
16115    ) {
16116        if self.supports_minimap(cx) {
16117            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16118        }
16119    }
16120
16121    fn refresh_inline_diagnostics(
16122        &mut self,
16123        debounce: bool,
16124        window: &mut Window,
16125        cx: &mut Context<Self>,
16126    ) {
16127        let max_severity = ProjectSettings::get_global(cx)
16128            .diagnostics
16129            .inline
16130            .max_severity
16131            .unwrap_or(self.diagnostics_max_severity);
16132
16133        if !self.inline_diagnostics_enabled()
16134            || !self.show_inline_diagnostics
16135            || max_severity == DiagnosticSeverity::Off
16136        {
16137            self.inline_diagnostics_update = Task::ready(());
16138            self.inline_diagnostics.clear();
16139            return;
16140        }
16141
16142        let debounce_ms = ProjectSettings::get_global(cx)
16143            .diagnostics
16144            .inline
16145            .update_debounce_ms;
16146        let debounce = if debounce && debounce_ms > 0 {
16147            Some(Duration::from_millis(debounce_ms))
16148        } else {
16149            None
16150        };
16151        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16152            if let Some(debounce) = debounce {
16153                cx.background_executor().timer(debounce).await;
16154            }
16155            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16156                editor
16157                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16158                    .ok()
16159            }) else {
16160                return;
16161            };
16162
16163            let new_inline_diagnostics = cx
16164                .background_spawn(async move {
16165                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16166                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16167                        let message = diagnostic_entry
16168                            .diagnostic
16169                            .message
16170                            .split_once('\n')
16171                            .map(|(line, _)| line)
16172                            .map(SharedString::new)
16173                            .unwrap_or_else(|| {
16174                                SharedString::from(diagnostic_entry.diagnostic.message)
16175                            });
16176                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16177                        let (Ok(i) | Err(i)) = inline_diagnostics
16178                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16179                        inline_diagnostics.insert(
16180                            i,
16181                            (
16182                                start_anchor,
16183                                InlineDiagnostic {
16184                                    message,
16185                                    group_id: diagnostic_entry.diagnostic.group_id,
16186                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16187                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16188                                    severity: diagnostic_entry.diagnostic.severity,
16189                                },
16190                            ),
16191                        );
16192                    }
16193                    inline_diagnostics
16194                })
16195                .await;
16196
16197            editor
16198                .update(cx, |editor, cx| {
16199                    editor.inline_diagnostics = new_inline_diagnostics;
16200                    cx.notify();
16201                })
16202                .ok();
16203        });
16204    }
16205
16206    fn pull_diagnostics(
16207        &mut self,
16208        buffer_id: Option<BufferId>,
16209        window: &Window,
16210        cx: &mut Context<Self>,
16211    ) -> Option<()> {
16212        if !self.mode().is_full() {
16213            return None;
16214        }
16215        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16216            .diagnostics
16217            .lsp_pull_diagnostics;
16218        if !pull_diagnostics_settings.enabled {
16219            return None;
16220        }
16221        let project = self.project.as_ref()?.downgrade();
16222        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16223        let mut buffers = self.buffer.read(cx).all_buffers();
16224        if let Some(buffer_id) = buffer_id {
16225            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16226        }
16227
16228        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16229            cx.background_executor().timer(debounce).await;
16230
16231            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16232                buffers
16233                    .into_iter()
16234                    .flat_map(|buffer| {
16235                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16236                    })
16237                    .collect::<FuturesUnordered<_>>()
16238            }) else {
16239                return;
16240            };
16241
16242            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16243                match pull_task {
16244                    Ok(()) => {
16245                        if editor
16246                            .update_in(cx, |editor, window, cx| {
16247                                editor.update_diagnostics_state(window, cx);
16248                            })
16249                            .is_err()
16250                        {
16251                            return;
16252                        }
16253                    }
16254                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16255                }
16256            }
16257        });
16258
16259        Some(())
16260    }
16261
16262    pub fn set_selections_from_remote(
16263        &mut self,
16264        selections: Vec<Selection<Anchor>>,
16265        pending_selection: Option<Selection<Anchor>>,
16266        window: &mut Window,
16267        cx: &mut Context<Self>,
16268    ) {
16269        let old_cursor_position = self.selections.newest_anchor().head();
16270        self.selections.change_with(cx, |s| {
16271            s.select_anchors(selections);
16272            if let Some(pending_selection) = pending_selection {
16273                s.set_pending(pending_selection, SelectMode::Character);
16274            } else {
16275                s.clear_pending();
16276            }
16277        });
16278        self.selections_did_change(
16279            false,
16280            &old_cursor_position,
16281            SelectionEffects::default(),
16282            window,
16283            cx,
16284        );
16285    }
16286
16287    pub fn transact(
16288        &mut self,
16289        window: &mut Window,
16290        cx: &mut Context<Self>,
16291        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16292    ) -> Option<TransactionId> {
16293        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16294            this.start_transaction_at(Instant::now(), window, cx);
16295            update(this, window, cx);
16296            this.end_transaction_at(Instant::now(), cx)
16297        })
16298    }
16299
16300    pub fn start_transaction_at(
16301        &mut self,
16302        now: Instant,
16303        window: &mut Window,
16304        cx: &mut Context<Self>,
16305    ) {
16306        self.end_selection(window, cx);
16307        if let Some(tx_id) = self
16308            .buffer
16309            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16310        {
16311            self.selection_history
16312                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16313            cx.emit(EditorEvent::TransactionBegun {
16314                transaction_id: tx_id,
16315            })
16316        }
16317    }
16318
16319    pub fn end_transaction_at(
16320        &mut self,
16321        now: Instant,
16322        cx: &mut Context<Self>,
16323    ) -> Option<TransactionId> {
16324        if let Some(transaction_id) = self
16325            .buffer
16326            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16327        {
16328            if let Some((_, end_selections)) =
16329                self.selection_history.transaction_mut(transaction_id)
16330            {
16331                *end_selections = Some(self.selections.disjoint_anchors());
16332            } else {
16333                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16334            }
16335
16336            cx.emit(EditorEvent::Edited { transaction_id });
16337            Some(transaction_id)
16338        } else {
16339            None
16340        }
16341    }
16342
16343    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16344        if self.selection_mark_mode {
16345            self.change_selections(None, window, cx, |s| {
16346                s.move_with(|_, sel| {
16347                    sel.collapse_to(sel.head(), SelectionGoal::None);
16348                });
16349            })
16350        }
16351        self.selection_mark_mode = true;
16352        cx.notify();
16353    }
16354
16355    pub fn swap_selection_ends(
16356        &mut self,
16357        _: &actions::SwapSelectionEnds,
16358        window: &mut Window,
16359        cx: &mut Context<Self>,
16360    ) {
16361        self.change_selections(None, window, cx, |s| {
16362            s.move_with(|_, sel| {
16363                if sel.start != sel.end {
16364                    sel.reversed = !sel.reversed
16365                }
16366            });
16367        });
16368        self.request_autoscroll(Autoscroll::newest(), cx);
16369        cx.notify();
16370    }
16371
16372    pub fn toggle_fold(
16373        &mut self,
16374        _: &actions::ToggleFold,
16375        window: &mut Window,
16376        cx: &mut Context<Self>,
16377    ) {
16378        if self.is_singleton(cx) {
16379            let selection = self.selections.newest::<Point>(cx);
16380
16381            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16382            let range = if selection.is_empty() {
16383                let point = selection.head().to_display_point(&display_map);
16384                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16385                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16386                    .to_point(&display_map);
16387                start..end
16388            } else {
16389                selection.range()
16390            };
16391            if display_map.folds_in_range(range).next().is_some() {
16392                self.unfold_lines(&Default::default(), window, cx)
16393            } else {
16394                self.fold(&Default::default(), window, cx)
16395            }
16396        } else {
16397            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16398            let buffer_ids: HashSet<_> = self
16399                .selections
16400                .disjoint_anchor_ranges()
16401                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16402                .collect();
16403
16404            let should_unfold = buffer_ids
16405                .iter()
16406                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16407
16408            for buffer_id in buffer_ids {
16409                if should_unfold {
16410                    self.unfold_buffer(buffer_id, cx);
16411                } else {
16412                    self.fold_buffer(buffer_id, cx);
16413                }
16414            }
16415        }
16416    }
16417
16418    pub fn toggle_fold_recursive(
16419        &mut self,
16420        _: &actions::ToggleFoldRecursive,
16421        window: &mut Window,
16422        cx: &mut Context<Self>,
16423    ) {
16424        let selection = self.selections.newest::<Point>(cx);
16425
16426        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16427        let range = if selection.is_empty() {
16428            let point = selection.head().to_display_point(&display_map);
16429            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16430            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16431                .to_point(&display_map);
16432            start..end
16433        } else {
16434            selection.range()
16435        };
16436        if display_map.folds_in_range(range).next().is_some() {
16437            self.unfold_recursive(&Default::default(), window, cx)
16438        } else {
16439            self.fold_recursive(&Default::default(), window, cx)
16440        }
16441    }
16442
16443    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16444        if self.is_singleton(cx) {
16445            let mut to_fold = Vec::new();
16446            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16447            let selections = self.selections.all_adjusted(cx);
16448
16449            for selection in selections {
16450                let range = selection.range().sorted();
16451                let buffer_start_row = range.start.row;
16452
16453                if range.start.row != range.end.row {
16454                    let mut found = false;
16455                    let mut row = range.start.row;
16456                    while row <= range.end.row {
16457                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16458                        {
16459                            found = true;
16460                            row = crease.range().end.row + 1;
16461                            to_fold.push(crease);
16462                        } else {
16463                            row += 1
16464                        }
16465                    }
16466                    if found {
16467                        continue;
16468                    }
16469                }
16470
16471                for row in (0..=range.start.row).rev() {
16472                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16473                        if crease.range().end.row >= buffer_start_row {
16474                            to_fold.push(crease);
16475                            if row <= range.start.row {
16476                                break;
16477                            }
16478                        }
16479                    }
16480                }
16481            }
16482
16483            self.fold_creases(to_fold, true, window, cx);
16484        } else {
16485            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16486            let buffer_ids = self
16487                .selections
16488                .disjoint_anchor_ranges()
16489                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16490                .collect::<HashSet<_>>();
16491            for buffer_id in buffer_ids {
16492                self.fold_buffer(buffer_id, cx);
16493            }
16494        }
16495    }
16496
16497    fn fold_at_level(
16498        &mut self,
16499        fold_at: &FoldAtLevel,
16500        window: &mut Window,
16501        cx: &mut Context<Self>,
16502    ) {
16503        if !self.buffer.read(cx).is_singleton() {
16504            return;
16505        }
16506
16507        let fold_at_level = fold_at.0;
16508        let snapshot = self.buffer.read(cx).snapshot(cx);
16509        let mut to_fold = Vec::new();
16510        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16511
16512        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16513            while start_row < end_row {
16514                match self
16515                    .snapshot(window, cx)
16516                    .crease_for_buffer_row(MultiBufferRow(start_row))
16517                {
16518                    Some(crease) => {
16519                        let nested_start_row = crease.range().start.row + 1;
16520                        let nested_end_row = crease.range().end.row;
16521
16522                        if current_level < fold_at_level {
16523                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16524                        } else if current_level == fold_at_level {
16525                            to_fold.push(crease);
16526                        }
16527
16528                        start_row = nested_end_row + 1;
16529                    }
16530                    None => start_row += 1,
16531                }
16532            }
16533        }
16534
16535        self.fold_creases(to_fold, true, window, cx);
16536    }
16537
16538    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16539        if self.buffer.read(cx).is_singleton() {
16540            let mut fold_ranges = Vec::new();
16541            let snapshot = self.buffer.read(cx).snapshot(cx);
16542
16543            for row in 0..snapshot.max_row().0 {
16544                if let Some(foldable_range) = self
16545                    .snapshot(window, cx)
16546                    .crease_for_buffer_row(MultiBufferRow(row))
16547                {
16548                    fold_ranges.push(foldable_range);
16549                }
16550            }
16551
16552            self.fold_creases(fold_ranges, true, window, cx);
16553        } else {
16554            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16555                editor
16556                    .update_in(cx, |editor, _, cx| {
16557                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16558                            editor.fold_buffer(buffer_id, cx);
16559                        }
16560                    })
16561                    .ok();
16562            });
16563        }
16564    }
16565
16566    pub fn fold_function_bodies(
16567        &mut self,
16568        _: &actions::FoldFunctionBodies,
16569        window: &mut Window,
16570        cx: &mut Context<Self>,
16571    ) {
16572        let snapshot = self.buffer.read(cx).snapshot(cx);
16573
16574        let ranges = snapshot
16575            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16576            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16577            .collect::<Vec<_>>();
16578
16579        let creases = ranges
16580            .into_iter()
16581            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16582            .collect();
16583
16584        self.fold_creases(creases, true, window, cx);
16585    }
16586
16587    pub fn fold_recursive(
16588        &mut self,
16589        _: &actions::FoldRecursive,
16590        window: &mut Window,
16591        cx: &mut Context<Self>,
16592    ) {
16593        let mut to_fold = Vec::new();
16594        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16595        let selections = self.selections.all_adjusted(cx);
16596
16597        for selection in selections {
16598            let range = selection.range().sorted();
16599            let buffer_start_row = range.start.row;
16600
16601            if range.start.row != range.end.row {
16602                let mut found = false;
16603                for row in range.start.row..=range.end.row {
16604                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16605                        found = true;
16606                        to_fold.push(crease);
16607                    }
16608                }
16609                if found {
16610                    continue;
16611                }
16612            }
16613
16614            for row in (0..=range.start.row).rev() {
16615                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16616                    if crease.range().end.row >= buffer_start_row {
16617                        to_fold.push(crease);
16618                    } else {
16619                        break;
16620                    }
16621                }
16622            }
16623        }
16624
16625        self.fold_creases(to_fold, true, window, cx);
16626    }
16627
16628    pub fn fold_at(
16629        &mut self,
16630        buffer_row: MultiBufferRow,
16631        window: &mut Window,
16632        cx: &mut Context<Self>,
16633    ) {
16634        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16635
16636        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16637            let autoscroll = self
16638                .selections
16639                .all::<Point>(cx)
16640                .iter()
16641                .any(|selection| crease.range().overlaps(&selection.range()));
16642
16643            self.fold_creases(vec![crease], autoscroll, window, cx);
16644        }
16645    }
16646
16647    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16648        if self.is_singleton(cx) {
16649            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16650            let buffer = &display_map.buffer_snapshot;
16651            let selections = self.selections.all::<Point>(cx);
16652            let ranges = selections
16653                .iter()
16654                .map(|s| {
16655                    let range = s.display_range(&display_map).sorted();
16656                    let mut start = range.start.to_point(&display_map);
16657                    let mut end = range.end.to_point(&display_map);
16658                    start.column = 0;
16659                    end.column = buffer.line_len(MultiBufferRow(end.row));
16660                    start..end
16661                })
16662                .collect::<Vec<_>>();
16663
16664            self.unfold_ranges(&ranges, true, true, cx);
16665        } else {
16666            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16667            let buffer_ids = self
16668                .selections
16669                .disjoint_anchor_ranges()
16670                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16671                .collect::<HashSet<_>>();
16672            for buffer_id in buffer_ids {
16673                self.unfold_buffer(buffer_id, cx);
16674            }
16675        }
16676    }
16677
16678    pub fn unfold_recursive(
16679        &mut self,
16680        _: &UnfoldRecursive,
16681        _window: &mut Window,
16682        cx: &mut Context<Self>,
16683    ) {
16684        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16685        let selections = self.selections.all::<Point>(cx);
16686        let ranges = selections
16687            .iter()
16688            .map(|s| {
16689                let mut range = s.display_range(&display_map).sorted();
16690                *range.start.column_mut() = 0;
16691                *range.end.column_mut() = display_map.line_len(range.end.row());
16692                let start = range.start.to_point(&display_map);
16693                let end = range.end.to_point(&display_map);
16694                start..end
16695            })
16696            .collect::<Vec<_>>();
16697
16698        self.unfold_ranges(&ranges, true, true, cx);
16699    }
16700
16701    pub fn unfold_at(
16702        &mut self,
16703        buffer_row: MultiBufferRow,
16704        _window: &mut Window,
16705        cx: &mut Context<Self>,
16706    ) {
16707        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16708
16709        let intersection_range = Point::new(buffer_row.0, 0)
16710            ..Point::new(
16711                buffer_row.0,
16712                display_map.buffer_snapshot.line_len(buffer_row),
16713            );
16714
16715        let autoscroll = self
16716            .selections
16717            .all::<Point>(cx)
16718            .iter()
16719            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16720
16721        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16722    }
16723
16724    pub fn unfold_all(
16725        &mut self,
16726        _: &actions::UnfoldAll,
16727        _window: &mut Window,
16728        cx: &mut Context<Self>,
16729    ) {
16730        if self.buffer.read(cx).is_singleton() {
16731            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16732            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16733        } else {
16734            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16735                editor
16736                    .update(cx, |editor, cx| {
16737                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16738                            editor.unfold_buffer(buffer_id, cx);
16739                        }
16740                    })
16741                    .ok();
16742            });
16743        }
16744    }
16745
16746    pub fn fold_selected_ranges(
16747        &mut self,
16748        _: &FoldSelectedRanges,
16749        window: &mut Window,
16750        cx: &mut Context<Self>,
16751    ) {
16752        let selections = self.selections.all_adjusted(cx);
16753        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16754        let ranges = selections
16755            .into_iter()
16756            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16757            .collect::<Vec<_>>();
16758        self.fold_creases(ranges, true, window, cx);
16759    }
16760
16761    pub fn fold_ranges<T: ToOffset + Clone>(
16762        &mut self,
16763        ranges: Vec<Range<T>>,
16764        auto_scroll: bool,
16765        window: &mut Window,
16766        cx: &mut Context<Self>,
16767    ) {
16768        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16769        let ranges = ranges
16770            .into_iter()
16771            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16772            .collect::<Vec<_>>();
16773        self.fold_creases(ranges, auto_scroll, window, cx);
16774    }
16775
16776    pub fn fold_creases<T: ToOffset + Clone>(
16777        &mut self,
16778        creases: Vec<Crease<T>>,
16779        auto_scroll: bool,
16780        _window: &mut Window,
16781        cx: &mut Context<Self>,
16782    ) {
16783        if creases.is_empty() {
16784            return;
16785        }
16786
16787        let mut buffers_affected = HashSet::default();
16788        let multi_buffer = self.buffer().read(cx);
16789        for crease in &creases {
16790            if let Some((_, buffer, _)) =
16791                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16792            {
16793                buffers_affected.insert(buffer.read(cx).remote_id());
16794            };
16795        }
16796
16797        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16798
16799        if auto_scroll {
16800            self.request_autoscroll(Autoscroll::fit(), cx);
16801        }
16802
16803        cx.notify();
16804
16805        self.scrollbar_marker_state.dirty = true;
16806        self.folds_did_change(cx);
16807    }
16808
16809    /// Removes any folds whose ranges intersect any of the given ranges.
16810    pub fn unfold_ranges<T: ToOffset + Clone>(
16811        &mut self,
16812        ranges: &[Range<T>],
16813        inclusive: bool,
16814        auto_scroll: bool,
16815        cx: &mut Context<Self>,
16816    ) {
16817        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16818            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16819        });
16820        self.folds_did_change(cx);
16821    }
16822
16823    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16824        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16825            return;
16826        }
16827        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16828        self.display_map.update(cx, |display_map, cx| {
16829            display_map.fold_buffers([buffer_id], cx)
16830        });
16831        cx.emit(EditorEvent::BufferFoldToggled {
16832            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16833            folded: true,
16834        });
16835        cx.notify();
16836    }
16837
16838    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16839        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16840            return;
16841        }
16842        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16843        self.display_map.update(cx, |display_map, cx| {
16844            display_map.unfold_buffers([buffer_id], cx);
16845        });
16846        cx.emit(EditorEvent::BufferFoldToggled {
16847            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16848            folded: false,
16849        });
16850        cx.notify();
16851    }
16852
16853    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16854        self.display_map.read(cx).is_buffer_folded(buffer)
16855    }
16856
16857    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16858        self.display_map.read(cx).folded_buffers()
16859    }
16860
16861    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16862        self.display_map.update(cx, |display_map, cx| {
16863            display_map.disable_header_for_buffer(buffer_id, cx);
16864        });
16865        cx.notify();
16866    }
16867
16868    /// Removes any folds with the given ranges.
16869    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16870        &mut self,
16871        ranges: &[Range<T>],
16872        type_id: TypeId,
16873        auto_scroll: bool,
16874        cx: &mut Context<Self>,
16875    ) {
16876        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16877            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16878        });
16879        self.folds_did_change(cx);
16880    }
16881
16882    fn remove_folds_with<T: ToOffset + Clone>(
16883        &mut self,
16884        ranges: &[Range<T>],
16885        auto_scroll: bool,
16886        cx: &mut Context<Self>,
16887        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16888    ) {
16889        if ranges.is_empty() {
16890            return;
16891        }
16892
16893        let mut buffers_affected = HashSet::default();
16894        let multi_buffer = self.buffer().read(cx);
16895        for range in ranges {
16896            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16897                buffers_affected.insert(buffer.read(cx).remote_id());
16898            };
16899        }
16900
16901        self.display_map.update(cx, update);
16902
16903        if auto_scroll {
16904            self.request_autoscroll(Autoscroll::fit(), cx);
16905        }
16906
16907        cx.notify();
16908        self.scrollbar_marker_state.dirty = true;
16909        self.active_indent_guides_state.dirty = true;
16910    }
16911
16912    pub fn update_fold_widths(
16913        &mut self,
16914        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16915        cx: &mut Context<Self>,
16916    ) -> bool {
16917        self.display_map
16918            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16919    }
16920
16921    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16922        self.display_map.read(cx).fold_placeholder.clone()
16923    }
16924
16925    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16926        self.buffer.update(cx, |buffer, cx| {
16927            buffer.set_all_diff_hunks_expanded(cx);
16928        });
16929    }
16930
16931    pub fn expand_all_diff_hunks(
16932        &mut self,
16933        _: &ExpandAllDiffHunks,
16934        _window: &mut Window,
16935        cx: &mut Context<Self>,
16936    ) {
16937        self.buffer.update(cx, |buffer, cx| {
16938            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16939        });
16940    }
16941
16942    pub fn toggle_selected_diff_hunks(
16943        &mut self,
16944        _: &ToggleSelectedDiffHunks,
16945        _window: &mut Window,
16946        cx: &mut Context<Self>,
16947    ) {
16948        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16949        self.toggle_diff_hunks_in_ranges(ranges, cx);
16950    }
16951
16952    pub fn diff_hunks_in_ranges<'a>(
16953        &'a self,
16954        ranges: &'a [Range<Anchor>],
16955        buffer: &'a MultiBufferSnapshot,
16956    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16957        ranges.iter().flat_map(move |range| {
16958            let end_excerpt_id = range.end.excerpt_id;
16959            let range = range.to_point(buffer);
16960            let mut peek_end = range.end;
16961            if range.end.row < buffer.max_row().0 {
16962                peek_end = Point::new(range.end.row + 1, 0);
16963            }
16964            buffer
16965                .diff_hunks_in_range(range.start..peek_end)
16966                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16967        })
16968    }
16969
16970    pub fn has_stageable_diff_hunks_in_ranges(
16971        &self,
16972        ranges: &[Range<Anchor>],
16973        snapshot: &MultiBufferSnapshot,
16974    ) -> bool {
16975        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16976        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16977    }
16978
16979    pub fn toggle_staged_selected_diff_hunks(
16980        &mut self,
16981        _: &::git::ToggleStaged,
16982        _: &mut Window,
16983        cx: &mut Context<Self>,
16984    ) {
16985        let snapshot = self.buffer.read(cx).snapshot(cx);
16986        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16987        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16988        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16989    }
16990
16991    pub fn set_render_diff_hunk_controls(
16992        &mut self,
16993        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16994        cx: &mut Context<Self>,
16995    ) {
16996        self.render_diff_hunk_controls = render_diff_hunk_controls;
16997        cx.notify();
16998    }
16999
17000    pub fn stage_and_next(
17001        &mut self,
17002        _: &::git::StageAndNext,
17003        window: &mut Window,
17004        cx: &mut Context<Self>,
17005    ) {
17006        self.do_stage_or_unstage_and_next(true, window, cx);
17007    }
17008
17009    pub fn unstage_and_next(
17010        &mut self,
17011        _: &::git::UnstageAndNext,
17012        window: &mut Window,
17013        cx: &mut Context<Self>,
17014    ) {
17015        self.do_stage_or_unstage_and_next(false, window, cx);
17016    }
17017
17018    pub fn stage_or_unstage_diff_hunks(
17019        &mut self,
17020        stage: bool,
17021        ranges: Vec<Range<Anchor>>,
17022        cx: &mut Context<Self>,
17023    ) {
17024        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17025        cx.spawn(async move |this, cx| {
17026            task.await?;
17027            this.update(cx, |this, cx| {
17028                let snapshot = this.buffer.read(cx).snapshot(cx);
17029                let chunk_by = this
17030                    .diff_hunks_in_ranges(&ranges, &snapshot)
17031                    .chunk_by(|hunk| hunk.buffer_id);
17032                for (buffer_id, hunks) in &chunk_by {
17033                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17034                }
17035            })
17036        })
17037        .detach_and_log_err(cx);
17038    }
17039
17040    fn save_buffers_for_ranges_if_needed(
17041        &mut self,
17042        ranges: &[Range<Anchor>],
17043        cx: &mut Context<Editor>,
17044    ) -> Task<Result<()>> {
17045        let multibuffer = self.buffer.read(cx);
17046        let snapshot = multibuffer.read(cx);
17047        let buffer_ids: HashSet<_> = ranges
17048            .iter()
17049            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17050            .collect();
17051        drop(snapshot);
17052
17053        let mut buffers = HashSet::default();
17054        for buffer_id in buffer_ids {
17055            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17056                let buffer = buffer_entity.read(cx);
17057                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17058                {
17059                    buffers.insert(buffer_entity);
17060                }
17061            }
17062        }
17063
17064        if let Some(project) = &self.project {
17065            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17066        } else {
17067            Task::ready(Ok(()))
17068        }
17069    }
17070
17071    fn do_stage_or_unstage_and_next(
17072        &mut self,
17073        stage: bool,
17074        window: &mut Window,
17075        cx: &mut Context<Self>,
17076    ) {
17077        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17078
17079        if ranges.iter().any(|range| range.start != range.end) {
17080            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17081            return;
17082        }
17083
17084        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17085        let snapshot = self.snapshot(window, cx);
17086        let position = self.selections.newest::<Point>(cx).head();
17087        let mut row = snapshot
17088            .buffer_snapshot
17089            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17090            .find(|hunk| hunk.row_range.start.0 > position.row)
17091            .map(|hunk| hunk.row_range.start);
17092
17093        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17094        // Outside of the project diff editor, wrap around to the beginning.
17095        if !all_diff_hunks_expanded {
17096            row = row.or_else(|| {
17097                snapshot
17098                    .buffer_snapshot
17099                    .diff_hunks_in_range(Point::zero()..position)
17100                    .find(|hunk| hunk.row_range.end.0 < position.row)
17101                    .map(|hunk| hunk.row_range.start)
17102            });
17103        }
17104
17105        if let Some(row) = row {
17106            let destination = Point::new(row.0, 0);
17107            let autoscroll = Autoscroll::center();
17108
17109            self.unfold_ranges(&[destination..destination], false, false, cx);
17110            self.change_selections(Some(autoscroll), window, cx, |s| {
17111                s.select_ranges([destination..destination]);
17112            });
17113        }
17114    }
17115
17116    fn do_stage_or_unstage(
17117        &self,
17118        stage: bool,
17119        buffer_id: BufferId,
17120        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17121        cx: &mut App,
17122    ) -> Option<()> {
17123        let project = self.project.as_ref()?;
17124        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17125        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17126        let buffer_snapshot = buffer.read(cx).snapshot();
17127        let file_exists = buffer_snapshot
17128            .file()
17129            .is_some_and(|file| file.disk_state().exists());
17130        diff.update(cx, |diff, cx| {
17131            diff.stage_or_unstage_hunks(
17132                stage,
17133                &hunks
17134                    .map(|hunk| buffer_diff::DiffHunk {
17135                        buffer_range: hunk.buffer_range,
17136                        diff_base_byte_range: hunk.diff_base_byte_range,
17137                        secondary_status: hunk.secondary_status,
17138                        range: Point::zero()..Point::zero(), // unused
17139                    })
17140                    .collect::<Vec<_>>(),
17141                &buffer_snapshot,
17142                file_exists,
17143                cx,
17144            )
17145        });
17146        None
17147    }
17148
17149    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17150        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17151        self.buffer
17152            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17153    }
17154
17155    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17156        self.buffer.update(cx, |buffer, cx| {
17157            let ranges = vec![Anchor::min()..Anchor::max()];
17158            if !buffer.all_diff_hunks_expanded()
17159                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17160            {
17161                buffer.collapse_diff_hunks(ranges, cx);
17162                true
17163            } else {
17164                false
17165            }
17166        })
17167    }
17168
17169    fn toggle_diff_hunks_in_ranges(
17170        &mut self,
17171        ranges: Vec<Range<Anchor>>,
17172        cx: &mut Context<Editor>,
17173    ) {
17174        self.buffer.update(cx, |buffer, cx| {
17175            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17176            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17177        })
17178    }
17179
17180    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17181        self.buffer.update(cx, |buffer, cx| {
17182            let snapshot = buffer.snapshot(cx);
17183            let excerpt_id = range.end.excerpt_id;
17184            let point_range = range.to_point(&snapshot);
17185            let expand = !buffer.single_hunk_is_expanded(range, cx);
17186            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17187        })
17188    }
17189
17190    pub(crate) fn apply_all_diff_hunks(
17191        &mut self,
17192        _: &ApplyAllDiffHunks,
17193        window: &mut Window,
17194        cx: &mut Context<Self>,
17195    ) {
17196        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17197
17198        let buffers = self.buffer.read(cx).all_buffers();
17199        for branch_buffer in buffers {
17200            branch_buffer.update(cx, |branch_buffer, cx| {
17201                branch_buffer.merge_into_base(Vec::new(), cx);
17202            });
17203        }
17204
17205        if let Some(project) = self.project.clone() {
17206            self.save(
17207                SaveOptions {
17208                    format: true,
17209                    autosave: false,
17210                },
17211                project,
17212                window,
17213                cx,
17214            )
17215            .detach_and_log_err(cx);
17216        }
17217    }
17218
17219    pub(crate) fn apply_selected_diff_hunks(
17220        &mut self,
17221        _: &ApplyDiffHunk,
17222        window: &mut Window,
17223        cx: &mut Context<Self>,
17224    ) {
17225        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17226        let snapshot = self.snapshot(window, cx);
17227        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17228        let mut ranges_by_buffer = HashMap::default();
17229        self.transact(window, cx, |editor, _window, cx| {
17230            for hunk in hunks {
17231                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17232                    ranges_by_buffer
17233                        .entry(buffer.clone())
17234                        .or_insert_with(Vec::new)
17235                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17236                }
17237            }
17238
17239            for (buffer, ranges) in ranges_by_buffer {
17240                buffer.update(cx, |buffer, cx| {
17241                    buffer.merge_into_base(ranges, cx);
17242                });
17243            }
17244        });
17245
17246        if let Some(project) = self.project.clone() {
17247            self.save(
17248                SaveOptions {
17249                    format: true,
17250                    autosave: false,
17251                },
17252                project,
17253                window,
17254                cx,
17255            )
17256            .detach_and_log_err(cx);
17257        }
17258    }
17259
17260    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17261        if hovered != self.gutter_hovered {
17262            self.gutter_hovered = hovered;
17263            cx.notify();
17264        }
17265    }
17266
17267    pub fn insert_blocks(
17268        &mut self,
17269        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17270        autoscroll: Option<Autoscroll>,
17271        cx: &mut Context<Self>,
17272    ) -> Vec<CustomBlockId> {
17273        let blocks = self
17274            .display_map
17275            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17276        if let Some(autoscroll) = autoscroll {
17277            self.request_autoscroll(autoscroll, cx);
17278        }
17279        cx.notify();
17280        blocks
17281    }
17282
17283    pub fn resize_blocks(
17284        &mut self,
17285        heights: HashMap<CustomBlockId, u32>,
17286        autoscroll: Option<Autoscroll>,
17287        cx: &mut Context<Self>,
17288    ) {
17289        self.display_map
17290            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17291        if let Some(autoscroll) = autoscroll {
17292            self.request_autoscroll(autoscroll, cx);
17293        }
17294        cx.notify();
17295    }
17296
17297    pub fn replace_blocks(
17298        &mut self,
17299        renderers: HashMap<CustomBlockId, RenderBlock>,
17300        autoscroll: Option<Autoscroll>,
17301        cx: &mut Context<Self>,
17302    ) {
17303        self.display_map
17304            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17305        if let Some(autoscroll) = autoscroll {
17306            self.request_autoscroll(autoscroll, cx);
17307        }
17308        cx.notify();
17309    }
17310
17311    pub fn remove_blocks(
17312        &mut self,
17313        block_ids: HashSet<CustomBlockId>,
17314        autoscroll: Option<Autoscroll>,
17315        cx: &mut Context<Self>,
17316    ) {
17317        self.display_map.update(cx, |display_map, cx| {
17318            display_map.remove_blocks(block_ids, cx)
17319        });
17320        if let Some(autoscroll) = autoscroll {
17321            self.request_autoscroll(autoscroll, cx);
17322        }
17323        cx.notify();
17324    }
17325
17326    pub fn row_for_block(
17327        &self,
17328        block_id: CustomBlockId,
17329        cx: &mut Context<Self>,
17330    ) -> Option<DisplayRow> {
17331        self.display_map
17332            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17333    }
17334
17335    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17336        self.focused_block = Some(focused_block);
17337    }
17338
17339    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17340        self.focused_block.take()
17341    }
17342
17343    pub fn insert_creases(
17344        &mut self,
17345        creases: impl IntoIterator<Item = Crease<Anchor>>,
17346        cx: &mut Context<Self>,
17347    ) -> Vec<CreaseId> {
17348        self.display_map
17349            .update(cx, |map, cx| map.insert_creases(creases, cx))
17350    }
17351
17352    pub fn remove_creases(
17353        &mut self,
17354        ids: impl IntoIterator<Item = CreaseId>,
17355        cx: &mut Context<Self>,
17356    ) -> Vec<(CreaseId, Range<Anchor>)> {
17357        self.display_map
17358            .update(cx, |map, cx| map.remove_creases(ids, cx))
17359    }
17360
17361    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17362        self.display_map
17363            .update(cx, |map, cx| map.snapshot(cx))
17364            .longest_row()
17365    }
17366
17367    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17368        self.display_map
17369            .update(cx, |map, cx| map.snapshot(cx))
17370            .max_point()
17371    }
17372
17373    pub fn text(&self, cx: &App) -> String {
17374        self.buffer.read(cx).read(cx).text()
17375    }
17376
17377    pub fn is_empty(&self, cx: &App) -> bool {
17378        self.buffer.read(cx).read(cx).is_empty()
17379    }
17380
17381    pub fn text_option(&self, cx: &App) -> Option<String> {
17382        let text = self.text(cx);
17383        let text = text.trim();
17384
17385        if text.is_empty() {
17386            return None;
17387        }
17388
17389        Some(text.to_string())
17390    }
17391
17392    pub fn set_text(
17393        &mut self,
17394        text: impl Into<Arc<str>>,
17395        window: &mut Window,
17396        cx: &mut Context<Self>,
17397    ) {
17398        self.transact(window, cx, |this, _, cx| {
17399            this.buffer
17400                .read(cx)
17401                .as_singleton()
17402                .expect("you can only call set_text on editors for singleton buffers")
17403                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17404        });
17405    }
17406
17407    pub fn display_text(&self, cx: &mut App) -> String {
17408        self.display_map
17409            .update(cx, |map, cx| map.snapshot(cx))
17410            .text()
17411    }
17412
17413    fn create_minimap(
17414        &self,
17415        minimap_settings: MinimapSettings,
17416        window: &mut Window,
17417        cx: &mut Context<Self>,
17418    ) -> Option<Entity<Self>> {
17419        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17420            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17421    }
17422
17423    fn initialize_new_minimap(
17424        &self,
17425        minimap_settings: MinimapSettings,
17426        window: &mut Window,
17427        cx: &mut Context<Self>,
17428    ) -> Entity<Self> {
17429        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17430
17431        let mut minimap = Editor::new_internal(
17432            EditorMode::Minimap {
17433                parent: cx.weak_entity(),
17434            },
17435            self.buffer.clone(),
17436            self.project.clone(),
17437            Some(self.display_map.clone()),
17438            window,
17439            cx,
17440        );
17441        minimap.scroll_manager.clone_state(&self.scroll_manager);
17442        minimap.set_text_style_refinement(TextStyleRefinement {
17443            font_size: Some(MINIMAP_FONT_SIZE),
17444            font_weight: Some(MINIMAP_FONT_WEIGHT),
17445            ..Default::default()
17446        });
17447        minimap.update_minimap_configuration(minimap_settings, cx);
17448        cx.new(|_| minimap)
17449    }
17450
17451    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17452        let current_line_highlight = minimap_settings
17453            .current_line_highlight
17454            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17455        self.set_current_line_highlight(Some(current_line_highlight));
17456    }
17457
17458    pub fn minimap(&self) -> Option<&Entity<Self>> {
17459        self.minimap
17460            .as_ref()
17461            .filter(|_| self.minimap_visibility.visible())
17462    }
17463
17464    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17465        let mut wrap_guides = smallvec![];
17466
17467        if self.show_wrap_guides == Some(false) {
17468            return wrap_guides;
17469        }
17470
17471        let settings = self.buffer.read(cx).language_settings(cx);
17472        if settings.show_wrap_guides {
17473            match self.soft_wrap_mode(cx) {
17474                SoftWrap::Column(soft_wrap) => {
17475                    wrap_guides.push((soft_wrap as usize, true));
17476                }
17477                SoftWrap::Bounded(soft_wrap) => {
17478                    wrap_guides.push((soft_wrap as usize, true));
17479                }
17480                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17481            }
17482            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17483        }
17484
17485        wrap_guides
17486    }
17487
17488    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17489        let settings = self.buffer.read(cx).language_settings(cx);
17490        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17491        match mode {
17492            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17493                SoftWrap::None
17494            }
17495            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17496            language_settings::SoftWrap::PreferredLineLength => {
17497                SoftWrap::Column(settings.preferred_line_length)
17498            }
17499            language_settings::SoftWrap::Bounded => {
17500                SoftWrap::Bounded(settings.preferred_line_length)
17501            }
17502        }
17503    }
17504
17505    pub fn set_soft_wrap_mode(
17506        &mut self,
17507        mode: language_settings::SoftWrap,
17508
17509        cx: &mut Context<Self>,
17510    ) {
17511        self.soft_wrap_mode_override = Some(mode);
17512        cx.notify();
17513    }
17514
17515    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17516        self.hard_wrap = hard_wrap;
17517        cx.notify();
17518    }
17519
17520    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17521        self.text_style_refinement = Some(style);
17522    }
17523
17524    /// called by the Element so we know what style we were most recently rendered with.
17525    pub(crate) fn set_style(
17526        &mut self,
17527        style: EditorStyle,
17528        window: &mut Window,
17529        cx: &mut Context<Self>,
17530    ) {
17531        // We intentionally do not inform the display map about the minimap style
17532        // so that wrapping is not recalculated and stays consistent for the editor
17533        // and its linked minimap.
17534        if !self.mode.is_minimap() {
17535            let rem_size = window.rem_size();
17536            self.display_map.update(cx, |map, cx| {
17537                map.set_font(
17538                    style.text.font(),
17539                    style.text.font_size.to_pixels(rem_size),
17540                    cx,
17541                )
17542            });
17543        }
17544        self.style = Some(style);
17545    }
17546
17547    pub fn style(&self) -> Option<&EditorStyle> {
17548        self.style.as_ref()
17549    }
17550
17551    // Called by the element. This method is not designed to be called outside of the editor
17552    // element's layout code because it does not notify when rewrapping is computed synchronously.
17553    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17554        self.display_map
17555            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17556    }
17557
17558    pub fn set_soft_wrap(&mut self) {
17559        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17560    }
17561
17562    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17563        if self.soft_wrap_mode_override.is_some() {
17564            self.soft_wrap_mode_override.take();
17565        } else {
17566            let soft_wrap = match self.soft_wrap_mode(cx) {
17567                SoftWrap::GitDiff => return,
17568                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17569                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17570                    language_settings::SoftWrap::None
17571                }
17572            };
17573            self.soft_wrap_mode_override = Some(soft_wrap);
17574        }
17575        cx.notify();
17576    }
17577
17578    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17579        let Some(workspace) = self.workspace() else {
17580            return;
17581        };
17582        let fs = workspace.read(cx).app_state().fs.clone();
17583        let current_show = TabBarSettings::get_global(cx).show;
17584        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17585            setting.show = Some(!current_show);
17586        });
17587    }
17588
17589    pub fn toggle_indent_guides(
17590        &mut self,
17591        _: &ToggleIndentGuides,
17592        _: &mut Window,
17593        cx: &mut Context<Self>,
17594    ) {
17595        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17596            self.buffer
17597                .read(cx)
17598                .language_settings(cx)
17599                .indent_guides
17600                .enabled
17601        });
17602        self.show_indent_guides = Some(!currently_enabled);
17603        cx.notify();
17604    }
17605
17606    fn should_show_indent_guides(&self) -> Option<bool> {
17607        self.show_indent_guides
17608    }
17609
17610    pub fn toggle_line_numbers(
17611        &mut self,
17612        _: &ToggleLineNumbers,
17613        _: &mut Window,
17614        cx: &mut Context<Self>,
17615    ) {
17616        let mut editor_settings = EditorSettings::get_global(cx).clone();
17617        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17618        EditorSettings::override_global(editor_settings, cx);
17619    }
17620
17621    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17622        if let Some(show_line_numbers) = self.show_line_numbers {
17623            return show_line_numbers;
17624        }
17625        EditorSettings::get_global(cx).gutter.line_numbers
17626    }
17627
17628    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17629        self.use_relative_line_numbers
17630            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17631    }
17632
17633    pub fn toggle_relative_line_numbers(
17634        &mut self,
17635        _: &ToggleRelativeLineNumbers,
17636        _: &mut Window,
17637        cx: &mut Context<Self>,
17638    ) {
17639        let is_relative = self.should_use_relative_line_numbers(cx);
17640        self.set_relative_line_number(Some(!is_relative), cx)
17641    }
17642
17643    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17644        self.use_relative_line_numbers = is_relative;
17645        cx.notify();
17646    }
17647
17648    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17649        self.show_gutter = show_gutter;
17650        cx.notify();
17651    }
17652
17653    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17654        self.show_scrollbars = ScrollbarAxes {
17655            horizontal: show,
17656            vertical: show,
17657        };
17658        cx.notify();
17659    }
17660
17661    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17662        self.show_scrollbars.vertical = show;
17663        cx.notify();
17664    }
17665
17666    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17667        self.show_scrollbars.horizontal = show;
17668        cx.notify();
17669    }
17670
17671    pub fn set_minimap_visibility(
17672        &mut self,
17673        minimap_visibility: MinimapVisibility,
17674        window: &mut Window,
17675        cx: &mut Context<Self>,
17676    ) {
17677        if self.minimap_visibility != minimap_visibility {
17678            if minimap_visibility.visible() && self.minimap.is_none() {
17679                let minimap_settings = EditorSettings::get_global(cx).minimap;
17680                self.minimap =
17681                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17682            }
17683            self.minimap_visibility = minimap_visibility;
17684            cx.notify();
17685        }
17686    }
17687
17688    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17689        self.set_show_scrollbars(false, cx);
17690        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17691    }
17692
17693    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17694        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17695    }
17696
17697    /// Normally the text in full mode and auto height editors is padded on the
17698    /// left side by roughly half a character width for improved hit testing.
17699    ///
17700    /// Use this method to disable this for cases where this is not wanted (e.g.
17701    /// if you want to align the editor text with some other text above or below)
17702    /// or if you want to add this padding to single-line editors.
17703    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17704        self.offset_content = offset_content;
17705        cx.notify();
17706    }
17707
17708    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17709        self.show_line_numbers = Some(show_line_numbers);
17710        cx.notify();
17711    }
17712
17713    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17714        self.disable_expand_excerpt_buttons = true;
17715        cx.notify();
17716    }
17717
17718    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17719        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17720        cx.notify();
17721    }
17722
17723    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17724        self.show_code_actions = Some(show_code_actions);
17725        cx.notify();
17726    }
17727
17728    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17729        self.show_runnables = Some(show_runnables);
17730        cx.notify();
17731    }
17732
17733    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17734        self.show_breakpoints = Some(show_breakpoints);
17735        cx.notify();
17736    }
17737
17738    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17739        if self.display_map.read(cx).masked != masked {
17740            self.display_map.update(cx, |map, _| map.masked = masked);
17741        }
17742        cx.notify()
17743    }
17744
17745    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17746        self.show_wrap_guides = Some(show_wrap_guides);
17747        cx.notify();
17748    }
17749
17750    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17751        self.show_indent_guides = Some(show_indent_guides);
17752        cx.notify();
17753    }
17754
17755    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17756        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17757            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17758                if let Some(dir) = file.abs_path(cx).parent() {
17759                    return Some(dir.to_owned());
17760                }
17761            }
17762
17763            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17764                return Some(project_path.path.to_path_buf());
17765            }
17766        }
17767
17768        None
17769    }
17770
17771    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17772        self.active_excerpt(cx)?
17773            .1
17774            .read(cx)
17775            .file()
17776            .and_then(|f| f.as_local())
17777    }
17778
17779    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17780        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17781            let buffer = buffer.read(cx);
17782            if let Some(project_path) = buffer.project_path(cx) {
17783                let project = self.project.as_ref()?.read(cx);
17784                project.absolute_path(&project_path, cx)
17785            } else {
17786                buffer
17787                    .file()
17788                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17789            }
17790        })
17791    }
17792
17793    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17794        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17795            let project_path = buffer.read(cx).project_path(cx)?;
17796            let project = self.project.as_ref()?.read(cx);
17797            let entry = project.entry_for_path(&project_path, cx)?;
17798            let path = entry.path.to_path_buf();
17799            Some(path)
17800        })
17801    }
17802
17803    pub fn reveal_in_finder(
17804        &mut self,
17805        _: &RevealInFileManager,
17806        _window: &mut Window,
17807        cx: &mut Context<Self>,
17808    ) {
17809        if let Some(target) = self.target_file(cx) {
17810            cx.reveal_path(&target.abs_path(cx));
17811        }
17812    }
17813
17814    pub fn copy_path(
17815        &mut self,
17816        _: &zed_actions::workspace::CopyPath,
17817        _window: &mut Window,
17818        cx: &mut Context<Self>,
17819    ) {
17820        if let Some(path) = self.target_file_abs_path(cx) {
17821            if let Some(path) = path.to_str() {
17822                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17823            }
17824        }
17825    }
17826
17827    pub fn copy_relative_path(
17828        &mut self,
17829        _: &zed_actions::workspace::CopyRelativePath,
17830        _window: &mut Window,
17831        cx: &mut Context<Self>,
17832    ) {
17833        if let Some(path) = self.target_file_path(cx) {
17834            if let Some(path) = path.to_str() {
17835                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17836            }
17837        }
17838    }
17839
17840    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17841        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17842            buffer.read(cx).project_path(cx)
17843        } else {
17844            None
17845        }
17846    }
17847
17848    // Returns true if the editor handled a go-to-line request
17849    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17850        maybe!({
17851            let breakpoint_store = self.breakpoint_store.as_ref()?;
17852
17853            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17854            else {
17855                self.clear_row_highlights::<ActiveDebugLine>();
17856                return None;
17857            };
17858
17859            let position = active_stack_frame.position;
17860            let buffer_id = position.buffer_id?;
17861            let snapshot = self
17862                .project
17863                .as_ref()?
17864                .read(cx)
17865                .buffer_for_id(buffer_id, cx)?
17866                .read(cx)
17867                .snapshot();
17868
17869            let mut handled = false;
17870            for (id, ExcerptRange { context, .. }) in
17871                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17872            {
17873                if context.start.cmp(&position, &snapshot).is_ge()
17874                    || context.end.cmp(&position, &snapshot).is_lt()
17875                {
17876                    continue;
17877                }
17878                let snapshot = self.buffer.read(cx).snapshot(cx);
17879                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17880
17881                handled = true;
17882                self.clear_row_highlights::<ActiveDebugLine>();
17883
17884                self.go_to_line::<ActiveDebugLine>(
17885                    multibuffer_anchor,
17886                    Some(cx.theme().colors().editor_debugger_active_line_background),
17887                    window,
17888                    cx,
17889                );
17890
17891                cx.notify();
17892            }
17893
17894            handled.then_some(())
17895        })
17896        .is_some()
17897    }
17898
17899    pub fn copy_file_name_without_extension(
17900        &mut self,
17901        _: &CopyFileNameWithoutExtension,
17902        _: &mut Window,
17903        cx: &mut Context<Self>,
17904    ) {
17905        if let Some(file) = self.target_file(cx) {
17906            if let Some(file_stem) = file.path().file_stem() {
17907                if let Some(name) = file_stem.to_str() {
17908                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17909                }
17910            }
17911        }
17912    }
17913
17914    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17915        if let Some(file) = self.target_file(cx) {
17916            if let Some(file_name) = file.path().file_name() {
17917                if let Some(name) = file_name.to_str() {
17918                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17919                }
17920            }
17921        }
17922    }
17923
17924    pub fn toggle_git_blame(
17925        &mut self,
17926        _: &::git::Blame,
17927        window: &mut Window,
17928        cx: &mut Context<Self>,
17929    ) {
17930        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17931
17932        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17933            self.start_git_blame(true, window, cx);
17934        }
17935
17936        cx.notify();
17937    }
17938
17939    pub fn toggle_git_blame_inline(
17940        &mut self,
17941        _: &ToggleGitBlameInline,
17942        window: &mut Window,
17943        cx: &mut Context<Self>,
17944    ) {
17945        self.toggle_git_blame_inline_internal(true, window, cx);
17946        cx.notify();
17947    }
17948
17949    pub fn open_git_blame_commit(
17950        &mut self,
17951        _: &OpenGitBlameCommit,
17952        window: &mut Window,
17953        cx: &mut Context<Self>,
17954    ) {
17955        self.open_git_blame_commit_internal(window, cx);
17956    }
17957
17958    fn open_git_blame_commit_internal(
17959        &mut self,
17960        window: &mut Window,
17961        cx: &mut Context<Self>,
17962    ) -> Option<()> {
17963        let blame = self.blame.as_ref()?;
17964        let snapshot = self.snapshot(window, cx);
17965        let cursor = self.selections.newest::<Point>(cx).head();
17966        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17967        let blame_entry = blame
17968            .update(cx, |blame, cx| {
17969                blame
17970                    .blame_for_rows(
17971                        &[RowInfo {
17972                            buffer_id: Some(buffer.remote_id()),
17973                            buffer_row: Some(point.row),
17974                            ..Default::default()
17975                        }],
17976                        cx,
17977                    )
17978                    .next()
17979            })
17980            .flatten()?;
17981        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17982        let repo = blame.read(cx).repository(cx)?;
17983        let workspace = self.workspace()?.downgrade();
17984        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17985        None
17986    }
17987
17988    pub fn git_blame_inline_enabled(&self) -> bool {
17989        self.git_blame_inline_enabled
17990    }
17991
17992    pub fn toggle_selection_menu(
17993        &mut self,
17994        _: &ToggleSelectionMenu,
17995        _: &mut Window,
17996        cx: &mut Context<Self>,
17997    ) {
17998        self.show_selection_menu = self
17999            .show_selection_menu
18000            .map(|show_selections_menu| !show_selections_menu)
18001            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18002
18003        cx.notify();
18004    }
18005
18006    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18007        self.show_selection_menu
18008            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18009    }
18010
18011    fn start_git_blame(
18012        &mut self,
18013        user_triggered: bool,
18014        window: &mut Window,
18015        cx: &mut Context<Self>,
18016    ) {
18017        if let Some(project) = self.project.as_ref() {
18018            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18019                return;
18020            };
18021
18022            if buffer.read(cx).file().is_none() {
18023                return;
18024            }
18025
18026            let focused = self.focus_handle(cx).contains_focused(window, cx);
18027
18028            let project = project.clone();
18029            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18030            self.blame_subscription =
18031                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18032            self.blame = Some(blame);
18033        }
18034    }
18035
18036    fn toggle_git_blame_inline_internal(
18037        &mut self,
18038        user_triggered: bool,
18039        window: &mut Window,
18040        cx: &mut Context<Self>,
18041    ) {
18042        if self.git_blame_inline_enabled {
18043            self.git_blame_inline_enabled = false;
18044            self.show_git_blame_inline = false;
18045            self.show_git_blame_inline_delay_task.take();
18046        } else {
18047            self.git_blame_inline_enabled = true;
18048            self.start_git_blame_inline(user_triggered, window, cx);
18049        }
18050
18051        cx.notify();
18052    }
18053
18054    fn start_git_blame_inline(
18055        &mut self,
18056        user_triggered: bool,
18057        window: &mut Window,
18058        cx: &mut Context<Self>,
18059    ) {
18060        self.start_git_blame(user_triggered, window, cx);
18061
18062        if ProjectSettings::get_global(cx)
18063            .git
18064            .inline_blame_delay()
18065            .is_some()
18066        {
18067            self.start_inline_blame_timer(window, cx);
18068        } else {
18069            self.show_git_blame_inline = true
18070        }
18071    }
18072
18073    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18074        self.blame.as_ref()
18075    }
18076
18077    pub fn show_git_blame_gutter(&self) -> bool {
18078        self.show_git_blame_gutter
18079    }
18080
18081    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18082        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18083    }
18084
18085    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18086        self.show_git_blame_inline
18087            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18088            && !self.newest_selection_head_on_empty_line(cx)
18089            && self.has_blame_entries(cx)
18090    }
18091
18092    fn has_blame_entries(&self, cx: &App) -> bool {
18093        self.blame()
18094            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18095    }
18096
18097    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18098        let cursor_anchor = self.selections.newest_anchor().head();
18099
18100        let snapshot = self.buffer.read(cx).snapshot(cx);
18101        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18102
18103        snapshot.line_len(buffer_row) == 0
18104    }
18105
18106    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18107        let buffer_and_selection = maybe!({
18108            let selection = self.selections.newest::<Point>(cx);
18109            let selection_range = selection.range();
18110
18111            let multi_buffer = self.buffer().read(cx);
18112            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18113            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18114
18115            let (buffer, range, _) = if selection.reversed {
18116                buffer_ranges.first()
18117            } else {
18118                buffer_ranges.last()
18119            }?;
18120
18121            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18122                ..text::ToPoint::to_point(&range.end, &buffer).row;
18123            Some((
18124                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18125                selection,
18126            ))
18127        });
18128
18129        let Some((buffer, selection)) = buffer_and_selection else {
18130            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18131        };
18132
18133        let Some(project) = self.project.as_ref() else {
18134            return Task::ready(Err(anyhow!("editor does not have project")));
18135        };
18136
18137        project.update(cx, |project, cx| {
18138            project.get_permalink_to_line(&buffer, selection, cx)
18139        })
18140    }
18141
18142    pub fn copy_permalink_to_line(
18143        &mut self,
18144        _: &CopyPermalinkToLine,
18145        window: &mut Window,
18146        cx: &mut Context<Self>,
18147    ) {
18148        let permalink_task = self.get_permalink_to_line(cx);
18149        let workspace = self.workspace();
18150
18151        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18152            Ok(permalink) => {
18153                cx.update(|_, cx| {
18154                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18155                })
18156                .ok();
18157            }
18158            Err(err) => {
18159                let message = format!("Failed to copy permalink: {err}");
18160
18161                anyhow::Result::<()>::Err(err).log_err();
18162
18163                if let Some(workspace) = workspace {
18164                    workspace
18165                        .update_in(cx, |workspace, _, cx| {
18166                            struct CopyPermalinkToLine;
18167
18168                            workspace.show_toast(
18169                                Toast::new(
18170                                    NotificationId::unique::<CopyPermalinkToLine>(),
18171                                    message,
18172                                ),
18173                                cx,
18174                            )
18175                        })
18176                        .ok();
18177                }
18178            }
18179        })
18180        .detach();
18181    }
18182
18183    pub fn copy_file_location(
18184        &mut self,
18185        _: &CopyFileLocation,
18186        _: &mut Window,
18187        cx: &mut Context<Self>,
18188    ) {
18189        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18190        if let Some(file) = self.target_file(cx) {
18191            if let Some(path) = file.path().to_str() {
18192                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18193            }
18194        }
18195    }
18196
18197    pub fn open_permalink_to_line(
18198        &mut self,
18199        _: &OpenPermalinkToLine,
18200        window: &mut Window,
18201        cx: &mut Context<Self>,
18202    ) {
18203        let permalink_task = self.get_permalink_to_line(cx);
18204        let workspace = self.workspace();
18205
18206        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18207            Ok(permalink) => {
18208                cx.update(|_, cx| {
18209                    cx.open_url(permalink.as_ref());
18210                })
18211                .ok();
18212            }
18213            Err(err) => {
18214                let message = format!("Failed to open permalink: {err}");
18215
18216                anyhow::Result::<()>::Err(err).log_err();
18217
18218                if let Some(workspace) = workspace {
18219                    workspace
18220                        .update(cx, |workspace, cx| {
18221                            struct OpenPermalinkToLine;
18222
18223                            workspace.show_toast(
18224                                Toast::new(
18225                                    NotificationId::unique::<OpenPermalinkToLine>(),
18226                                    message,
18227                                ),
18228                                cx,
18229                            )
18230                        })
18231                        .ok();
18232                }
18233            }
18234        })
18235        .detach();
18236    }
18237
18238    pub fn insert_uuid_v4(
18239        &mut self,
18240        _: &InsertUuidV4,
18241        window: &mut Window,
18242        cx: &mut Context<Self>,
18243    ) {
18244        self.insert_uuid(UuidVersion::V4, window, cx);
18245    }
18246
18247    pub fn insert_uuid_v7(
18248        &mut self,
18249        _: &InsertUuidV7,
18250        window: &mut Window,
18251        cx: &mut Context<Self>,
18252    ) {
18253        self.insert_uuid(UuidVersion::V7, window, cx);
18254    }
18255
18256    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18257        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18258        self.transact(window, cx, |this, window, cx| {
18259            let edits = this
18260                .selections
18261                .all::<Point>(cx)
18262                .into_iter()
18263                .map(|selection| {
18264                    let uuid = match version {
18265                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18266                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18267                    };
18268
18269                    (selection.range(), uuid.to_string())
18270                });
18271            this.edit(edits, cx);
18272            this.refresh_inline_completion(true, false, window, cx);
18273        });
18274    }
18275
18276    pub fn open_selections_in_multibuffer(
18277        &mut self,
18278        _: &OpenSelectionsInMultibuffer,
18279        window: &mut Window,
18280        cx: &mut Context<Self>,
18281    ) {
18282        let multibuffer = self.buffer.read(cx);
18283
18284        let Some(buffer) = multibuffer.as_singleton() else {
18285            return;
18286        };
18287
18288        let Some(workspace) = self.workspace() else {
18289            return;
18290        };
18291
18292        let locations = self
18293            .selections
18294            .disjoint_anchors()
18295            .iter()
18296            .map(|range| Location {
18297                buffer: buffer.clone(),
18298                range: range.start.text_anchor..range.end.text_anchor,
18299            })
18300            .collect::<Vec<_>>();
18301
18302        let title = multibuffer.title(cx).to_string();
18303
18304        cx.spawn_in(window, async move |_, cx| {
18305            workspace.update_in(cx, |workspace, window, cx| {
18306                Self::open_locations_in_multibuffer(
18307                    workspace,
18308                    locations,
18309                    format!("Selections for '{title}'"),
18310                    false,
18311                    MultibufferSelectionMode::All,
18312                    window,
18313                    cx,
18314                );
18315            })
18316        })
18317        .detach();
18318    }
18319
18320    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18321    /// last highlight added will be used.
18322    ///
18323    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18324    pub fn highlight_rows<T: 'static>(
18325        &mut self,
18326        range: Range<Anchor>,
18327        color: Hsla,
18328        options: RowHighlightOptions,
18329        cx: &mut Context<Self>,
18330    ) {
18331        let snapshot = self.buffer().read(cx).snapshot(cx);
18332        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18333        let ix = row_highlights.binary_search_by(|highlight| {
18334            Ordering::Equal
18335                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18336                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18337        });
18338
18339        if let Err(mut ix) = ix {
18340            let index = post_inc(&mut self.highlight_order);
18341
18342            // If this range intersects with the preceding highlight, then merge it with
18343            // the preceding highlight. Otherwise insert a new highlight.
18344            let mut merged = false;
18345            if ix > 0 {
18346                let prev_highlight = &mut row_highlights[ix - 1];
18347                if prev_highlight
18348                    .range
18349                    .end
18350                    .cmp(&range.start, &snapshot)
18351                    .is_ge()
18352                {
18353                    ix -= 1;
18354                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18355                        prev_highlight.range.end = range.end;
18356                    }
18357                    merged = true;
18358                    prev_highlight.index = index;
18359                    prev_highlight.color = color;
18360                    prev_highlight.options = options;
18361                }
18362            }
18363
18364            if !merged {
18365                row_highlights.insert(
18366                    ix,
18367                    RowHighlight {
18368                        range: range.clone(),
18369                        index,
18370                        color,
18371                        options,
18372                        type_id: TypeId::of::<T>(),
18373                    },
18374                );
18375            }
18376
18377            // If any of the following highlights intersect with this one, merge them.
18378            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18379                let highlight = &row_highlights[ix];
18380                if next_highlight
18381                    .range
18382                    .start
18383                    .cmp(&highlight.range.end, &snapshot)
18384                    .is_le()
18385                {
18386                    if next_highlight
18387                        .range
18388                        .end
18389                        .cmp(&highlight.range.end, &snapshot)
18390                        .is_gt()
18391                    {
18392                        row_highlights[ix].range.end = next_highlight.range.end;
18393                    }
18394                    row_highlights.remove(ix + 1);
18395                } else {
18396                    break;
18397                }
18398            }
18399        }
18400    }
18401
18402    /// Remove any highlighted row ranges of the given type that intersect the
18403    /// given ranges.
18404    pub fn remove_highlighted_rows<T: 'static>(
18405        &mut self,
18406        ranges_to_remove: Vec<Range<Anchor>>,
18407        cx: &mut Context<Self>,
18408    ) {
18409        let snapshot = self.buffer().read(cx).snapshot(cx);
18410        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18411        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18412        row_highlights.retain(|highlight| {
18413            while let Some(range_to_remove) = ranges_to_remove.peek() {
18414                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18415                    Ordering::Less | Ordering::Equal => {
18416                        ranges_to_remove.next();
18417                    }
18418                    Ordering::Greater => {
18419                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18420                            Ordering::Less | Ordering::Equal => {
18421                                return false;
18422                            }
18423                            Ordering::Greater => break,
18424                        }
18425                    }
18426                }
18427            }
18428
18429            true
18430        })
18431    }
18432
18433    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18434    pub fn clear_row_highlights<T: 'static>(&mut self) {
18435        self.highlighted_rows.remove(&TypeId::of::<T>());
18436    }
18437
18438    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18439    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18440        self.highlighted_rows
18441            .get(&TypeId::of::<T>())
18442            .map_or(&[] as &[_], |vec| vec.as_slice())
18443            .iter()
18444            .map(|highlight| (highlight.range.clone(), highlight.color))
18445    }
18446
18447    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18448    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18449    /// Allows to ignore certain kinds of highlights.
18450    pub fn highlighted_display_rows(
18451        &self,
18452        window: &mut Window,
18453        cx: &mut App,
18454    ) -> BTreeMap<DisplayRow, LineHighlight> {
18455        let snapshot = self.snapshot(window, cx);
18456        let mut used_highlight_orders = HashMap::default();
18457        self.highlighted_rows
18458            .iter()
18459            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18460            .fold(
18461                BTreeMap::<DisplayRow, LineHighlight>::new(),
18462                |mut unique_rows, highlight| {
18463                    let start = highlight.range.start.to_display_point(&snapshot);
18464                    let end = highlight.range.end.to_display_point(&snapshot);
18465                    let start_row = start.row().0;
18466                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18467                        && end.column() == 0
18468                    {
18469                        end.row().0.saturating_sub(1)
18470                    } else {
18471                        end.row().0
18472                    };
18473                    for row in start_row..=end_row {
18474                        let used_index =
18475                            used_highlight_orders.entry(row).or_insert(highlight.index);
18476                        if highlight.index >= *used_index {
18477                            *used_index = highlight.index;
18478                            unique_rows.insert(
18479                                DisplayRow(row),
18480                                LineHighlight {
18481                                    include_gutter: highlight.options.include_gutter,
18482                                    border: None,
18483                                    background: highlight.color.into(),
18484                                    type_id: Some(highlight.type_id),
18485                                },
18486                            );
18487                        }
18488                    }
18489                    unique_rows
18490                },
18491            )
18492    }
18493
18494    pub fn highlighted_display_row_for_autoscroll(
18495        &self,
18496        snapshot: &DisplaySnapshot,
18497    ) -> Option<DisplayRow> {
18498        self.highlighted_rows
18499            .values()
18500            .flat_map(|highlighted_rows| highlighted_rows.iter())
18501            .filter_map(|highlight| {
18502                if highlight.options.autoscroll {
18503                    Some(highlight.range.start.to_display_point(snapshot).row())
18504                } else {
18505                    None
18506                }
18507            })
18508            .min()
18509    }
18510
18511    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18512        self.highlight_background::<SearchWithinRange>(
18513            ranges,
18514            |theme| theme.colors().editor_document_highlight_read_background,
18515            cx,
18516        )
18517    }
18518
18519    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18520        self.breadcrumb_header = Some(new_header);
18521    }
18522
18523    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18524        self.clear_background_highlights::<SearchWithinRange>(cx);
18525    }
18526
18527    pub fn highlight_background<T: 'static>(
18528        &mut self,
18529        ranges: &[Range<Anchor>],
18530        color_fetcher: fn(&Theme) -> Hsla,
18531        cx: &mut Context<Self>,
18532    ) {
18533        let highlights = ranges
18534            .iter()
18535            .map(|range| BackgroundHighlight {
18536                range: range.clone(),
18537                color_fetcher,
18538            })
18539            .collect();
18540        self.background_highlights
18541            .insert(TypeId::of::<T>(), highlights);
18542        self.scrollbar_marker_state.dirty = true;
18543        cx.notify();
18544    }
18545
18546    pub fn highlight_background_ranges<T: 'static>(
18547        &mut self,
18548        background_highlights: Vec<BackgroundHighlight>,
18549        cx: &mut Context<'_, Editor>,
18550    ) {
18551        self.background_highlights
18552            .insert(TypeId::of::<T>(), background_highlights);
18553        self.scrollbar_marker_state.dirty = true;
18554        cx.notify();
18555    }
18556
18557    pub fn clear_background_highlights<T: 'static>(
18558        &mut self,
18559        cx: &mut Context<Self>,
18560    ) -> Option<Vec<BackgroundHighlight>> {
18561        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18562        if !text_highlights.is_empty() {
18563            self.scrollbar_marker_state.dirty = true;
18564            cx.notify();
18565        }
18566        Some(text_highlights)
18567    }
18568
18569    pub fn highlight_gutter<T: 'static>(
18570        &mut self,
18571        ranges: impl Into<Vec<Range<Anchor>>>,
18572        color_fetcher: fn(&App) -> Hsla,
18573        cx: &mut Context<Self>,
18574    ) {
18575        self.gutter_highlights
18576            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18577        cx.notify();
18578    }
18579
18580    pub fn clear_gutter_highlights<T: 'static>(
18581        &mut self,
18582        cx: &mut Context<Self>,
18583    ) -> Option<GutterHighlight> {
18584        cx.notify();
18585        self.gutter_highlights.remove(&TypeId::of::<T>())
18586    }
18587
18588    pub fn insert_gutter_highlight<T: 'static>(
18589        &mut self,
18590        range: Range<Anchor>,
18591        color_fetcher: fn(&App) -> Hsla,
18592        cx: &mut Context<Self>,
18593    ) {
18594        let snapshot = self.buffer().read(cx).snapshot(cx);
18595        let mut highlights = self
18596            .gutter_highlights
18597            .remove(&TypeId::of::<T>())
18598            .map(|(_, highlights)| highlights)
18599            .unwrap_or_default();
18600        let ix = highlights.binary_search_by(|highlight| {
18601            Ordering::Equal
18602                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18603                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18604        });
18605        if let Err(ix) = ix {
18606            highlights.insert(ix, range);
18607        }
18608        self.gutter_highlights
18609            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18610    }
18611
18612    pub fn remove_gutter_highlights<T: 'static>(
18613        &mut self,
18614        ranges_to_remove: Vec<Range<Anchor>>,
18615        cx: &mut Context<Self>,
18616    ) {
18617        let snapshot = self.buffer().read(cx).snapshot(cx);
18618        let Some((color_fetcher, mut gutter_highlights)) =
18619            self.gutter_highlights.remove(&TypeId::of::<T>())
18620        else {
18621            return;
18622        };
18623        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18624        gutter_highlights.retain(|highlight| {
18625            while let Some(range_to_remove) = ranges_to_remove.peek() {
18626                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18627                    Ordering::Less | Ordering::Equal => {
18628                        ranges_to_remove.next();
18629                    }
18630                    Ordering::Greater => {
18631                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18632                            Ordering::Less | Ordering::Equal => {
18633                                return false;
18634                            }
18635                            Ordering::Greater => break,
18636                        }
18637                    }
18638                }
18639            }
18640
18641            true
18642        });
18643        self.gutter_highlights
18644            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18645    }
18646
18647    #[cfg(feature = "test-support")]
18648    pub fn all_text_background_highlights(
18649        &self,
18650        window: &mut Window,
18651        cx: &mut Context<Self>,
18652    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18653        let snapshot = self.snapshot(window, cx);
18654        let buffer = &snapshot.buffer_snapshot;
18655        let start = buffer.anchor_before(0);
18656        let end = buffer.anchor_after(buffer.len());
18657        let theme = cx.theme();
18658        self.background_highlights_in_range(start..end, &snapshot, theme)
18659    }
18660
18661    #[cfg(feature = "test-support")]
18662    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18663        let snapshot = self.buffer().read(cx).snapshot(cx);
18664
18665        let highlights = self
18666            .background_highlights
18667            .get(&TypeId::of::<items::BufferSearchHighlights>());
18668
18669        if let Some(highlights) = highlights {
18670            highlights
18671                .iter()
18672                .map(|highlight| {
18673                    highlight.range.start.to_point(&snapshot)
18674                        ..highlight.range.end.to_point(&snapshot)
18675                })
18676                .collect_vec()
18677        } else {
18678            vec![]
18679        }
18680    }
18681
18682    fn document_highlights_for_position<'a>(
18683        &'a self,
18684        position: Anchor,
18685        buffer: &'a MultiBufferSnapshot,
18686    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18687        let read_highlights = self
18688            .background_highlights
18689            .get(&TypeId::of::<DocumentHighlightRead>());
18690        let write_highlights = self
18691            .background_highlights
18692            .get(&TypeId::of::<DocumentHighlightWrite>());
18693        let left_position = position.bias_left(buffer);
18694        let right_position = position.bias_right(buffer);
18695        read_highlights
18696            .into_iter()
18697            .chain(write_highlights)
18698            .flat_map(move |highlights| {
18699                let start_ix = match highlights.binary_search_by(|probe| {
18700                    let cmp = probe.range.end.cmp(&left_position, buffer);
18701                    if cmp.is_ge() {
18702                        Ordering::Greater
18703                    } else {
18704                        Ordering::Less
18705                    }
18706                }) {
18707                    Ok(i) | Err(i) => i,
18708                };
18709
18710                highlights[start_ix..]
18711                    .iter()
18712                    .take_while(move |highlight| {
18713                        highlight.range.start.cmp(&right_position, buffer).is_le()
18714                    })
18715                    .map(|highlight| &highlight.range)
18716            })
18717    }
18718
18719    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18720        self.background_highlights
18721            .get(&TypeId::of::<T>())
18722            .map_or(false, |highlights| !highlights.is_empty())
18723    }
18724
18725    pub fn background_highlights_in_range(
18726        &self,
18727        search_range: Range<Anchor>,
18728        display_snapshot: &DisplaySnapshot,
18729        theme: &Theme,
18730    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18731        let mut results = Vec::new();
18732        for highlights in self.background_highlights.values() {
18733            let start_ix = match highlights.binary_search_by(|probe| {
18734                let cmp = probe
18735                    .range
18736                    .end
18737                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18738                if cmp.is_gt() {
18739                    Ordering::Greater
18740                } else {
18741                    Ordering::Less
18742                }
18743            }) {
18744                Ok(i) | Err(i) => i,
18745            };
18746            for highlight in &highlights[start_ix..] {
18747                if highlight
18748                    .range
18749                    .start
18750                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18751                    .is_ge()
18752                {
18753                    break;
18754                }
18755
18756                let start = highlight.range.start.to_display_point(display_snapshot);
18757                let end = highlight.range.end.to_display_point(display_snapshot);
18758                let color = (highlight.color_fetcher)(theme);
18759                results.push((start..end, color))
18760            }
18761        }
18762        results
18763    }
18764
18765    pub fn background_highlight_row_ranges<T: 'static>(
18766        &self,
18767        search_range: Range<Anchor>,
18768        display_snapshot: &DisplaySnapshot,
18769        count: usize,
18770    ) -> Vec<RangeInclusive<DisplayPoint>> {
18771        let mut results = Vec::new();
18772        let Some(highlights) = self.background_highlights.get(&TypeId::of::<T>()) else {
18773            return vec![];
18774        };
18775
18776        let start_ix = match highlights.binary_search_by(|probe| {
18777            let cmp = probe
18778                .range
18779                .end
18780                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18781            if cmp.is_gt() {
18782                Ordering::Greater
18783            } else {
18784                Ordering::Less
18785            }
18786        }) {
18787            Ok(i) | Err(i) => i,
18788        };
18789        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18790            if let (Some(start_display), Some(end_display)) = (start, end) {
18791                results.push(
18792                    start_display.to_display_point(display_snapshot)
18793                        ..=end_display.to_display_point(display_snapshot),
18794                );
18795            }
18796        };
18797        let mut start_row: Option<Point> = None;
18798        let mut end_row: Option<Point> = None;
18799        if highlights.len() > count {
18800            return Vec::new();
18801        }
18802        for highlight in &highlights[start_ix..] {
18803            if highlight
18804                .range
18805                .start
18806                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18807                .is_ge()
18808            {
18809                break;
18810            }
18811            let end = highlight
18812                .range
18813                .end
18814                .to_point(&display_snapshot.buffer_snapshot);
18815            if let Some(current_row) = &end_row {
18816                if end.row == current_row.row {
18817                    continue;
18818                }
18819            }
18820            let start = highlight
18821                .range
18822                .start
18823                .to_point(&display_snapshot.buffer_snapshot);
18824            if start_row.is_none() {
18825                assert_eq!(end_row, None);
18826                start_row = Some(start);
18827                end_row = Some(end);
18828                continue;
18829            }
18830            if let Some(current_end) = end_row.as_mut() {
18831                if start.row > current_end.row + 1 {
18832                    push_region(start_row, end_row);
18833                    start_row = Some(start);
18834                    end_row = Some(end);
18835                } else {
18836                    // Merge two hunks.
18837                    *current_end = end;
18838                }
18839            } else {
18840                unreachable!();
18841            }
18842        }
18843        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18844        push_region(start_row, end_row);
18845        results
18846    }
18847
18848    pub fn gutter_highlights_in_range(
18849        &self,
18850        search_range: Range<Anchor>,
18851        display_snapshot: &DisplaySnapshot,
18852        cx: &App,
18853    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18854        let mut results = Vec::new();
18855        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18856            let color = color_fetcher(cx);
18857            let start_ix = match ranges.binary_search_by(|probe| {
18858                let cmp = probe
18859                    .end
18860                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18861                if cmp.is_gt() {
18862                    Ordering::Greater
18863                } else {
18864                    Ordering::Less
18865                }
18866            }) {
18867                Ok(i) | Err(i) => i,
18868            };
18869            for range in &ranges[start_ix..] {
18870                if range
18871                    .start
18872                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18873                    .is_ge()
18874                {
18875                    break;
18876                }
18877
18878                let start = range.start.to_display_point(display_snapshot);
18879                let end = range.end.to_display_point(display_snapshot);
18880                results.push((start..end, color))
18881            }
18882        }
18883        results
18884    }
18885
18886    /// Get the text ranges corresponding to the redaction query
18887    pub fn redacted_ranges(
18888        &self,
18889        search_range: Range<Anchor>,
18890        display_snapshot: &DisplaySnapshot,
18891        cx: &App,
18892    ) -> Vec<Range<DisplayPoint>> {
18893        display_snapshot
18894            .buffer_snapshot
18895            .redacted_ranges(search_range, |file| {
18896                if let Some(file) = file {
18897                    file.is_private()
18898                        && EditorSettings::get(
18899                            Some(SettingsLocation {
18900                                worktree_id: file.worktree_id(cx),
18901                                path: file.path().as_ref(),
18902                            }),
18903                            cx,
18904                        )
18905                        .redact_private_values
18906                } else {
18907                    false
18908                }
18909            })
18910            .map(|range| {
18911                range.start.to_display_point(display_snapshot)
18912                    ..range.end.to_display_point(display_snapshot)
18913            })
18914            .collect()
18915    }
18916
18917    pub fn highlight_text<T: 'static>(
18918        &mut self,
18919        ranges: Vec<(Range<Anchor>, HighlightStyle)>,
18920        cx: &mut Context<Self>,
18921    ) {
18922        self.display_map
18923            .update(cx, |map, _| map.highlight_text(TypeId::of::<T>(), ranges));
18924        cx.notify();
18925    }
18926
18927    pub(crate) fn highlight_inlays<T: 'static>(
18928        &mut self,
18929        highlights: Vec<InlayHighlight>,
18930        style: HighlightStyle,
18931        cx: &mut Context<Self>,
18932    ) {
18933        self.display_map.update(cx, |map, _| {
18934            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18935        });
18936        cx.notify();
18937    }
18938
18939    pub fn text_highlights<'a, T: 'static>(
18940        &'a self,
18941        cx: &'a App,
18942    ) -> Option<&'a [(Range<Anchor>, HighlightStyle)]> {
18943        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18944    }
18945
18946    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18947        let cleared = self
18948            .display_map
18949            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18950        if cleared {
18951            cx.notify();
18952        }
18953    }
18954
18955    pub fn remove_text_highlights<T: 'static>(
18956        &mut self,
18957        cx: &mut Context<Self>,
18958    ) -> Option<Vec<(Range<Anchor>, HighlightStyle)>> {
18959        self.display_map
18960            .update(cx, |map, _| map.remove_text_highlights(TypeId::of::<T>()))
18961    }
18962
18963    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18964        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18965            && self.focus_handle.is_focused(window)
18966    }
18967
18968    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18969        self.show_cursor_when_unfocused = is_enabled;
18970        cx.notify();
18971    }
18972
18973    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18974        cx.notify();
18975    }
18976
18977    fn on_debug_session_event(
18978        &mut self,
18979        _session: Entity<Session>,
18980        event: &SessionEvent,
18981        cx: &mut Context<Self>,
18982    ) {
18983        match event {
18984            SessionEvent::InvalidateInlineValue => {
18985                self.refresh_inline_values(cx);
18986            }
18987            _ => {}
18988        }
18989    }
18990
18991    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18992        let Some(project) = self.project.clone() else {
18993            return;
18994        };
18995
18996        if !self.inline_value_cache.enabled {
18997            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18998            self.splice_inlays(&inlays, Vec::new(), cx);
18999            return;
19000        }
19001
19002        let current_execution_position = self
19003            .highlighted_rows
19004            .get(&TypeId::of::<ActiveDebugLine>())
19005            .and_then(|lines| lines.last().map(|line| line.range.start));
19006
19007        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19008            let inline_values = editor
19009                .update(cx, |editor, cx| {
19010                    let Some(current_execution_position) = current_execution_position else {
19011                        return Some(Task::ready(Ok(Vec::new())));
19012                    };
19013
19014                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19015                        let snapshot = buffer.snapshot(cx);
19016
19017                        let excerpt = snapshot.excerpt_containing(
19018                            current_execution_position..current_execution_position,
19019                        )?;
19020
19021                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19022                    })?;
19023
19024                    let range =
19025                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19026
19027                    project.inline_values(buffer, range, cx)
19028                })
19029                .ok()
19030                .flatten()?
19031                .await
19032                .context("refreshing debugger inlays")
19033                .log_err()?;
19034
19035            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19036
19037            for (buffer_id, inline_value) in inline_values
19038                .into_iter()
19039                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19040            {
19041                buffer_inline_values
19042                    .entry(buffer_id)
19043                    .or_default()
19044                    .push(inline_value);
19045            }
19046
19047            editor
19048                .update(cx, |editor, cx| {
19049                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19050                    let mut new_inlays = Vec::default();
19051
19052                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19053                        let buffer_id = buffer_snapshot.remote_id();
19054                        buffer_inline_values
19055                            .get(&buffer_id)
19056                            .into_iter()
19057                            .flatten()
19058                            .for_each(|hint| {
19059                                let inlay = Inlay::debugger_hint(
19060                                    post_inc(&mut editor.next_inlay_id),
19061                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19062                                    hint.text(),
19063                                );
19064
19065                                new_inlays.push(inlay);
19066                            });
19067                    }
19068
19069                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19070                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19071
19072                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19073                })
19074                .ok()?;
19075            Some(())
19076        });
19077    }
19078
19079    fn on_buffer_event(
19080        &mut self,
19081        multibuffer: &Entity<MultiBuffer>,
19082        event: &multi_buffer::Event,
19083        window: &mut Window,
19084        cx: &mut Context<Self>,
19085    ) {
19086        match event {
19087            multi_buffer::Event::Edited {
19088                singleton_buffer_edited,
19089                edited_buffer,
19090            } => {
19091                self.scrollbar_marker_state.dirty = true;
19092                self.active_indent_guides_state.dirty = true;
19093                self.refresh_active_diagnostics(cx);
19094                self.refresh_code_actions(window, cx);
19095                self.refresh_selected_text_highlights(true, window, cx);
19096                refresh_matching_bracket_highlights(self, window, cx);
19097                if self.has_active_inline_completion() {
19098                    self.update_visible_inline_completion(window, cx);
19099                }
19100                if let Some(project) = self.project.as_ref() {
19101                    if let Some(edited_buffer) = edited_buffer {
19102                        project.update(cx, |project, cx| {
19103                            self.registered_buffers
19104                                .entry(edited_buffer.read(cx).remote_id())
19105                                .or_insert_with(|| {
19106                                    project
19107                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19108                                });
19109                        });
19110                        if edited_buffer.read(cx).file().is_some() {
19111                            self.pull_diagnostics(
19112                                Some(edited_buffer.read(cx).remote_id()),
19113                                window,
19114                                cx,
19115                            );
19116                        }
19117                    }
19118                }
19119                cx.emit(EditorEvent::BufferEdited);
19120                cx.emit(SearchEvent::MatchesInvalidated);
19121                if *singleton_buffer_edited {
19122                    if let Some(buffer) = edited_buffer {
19123                        if buffer.read(cx).file().is_none() {
19124                            cx.emit(EditorEvent::TitleChanged);
19125                        }
19126                    }
19127                    if let Some(project) = &self.project {
19128                        #[allow(clippy::mutable_key_type)]
19129                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19130                            multibuffer
19131                                .all_buffers()
19132                                .into_iter()
19133                                .filter_map(|buffer| {
19134                                    buffer.update(cx, |buffer, cx| {
19135                                        let language = buffer.language()?;
19136                                        let should_discard = project.update(cx, |project, cx| {
19137                                            project.is_local()
19138                                                && !project.has_language_servers_for(buffer, cx)
19139                                        });
19140                                        should_discard.not().then_some(language.clone())
19141                                    })
19142                                })
19143                                .collect::<HashSet<_>>()
19144                        });
19145                        if !languages_affected.is_empty() {
19146                            self.refresh_inlay_hints(
19147                                InlayHintRefreshReason::BufferEdited(languages_affected),
19148                                cx,
19149                            );
19150                        }
19151                    }
19152                }
19153
19154                let Some(project) = &self.project else { return };
19155                let (telemetry, is_via_ssh) = {
19156                    let project = project.read(cx);
19157                    let telemetry = project.client().telemetry().clone();
19158                    let is_via_ssh = project.is_via_ssh();
19159                    (telemetry, is_via_ssh)
19160                };
19161                refresh_linked_ranges(self, window, cx);
19162                telemetry.log_edit_event("editor", is_via_ssh);
19163            }
19164            multi_buffer::Event::ExcerptsAdded {
19165                buffer,
19166                predecessor,
19167                excerpts,
19168            } => {
19169                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19170                let buffer_id = buffer.read(cx).remote_id();
19171                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19172                    if let Some(project) = &self.project {
19173                        update_uncommitted_diff_for_buffer(
19174                            cx.entity(),
19175                            project,
19176                            [buffer.clone()],
19177                            self.buffer.clone(),
19178                            cx,
19179                        )
19180                        .detach();
19181                    }
19182                }
19183                cx.emit(EditorEvent::ExcerptsAdded {
19184                    buffer: buffer.clone(),
19185                    predecessor: *predecessor,
19186                    excerpts: excerpts.clone(),
19187                });
19188                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19189            }
19190            multi_buffer::Event::ExcerptsRemoved {
19191                ids,
19192                removed_buffer_ids,
19193            } => {
19194                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19195                let buffer = self.buffer.read(cx);
19196                self.registered_buffers
19197                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19198                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19199                cx.emit(EditorEvent::ExcerptsRemoved {
19200                    ids: ids.clone(),
19201                    removed_buffer_ids: removed_buffer_ids.clone(),
19202                })
19203            }
19204            multi_buffer::Event::ExcerptsEdited {
19205                excerpt_ids,
19206                buffer_ids,
19207            } => {
19208                self.display_map.update(cx, |map, cx| {
19209                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19210                });
19211                cx.emit(EditorEvent::ExcerptsEdited {
19212                    ids: excerpt_ids.clone(),
19213                })
19214            }
19215            multi_buffer::Event::ExcerptsExpanded { ids } => {
19216                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19217                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19218            }
19219            multi_buffer::Event::Reparsed(buffer_id) => {
19220                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19221                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19222
19223                cx.emit(EditorEvent::Reparsed(*buffer_id));
19224            }
19225            multi_buffer::Event::DiffHunksToggled => {
19226                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19227            }
19228            multi_buffer::Event::LanguageChanged(buffer_id) => {
19229                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19230                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19231                cx.emit(EditorEvent::Reparsed(*buffer_id));
19232                cx.notify();
19233            }
19234            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19235            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19236            multi_buffer::Event::FileHandleChanged
19237            | multi_buffer::Event::Reloaded
19238            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19239            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19240            multi_buffer::Event::DiagnosticsUpdated => {
19241                self.update_diagnostics_state(window, cx);
19242            }
19243            _ => {}
19244        };
19245    }
19246
19247    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19248        self.refresh_active_diagnostics(cx);
19249        self.refresh_inline_diagnostics(true, window, cx);
19250        self.scrollbar_marker_state.dirty = true;
19251        cx.notify();
19252    }
19253
19254    pub fn start_temporary_diff_override(&mut self) {
19255        self.load_diff_task.take();
19256        self.temporary_diff_override = true;
19257    }
19258
19259    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19260        self.temporary_diff_override = false;
19261        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19262        self.buffer.update(cx, |buffer, cx| {
19263            buffer.set_all_diff_hunks_collapsed(cx);
19264        });
19265
19266        if let Some(project) = self.project.clone() {
19267            self.load_diff_task = Some(
19268                update_uncommitted_diff_for_buffer(
19269                    cx.entity(),
19270                    &project,
19271                    self.buffer.read(cx).all_buffers(),
19272                    self.buffer.clone(),
19273                    cx,
19274                )
19275                .shared(),
19276            );
19277        }
19278    }
19279
19280    fn on_display_map_changed(
19281        &mut self,
19282        _: Entity<DisplayMap>,
19283        _: &mut Window,
19284        cx: &mut Context<Self>,
19285    ) {
19286        cx.notify();
19287    }
19288
19289    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19290        let new_severity = if self.diagnostics_enabled() {
19291            EditorSettings::get_global(cx)
19292                .diagnostics_max_severity
19293                .unwrap_or(DiagnosticSeverity::Hint)
19294        } else {
19295            DiagnosticSeverity::Off
19296        };
19297        self.set_max_diagnostics_severity(new_severity, cx);
19298        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19299        self.update_edit_prediction_settings(cx);
19300        self.refresh_inline_completion(true, false, window, cx);
19301        self.refresh_inlay_hints(
19302            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19303                self.selections.newest_anchor().head(),
19304                &self.buffer.read(cx).snapshot(cx),
19305                cx,
19306            )),
19307            cx,
19308        );
19309
19310        let old_cursor_shape = self.cursor_shape;
19311
19312        {
19313            let editor_settings = EditorSettings::get_global(cx);
19314            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19315            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19316            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19317            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19318            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19319        }
19320
19321        if old_cursor_shape != self.cursor_shape {
19322            cx.emit(EditorEvent::CursorShapeChanged);
19323        }
19324
19325        let project_settings = ProjectSettings::get_global(cx);
19326        self.serialize_dirty_buffers =
19327            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19328
19329        if self.mode.is_full() {
19330            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19331            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19332            if self.show_inline_diagnostics != show_inline_diagnostics {
19333                self.show_inline_diagnostics = show_inline_diagnostics;
19334                self.refresh_inline_diagnostics(false, window, cx);
19335            }
19336
19337            if self.git_blame_inline_enabled != inline_blame_enabled {
19338                self.toggle_git_blame_inline_internal(false, window, cx);
19339            }
19340
19341            let minimap_settings = EditorSettings::get_global(cx).minimap;
19342            if self.minimap_visibility != MinimapVisibility::Disabled {
19343                if self.minimap_visibility.settings_visibility()
19344                    != minimap_settings.minimap_enabled()
19345                {
19346                    self.set_minimap_visibility(
19347                        MinimapVisibility::for_mode(self.mode(), cx),
19348                        window,
19349                        cx,
19350                    );
19351                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19352                    minimap_entity.update(cx, |minimap_editor, cx| {
19353                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19354                    })
19355                }
19356            }
19357        }
19358
19359        cx.notify();
19360    }
19361
19362    pub fn set_searchable(&mut self, searchable: bool) {
19363        self.searchable = searchable;
19364    }
19365
19366    pub fn searchable(&self) -> bool {
19367        self.searchable
19368    }
19369
19370    fn open_proposed_changes_editor(
19371        &mut self,
19372        _: &OpenProposedChangesEditor,
19373        window: &mut Window,
19374        cx: &mut Context<Self>,
19375    ) {
19376        let Some(workspace) = self.workspace() else {
19377            cx.propagate();
19378            return;
19379        };
19380
19381        let selections = self.selections.all::<usize>(cx);
19382        let multi_buffer = self.buffer.read(cx);
19383        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19384        let mut new_selections_by_buffer = HashMap::default();
19385        for selection in selections {
19386            for (buffer, range, _) in
19387                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19388            {
19389                let mut range = range.to_point(buffer);
19390                range.start.column = 0;
19391                range.end.column = buffer.line_len(range.end.row);
19392                new_selections_by_buffer
19393                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19394                    .or_insert(Vec::new())
19395                    .push(range)
19396            }
19397        }
19398
19399        let proposed_changes_buffers = new_selections_by_buffer
19400            .into_iter()
19401            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19402            .collect::<Vec<_>>();
19403        let proposed_changes_editor = cx.new(|cx| {
19404            ProposedChangesEditor::new(
19405                "Proposed changes",
19406                proposed_changes_buffers,
19407                self.project.clone(),
19408                window,
19409                cx,
19410            )
19411        });
19412
19413        window.defer(cx, move |window, cx| {
19414            workspace.update(cx, |workspace, cx| {
19415                workspace.active_pane().update(cx, |pane, cx| {
19416                    pane.add_item(
19417                        Box::new(proposed_changes_editor),
19418                        true,
19419                        true,
19420                        None,
19421                        window,
19422                        cx,
19423                    );
19424                });
19425            });
19426        });
19427    }
19428
19429    pub fn open_excerpts_in_split(
19430        &mut self,
19431        _: &OpenExcerptsSplit,
19432        window: &mut Window,
19433        cx: &mut Context<Self>,
19434    ) {
19435        self.open_excerpts_common(None, true, window, cx)
19436    }
19437
19438    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19439        self.open_excerpts_common(None, false, window, cx)
19440    }
19441
19442    fn open_excerpts_common(
19443        &mut self,
19444        jump_data: Option<JumpData>,
19445        split: bool,
19446        window: &mut Window,
19447        cx: &mut Context<Self>,
19448    ) {
19449        let Some(workspace) = self.workspace() else {
19450            cx.propagate();
19451            return;
19452        };
19453
19454        if self.buffer.read(cx).is_singleton() {
19455            cx.propagate();
19456            return;
19457        }
19458
19459        let mut new_selections_by_buffer = HashMap::default();
19460        match &jump_data {
19461            Some(JumpData::MultiBufferPoint {
19462                excerpt_id,
19463                position,
19464                anchor,
19465                line_offset_from_top,
19466            }) => {
19467                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19468                if let Some(buffer) = multi_buffer_snapshot
19469                    .buffer_id_for_excerpt(*excerpt_id)
19470                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19471                {
19472                    let buffer_snapshot = buffer.read(cx).snapshot();
19473                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19474                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19475                    } else {
19476                        buffer_snapshot.clip_point(*position, Bias::Left)
19477                    };
19478                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19479                    new_selections_by_buffer.insert(
19480                        buffer,
19481                        (
19482                            vec![jump_to_offset..jump_to_offset],
19483                            Some(*line_offset_from_top),
19484                        ),
19485                    );
19486                }
19487            }
19488            Some(JumpData::MultiBufferRow {
19489                row,
19490                line_offset_from_top,
19491            }) => {
19492                let point = MultiBufferPoint::new(row.0, 0);
19493                if let Some((buffer, buffer_point, _)) =
19494                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19495                {
19496                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19497                    new_selections_by_buffer
19498                        .entry(buffer)
19499                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19500                        .0
19501                        .push(buffer_offset..buffer_offset)
19502                }
19503            }
19504            None => {
19505                let selections = self.selections.all::<usize>(cx);
19506                let multi_buffer = self.buffer.read(cx);
19507                for selection in selections {
19508                    for (snapshot, range, _, anchor) in multi_buffer
19509                        .snapshot(cx)
19510                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19511                    {
19512                        if let Some(anchor) = anchor {
19513                            // selection is in a deleted hunk
19514                            let Some(buffer_id) = anchor.buffer_id else {
19515                                continue;
19516                            };
19517                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19518                                continue;
19519                            };
19520                            let offset = text::ToOffset::to_offset(
19521                                &anchor.text_anchor,
19522                                &buffer_handle.read(cx).snapshot(),
19523                            );
19524                            let range = offset..offset;
19525                            new_selections_by_buffer
19526                                .entry(buffer_handle)
19527                                .or_insert((Vec::new(), None))
19528                                .0
19529                                .push(range)
19530                        } else {
19531                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19532                            else {
19533                                continue;
19534                            };
19535                            new_selections_by_buffer
19536                                .entry(buffer_handle)
19537                                .or_insert((Vec::new(), None))
19538                                .0
19539                                .push(range)
19540                        }
19541                    }
19542                }
19543            }
19544        }
19545
19546        new_selections_by_buffer
19547            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19548
19549        if new_selections_by_buffer.is_empty() {
19550            return;
19551        }
19552
19553        // We defer the pane interaction because we ourselves are a workspace item
19554        // and activating a new item causes the pane to call a method on us reentrantly,
19555        // which panics if we're on the stack.
19556        window.defer(cx, move |window, cx| {
19557            workspace.update(cx, |workspace, cx| {
19558                let pane = if split {
19559                    workspace.adjacent_pane(window, cx)
19560                } else {
19561                    workspace.active_pane().clone()
19562                };
19563
19564                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19565                    let editor = buffer
19566                        .read(cx)
19567                        .file()
19568                        .is_none()
19569                        .then(|| {
19570                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19571                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19572                            // Instead, we try to activate the existing editor in the pane first.
19573                            let (editor, pane_item_index) =
19574                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19575                                    let editor = item.downcast::<Editor>()?;
19576                                    let singleton_buffer =
19577                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19578                                    if singleton_buffer == buffer {
19579                                        Some((editor, i))
19580                                    } else {
19581                                        None
19582                                    }
19583                                })?;
19584                            pane.update(cx, |pane, cx| {
19585                                pane.activate_item(pane_item_index, true, true, window, cx)
19586                            });
19587                            Some(editor)
19588                        })
19589                        .flatten()
19590                        .unwrap_or_else(|| {
19591                            workspace.open_project_item::<Self>(
19592                                pane.clone(),
19593                                buffer,
19594                                true,
19595                                true,
19596                                window,
19597                                cx,
19598                            )
19599                        });
19600
19601                    editor.update(cx, |editor, cx| {
19602                        let autoscroll = match scroll_offset {
19603                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19604                            None => Autoscroll::newest(),
19605                        };
19606                        let nav_history = editor.nav_history.take();
19607                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19608                            s.select_ranges(ranges);
19609                        });
19610                        editor.nav_history = nav_history;
19611                    });
19612                }
19613            })
19614        });
19615    }
19616
19617    // For now, don't allow opening excerpts in buffers that aren't backed by
19618    // regular project files.
19619    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19620        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19621    }
19622
19623    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19624        let snapshot = self.buffer.read(cx).read(cx);
19625        let ranges = self.text_highlights::<InputComposition>(cx)?;
19626        Some(
19627            ranges
19628                .iter()
19629                .map(move |(range, _)| {
19630                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19631                })
19632                .collect(),
19633        )
19634    }
19635
19636    fn selection_replacement_ranges(
19637        &self,
19638        range: Range<OffsetUtf16>,
19639        cx: &mut App,
19640    ) -> Vec<Range<OffsetUtf16>> {
19641        let selections = self.selections.all::<OffsetUtf16>(cx);
19642        let newest_selection = selections
19643            .iter()
19644            .max_by_key(|selection| selection.id)
19645            .unwrap();
19646        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19647        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19648        let snapshot = self.buffer.read(cx).read(cx);
19649        selections
19650            .into_iter()
19651            .map(|mut selection| {
19652                selection.start.0 =
19653                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19654                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19655                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19656                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19657            })
19658            .collect()
19659    }
19660
19661    fn report_editor_event(
19662        &self,
19663        event_type: &'static str,
19664        file_extension: Option<String>,
19665        cx: &App,
19666    ) {
19667        if cfg!(any(test, feature = "test-support")) {
19668            return;
19669        }
19670
19671        let Some(project) = &self.project else { return };
19672
19673        // If None, we are in a file without an extension
19674        let file = self
19675            .buffer
19676            .read(cx)
19677            .as_singleton()
19678            .and_then(|b| b.read(cx).file());
19679        let file_extension = file_extension.or(file
19680            .as_ref()
19681            .and_then(|file| Path::new(file.file_name(cx)).extension())
19682            .and_then(|e| e.to_str())
19683            .map(|a| a.to_string()));
19684
19685        let vim_mode = vim_enabled(cx);
19686
19687        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19688        let copilot_enabled = edit_predictions_provider
19689            == language::language_settings::EditPredictionProvider::Copilot;
19690        let copilot_enabled_for_language = self
19691            .buffer
19692            .read(cx)
19693            .language_settings(cx)
19694            .show_edit_predictions;
19695
19696        let project = project.read(cx);
19697        telemetry::event!(
19698            event_type,
19699            file_extension,
19700            vim_mode,
19701            copilot_enabled,
19702            copilot_enabled_for_language,
19703            edit_predictions_provider,
19704            is_via_ssh = project.is_via_ssh(),
19705        );
19706    }
19707
19708    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19709    /// with each line being an array of {text, highlight} objects.
19710    fn copy_highlight_json(
19711        &mut self,
19712        _: &CopyHighlightJson,
19713        window: &mut Window,
19714        cx: &mut Context<Self>,
19715    ) {
19716        #[derive(Serialize)]
19717        struct Chunk<'a> {
19718            text: String,
19719            highlight: Option<&'a str>,
19720        }
19721
19722        let snapshot = self.buffer.read(cx).snapshot(cx);
19723        let range = self
19724            .selected_text_range(false, window, cx)
19725            .and_then(|selection| {
19726                if selection.range.is_empty() {
19727                    None
19728                } else {
19729                    Some(selection.range)
19730                }
19731            })
19732            .unwrap_or_else(|| 0..snapshot.len());
19733
19734        let chunks = snapshot.chunks(range, true);
19735        let mut lines = Vec::new();
19736        let mut line: VecDeque<Chunk> = VecDeque::new();
19737
19738        let Some(style) = self.style.as_ref() else {
19739            return;
19740        };
19741
19742        for chunk in chunks {
19743            let highlight = chunk
19744                .syntax_highlight_id
19745                .and_then(|id| id.name(&style.syntax));
19746            let mut chunk_lines = chunk.text.split('\n').peekable();
19747            while let Some(text) = chunk_lines.next() {
19748                let mut merged_with_last_token = false;
19749                if let Some(last_token) = line.back_mut() {
19750                    if last_token.highlight == highlight {
19751                        last_token.text.push_str(text);
19752                        merged_with_last_token = true;
19753                    }
19754                }
19755
19756                if !merged_with_last_token {
19757                    line.push_back(Chunk {
19758                        text: text.into(),
19759                        highlight,
19760                    });
19761                }
19762
19763                if chunk_lines.peek().is_some() {
19764                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19765                        line.pop_front();
19766                    }
19767                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19768                        line.pop_back();
19769                    }
19770
19771                    lines.push(mem::take(&mut line));
19772                }
19773            }
19774        }
19775
19776        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19777            return;
19778        };
19779        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19780    }
19781
19782    pub fn open_context_menu(
19783        &mut self,
19784        _: &OpenContextMenu,
19785        window: &mut Window,
19786        cx: &mut Context<Self>,
19787    ) {
19788        self.request_autoscroll(Autoscroll::newest(), cx);
19789        let position = self.selections.newest_display(cx).start;
19790        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19791    }
19792
19793    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19794        &self.inlay_hint_cache
19795    }
19796
19797    pub fn replay_insert_event(
19798        &mut self,
19799        text: &str,
19800        relative_utf16_range: Option<Range<isize>>,
19801        window: &mut Window,
19802        cx: &mut Context<Self>,
19803    ) {
19804        if !self.input_enabled {
19805            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19806            return;
19807        }
19808        if let Some(relative_utf16_range) = relative_utf16_range {
19809            let selections = self.selections.all::<OffsetUtf16>(cx);
19810            self.change_selections(None, window, cx, |s| {
19811                let new_ranges = selections.into_iter().map(|range| {
19812                    let start = OffsetUtf16(
19813                        range
19814                            .head()
19815                            .0
19816                            .saturating_add_signed(relative_utf16_range.start),
19817                    );
19818                    let end = OffsetUtf16(
19819                        range
19820                            .head()
19821                            .0
19822                            .saturating_add_signed(relative_utf16_range.end),
19823                    );
19824                    start..end
19825                });
19826                s.select_ranges(new_ranges);
19827            });
19828        }
19829
19830        self.handle_input(text, window, cx);
19831    }
19832
19833    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19834        let Some(provider) = self.semantics_provider.as_ref() else {
19835            return false;
19836        };
19837
19838        let mut supports = false;
19839        self.buffer().update(cx, |this, cx| {
19840            this.for_each_buffer(|buffer| {
19841                supports |= provider.supports_inlay_hints(buffer, cx);
19842            });
19843        });
19844
19845        supports
19846    }
19847
19848    pub fn is_focused(&self, window: &Window) -> bool {
19849        self.focus_handle.is_focused(window)
19850    }
19851
19852    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19853        cx.emit(EditorEvent::Focused);
19854
19855        if let Some(descendant) = self
19856            .last_focused_descendant
19857            .take()
19858            .and_then(|descendant| descendant.upgrade())
19859        {
19860            window.focus(&descendant);
19861        } else {
19862            if let Some(blame) = self.blame.as_ref() {
19863                blame.update(cx, GitBlame::focus)
19864            }
19865
19866            self.blink_manager.update(cx, BlinkManager::enable);
19867            self.show_cursor_names(window, cx);
19868            self.buffer.update(cx, |buffer, cx| {
19869                buffer.finalize_last_transaction(cx);
19870                if self.leader_id.is_none() {
19871                    buffer.set_active_selections(
19872                        &self.selections.disjoint_anchors(),
19873                        self.selections.line_mode,
19874                        self.cursor_shape,
19875                        cx,
19876                    );
19877                }
19878            });
19879        }
19880    }
19881
19882    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19883        cx.emit(EditorEvent::FocusedIn)
19884    }
19885
19886    fn handle_focus_out(
19887        &mut self,
19888        event: FocusOutEvent,
19889        _window: &mut Window,
19890        cx: &mut Context<Self>,
19891    ) {
19892        if event.blurred != self.focus_handle {
19893            self.last_focused_descendant = Some(event.blurred);
19894        }
19895        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19896    }
19897
19898    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19899        self.blink_manager.update(cx, BlinkManager::disable);
19900        self.buffer
19901            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19902
19903        if let Some(blame) = self.blame.as_ref() {
19904            blame.update(cx, GitBlame::blur)
19905        }
19906        if !self.hover_state.focused(window, cx) {
19907            hide_hover(self, cx);
19908        }
19909        if !self
19910            .context_menu
19911            .borrow()
19912            .as_ref()
19913            .is_some_and(|context_menu| context_menu.focused(window, cx))
19914        {
19915            self.hide_context_menu(window, cx);
19916        }
19917        self.discard_inline_completion(false, cx);
19918        cx.emit(EditorEvent::Blurred);
19919        cx.notify();
19920    }
19921
19922    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19923        let mut pending: String = window
19924            .pending_input_keystrokes()
19925            .into_iter()
19926            .flatten()
19927            .filter_map(|keystroke| {
19928                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19929                    keystroke.key_char.clone()
19930                } else {
19931                    None
19932                }
19933            })
19934            .collect();
19935
19936        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19937            pending = "".to_string();
19938        }
19939
19940        let existing_pending = self.text_highlights::<PendingInput>(cx).map(|ranges| {
19941            ranges
19942                .iter()
19943                .map(|(range, _)| range.clone())
19944                .collect::<Vec<_>>()
19945        });
19946        if existing_pending.is_none() && pending.is_empty() {
19947            return;
19948        }
19949        let transaction =
19950            self.transact(window, cx, |this, window, cx| {
19951                let selections = this.selections.all::<usize>(cx);
19952                let edits = selections
19953                    .iter()
19954                    .map(|selection| (selection.end..selection.end, pending.clone()));
19955                this.edit(edits, cx);
19956                this.change_selections(None, window, cx, |s| {
19957                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19958                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19959                    }));
19960                });
19961                if let Some(existing_ranges) = existing_pending {
19962                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19963                    this.edit(edits, cx);
19964                }
19965            });
19966
19967        let snapshot = self.snapshot(window, cx);
19968        let ranges = self
19969            .selections
19970            .all::<usize>(cx)
19971            .into_iter()
19972            .map(|selection| {
19973                (
19974                    snapshot.buffer_snapshot.anchor_after(selection.end)
19975                        ..snapshot
19976                            .buffer_snapshot
19977                            .anchor_before(selection.end + pending.len()),
19978                    HighlightStyle {
19979                        underline: Some(UnderlineStyle {
19980                            thickness: px(1.),
19981                            color: None,
19982                            wavy: false,
19983                        }),
19984                        ..Default::default()
19985                    },
19986                )
19987            })
19988            .collect();
19989
19990        if pending.is_empty() {
19991            self.clear_highlights::<PendingInput>(cx);
19992        } else {
19993            self.highlight_text::<PendingInput>(ranges, cx);
19994        }
19995
19996        self.ime_transaction = self.ime_transaction.or(transaction);
19997        if let Some(transaction) = self.ime_transaction {
19998            self.buffer.update(cx, |buffer, cx| {
19999                buffer.group_until_transaction(transaction, cx);
20000            });
20001        }
20002
20003        if self.text_highlights::<PendingInput>(cx).is_none() {
20004            self.ime_transaction.take();
20005        }
20006    }
20007
20008    pub fn register_action_renderer(
20009        &mut self,
20010        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20011    ) -> Subscription {
20012        let id = self.next_editor_action_id.post_inc();
20013        self.editor_actions
20014            .borrow_mut()
20015            .insert(id, Box::new(listener));
20016
20017        let editor_actions = self.editor_actions.clone();
20018        Subscription::new(move || {
20019            editor_actions.borrow_mut().remove(&id);
20020        })
20021    }
20022
20023    pub fn register_action<A: Action>(
20024        &mut self,
20025        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20026    ) -> Subscription {
20027        let id = self.next_editor_action_id.post_inc();
20028        let listener = Arc::new(listener);
20029        self.editor_actions.borrow_mut().insert(
20030            id,
20031            Box::new(move |_, window, _| {
20032                let listener = listener.clone();
20033                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20034                    let action = action.downcast_ref().unwrap();
20035                    if phase == DispatchPhase::Bubble {
20036                        listener(action, window, cx)
20037                    }
20038                })
20039            }),
20040        );
20041
20042        let editor_actions = self.editor_actions.clone();
20043        Subscription::new(move || {
20044            editor_actions.borrow_mut().remove(&id);
20045        })
20046    }
20047
20048    pub fn file_header_size(&self) -> u32 {
20049        FILE_HEADER_HEIGHT
20050    }
20051
20052    pub fn restore(
20053        &mut self,
20054        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20055        window: &mut Window,
20056        cx: &mut Context<Self>,
20057    ) {
20058        let workspace = self.workspace();
20059        let project = self.project.as_ref();
20060        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20061            let mut tasks = Vec::new();
20062            for (buffer_id, changes) in revert_changes {
20063                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20064                    buffer.update(cx, |buffer, cx| {
20065                        buffer.edit(
20066                            changes
20067                                .into_iter()
20068                                .map(|(range, text)| (range, text.to_string())),
20069                            None,
20070                            cx,
20071                        );
20072                    });
20073
20074                    if let Some(project) =
20075                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20076                    {
20077                        project.update(cx, |project, cx| {
20078                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20079                        })
20080                    }
20081                }
20082            }
20083            tasks
20084        });
20085        cx.spawn_in(window, async move |_, cx| {
20086            for (buffer, task) in save_tasks {
20087                let result = task.await;
20088                if result.is_err() {
20089                    let Some(path) = buffer
20090                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20091                        .ok()
20092                    else {
20093                        continue;
20094                    };
20095                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20096                        let Some(task) = cx
20097                            .update_window_entity(&workspace, |workspace, window, cx| {
20098                                workspace
20099                                    .open_path_preview(path, None, false, false, false, window, cx)
20100                            })
20101                            .ok()
20102                        else {
20103                            continue;
20104                        };
20105                        task.await.log_err();
20106                    }
20107                }
20108            }
20109        })
20110        .detach();
20111        self.change_selections(None, window, cx, |selections| selections.refresh());
20112    }
20113
20114    pub fn to_pixel_point(
20115        &self,
20116        source: multi_buffer::Anchor,
20117        editor_snapshot: &EditorSnapshot,
20118        window: &mut Window,
20119    ) -> Option<gpui::Point<Pixels>> {
20120        let source_point = source.to_display_point(editor_snapshot);
20121        self.display_to_pixel_point(source_point, editor_snapshot, window)
20122    }
20123
20124    pub fn display_to_pixel_point(
20125        &self,
20126        source: DisplayPoint,
20127        editor_snapshot: &EditorSnapshot,
20128        window: &mut Window,
20129    ) -> Option<gpui::Point<Pixels>> {
20130        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20131        let text_layout_details = self.text_layout_details(window);
20132        let scroll_top = text_layout_details
20133            .scroll_anchor
20134            .scroll_position(editor_snapshot)
20135            .y;
20136
20137        if source.row().as_f32() < scroll_top.floor() {
20138            return None;
20139        }
20140        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20141        let source_y = line_height * (source.row().as_f32() - scroll_top);
20142        Some(gpui::Point::new(source_x, source_y))
20143    }
20144
20145    pub fn has_visible_completions_menu(&self) -> bool {
20146        !self.edit_prediction_preview_is_active()
20147            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20148                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20149            })
20150    }
20151
20152    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20153        if self.mode.is_minimap() {
20154            return;
20155        }
20156        self.addons
20157            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20158    }
20159
20160    pub fn unregister_addon<T: Addon>(&mut self) {
20161        self.addons.remove(&std::any::TypeId::of::<T>());
20162    }
20163
20164    pub fn addon<T: Addon>(&self) -> Option<&T> {
20165        let type_id = std::any::TypeId::of::<T>();
20166        self.addons
20167            .get(&type_id)
20168            .and_then(|item| item.to_any().downcast_ref::<T>())
20169    }
20170
20171    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20172        let type_id = std::any::TypeId::of::<T>();
20173        self.addons
20174            .get_mut(&type_id)
20175            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20176    }
20177
20178    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20179        let text_layout_details = self.text_layout_details(window);
20180        let style = &text_layout_details.editor_style;
20181        let font_id = window.text_system().resolve_font(&style.text.font());
20182        let font_size = style.text.font_size.to_pixels(window.rem_size());
20183        let line_height = style.text.line_height_in_pixels(window.rem_size());
20184        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20185
20186        gpui::Size::new(em_width, line_height)
20187    }
20188
20189    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20190        self.load_diff_task.clone()
20191    }
20192
20193    fn read_metadata_from_db(
20194        &mut self,
20195        item_id: u64,
20196        workspace_id: WorkspaceId,
20197        window: &mut Window,
20198        cx: &mut Context<Editor>,
20199    ) {
20200        if self.is_singleton(cx)
20201            && !self.mode.is_minimap()
20202            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20203        {
20204            let buffer_snapshot = OnceCell::new();
20205
20206            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20207                if !folds.is_empty() {
20208                    let snapshot =
20209                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20210                    self.fold_ranges(
20211                        folds
20212                            .into_iter()
20213                            .map(|(start, end)| {
20214                                snapshot.clip_offset(start, Bias::Left)
20215                                    ..snapshot.clip_offset(end, Bias::Right)
20216                            })
20217                            .collect(),
20218                        false,
20219                        window,
20220                        cx,
20221                    );
20222                }
20223            }
20224
20225            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20226                if !selections.is_empty() {
20227                    let snapshot =
20228                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20229                    // skip adding the initial selection to selection history
20230                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20231                    self.change_selections(None, window, cx, |s| {
20232                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20233                            snapshot.clip_offset(start, Bias::Left)
20234                                ..snapshot.clip_offset(end, Bias::Right)
20235                        }));
20236                    });
20237                    self.selection_history.mode = SelectionHistoryMode::Normal;
20238                }
20239            };
20240        }
20241
20242        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20243    }
20244}
20245
20246fn vim_enabled(cx: &App) -> bool {
20247    cx.global::<SettingsStore>()
20248        .raw_user_settings()
20249        .get("vim_mode")
20250        == Some(&serde_json::Value::Bool(true))
20251}
20252
20253fn process_completion_for_edit(
20254    completion: &Completion,
20255    intent: CompletionIntent,
20256    buffer: &Entity<Buffer>,
20257    cursor_position: &text::Anchor,
20258    cx: &mut Context<Editor>,
20259) -> CompletionEdit {
20260    let buffer = buffer.read(cx);
20261    let buffer_snapshot = buffer.snapshot();
20262    let (snippet, new_text) = if completion.is_snippet() {
20263        // Workaround for typescript language server issues so that methods don't expand within
20264        // strings and functions with type expressions. The previous point is used because the query
20265        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20266        let mut snippet_source = completion.new_text.clone();
20267        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20268        previous_point.column = previous_point.column.saturating_sub(1);
20269        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20270            if scope.prefers_label_for_snippet_in_completion() {
20271                if let Some(label) = completion.label() {
20272                    if matches!(
20273                        completion.kind(),
20274                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20275                    ) {
20276                        snippet_source = label;
20277                    }
20278                }
20279            }
20280        }
20281        match Snippet::parse(&snippet_source).log_err() {
20282            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20283            None => (None, completion.new_text.clone()),
20284        }
20285    } else {
20286        (None, completion.new_text.clone())
20287    };
20288
20289    let mut range_to_replace = {
20290        let replace_range = &completion.replace_range;
20291        if let CompletionSource::Lsp {
20292            insert_range: Some(insert_range),
20293            ..
20294        } = &completion.source
20295        {
20296            debug_assert_eq!(
20297                insert_range.start, replace_range.start,
20298                "insert_range and replace_range should start at the same position"
20299            );
20300            debug_assert!(
20301                insert_range
20302                    .start
20303                    .cmp(&cursor_position, &buffer_snapshot)
20304                    .is_le(),
20305                "insert_range should start before or at cursor position"
20306            );
20307            debug_assert!(
20308                replace_range
20309                    .start
20310                    .cmp(&cursor_position, &buffer_snapshot)
20311                    .is_le(),
20312                "replace_range should start before or at cursor position"
20313            );
20314            debug_assert!(
20315                insert_range
20316                    .end
20317                    .cmp(&cursor_position, &buffer_snapshot)
20318                    .is_le(),
20319                "insert_range should end before or at cursor position"
20320            );
20321
20322            let should_replace = match intent {
20323                CompletionIntent::CompleteWithInsert => false,
20324                CompletionIntent::CompleteWithReplace => true,
20325                CompletionIntent::Complete | CompletionIntent::Compose => {
20326                    let insert_mode =
20327                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20328                            .completions
20329                            .lsp_insert_mode;
20330                    match insert_mode {
20331                        LspInsertMode::Insert => false,
20332                        LspInsertMode::Replace => true,
20333                        LspInsertMode::ReplaceSubsequence => {
20334                            let mut text_to_replace = buffer.chars_for_range(
20335                                buffer.anchor_before(replace_range.start)
20336                                    ..buffer.anchor_after(replace_range.end),
20337                            );
20338                            let mut current_needle = text_to_replace.next();
20339                            for haystack_ch in completion.label.text.chars() {
20340                                if let Some(needle_ch) = current_needle {
20341                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20342                                        current_needle = text_to_replace.next();
20343                                    }
20344                                }
20345                            }
20346                            current_needle.is_none()
20347                        }
20348                        LspInsertMode::ReplaceSuffix => {
20349                            if replace_range
20350                                .end
20351                                .cmp(&cursor_position, &buffer_snapshot)
20352                                .is_gt()
20353                            {
20354                                let range_after_cursor = *cursor_position..replace_range.end;
20355                                let text_after_cursor = buffer
20356                                    .text_for_range(
20357                                        buffer.anchor_before(range_after_cursor.start)
20358                                            ..buffer.anchor_after(range_after_cursor.end),
20359                                    )
20360                                    .collect::<String>()
20361                                    .to_ascii_lowercase();
20362                                completion
20363                                    .label
20364                                    .text
20365                                    .to_ascii_lowercase()
20366                                    .ends_with(&text_after_cursor)
20367                            } else {
20368                                true
20369                            }
20370                        }
20371                    }
20372                }
20373            };
20374
20375            if should_replace {
20376                replace_range.clone()
20377            } else {
20378                insert_range.clone()
20379            }
20380        } else {
20381            replace_range.clone()
20382        }
20383    };
20384
20385    if range_to_replace
20386        .end
20387        .cmp(&cursor_position, &buffer_snapshot)
20388        .is_lt()
20389    {
20390        range_to_replace.end = *cursor_position;
20391    }
20392
20393    CompletionEdit {
20394        new_text,
20395        replace_range: range_to_replace.to_offset(&buffer),
20396        snippet,
20397    }
20398}
20399
20400struct CompletionEdit {
20401    new_text: String,
20402    replace_range: Range<usize>,
20403    snippet: Option<Snippet>,
20404}
20405
20406fn insert_extra_newline_brackets(
20407    buffer: &MultiBufferSnapshot,
20408    range: Range<usize>,
20409    language: &language::LanguageScope,
20410) -> bool {
20411    let leading_whitespace_len = buffer
20412        .reversed_chars_at(range.start)
20413        .take_while(|c| c.is_whitespace() && *c != '\n')
20414        .map(|c| c.len_utf8())
20415        .sum::<usize>();
20416    let trailing_whitespace_len = buffer
20417        .chars_at(range.end)
20418        .take_while(|c| c.is_whitespace() && *c != '\n')
20419        .map(|c| c.len_utf8())
20420        .sum::<usize>();
20421    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20422
20423    language.brackets().any(|(pair, enabled)| {
20424        let pair_start = pair.start.trim_end();
20425        let pair_end = pair.end.trim_start();
20426
20427        enabled
20428            && pair.newline
20429            && buffer.contains_str_at(range.end, pair_end)
20430            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20431    })
20432}
20433
20434fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20435    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20436        [(buffer, range, _)] => (*buffer, range.clone()),
20437        _ => return false,
20438    };
20439    let pair = {
20440        let mut result: Option<BracketMatch> = None;
20441
20442        for pair in buffer
20443            .all_bracket_ranges(range.clone())
20444            .filter(move |pair| {
20445                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20446            })
20447        {
20448            let len = pair.close_range.end - pair.open_range.start;
20449
20450            if let Some(existing) = &result {
20451                let existing_len = existing.close_range.end - existing.open_range.start;
20452                if len > existing_len {
20453                    continue;
20454                }
20455            }
20456
20457            result = Some(pair);
20458        }
20459
20460        result
20461    };
20462    let Some(pair) = pair else {
20463        return false;
20464    };
20465    pair.newline_only
20466        && buffer
20467            .chars_for_range(pair.open_range.end..range.start)
20468            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20469            .all(|c| c.is_whitespace() && c != '\n')
20470}
20471
20472fn update_uncommitted_diff_for_buffer(
20473    editor: Entity<Editor>,
20474    project: &Entity<Project>,
20475    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20476    buffer: Entity<MultiBuffer>,
20477    cx: &mut App,
20478) -> Task<()> {
20479    let mut tasks = Vec::new();
20480    project.update(cx, |project, cx| {
20481        for buffer in buffers {
20482            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20483                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20484            }
20485        }
20486    });
20487    cx.spawn(async move |cx| {
20488        let diffs = future::join_all(tasks).await;
20489        if editor
20490            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20491            .unwrap_or(false)
20492        {
20493            return;
20494        }
20495
20496        buffer
20497            .update(cx, |buffer, cx| {
20498                for diff in diffs.into_iter().flatten() {
20499                    buffer.add_diff(diff, cx);
20500                }
20501            })
20502            .ok();
20503    })
20504}
20505
20506fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20507    let tab_size = tab_size.get() as usize;
20508    let mut width = offset;
20509
20510    for ch in text.chars() {
20511        width += if ch == '\t' {
20512            tab_size - (width % tab_size)
20513        } else {
20514            1
20515        };
20516    }
20517
20518    width - offset
20519}
20520
20521#[cfg(test)]
20522mod tests {
20523    use super::*;
20524
20525    #[test]
20526    fn test_string_size_with_expanded_tabs() {
20527        let nz = |val| NonZeroU32::new(val).unwrap();
20528        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20529        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20530        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20531        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20532        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20533        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20534        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20535        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20536    }
20537}
20538
20539/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20540struct WordBreakingTokenizer<'a> {
20541    input: &'a str,
20542}
20543
20544impl<'a> WordBreakingTokenizer<'a> {
20545    fn new(input: &'a str) -> Self {
20546        Self { input }
20547    }
20548}
20549
20550fn is_char_ideographic(ch: char) -> bool {
20551    use unicode_script::Script::*;
20552    use unicode_script::UnicodeScript;
20553    matches!(ch.script(), Han | Tangut | Yi)
20554}
20555
20556fn is_grapheme_ideographic(text: &str) -> bool {
20557    text.chars().any(is_char_ideographic)
20558}
20559
20560fn is_grapheme_whitespace(text: &str) -> bool {
20561    text.chars().any(|x| x.is_whitespace())
20562}
20563
20564fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20565    text.chars().next().map_or(false, |ch| {
20566        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20567    })
20568}
20569
20570#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20571enum WordBreakToken<'a> {
20572    Word { token: &'a str, grapheme_len: usize },
20573    InlineWhitespace { token: &'a str, grapheme_len: usize },
20574    Newline,
20575}
20576
20577impl<'a> Iterator for WordBreakingTokenizer<'a> {
20578    /// Yields a span, the count of graphemes in the token, and whether it was
20579    /// whitespace. Note that it also breaks at word boundaries.
20580    type Item = WordBreakToken<'a>;
20581
20582    fn next(&mut self) -> Option<Self::Item> {
20583        use unicode_segmentation::UnicodeSegmentation;
20584        if self.input.is_empty() {
20585            return None;
20586        }
20587
20588        let mut iter = self.input.graphemes(true).peekable();
20589        let mut offset = 0;
20590        let mut grapheme_len = 0;
20591        if let Some(first_grapheme) = iter.next() {
20592            let is_newline = first_grapheme == "\n";
20593            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20594            offset += first_grapheme.len();
20595            grapheme_len += 1;
20596            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20597                if let Some(grapheme) = iter.peek().copied() {
20598                    if should_stay_with_preceding_ideograph(grapheme) {
20599                        offset += grapheme.len();
20600                        grapheme_len += 1;
20601                    }
20602                }
20603            } else {
20604                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20605                let mut next_word_bound = words.peek().copied();
20606                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20607                    next_word_bound = words.next();
20608                }
20609                while let Some(grapheme) = iter.peek().copied() {
20610                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20611                        break;
20612                    };
20613                    if is_grapheme_whitespace(grapheme) != is_whitespace
20614                        || (grapheme == "\n") != is_newline
20615                    {
20616                        break;
20617                    };
20618                    offset += grapheme.len();
20619                    grapheme_len += 1;
20620                    iter.next();
20621                }
20622            }
20623            let token = &self.input[..offset];
20624            self.input = &self.input[offset..];
20625            if token == "\n" {
20626                Some(WordBreakToken::Newline)
20627            } else if is_whitespace {
20628                Some(WordBreakToken::InlineWhitespace {
20629                    token,
20630                    grapheme_len,
20631                })
20632            } else {
20633                Some(WordBreakToken::Word {
20634                    token,
20635                    grapheme_len,
20636                })
20637            }
20638        } else {
20639            None
20640        }
20641    }
20642}
20643
20644#[test]
20645fn test_word_breaking_tokenizer() {
20646    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20647        ("", &[]),
20648        ("  ", &[whitespace("  ", 2)]),
20649        ("Ʒ", &[word("Ʒ", 1)]),
20650        ("Ǽ", &[word("Ǽ", 1)]),
20651        ("", &[word("", 1)]),
20652        ("⋑⋑", &[word("⋑⋑", 2)]),
20653        (
20654            "原理,进而",
20655            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20656        ),
20657        (
20658            "hello world",
20659            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20660        ),
20661        (
20662            "hello, world",
20663            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20664        ),
20665        (
20666            "  hello world",
20667            &[
20668                whitespace("  ", 2),
20669                word("hello", 5),
20670                whitespace(" ", 1),
20671                word("world", 5),
20672            ],
20673        ),
20674        (
20675            "这是什么 \n 钢笔",
20676            &[
20677                word("", 1),
20678                word("", 1),
20679                word("", 1),
20680                word("", 1),
20681                whitespace(" ", 1),
20682                newline(),
20683                whitespace(" ", 1),
20684                word("", 1),
20685                word("", 1),
20686            ],
20687        ),
20688        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20689    ];
20690
20691    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20692        WordBreakToken::Word {
20693            token,
20694            grapheme_len,
20695        }
20696    }
20697
20698    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20699        WordBreakToken::InlineWhitespace {
20700            token,
20701            grapheme_len,
20702        }
20703    }
20704
20705    fn newline() -> WordBreakToken<'static> {
20706        WordBreakToken::Newline
20707    }
20708
20709    for (input, result) in tests {
20710        assert_eq!(
20711            WordBreakingTokenizer::new(input)
20712                .collect::<Vec<_>>()
20713                .as_slice(),
20714            *result,
20715        );
20716    }
20717}
20718
20719fn wrap_with_prefix(
20720    line_prefix: String,
20721    unwrapped_text: String,
20722    wrap_column: usize,
20723    tab_size: NonZeroU32,
20724    preserve_existing_whitespace: bool,
20725) -> String {
20726    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20727    let mut wrapped_text = String::new();
20728    let mut current_line = line_prefix.clone();
20729
20730    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20731    let mut current_line_len = line_prefix_len;
20732    let mut in_whitespace = false;
20733    for token in tokenizer {
20734        let have_preceding_whitespace = in_whitespace;
20735        match token {
20736            WordBreakToken::Word {
20737                token,
20738                grapheme_len,
20739            } => {
20740                in_whitespace = false;
20741                if current_line_len + grapheme_len > wrap_column
20742                    && current_line_len != line_prefix_len
20743                {
20744                    wrapped_text.push_str(current_line.trim_end());
20745                    wrapped_text.push('\n');
20746                    current_line.truncate(line_prefix.len());
20747                    current_line_len = line_prefix_len;
20748                }
20749                current_line.push_str(token);
20750                current_line_len += grapheme_len;
20751            }
20752            WordBreakToken::InlineWhitespace {
20753                mut token,
20754                mut grapheme_len,
20755            } => {
20756                in_whitespace = true;
20757                if have_preceding_whitespace && !preserve_existing_whitespace {
20758                    continue;
20759                }
20760                if !preserve_existing_whitespace {
20761                    token = " ";
20762                    grapheme_len = 1;
20763                }
20764                if current_line_len + grapheme_len > wrap_column {
20765                    wrapped_text.push_str(current_line.trim_end());
20766                    wrapped_text.push('\n');
20767                    current_line.truncate(line_prefix.len());
20768                    current_line_len = line_prefix_len;
20769                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20770                    current_line.push_str(token);
20771                    current_line_len += grapheme_len;
20772                }
20773            }
20774            WordBreakToken::Newline => {
20775                in_whitespace = true;
20776                if preserve_existing_whitespace {
20777                    wrapped_text.push_str(current_line.trim_end());
20778                    wrapped_text.push('\n');
20779                    current_line.truncate(line_prefix.len());
20780                    current_line_len = line_prefix_len;
20781                } else if have_preceding_whitespace {
20782                    continue;
20783                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20784                {
20785                    wrapped_text.push_str(current_line.trim_end());
20786                    wrapped_text.push('\n');
20787                    current_line.truncate(line_prefix.len());
20788                    current_line_len = line_prefix_len;
20789                } else if current_line_len != line_prefix_len {
20790                    current_line.push(' ');
20791                    current_line_len += 1;
20792                }
20793            }
20794        }
20795    }
20796
20797    if !current_line.is_empty() {
20798        wrapped_text.push_str(&current_line);
20799    }
20800    wrapped_text
20801}
20802
20803#[test]
20804fn test_wrap_with_prefix() {
20805    assert_eq!(
20806        wrap_with_prefix(
20807            "# ".to_string(),
20808            "abcdefg".to_string(),
20809            4,
20810            NonZeroU32::new(4).unwrap(),
20811            false,
20812        ),
20813        "# abcdefg"
20814    );
20815    assert_eq!(
20816        wrap_with_prefix(
20817            "".to_string(),
20818            "\thello world".to_string(),
20819            8,
20820            NonZeroU32::new(4).unwrap(),
20821            false,
20822        ),
20823        "hello\nworld"
20824    );
20825    assert_eq!(
20826        wrap_with_prefix(
20827            "// ".to_string(),
20828            "xx \nyy zz aa bb cc".to_string(),
20829            12,
20830            NonZeroU32::new(4).unwrap(),
20831            false,
20832        ),
20833        "// xx yy zz\n// aa bb cc"
20834    );
20835    assert_eq!(
20836        wrap_with_prefix(
20837            String::new(),
20838            "这是什么 \n 钢笔".to_string(),
20839            3,
20840            NonZeroU32::new(4).unwrap(),
20841            false,
20842        ),
20843        "这是什\n么 钢\n"
20844    );
20845}
20846
20847pub trait CollaborationHub {
20848    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20849    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20850    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20851}
20852
20853impl CollaborationHub for Entity<Project> {
20854    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20855        self.read(cx).collaborators()
20856    }
20857
20858    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20859        self.read(cx).user_store().read(cx).participant_indices()
20860    }
20861
20862    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20863        let this = self.read(cx);
20864        let user_ids = this.collaborators().values().map(|c| c.user_id);
20865        this.user_store().read(cx).participant_names(user_ids, cx)
20866    }
20867}
20868
20869pub trait SemanticsProvider {
20870    fn hover(
20871        &self,
20872        buffer: &Entity<Buffer>,
20873        position: text::Anchor,
20874        cx: &mut App,
20875    ) -> Option<Task<Vec<project::Hover>>>;
20876
20877    fn inline_values(
20878        &self,
20879        buffer_handle: Entity<Buffer>,
20880        range: Range<text::Anchor>,
20881        cx: &mut App,
20882    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20883
20884    fn inlay_hints(
20885        &self,
20886        buffer_handle: Entity<Buffer>,
20887        range: Range<text::Anchor>,
20888        cx: &mut App,
20889    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20890
20891    fn resolve_inlay_hint(
20892        &self,
20893        hint: InlayHint,
20894        buffer_handle: Entity<Buffer>,
20895        server_id: LanguageServerId,
20896        cx: &mut App,
20897    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20898
20899    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20900
20901    fn document_highlights(
20902        &self,
20903        buffer: &Entity<Buffer>,
20904        position: text::Anchor,
20905        cx: &mut App,
20906    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20907
20908    fn definitions(
20909        &self,
20910        buffer: &Entity<Buffer>,
20911        position: text::Anchor,
20912        kind: GotoDefinitionKind,
20913        cx: &mut App,
20914    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20915
20916    fn range_for_rename(
20917        &self,
20918        buffer: &Entity<Buffer>,
20919        position: text::Anchor,
20920        cx: &mut App,
20921    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20922
20923    fn perform_rename(
20924        &self,
20925        buffer: &Entity<Buffer>,
20926        position: text::Anchor,
20927        new_name: String,
20928        cx: &mut App,
20929    ) -> Option<Task<Result<ProjectTransaction>>>;
20930
20931    fn pull_diagnostics_for_buffer(
20932        &self,
20933        buffer: Entity<Buffer>,
20934        cx: &mut App,
20935    ) -> Task<anyhow::Result<()>>;
20936}
20937
20938pub trait CompletionProvider {
20939    fn completions(
20940        &self,
20941        excerpt_id: ExcerptId,
20942        buffer: &Entity<Buffer>,
20943        buffer_position: text::Anchor,
20944        trigger: CompletionContext,
20945        window: &mut Window,
20946        cx: &mut Context<Editor>,
20947    ) -> Task<Result<Vec<CompletionResponse>>>;
20948
20949    fn resolve_completions(
20950        &self,
20951        _buffer: Entity<Buffer>,
20952        _completion_indices: Vec<usize>,
20953        _completions: Rc<RefCell<Box<[Completion]>>>,
20954        _cx: &mut Context<Editor>,
20955    ) -> Task<Result<bool>> {
20956        Task::ready(Ok(false))
20957    }
20958
20959    fn apply_additional_edits_for_completion(
20960        &self,
20961        _buffer: Entity<Buffer>,
20962        _completions: Rc<RefCell<Box<[Completion]>>>,
20963        _completion_index: usize,
20964        _push_to_history: bool,
20965        _cx: &mut Context<Editor>,
20966    ) -> Task<Result<Option<language::Transaction>>> {
20967        Task::ready(Ok(None))
20968    }
20969
20970    fn is_completion_trigger(
20971        &self,
20972        buffer: &Entity<Buffer>,
20973        position: language::Anchor,
20974        text: &str,
20975        trigger_in_words: bool,
20976        menu_is_open: bool,
20977        cx: &mut Context<Editor>,
20978    ) -> bool;
20979
20980    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20981
20982    fn sort_completions(&self) -> bool {
20983        true
20984    }
20985
20986    fn filter_completions(&self) -> bool {
20987        true
20988    }
20989}
20990
20991pub trait CodeActionProvider {
20992    fn id(&self) -> Arc<str>;
20993
20994    fn code_actions(
20995        &self,
20996        buffer: &Entity<Buffer>,
20997        range: Range<text::Anchor>,
20998        window: &mut Window,
20999        cx: &mut App,
21000    ) -> Task<Result<Vec<CodeAction>>>;
21001
21002    fn apply_code_action(
21003        &self,
21004        buffer_handle: Entity<Buffer>,
21005        action: CodeAction,
21006        excerpt_id: ExcerptId,
21007        push_to_history: bool,
21008        window: &mut Window,
21009        cx: &mut App,
21010    ) -> Task<Result<ProjectTransaction>>;
21011}
21012
21013impl CodeActionProvider for Entity<Project> {
21014    fn id(&self) -> Arc<str> {
21015        "project".into()
21016    }
21017
21018    fn code_actions(
21019        &self,
21020        buffer: &Entity<Buffer>,
21021        range: Range<text::Anchor>,
21022        _window: &mut Window,
21023        cx: &mut App,
21024    ) -> Task<Result<Vec<CodeAction>>> {
21025        self.update(cx, |project, cx| {
21026            let code_lens = project.code_lens(buffer, range.clone(), cx);
21027            let code_actions = project.code_actions(buffer, range, None, cx);
21028            cx.background_spawn(async move {
21029                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21030                Ok(code_lens
21031                    .context("code lens fetch")?
21032                    .into_iter()
21033                    .chain(code_actions.context("code action fetch")?)
21034                    .collect())
21035            })
21036        })
21037    }
21038
21039    fn apply_code_action(
21040        &self,
21041        buffer_handle: Entity<Buffer>,
21042        action: CodeAction,
21043        _excerpt_id: ExcerptId,
21044        push_to_history: bool,
21045        _window: &mut Window,
21046        cx: &mut App,
21047    ) -> Task<Result<ProjectTransaction>> {
21048        self.update(cx, |project, cx| {
21049            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21050        })
21051    }
21052}
21053
21054fn snippet_completions(
21055    project: &Project,
21056    buffer: &Entity<Buffer>,
21057    buffer_position: text::Anchor,
21058    cx: &mut App,
21059) -> Task<Result<CompletionResponse>> {
21060    let languages = buffer.read(cx).languages_at(buffer_position);
21061    let snippet_store = project.snippets().read(cx);
21062
21063    let scopes: Vec<_> = languages
21064        .iter()
21065        .filter_map(|language| {
21066            let language_name = language.lsp_id();
21067            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21068
21069            if snippets.is_empty() {
21070                None
21071            } else {
21072                Some((language.default_scope(), snippets))
21073            }
21074        })
21075        .collect();
21076
21077    if scopes.is_empty() {
21078        return Task::ready(Ok(CompletionResponse {
21079            completions: vec![],
21080            is_incomplete: false,
21081        }));
21082    }
21083
21084    let snapshot = buffer.read(cx).text_snapshot();
21085    let chars: String = snapshot
21086        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21087        .collect();
21088    let executor = cx.background_executor().clone();
21089
21090    cx.background_spawn(async move {
21091        let mut is_incomplete = false;
21092        let mut completions: Vec<Completion> = Vec::new();
21093        for (scope, snippets) in scopes.into_iter() {
21094            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21095            let mut last_word = chars
21096                .chars()
21097                .take_while(|c| classifier.is_word(*c))
21098                .collect::<String>();
21099            last_word = last_word.chars().rev().collect();
21100
21101            if last_word.is_empty() {
21102                return Ok(CompletionResponse {
21103                    completions: vec![],
21104                    is_incomplete: true,
21105                });
21106            }
21107
21108            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21109            let to_lsp = |point: &text::Anchor| {
21110                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21111                point_to_lsp(end)
21112            };
21113            let lsp_end = to_lsp(&buffer_position);
21114
21115            let candidates = snippets
21116                .iter()
21117                .enumerate()
21118                .flat_map(|(ix, snippet)| {
21119                    snippet
21120                        .prefix
21121                        .iter()
21122                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21123                })
21124                .collect::<Vec<StringMatchCandidate>>();
21125
21126            const MAX_RESULTS: usize = 100;
21127            let mut matches = fuzzy::match_strings(
21128                &candidates,
21129                &last_word,
21130                last_word.chars().any(|c| c.is_uppercase()),
21131                MAX_RESULTS,
21132                &Default::default(),
21133                executor.clone(),
21134            )
21135            .await;
21136
21137            if matches.len() >= MAX_RESULTS {
21138                is_incomplete = true;
21139            }
21140
21141            // Remove all candidates where the query's start does not match the start of any word in the candidate
21142            if let Some(query_start) = last_word.chars().next() {
21143                matches.retain(|string_match| {
21144                    split_words(&string_match.string).any(|word| {
21145                        // Check that the first codepoint of the word as lowercase matches the first
21146                        // codepoint of the query as lowercase
21147                        word.chars()
21148                            .flat_map(|codepoint| codepoint.to_lowercase())
21149                            .zip(query_start.to_lowercase())
21150                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21151                    })
21152                });
21153            }
21154
21155            let matched_strings = matches
21156                .into_iter()
21157                .map(|m| m.string)
21158                .collect::<HashSet<_>>();
21159
21160            completions.extend(snippets.iter().filter_map(|snippet| {
21161                let matching_prefix = snippet
21162                    .prefix
21163                    .iter()
21164                    .find(|prefix| matched_strings.contains(*prefix))?;
21165                let start = as_offset - last_word.len();
21166                let start = snapshot.anchor_before(start);
21167                let range = start..buffer_position;
21168                let lsp_start = to_lsp(&start);
21169                let lsp_range = lsp::Range {
21170                    start: lsp_start,
21171                    end: lsp_end,
21172                };
21173                Some(Completion {
21174                    replace_range: range,
21175                    new_text: snippet.body.clone(),
21176                    source: CompletionSource::Lsp {
21177                        insert_range: None,
21178                        server_id: LanguageServerId(usize::MAX),
21179                        resolved: true,
21180                        lsp_completion: Box::new(lsp::CompletionItem {
21181                            label: snippet.prefix.first().unwrap().clone(),
21182                            kind: Some(CompletionItemKind::SNIPPET),
21183                            label_details: snippet.description.as_ref().map(|description| {
21184                                lsp::CompletionItemLabelDetails {
21185                                    detail: Some(description.clone()),
21186                                    description: None,
21187                                }
21188                            }),
21189                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21190                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21191                                lsp::InsertReplaceEdit {
21192                                    new_text: snippet.body.clone(),
21193                                    insert: lsp_range,
21194                                    replace: lsp_range,
21195                                },
21196                            )),
21197                            filter_text: Some(snippet.body.clone()),
21198                            sort_text: Some(char::MAX.to_string()),
21199                            ..lsp::CompletionItem::default()
21200                        }),
21201                        lsp_defaults: None,
21202                    },
21203                    label: CodeLabel {
21204                        text: matching_prefix.clone(),
21205                        runs: Vec::new(),
21206                        filter_range: 0..matching_prefix.len(),
21207                    },
21208                    icon_path: None,
21209                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21210                        single_line: snippet.name.clone().into(),
21211                        plain_text: snippet
21212                            .description
21213                            .clone()
21214                            .map(|description| description.into()),
21215                    }),
21216                    insert_text_mode: None,
21217                    confirm: None,
21218                })
21219            }))
21220        }
21221
21222        Ok(CompletionResponse {
21223            completions,
21224            is_incomplete,
21225        })
21226    })
21227}
21228
21229impl CompletionProvider for Entity<Project> {
21230    fn completions(
21231        &self,
21232        _excerpt_id: ExcerptId,
21233        buffer: &Entity<Buffer>,
21234        buffer_position: text::Anchor,
21235        options: CompletionContext,
21236        _window: &mut Window,
21237        cx: &mut Context<Editor>,
21238    ) -> Task<Result<Vec<CompletionResponse>>> {
21239        self.update(cx, |project, cx| {
21240            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21241            let project_completions = project.completions(buffer, buffer_position, options, cx);
21242            cx.background_spawn(async move {
21243                let mut responses = project_completions.await?;
21244                let snippets = snippets.await?;
21245                if !snippets.completions.is_empty() {
21246                    responses.push(snippets);
21247                }
21248                Ok(responses)
21249            })
21250        })
21251    }
21252
21253    fn resolve_completions(
21254        &self,
21255        buffer: Entity<Buffer>,
21256        completion_indices: Vec<usize>,
21257        completions: Rc<RefCell<Box<[Completion]>>>,
21258        cx: &mut Context<Editor>,
21259    ) -> Task<Result<bool>> {
21260        self.update(cx, |project, cx| {
21261            project.lsp_store().update(cx, |lsp_store, cx| {
21262                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21263            })
21264        })
21265    }
21266
21267    fn apply_additional_edits_for_completion(
21268        &self,
21269        buffer: Entity<Buffer>,
21270        completions: Rc<RefCell<Box<[Completion]>>>,
21271        completion_index: usize,
21272        push_to_history: bool,
21273        cx: &mut Context<Editor>,
21274    ) -> Task<Result<Option<language::Transaction>>> {
21275        self.update(cx, |project, cx| {
21276            project.lsp_store().update(cx, |lsp_store, cx| {
21277                lsp_store.apply_additional_edits_for_completion(
21278                    buffer,
21279                    completions,
21280                    completion_index,
21281                    push_to_history,
21282                    cx,
21283                )
21284            })
21285        })
21286    }
21287
21288    fn is_completion_trigger(
21289        &self,
21290        buffer: &Entity<Buffer>,
21291        position: language::Anchor,
21292        text: &str,
21293        trigger_in_words: bool,
21294        menu_is_open: bool,
21295        cx: &mut Context<Editor>,
21296    ) -> bool {
21297        let mut chars = text.chars();
21298        let char = if let Some(char) = chars.next() {
21299            char
21300        } else {
21301            return false;
21302        };
21303        if chars.next().is_some() {
21304            return false;
21305        }
21306
21307        let buffer = buffer.read(cx);
21308        let snapshot = buffer.snapshot();
21309        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21310            return false;
21311        }
21312        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21313        if trigger_in_words && classifier.is_word(char) {
21314            return true;
21315        }
21316
21317        buffer.completion_triggers().contains(text)
21318    }
21319}
21320
21321impl SemanticsProvider for Entity<Project> {
21322    fn hover(
21323        &self,
21324        buffer: &Entity<Buffer>,
21325        position: text::Anchor,
21326        cx: &mut App,
21327    ) -> Option<Task<Vec<project::Hover>>> {
21328        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21329    }
21330
21331    fn document_highlights(
21332        &self,
21333        buffer: &Entity<Buffer>,
21334        position: text::Anchor,
21335        cx: &mut App,
21336    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21337        Some(self.update(cx, |project, cx| {
21338            project.document_highlights(buffer, position, cx)
21339        }))
21340    }
21341
21342    fn definitions(
21343        &self,
21344        buffer: &Entity<Buffer>,
21345        position: text::Anchor,
21346        kind: GotoDefinitionKind,
21347        cx: &mut App,
21348    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21349        Some(self.update(cx, |project, cx| match kind {
21350            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21351            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21352            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21353            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21354        }))
21355    }
21356
21357    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21358        // TODO: make this work for remote projects
21359        self.update(cx, |project, cx| {
21360            if project
21361                .active_debug_session(cx)
21362                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21363            {
21364                return true;
21365            }
21366
21367            buffer.update(cx, |buffer, cx| {
21368                project.any_language_server_supports_inlay_hints(buffer, cx)
21369            })
21370        })
21371    }
21372
21373    fn inline_values(
21374        &self,
21375        buffer_handle: Entity<Buffer>,
21376
21377        range: Range<text::Anchor>,
21378        cx: &mut App,
21379    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21380        self.update(cx, |project, cx| {
21381            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21382
21383            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21384        })
21385    }
21386
21387    fn inlay_hints(
21388        &self,
21389        buffer_handle: Entity<Buffer>,
21390        range: Range<text::Anchor>,
21391        cx: &mut App,
21392    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21393        Some(self.update(cx, |project, cx| {
21394            project.inlay_hints(buffer_handle, range, cx)
21395        }))
21396    }
21397
21398    fn resolve_inlay_hint(
21399        &self,
21400        hint: InlayHint,
21401        buffer_handle: Entity<Buffer>,
21402        server_id: LanguageServerId,
21403        cx: &mut App,
21404    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21405        Some(self.update(cx, |project, cx| {
21406            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21407        }))
21408    }
21409
21410    fn range_for_rename(
21411        &self,
21412        buffer: &Entity<Buffer>,
21413        position: text::Anchor,
21414        cx: &mut App,
21415    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21416        Some(self.update(cx, |project, cx| {
21417            let buffer = buffer.clone();
21418            let task = project.prepare_rename(buffer.clone(), position, cx);
21419            cx.spawn(async move |_, cx| {
21420                Ok(match task.await? {
21421                    PrepareRenameResponse::Success(range) => Some(range),
21422                    PrepareRenameResponse::InvalidPosition => None,
21423                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21424                        // Fallback on using TreeSitter info to determine identifier range
21425                        buffer.read_with(cx, |buffer, _| {
21426                            let snapshot = buffer.snapshot();
21427                            let (range, kind) = snapshot.surrounding_word(position);
21428                            if kind != Some(CharKind::Word) {
21429                                return None;
21430                            }
21431                            Some(
21432                                snapshot.anchor_before(range.start)
21433                                    ..snapshot.anchor_after(range.end),
21434                            )
21435                        })?
21436                    }
21437                })
21438            })
21439        }))
21440    }
21441
21442    fn perform_rename(
21443        &self,
21444        buffer: &Entity<Buffer>,
21445        position: text::Anchor,
21446        new_name: String,
21447        cx: &mut App,
21448    ) -> Option<Task<Result<ProjectTransaction>>> {
21449        Some(self.update(cx, |project, cx| {
21450            project.perform_rename(buffer.clone(), position, new_name, cx)
21451        }))
21452    }
21453
21454    fn pull_diagnostics_for_buffer(
21455        &self,
21456        buffer: Entity<Buffer>,
21457        cx: &mut App,
21458    ) -> Task<anyhow::Result<()>> {
21459        let diagnostics = self.update(cx, |project, cx| {
21460            project
21461                .lsp_store()
21462                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21463        });
21464        let project = self.clone();
21465        cx.spawn(async move |cx| {
21466            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21467            project.update(cx, |project, cx| {
21468                project.lsp_store().update(cx, |lsp_store, cx| {
21469                    for diagnostics_set in diagnostics {
21470                        let LspPullDiagnostics::Response {
21471                            server_id,
21472                            uri,
21473                            diagnostics,
21474                        } = diagnostics_set
21475                        else {
21476                            continue;
21477                        };
21478
21479                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21480                        let disk_based_sources = adapter
21481                            .as_ref()
21482                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21483                            .unwrap_or(&[]);
21484                        match diagnostics {
21485                            PulledDiagnostics::Unchanged { result_id } => {
21486                                lsp_store
21487                                    .merge_diagnostics(
21488                                        server_id,
21489                                        lsp::PublishDiagnosticsParams {
21490                                            uri: uri.clone(),
21491                                            diagnostics: Vec::new(),
21492                                            version: None,
21493                                        },
21494                                        Some(result_id),
21495                                        DiagnosticSourceKind::Pulled,
21496                                        disk_based_sources,
21497                                        |_, _| true,
21498                                        cx,
21499                                    )
21500                                    .log_err();
21501                            }
21502                            PulledDiagnostics::Changed {
21503                                diagnostics,
21504                                result_id,
21505                            } => {
21506                                lsp_store
21507                                    .merge_diagnostics(
21508                                        server_id,
21509                                        lsp::PublishDiagnosticsParams {
21510                                            uri: uri.clone(),
21511                                            diagnostics,
21512                                            version: None,
21513                                        },
21514                                        result_id,
21515                                        DiagnosticSourceKind::Pulled,
21516                                        disk_based_sources,
21517                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21518                                            DiagnosticSourceKind::Pulled => false,
21519                                            DiagnosticSourceKind::Other
21520                                            | DiagnosticSourceKind::Pushed => true,
21521                                        },
21522                                        cx,
21523                                    )
21524                                    .log_err();
21525                            }
21526                        }
21527                    }
21528                })
21529            })
21530        })
21531    }
21532}
21533
21534fn inlay_hint_settings(
21535    location: Anchor,
21536    snapshot: &MultiBufferSnapshot,
21537    cx: &mut Context<Editor>,
21538) -> InlayHintSettings {
21539    let file = snapshot.file_at(location);
21540    let language = snapshot.language_at(location).map(|l| l.name());
21541    language_settings(language, file, cx).inlay_hints
21542}
21543
21544fn consume_contiguous_rows(
21545    contiguous_row_selections: &mut Vec<Selection<Point>>,
21546    selection: &Selection<Point>,
21547    display_map: &DisplaySnapshot,
21548    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21549) -> (MultiBufferRow, MultiBufferRow) {
21550    contiguous_row_selections.push(selection.clone());
21551    let start_row = MultiBufferRow(selection.start.row);
21552    let mut end_row = ending_row(selection, display_map);
21553
21554    while let Some(next_selection) = selections.peek() {
21555        if next_selection.start.row <= end_row.0 {
21556            end_row = ending_row(next_selection, display_map);
21557            contiguous_row_selections.push(selections.next().unwrap().clone());
21558        } else {
21559            break;
21560        }
21561    }
21562    (start_row, end_row)
21563}
21564
21565fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21566    if next_selection.end.column > 0 || next_selection.is_empty() {
21567        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21568    } else {
21569        MultiBufferRow(next_selection.end.row)
21570    }
21571}
21572
21573impl EditorSnapshot {
21574    pub fn remote_selections_in_range<'a>(
21575        &'a self,
21576        range: &'a Range<Anchor>,
21577        collaboration_hub: &dyn CollaborationHub,
21578        cx: &'a App,
21579    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21580        let participant_names = collaboration_hub.user_names(cx);
21581        let participant_indices = collaboration_hub.user_participant_indices(cx);
21582        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21583        let collaborators_by_replica_id = collaborators_by_peer_id
21584            .values()
21585            .map(|collaborator| (collaborator.replica_id, collaborator))
21586            .collect::<HashMap<_, _>>();
21587        self.buffer_snapshot
21588            .selections_in_range(range, false)
21589            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21590                if replica_id == AGENT_REPLICA_ID {
21591                    Some(RemoteSelection {
21592                        replica_id,
21593                        selection,
21594                        cursor_shape,
21595                        line_mode,
21596                        collaborator_id: CollaboratorId::Agent,
21597                        user_name: Some("Agent".into()),
21598                        color: cx.theme().players().agent(),
21599                    })
21600                } else {
21601                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21602                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21603                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21604                    Some(RemoteSelection {
21605                        replica_id,
21606                        selection,
21607                        cursor_shape,
21608                        line_mode,
21609                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21610                        user_name,
21611                        color: if let Some(index) = participant_index {
21612                            cx.theme().players().color_for_participant(index.0)
21613                        } else {
21614                            cx.theme().players().absent()
21615                        },
21616                    })
21617                }
21618            })
21619    }
21620
21621    pub fn hunks_for_ranges(
21622        &self,
21623        ranges: impl IntoIterator<Item = Range<Point>>,
21624    ) -> Vec<MultiBufferDiffHunk> {
21625        let mut hunks = Vec::new();
21626        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21627            HashMap::default();
21628        for query_range in ranges {
21629            let query_rows =
21630                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21631            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21632                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21633            ) {
21634                // Include deleted hunks that are adjacent to the query range, because
21635                // otherwise they would be missed.
21636                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21637                if hunk.status().is_deleted() {
21638                    intersects_range |= hunk.row_range.start == query_rows.end;
21639                    intersects_range |= hunk.row_range.end == query_rows.start;
21640                }
21641                if intersects_range {
21642                    if !processed_buffer_rows
21643                        .entry(hunk.buffer_id)
21644                        .or_default()
21645                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21646                    {
21647                        continue;
21648                    }
21649                    hunks.push(hunk);
21650                }
21651            }
21652        }
21653
21654        hunks
21655    }
21656
21657    fn display_diff_hunks_for_rows<'a>(
21658        &'a self,
21659        display_rows: Range<DisplayRow>,
21660        folded_buffers: &'a HashSet<BufferId>,
21661    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21662        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21663        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21664
21665        self.buffer_snapshot
21666            .diff_hunks_in_range(buffer_start..buffer_end)
21667            .filter_map(|hunk| {
21668                if folded_buffers.contains(&hunk.buffer_id) {
21669                    return None;
21670                }
21671
21672                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21673                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21674
21675                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21676                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21677
21678                let display_hunk = if hunk_display_start.column() != 0 {
21679                    DisplayDiffHunk::Folded {
21680                        display_row: hunk_display_start.row(),
21681                    }
21682                } else {
21683                    let mut end_row = hunk_display_end.row();
21684                    if hunk_display_end.column() > 0 {
21685                        end_row.0 += 1;
21686                    }
21687                    let is_created_file = hunk.is_created_file();
21688                    DisplayDiffHunk::Unfolded {
21689                        status: hunk.status(),
21690                        diff_base_byte_range: hunk.diff_base_byte_range,
21691                        display_row_range: hunk_display_start.row()..end_row,
21692                        multi_buffer_range: Anchor::range_in_buffer(
21693                            hunk.excerpt_id,
21694                            hunk.buffer_id,
21695                            hunk.buffer_range,
21696                        ),
21697                        is_created_file,
21698                    }
21699                };
21700
21701                Some(display_hunk)
21702            })
21703    }
21704
21705    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21706        self.display_snapshot.buffer_snapshot.language_at(position)
21707    }
21708
21709    pub fn is_focused(&self) -> bool {
21710        self.is_focused
21711    }
21712
21713    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21714        self.placeholder_text.as_ref()
21715    }
21716
21717    pub fn scroll_position(&self) -> gpui::Point<f32> {
21718        self.scroll_anchor.scroll_position(&self.display_snapshot)
21719    }
21720
21721    fn gutter_dimensions(
21722        &self,
21723        font_id: FontId,
21724        font_size: Pixels,
21725        max_line_number_width: Pixels,
21726        cx: &App,
21727    ) -> Option<GutterDimensions> {
21728        if !self.show_gutter {
21729            return None;
21730        }
21731
21732        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21733        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21734
21735        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21736            matches!(
21737                ProjectSettings::get_global(cx).git.git_gutter,
21738                Some(GitGutterSetting::TrackedFiles)
21739            )
21740        });
21741        let gutter_settings = EditorSettings::get_global(cx).gutter;
21742        let show_line_numbers = self
21743            .show_line_numbers
21744            .unwrap_or(gutter_settings.line_numbers);
21745        let line_gutter_width = if show_line_numbers {
21746            // Avoid flicker-like gutter resizes when the line number gains another digit by
21747            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21748            let min_width_for_number_on_gutter =
21749                ch_advance * gutter_settings.min_line_number_digits as f32;
21750            max_line_number_width.max(min_width_for_number_on_gutter)
21751        } else {
21752            0.0.into()
21753        };
21754
21755        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21756        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21757
21758        let git_blame_entries_width =
21759            self.git_blame_gutter_max_author_length
21760                .map(|max_author_length| {
21761                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21762                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21763
21764                    /// The number of characters to dedicate to gaps and margins.
21765                    const SPACING_WIDTH: usize = 4;
21766
21767                    let max_char_count = max_author_length.min(renderer.max_author_length())
21768                        + ::git::SHORT_SHA_LENGTH
21769                        + MAX_RELATIVE_TIMESTAMP.len()
21770                        + SPACING_WIDTH;
21771
21772                    ch_advance * max_char_count
21773                });
21774
21775        let is_singleton = self.buffer_snapshot.is_singleton();
21776
21777        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21778        left_padding += if !is_singleton {
21779            ch_width * 4.0
21780        } else if show_runnables || show_breakpoints {
21781            ch_width * 3.0
21782        } else if show_git_gutter && show_line_numbers {
21783            ch_width * 2.0
21784        } else if show_git_gutter || show_line_numbers {
21785            ch_width
21786        } else {
21787            px(0.)
21788        };
21789
21790        let shows_folds = is_singleton && gutter_settings.folds;
21791
21792        let right_padding = if shows_folds && show_line_numbers {
21793            ch_width * 4.0
21794        } else if shows_folds || (!is_singleton && show_line_numbers) {
21795            ch_width * 3.0
21796        } else if show_line_numbers {
21797            ch_width
21798        } else {
21799            px(0.)
21800        };
21801
21802        Some(GutterDimensions {
21803            left_padding,
21804            right_padding,
21805            width: line_gutter_width + left_padding + right_padding,
21806            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21807            git_blame_entries_width,
21808        })
21809    }
21810
21811    pub fn render_crease_toggle(
21812        &self,
21813        buffer_row: MultiBufferRow,
21814        row_contains_cursor: bool,
21815        editor: Entity<Editor>,
21816        window: &mut Window,
21817        cx: &mut App,
21818    ) -> Option<AnyElement> {
21819        let folded = self.is_line_folded(buffer_row);
21820        let mut is_foldable = false;
21821
21822        if let Some(crease) = self
21823            .crease_snapshot
21824            .query_row(buffer_row, &self.buffer_snapshot)
21825        {
21826            is_foldable = true;
21827            match crease {
21828                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21829                    if let Some(render_toggle) = render_toggle {
21830                        let toggle_callback =
21831                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21832                                if folded {
21833                                    editor.update(cx, |editor, cx| {
21834                                        editor.fold_at(buffer_row, window, cx)
21835                                    });
21836                                } else {
21837                                    editor.update(cx, |editor, cx| {
21838                                        editor.unfold_at(buffer_row, window, cx)
21839                                    });
21840                                }
21841                            });
21842                        return Some((render_toggle)(
21843                            buffer_row,
21844                            folded,
21845                            toggle_callback,
21846                            window,
21847                            cx,
21848                        ));
21849                    }
21850                }
21851            }
21852        }
21853
21854        is_foldable |= self.starts_indent(buffer_row);
21855
21856        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21857            Some(
21858                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21859                    .toggle_state(folded)
21860                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21861                        if folded {
21862                            this.unfold_at(buffer_row, window, cx);
21863                        } else {
21864                            this.fold_at(buffer_row, window, cx);
21865                        }
21866                    }))
21867                    .into_any_element(),
21868            )
21869        } else {
21870            None
21871        }
21872    }
21873
21874    pub fn render_crease_trailer(
21875        &self,
21876        buffer_row: MultiBufferRow,
21877        window: &mut Window,
21878        cx: &mut App,
21879    ) -> Option<AnyElement> {
21880        let folded = self.is_line_folded(buffer_row);
21881        if let Crease::Inline { render_trailer, .. } = self
21882            .crease_snapshot
21883            .query_row(buffer_row, &self.buffer_snapshot)?
21884        {
21885            let render_trailer = render_trailer.as_ref()?;
21886            Some(render_trailer(buffer_row, folded, window, cx))
21887        } else {
21888            None
21889        }
21890    }
21891}
21892
21893impl Deref for EditorSnapshot {
21894    type Target = DisplaySnapshot;
21895
21896    fn deref(&self) -> &Self::Target {
21897        &self.display_snapshot
21898    }
21899}
21900
21901#[derive(Clone, Debug, PartialEq, Eq)]
21902pub enum EditorEvent {
21903    InputIgnored {
21904        text: Arc<str>,
21905    },
21906    InputHandled {
21907        utf16_range_to_replace: Option<Range<isize>>,
21908        text: Arc<str>,
21909    },
21910    ExcerptsAdded {
21911        buffer: Entity<Buffer>,
21912        predecessor: ExcerptId,
21913        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21914    },
21915    ExcerptsRemoved {
21916        ids: Vec<ExcerptId>,
21917        removed_buffer_ids: Vec<BufferId>,
21918    },
21919    BufferFoldToggled {
21920        ids: Vec<ExcerptId>,
21921        folded: bool,
21922    },
21923    ExcerptsEdited {
21924        ids: Vec<ExcerptId>,
21925    },
21926    ExcerptsExpanded {
21927        ids: Vec<ExcerptId>,
21928    },
21929    BufferEdited,
21930    Edited {
21931        transaction_id: clock::Lamport,
21932    },
21933    Reparsed(BufferId),
21934    Focused,
21935    FocusedIn,
21936    Blurred,
21937    DirtyChanged,
21938    Saved,
21939    TitleChanged,
21940    DiffBaseChanged,
21941    SelectionsChanged {
21942        local: bool,
21943    },
21944    ScrollPositionChanged {
21945        local: bool,
21946        autoscroll: bool,
21947    },
21948    Closed,
21949    TransactionUndone {
21950        transaction_id: clock::Lamport,
21951    },
21952    TransactionBegun {
21953        transaction_id: clock::Lamport,
21954    },
21955    Reloaded,
21956    CursorShapeChanged,
21957    PushedToNavHistory {
21958        anchor: Anchor,
21959        is_deactivate: bool,
21960    },
21961}
21962
21963impl EventEmitter<EditorEvent> for Editor {}
21964
21965impl Focusable for Editor {
21966    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21967        self.focus_handle.clone()
21968    }
21969}
21970
21971impl Render for Editor {
21972    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21973        let settings = ThemeSettings::get_global(cx);
21974
21975        let mut text_style = match self.mode {
21976            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21977                color: cx.theme().colors().editor_foreground,
21978                font_family: settings.ui_font.family.clone(),
21979                font_features: settings.ui_font.features.clone(),
21980                font_fallbacks: settings.ui_font.fallbacks.clone(),
21981                font_size: rems(0.875).into(),
21982                font_weight: settings.ui_font.weight,
21983                line_height: relative(settings.buffer_line_height.value()),
21984                ..Default::default()
21985            },
21986            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21987                color: cx.theme().colors().editor_foreground,
21988                font_family: settings.buffer_font.family.clone(),
21989                font_features: settings.buffer_font.features.clone(),
21990                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21991                font_size: settings.buffer_font_size(cx).into(),
21992                font_weight: settings.buffer_font.weight,
21993                line_height: relative(settings.buffer_line_height.value()),
21994                ..Default::default()
21995            },
21996        };
21997        if let Some(text_style_refinement) = &self.text_style_refinement {
21998            text_style.refine(text_style_refinement)
21999        }
22000
22001        let background = match self.mode {
22002            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22003            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22004            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22005            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22006        };
22007
22008        EditorElement::new(
22009            &cx.entity(),
22010            EditorStyle {
22011                background,
22012                local_player: cx.theme().players().local(),
22013                text: text_style,
22014                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22015                syntax: cx.theme().syntax().clone(),
22016                status: cx.theme().status().clone(),
22017                inlay_hints_style: make_inlay_hints_style(cx),
22018                inline_completion_styles: make_suggestion_styles(cx),
22019                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22020                show_underlines: !self.mode.is_minimap(),
22021            },
22022        )
22023    }
22024}
22025
22026impl EntityInputHandler for Editor {
22027    fn text_for_range(
22028        &mut self,
22029        range_utf16: Range<usize>,
22030        adjusted_range: &mut Option<Range<usize>>,
22031        _: &mut Window,
22032        cx: &mut Context<Self>,
22033    ) -> Option<String> {
22034        let snapshot = self.buffer.read(cx).read(cx);
22035        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22036        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22037        if (start.0..end.0) != range_utf16 {
22038            adjusted_range.replace(start.0..end.0);
22039        }
22040        Some(snapshot.text_for_range(start..end).collect())
22041    }
22042
22043    fn selected_text_range(
22044        &mut self,
22045        ignore_disabled_input: bool,
22046        _: &mut Window,
22047        cx: &mut Context<Self>,
22048    ) -> Option<UTF16Selection> {
22049        // Prevent the IME menu from appearing when holding down an alphabetic key
22050        // while input is disabled.
22051        if !ignore_disabled_input && !self.input_enabled {
22052            return None;
22053        }
22054
22055        let selection = self.selections.newest::<OffsetUtf16>(cx);
22056        let range = selection.range();
22057
22058        Some(UTF16Selection {
22059            range: range.start.0..range.end.0,
22060            reversed: selection.reversed,
22061        })
22062    }
22063
22064    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22065        let snapshot = self.buffer.read(cx).read(cx);
22066        let (range, _) = self.text_highlights::<InputComposition>(cx)?.first()?;
22067        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22068    }
22069
22070    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22071        self.clear_highlights::<InputComposition>(cx);
22072        self.ime_transaction.take();
22073    }
22074
22075    fn replace_text_in_range(
22076        &mut self,
22077        range_utf16: Option<Range<usize>>,
22078        text: &str,
22079        window: &mut Window,
22080        cx: &mut Context<Self>,
22081    ) {
22082        if !self.input_enabled {
22083            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22084            return;
22085        }
22086
22087        self.transact(window, cx, |this, window, cx| {
22088            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22089                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22090                Some(this.selection_replacement_ranges(range_utf16, cx))
22091            } else {
22092                this.marked_text_ranges(cx)
22093            };
22094
22095            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22096                let newest_selection_id = this.selections.newest_anchor().id;
22097                this.selections
22098                    .all::<OffsetUtf16>(cx)
22099                    .iter()
22100                    .zip(ranges_to_replace.iter())
22101                    .find_map(|(selection, range)| {
22102                        if selection.id == newest_selection_id {
22103                            Some(
22104                                (range.start.0 as isize - selection.head().0 as isize)
22105                                    ..(range.end.0 as isize - selection.head().0 as isize),
22106                            )
22107                        } else {
22108                            None
22109                        }
22110                    })
22111            });
22112
22113            cx.emit(EditorEvent::InputHandled {
22114                utf16_range_to_replace: range_to_replace,
22115                text: text.into(),
22116            });
22117
22118            if let Some(new_selected_ranges) = new_selected_ranges {
22119                this.change_selections(None, window, cx, |selections| {
22120                    selections.select_ranges(new_selected_ranges)
22121                });
22122                this.backspace(&Default::default(), window, cx);
22123            }
22124
22125            this.handle_input(text, window, cx);
22126        });
22127
22128        if let Some(transaction) = self.ime_transaction {
22129            self.buffer.update(cx, |buffer, cx| {
22130                buffer.group_until_transaction(transaction, cx);
22131            });
22132        }
22133
22134        self.unmark_text(window, cx);
22135    }
22136
22137    fn replace_and_mark_text_in_range(
22138        &mut self,
22139        range_utf16: Option<Range<usize>>,
22140        text: &str,
22141        new_selected_range_utf16: Option<Range<usize>>,
22142        window: &mut Window,
22143        cx: &mut Context<Self>,
22144    ) {
22145        if !self.input_enabled {
22146            return;
22147        }
22148
22149        let transaction = self.transact(window, cx, |this, window, cx| {
22150            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22151                let snapshot = this.buffer.read(cx).read(cx);
22152                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22153                    for marked_range in &mut marked_ranges {
22154                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22155                        marked_range.start.0 += relative_range_utf16.start;
22156                        marked_range.start =
22157                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22158                        marked_range.end =
22159                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22160                    }
22161                }
22162                Some(marked_ranges)
22163            } else if let Some(range_utf16) = range_utf16 {
22164                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22165                Some(this.selection_replacement_ranges(range_utf16, cx))
22166            } else {
22167                None
22168            };
22169
22170            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22171                let newest_selection_id = this.selections.newest_anchor().id;
22172                this.selections
22173                    .all::<OffsetUtf16>(cx)
22174                    .iter()
22175                    .zip(ranges_to_replace.iter())
22176                    .find_map(|(selection, range)| {
22177                        if selection.id == newest_selection_id {
22178                            Some(
22179                                (range.start.0 as isize - selection.head().0 as isize)
22180                                    ..(range.end.0 as isize - selection.head().0 as isize),
22181                            )
22182                        } else {
22183                            None
22184                        }
22185                    })
22186            });
22187
22188            cx.emit(EditorEvent::InputHandled {
22189                utf16_range_to_replace: range_to_replace,
22190                text: text.into(),
22191            });
22192
22193            if let Some(ranges) = ranges_to_replace {
22194                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22195            }
22196
22197            let marked_ranges = {
22198                let snapshot = this.buffer.read(cx).read(cx);
22199                this.selections
22200                    .disjoint_anchors()
22201                    .iter()
22202                    .map(|selection| {
22203                        (
22204                            selection.start.bias_left(&snapshot)
22205                                ..selection.end.bias_right(&snapshot),
22206                            HighlightStyle {
22207                                underline: Some(UnderlineStyle {
22208                                    thickness: px(1.),
22209                                    color: None,
22210                                    wavy: false,
22211                                }),
22212                                ..Default::default()
22213                            },
22214                        )
22215                    })
22216                    .collect::<Vec<_>>()
22217            };
22218
22219            if text.is_empty() {
22220                this.unmark_text(window, cx);
22221            } else {
22222                this.highlight_text::<InputComposition>(marked_ranges.clone(), cx);
22223            }
22224
22225            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22226            let use_autoclose = this.use_autoclose;
22227            let use_auto_surround = this.use_auto_surround;
22228            this.set_use_autoclose(false);
22229            this.set_use_auto_surround(false);
22230            this.handle_input(text, window, cx);
22231            this.set_use_autoclose(use_autoclose);
22232            this.set_use_auto_surround(use_auto_surround);
22233
22234            if let Some(new_selected_range) = new_selected_range_utf16 {
22235                let snapshot = this.buffer.read(cx).read(cx);
22236                let new_selected_ranges = marked_ranges
22237                    .into_iter()
22238                    .map(|(marked_range, _)| {
22239                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22240                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22241                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22242                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22243                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22244                    })
22245                    .collect::<Vec<_>>();
22246
22247                drop(snapshot);
22248                this.change_selections(None, window, cx, |selections| {
22249                    selections.select_ranges(new_selected_ranges)
22250                });
22251            }
22252        });
22253
22254        self.ime_transaction = self.ime_transaction.or(transaction);
22255        if let Some(transaction) = self.ime_transaction {
22256            self.buffer.update(cx, |buffer, cx| {
22257                buffer.group_until_transaction(transaction, cx);
22258            });
22259        }
22260
22261        if self.text_highlights::<InputComposition>(cx).is_none() {
22262            self.ime_transaction.take();
22263        }
22264    }
22265
22266    fn bounds_for_range(
22267        &mut self,
22268        range_utf16: Range<usize>,
22269        element_bounds: gpui::Bounds<Pixels>,
22270        window: &mut Window,
22271        cx: &mut Context<Self>,
22272    ) -> Option<gpui::Bounds<Pixels>> {
22273        let text_layout_details = self.text_layout_details(window);
22274        let gpui::Size {
22275            width: em_width,
22276            height: line_height,
22277        } = self.character_size(window);
22278
22279        let snapshot = self.snapshot(window, cx);
22280        let scroll_position = snapshot.scroll_position();
22281        let scroll_left = scroll_position.x * em_width;
22282
22283        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22284        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22285            + self.gutter_dimensions.width
22286            + self.gutter_dimensions.margin;
22287        let y = line_height * (start.row().as_f32() - scroll_position.y);
22288
22289        Some(Bounds {
22290            origin: element_bounds.origin + point(x, y),
22291            size: size(em_width, line_height),
22292        })
22293    }
22294
22295    fn character_index_for_point(
22296        &mut self,
22297        point: gpui::Point<Pixels>,
22298        _window: &mut Window,
22299        _cx: &mut Context<Self>,
22300    ) -> Option<usize> {
22301        let position_map = self.last_position_map.as_ref()?;
22302        if !position_map.text_hitbox.contains(&point) {
22303            return None;
22304        }
22305        let display_point = position_map.point_for_position(point).previous_valid;
22306        let anchor = position_map
22307            .snapshot
22308            .display_point_to_anchor(display_point, Bias::Left);
22309        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22310        Some(utf16_offset.0)
22311    }
22312}
22313
22314trait SelectionExt {
22315    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22316    fn spanned_rows(
22317        &self,
22318        include_end_if_at_line_start: bool,
22319        map: &DisplaySnapshot,
22320    ) -> Range<MultiBufferRow>;
22321}
22322
22323impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22324    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22325        let start = self
22326            .start
22327            .to_point(&map.buffer_snapshot)
22328            .to_display_point(map);
22329        let end = self
22330            .end
22331            .to_point(&map.buffer_snapshot)
22332            .to_display_point(map);
22333        if self.reversed {
22334            end..start
22335        } else {
22336            start..end
22337        }
22338    }
22339
22340    fn spanned_rows(
22341        &self,
22342        include_end_if_at_line_start: bool,
22343        map: &DisplaySnapshot,
22344    ) -> Range<MultiBufferRow> {
22345        let start = self.start.to_point(&map.buffer_snapshot);
22346        let mut end = self.end.to_point(&map.buffer_snapshot);
22347        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22348            end.row -= 1;
22349        }
22350
22351        let buffer_start = map.prev_line_boundary(start).0;
22352        let buffer_end = map.next_line_boundary(end).0;
22353        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22354    }
22355}
22356
22357impl<T: InvalidationRegion> InvalidationStack<T> {
22358    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22359    where
22360        S: Clone + ToOffset,
22361    {
22362        while let Some(region) = self.last() {
22363            let all_selections_inside_invalidation_ranges =
22364                if selections.len() == region.ranges().len() {
22365                    selections
22366                        .iter()
22367                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22368                        .all(|(selection, invalidation_range)| {
22369                            let head = selection.head().to_offset(buffer);
22370                            invalidation_range.start <= head && invalidation_range.end >= head
22371                        })
22372                } else {
22373                    false
22374                };
22375
22376            if all_selections_inside_invalidation_ranges {
22377                break;
22378            } else {
22379                self.pop();
22380            }
22381        }
22382    }
22383}
22384
22385impl<T> Default for InvalidationStack<T> {
22386    fn default() -> Self {
22387        Self(Default::default())
22388    }
22389}
22390
22391impl<T> Deref for InvalidationStack<T> {
22392    type Target = Vec<T>;
22393
22394    fn deref(&self) -> &Self::Target {
22395        &self.0
22396    }
22397}
22398
22399impl<T> DerefMut for InvalidationStack<T> {
22400    fn deref_mut(&mut self) -> &mut Self::Target {
22401        &mut self.0
22402    }
22403}
22404
22405impl InvalidationRegion for SnippetState {
22406    fn ranges(&self) -> &[Range<Anchor>] {
22407        &self.ranges[self.active_index]
22408    }
22409}
22410
22411fn inline_completion_edit_text(
22412    current_snapshot: &BufferSnapshot,
22413    edits: &[(Range<Anchor>, String)],
22414    edit_preview: &EditPreview,
22415    include_deletions: bool,
22416    cx: &App,
22417) -> HighlightedText {
22418    let edits = edits
22419        .iter()
22420        .map(|(anchor, text)| {
22421            (
22422                anchor.start.text_anchor..anchor.end.text_anchor,
22423                text.clone(),
22424            )
22425        })
22426        .collect::<Vec<_>>();
22427
22428    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22429}
22430
22431pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22432    match severity {
22433        lsp::DiagnosticSeverity::ERROR => colors.error,
22434        lsp::DiagnosticSeverity::WARNING => colors.warning,
22435        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22436        lsp::DiagnosticSeverity::HINT => colors.info,
22437        _ => colors.ignored,
22438    }
22439}
22440
22441pub fn styled_runs_for_code_label<'a>(
22442    label: &'a CodeLabel,
22443    syntax_theme: &'a theme::SyntaxTheme,
22444) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22445    let fade_out = HighlightStyle {
22446        fade_out: Some(0.35),
22447        ..Default::default()
22448    };
22449
22450    let mut prev_end = label.filter_range.end;
22451    label
22452        .runs
22453        .iter()
22454        .enumerate()
22455        .flat_map(move |(ix, (range, highlight_id))| {
22456            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22457                style
22458            } else {
22459                return Default::default();
22460            };
22461            let mut muted_style = style;
22462            muted_style.highlight(fade_out);
22463
22464            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22465            if range.start >= label.filter_range.end {
22466                if range.start > prev_end {
22467                    runs.push((prev_end..range.start, fade_out));
22468                }
22469                runs.push((range.clone(), muted_style));
22470            } else if range.end <= label.filter_range.end {
22471                runs.push((range.clone(), style));
22472            } else {
22473                runs.push((range.start..label.filter_range.end, style));
22474                runs.push((label.filter_range.end..range.end, muted_style));
22475            }
22476            prev_end = cmp::max(prev_end, range.end);
22477
22478            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22479                runs.push((prev_end..label.text.len(), fade_out));
22480            }
22481
22482            runs
22483        })
22484}
22485
22486pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22487    let mut prev_index = 0;
22488    let mut prev_codepoint: Option<char> = None;
22489    text.char_indices()
22490        .chain([(text.len(), '\0')])
22491        .filter_map(move |(index, codepoint)| {
22492            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22493            let is_boundary = index == text.len()
22494                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22495                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22496            if is_boundary {
22497                let chunk = &text[prev_index..index];
22498                prev_index = index;
22499                Some(chunk)
22500            } else {
22501                None
22502            }
22503        })
22504}
22505
22506pub trait RangeToAnchorExt: Sized {
22507    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22508
22509    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22510        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22511        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22512    }
22513}
22514
22515impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22516    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22517        let start_offset = self.start.to_offset(snapshot);
22518        let end_offset = self.end.to_offset(snapshot);
22519        if start_offset == end_offset {
22520            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22521        } else {
22522            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22523        }
22524    }
22525}
22526
22527pub trait RowExt {
22528    fn as_f32(&self) -> f32;
22529
22530    fn next_row(&self) -> Self;
22531
22532    fn previous_row(&self) -> Self;
22533
22534    fn minus(&self, other: Self) -> u32;
22535}
22536
22537impl RowExt for DisplayRow {
22538    fn as_f32(&self) -> f32 {
22539        self.0 as f32
22540    }
22541
22542    fn next_row(&self) -> Self {
22543        Self(self.0 + 1)
22544    }
22545
22546    fn previous_row(&self) -> Self {
22547        Self(self.0.saturating_sub(1))
22548    }
22549
22550    fn minus(&self, other: Self) -> u32 {
22551        self.0 - other.0
22552    }
22553}
22554
22555impl RowExt for MultiBufferRow {
22556    fn as_f32(&self) -> f32 {
22557        self.0 as f32
22558    }
22559
22560    fn next_row(&self) -> Self {
22561        Self(self.0 + 1)
22562    }
22563
22564    fn previous_row(&self) -> Self {
22565        Self(self.0.saturating_sub(1))
22566    }
22567
22568    fn minus(&self, other: Self) -> u32 {
22569        self.0 - other.0
22570    }
22571}
22572
22573trait RowRangeExt {
22574    type Row;
22575
22576    fn len(&self) -> usize;
22577
22578    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22579}
22580
22581impl RowRangeExt for Range<MultiBufferRow> {
22582    type Row = MultiBufferRow;
22583
22584    fn len(&self) -> usize {
22585        (self.end.0 - self.start.0) as usize
22586    }
22587
22588    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22589        (self.start.0..self.end.0).map(MultiBufferRow)
22590    }
22591}
22592
22593impl RowRangeExt for Range<DisplayRow> {
22594    type Row = DisplayRow;
22595
22596    fn len(&self) -> usize {
22597        (self.end.0 - self.start.0) as usize
22598    }
22599
22600    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22601        (self.start.0..self.end.0).map(DisplayRow)
22602    }
22603}
22604
22605/// If select range has more than one line, we
22606/// just point the cursor to range.start.
22607fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22608    if range.start.row == range.end.row {
22609        range
22610    } else {
22611        range.start..range.start
22612    }
22613}
22614pub struct KillRing(ClipboardItem);
22615impl Global for KillRing {}
22616
22617const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22618
22619enum BreakpointPromptEditAction {
22620    Log,
22621    Condition,
22622    HitCondition,
22623}
22624
22625struct BreakpointPromptEditor {
22626    pub(crate) prompt: Entity<Editor>,
22627    editor: WeakEntity<Editor>,
22628    breakpoint_anchor: Anchor,
22629    breakpoint: Breakpoint,
22630    edit_action: BreakpointPromptEditAction,
22631    block_ids: HashSet<CustomBlockId>,
22632    editor_margins: Arc<Mutex<EditorMargins>>,
22633    _subscriptions: Vec<Subscription>,
22634}
22635
22636impl BreakpointPromptEditor {
22637    const MAX_LINES: u8 = 4;
22638
22639    fn new(
22640        editor: WeakEntity<Editor>,
22641        breakpoint_anchor: Anchor,
22642        breakpoint: Breakpoint,
22643        edit_action: BreakpointPromptEditAction,
22644        window: &mut Window,
22645        cx: &mut Context<Self>,
22646    ) -> Self {
22647        let base_text = match edit_action {
22648            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22649            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22650            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22651        }
22652        .map(|msg| msg.to_string())
22653        .unwrap_or_default();
22654
22655        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22656        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22657
22658        let prompt = cx.new(|cx| {
22659            let mut prompt = Editor::new(
22660                EditorMode::AutoHeight {
22661                    min_lines: 1,
22662                    max_lines: Self::MAX_LINES as usize,
22663                },
22664                buffer,
22665                None,
22666                window,
22667                cx,
22668            );
22669            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22670            prompt.set_show_cursor_when_unfocused(false, cx);
22671            prompt.set_placeholder_text(
22672                match edit_action {
22673                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22674                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22675                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22676                },
22677                cx,
22678            );
22679
22680            prompt
22681        });
22682
22683        Self {
22684            prompt,
22685            editor,
22686            breakpoint_anchor,
22687            breakpoint,
22688            edit_action,
22689            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22690            block_ids: Default::default(),
22691            _subscriptions: vec![],
22692        }
22693    }
22694
22695    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22696        self.block_ids.extend(block_ids)
22697    }
22698
22699    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22700        if let Some(editor) = self.editor.upgrade() {
22701            let message = self
22702                .prompt
22703                .read(cx)
22704                .buffer
22705                .read(cx)
22706                .as_singleton()
22707                .expect("A multi buffer in breakpoint prompt isn't possible")
22708                .read(cx)
22709                .as_rope()
22710                .to_string();
22711
22712            editor.update(cx, |editor, cx| {
22713                editor.edit_breakpoint_at_anchor(
22714                    self.breakpoint_anchor,
22715                    self.breakpoint.clone(),
22716                    match self.edit_action {
22717                        BreakpointPromptEditAction::Log => {
22718                            BreakpointEditAction::EditLogMessage(message.into())
22719                        }
22720                        BreakpointPromptEditAction::Condition => {
22721                            BreakpointEditAction::EditCondition(message.into())
22722                        }
22723                        BreakpointPromptEditAction::HitCondition => {
22724                            BreakpointEditAction::EditHitCondition(message.into())
22725                        }
22726                    },
22727                    cx,
22728                );
22729
22730                editor.remove_blocks(self.block_ids.clone(), None, cx);
22731                cx.focus_self(window);
22732            });
22733        }
22734    }
22735
22736    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22737        self.editor
22738            .update(cx, |editor, cx| {
22739                editor.remove_blocks(self.block_ids.clone(), None, cx);
22740                window.focus(&editor.focus_handle);
22741            })
22742            .log_err();
22743    }
22744
22745    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22746        let settings = ThemeSettings::get_global(cx);
22747        let text_style = TextStyle {
22748            color: if self.prompt.read(cx).read_only(cx) {
22749                cx.theme().colors().text_disabled
22750            } else {
22751                cx.theme().colors().text
22752            },
22753            font_family: settings.buffer_font.family.clone(),
22754            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22755            font_size: settings.buffer_font_size(cx).into(),
22756            font_weight: settings.buffer_font.weight,
22757            line_height: relative(settings.buffer_line_height.value()),
22758            ..Default::default()
22759        };
22760        EditorElement::new(
22761            &self.prompt,
22762            EditorStyle {
22763                background: cx.theme().colors().editor_background,
22764                local_player: cx.theme().players().local(),
22765                text: text_style,
22766                ..Default::default()
22767            },
22768        )
22769    }
22770}
22771
22772impl Render for BreakpointPromptEditor {
22773    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22774        let editor_margins = *self.editor_margins.lock();
22775        let gutter_dimensions = editor_margins.gutter;
22776        h_flex()
22777            .key_context("Editor")
22778            .bg(cx.theme().colors().editor_background)
22779            .border_y_1()
22780            .border_color(cx.theme().status().info_border)
22781            .size_full()
22782            .py(window.line_height() / 2.5)
22783            .on_action(cx.listener(Self::confirm))
22784            .on_action(cx.listener(Self::cancel))
22785            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22786            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22787    }
22788}
22789
22790impl Focusable for BreakpointPromptEditor {
22791    fn focus_handle(&self, cx: &App) -> FocusHandle {
22792        self.prompt.focus_handle(cx)
22793    }
22794}
22795
22796fn all_edits_insertions_or_deletions(
22797    edits: &Vec<(Range<Anchor>, String)>,
22798    snapshot: &MultiBufferSnapshot,
22799) -> bool {
22800    let mut all_insertions = true;
22801    let mut all_deletions = true;
22802
22803    for (range, new_text) in edits.iter() {
22804        let range_is_empty = range.to_offset(&snapshot).is_empty();
22805        let text_is_empty = new_text.is_empty();
22806
22807        if range_is_empty != text_is_empty {
22808            if range_is_empty {
22809                all_deletions = false;
22810            } else {
22811                all_insertions = false;
22812            }
22813        } else {
22814            return false;
22815        }
22816
22817        if !all_insertions && !all_deletions {
22818            return false;
22819        }
22820    }
22821    all_insertions || all_deletions
22822}
22823
22824struct MissingEditPredictionKeybindingTooltip;
22825
22826impl Render for MissingEditPredictionKeybindingTooltip {
22827    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22828        ui::tooltip_container(window, cx, |container, _, cx| {
22829            container
22830                .flex_shrink_0()
22831                .max_w_80()
22832                .min_h(rems_from_px(124.))
22833                .justify_between()
22834                .child(
22835                    v_flex()
22836                        .flex_1()
22837                        .text_ui_sm(cx)
22838                        .child(Label::new("Conflict with Accept Keybinding"))
22839                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22840                )
22841                .child(
22842                    h_flex()
22843                        .pb_1()
22844                        .gap_1()
22845                        .items_end()
22846                        .w_full()
22847                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22848                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22849                        }))
22850                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22851                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22852                        })),
22853                )
22854        })
22855    }
22856}
22857
22858#[derive(Debug, Clone, Copy, PartialEq)]
22859pub struct LineHighlight {
22860    pub background: Background,
22861    pub border: Option<gpui::Hsla>,
22862    pub include_gutter: bool,
22863    pub type_id: Option<TypeId>,
22864}
22865
22866fn render_diff_hunk_controls(
22867    row: u32,
22868    status: &DiffHunkStatus,
22869    hunk_range: Range<Anchor>,
22870    is_created_file: bool,
22871    line_height: Pixels,
22872    editor: &Entity<Editor>,
22873    _window: &mut Window,
22874    cx: &mut App,
22875) -> AnyElement {
22876    h_flex()
22877        .h(line_height)
22878        .mr_1()
22879        .gap_1()
22880        .px_0p5()
22881        .pb_1()
22882        .border_x_1()
22883        .border_b_1()
22884        .border_color(cx.theme().colors().border_variant)
22885        .rounded_b_lg()
22886        .bg(cx.theme().colors().editor_background)
22887        .gap_1()
22888        .block_mouse_except_scroll()
22889        .shadow_md()
22890        .child(if status.has_secondary_hunk() {
22891            Button::new(("stage", row as u64), "Stage")
22892                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22893                .tooltip({
22894                    let focus_handle = editor.focus_handle(cx);
22895                    move |window, cx| {
22896                        Tooltip::for_action_in(
22897                            "Stage Hunk",
22898                            &::git::ToggleStaged,
22899                            &focus_handle,
22900                            window,
22901                            cx,
22902                        )
22903                    }
22904                })
22905                .on_click({
22906                    let editor = editor.clone();
22907                    move |_event, _window, cx| {
22908                        editor.update(cx, |editor, cx| {
22909                            editor.stage_or_unstage_diff_hunks(
22910                                true,
22911                                vec![hunk_range.start..hunk_range.start],
22912                                cx,
22913                            );
22914                        });
22915                    }
22916                })
22917        } else {
22918            Button::new(("unstage", row as u64), "Unstage")
22919                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22920                .tooltip({
22921                    let focus_handle = editor.focus_handle(cx);
22922                    move |window, cx| {
22923                        Tooltip::for_action_in(
22924                            "Unstage Hunk",
22925                            &::git::ToggleStaged,
22926                            &focus_handle,
22927                            window,
22928                            cx,
22929                        )
22930                    }
22931                })
22932                .on_click({
22933                    let editor = editor.clone();
22934                    move |_event, _window, cx| {
22935                        editor.update(cx, |editor, cx| {
22936                            editor.stage_or_unstage_diff_hunks(
22937                                false,
22938                                vec![hunk_range.start..hunk_range.start],
22939                                cx,
22940                            );
22941                        });
22942                    }
22943                })
22944        })
22945        .child(
22946            Button::new(("restore", row as u64), "Restore")
22947                .tooltip({
22948                    let focus_handle = editor.focus_handle(cx);
22949                    move |window, cx| {
22950                        Tooltip::for_action_in(
22951                            "Restore Hunk",
22952                            &::git::Restore,
22953                            &focus_handle,
22954                            window,
22955                            cx,
22956                        )
22957                    }
22958                })
22959                .on_click({
22960                    let editor = editor.clone();
22961                    move |_event, window, cx| {
22962                        editor.update(cx, |editor, cx| {
22963                            let snapshot = editor.snapshot(window, cx);
22964                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22965                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22966                        });
22967                    }
22968                })
22969                .disabled(is_created_file),
22970        )
22971        .when(
22972            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22973            |el| {
22974                el.child(
22975                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22976                        .shape(IconButtonShape::Square)
22977                        .icon_size(IconSize::Small)
22978                        // .disabled(!has_multiple_hunks)
22979                        .tooltip({
22980                            let focus_handle = editor.focus_handle(cx);
22981                            move |window, cx| {
22982                                Tooltip::for_action_in(
22983                                    "Next Hunk",
22984                                    &GoToHunk,
22985                                    &focus_handle,
22986                                    window,
22987                                    cx,
22988                                )
22989                            }
22990                        })
22991                        .on_click({
22992                            let editor = editor.clone();
22993                            move |_event, window, cx| {
22994                                editor.update(cx, |editor, cx| {
22995                                    let snapshot = editor.snapshot(window, cx);
22996                                    let position =
22997                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22998                                    editor.go_to_hunk_before_or_after_position(
22999                                        &snapshot,
23000                                        position,
23001                                        Direction::Next,
23002                                        window,
23003                                        cx,
23004                                    );
23005                                    editor.expand_selected_diff_hunks(cx);
23006                                });
23007                            }
23008                        }),
23009                )
23010                .child(
23011                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23012                        .shape(IconButtonShape::Square)
23013                        .icon_size(IconSize::Small)
23014                        // .disabled(!has_multiple_hunks)
23015                        .tooltip({
23016                            let focus_handle = editor.focus_handle(cx);
23017                            move |window, cx| {
23018                                Tooltip::for_action_in(
23019                                    "Previous Hunk",
23020                                    &GoToPreviousHunk,
23021                                    &focus_handle,
23022                                    window,
23023                                    cx,
23024                                )
23025                            }
23026                        })
23027                        .on_click({
23028                            let editor = editor.clone();
23029                            move |_event, window, cx| {
23030                                editor.update(cx, |editor, cx| {
23031                                    let snapshot = editor.snapshot(window, cx);
23032                                    let point =
23033                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23034                                    editor.go_to_hunk_before_or_after_position(
23035                                        &snapshot,
23036                                        point,
23037                                        Direction::Prev,
23038                                        window,
23039                                        cx,
23040                                    );
23041                                    editor.expand_selected_diff_hunks(cx);
23042                                });
23043                            }
23044                        }),
23045                )
23046            },
23047        )
23048        .into_any_element()
23049}