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: Vec<Location> = 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                if locations.is_empty() {
15141                    return Ok(Navigated::No);
15142                }
15143
15144                let Some(workspace) = workspace else {
15145                    return Ok(Navigated::No);
15146                };
15147
15148                let opened = workspace
15149                    .update_in(cx, |workspace, window, cx| {
15150                        Self::open_locations_in_multibuffer(
15151                            workspace,
15152                            locations,
15153                            title,
15154                            split,
15155                            MultibufferSelectionMode::First,
15156                            window,
15157                            cx,
15158                        )
15159                    })
15160                    .ok();
15161
15162                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15163            })
15164        } else {
15165            Task::ready(Ok(Navigated::No))
15166        }
15167    }
15168
15169    fn compute_target_location(
15170        &self,
15171        lsp_location: lsp::Location,
15172        server_id: LanguageServerId,
15173        window: &mut Window,
15174        cx: &mut Context<Self>,
15175    ) -> Task<anyhow::Result<Option<Location>>> {
15176        let Some(project) = self.project.clone() else {
15177            return Task::ready(Ok(None));
15178        };
15179
15180        cx.spawn_in(window, async move |editor, cx| {
15181            let location_task = editor.update(cx, |_, cx| {
15182                project.update(cx, |project, cx| {
15183                    let language_server_name = project
15184                        .language_server_statuses(cx)
15185                        .find(|(id, _)| server_id == *id)
15186                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15187                    language_server_name.map(|language_server_name| {
15188                        project.open_local_buffer_via_lsp(
15189                            lsp_location.uri.clone(),
15190                            server_id,
15191                            language_server_name,
15192                            cx,
15193                        )
15194                    })
15195                })
15196            })?;
15197            let location = match location_task {
15198                Some(task) => Some({
15199                    let target_buffer_handle = task.await.context("open local buffer")?;
15200                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15201                        let target_start = target_buffer
15202                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15203                        let target_end = target_buffer
15204                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15205                        target_buffer.anchor_after(target_start)
15206                            ..target_buffer.anchor_before(target_end)
15207                    })?;
15208                    Location {
15209                        buffer: target_buffer_handle,
15210                        range,
15211                    }
15212                }),
15213                None => None,
15214            };
15215            Ok(location)
15216        })
15217    }
15218
15219    pub fn find_all_references(
15220        &mut self,
15221        _: &FindAllReferences,
15222        window: &mut Window,
15223        cx: &mut Context<Self>,
15224    ) -> Option<Task<Result<Navigated>>> {
15225        let selection = self.selections.newest::<usize>(cx);
15226        let multi_buffer = self.buffer.read(cx);
15227        let head = selection.head();
15228
15229        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15230        let head_anchor = multi_buffer_snapshot.anchor_at(
15231            head,
15232            if head < selection.tail() {
15233                Bias::Right
15234            } else {
15235                Bias::Left
15236            },
15237        );
15238
15239        match self
15240            .find_all_references_task_sources
15241            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15242        {
15243            Ok(_) => {
15244                log::info!(
15245                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15246                );
15247                return None;
15248            }
15249            Err(i) => {
15250                self.find_all_references_task_sources.insert(i, head_anchor);
15251            }
15252        }
15253
15254        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15255        let workspace = self.workspace()?;
15256        let project = workspace.read(cx).project().clone();
15257        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15258        Some(cx.spawn_in(window, async move |editor, cx| {
15259            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15260                if let Ok(i) = editor
15261                    .find_all_references_task_sources
15262                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15263                {
15264                    editor.find_all_references_task_sources.remove(i);
15265                }
15266            });
15267
15268            let locations = references.await?;
15269            if locations.is_empty() {
15270                return anyhow::Ok(Navigated::No);
15271            }
15272
15273            workspace.update_in(cx, |workspace, window, cx| {
15274                let title = locations
15275                    .first()
15276                    .as_ref()
15277                    .map(|location| {
15278                        let buffer = location.buffer.read(cx);
15279                        format!(
15280                            "References to `{}`",
15281                            buffer
15282                                .text_for_range(location.range.clone())
15283                                .collect::<String>()
15284                        )
15285                    })
15286                    .unwrap();
15287                Self::open_locations_in_multibuffer(
15288                    workspace,
15289                    locations,
15290                    title,
15291                    false,
15292                    MultibufferSelectionMode::First,
15293                    window,
15294                    cx,
15295                );
15296                Navigated::Yes
15297            })
15298        }))
15299    }
15300
15301    /// Opens a multibuffer with the given project locations in it
15302    pub fn open_locations_in_multibuffer(
15303        workspace: &mut Workspace,
15304        mut locations: Vec<Location>,
15305        title: String,
15306        split: bool,
15307        multibuffer_selection_mode: MultibufferSelectionMode,
15308        window: &mut Window,
15309        cx: &mut Context<Workspace>,
15310    ) {
15311        if locations.is_empty() {
15312            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15313            return;
15314        }
15315
15316        // If there are multiple definitions, open them in a multibuffer
15317        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15318        let mut locations = locations.into_iter().peekable();
15319        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15320        let capability = workspace.project().read(cx).capability();
15321
15322        let excerpt_buffer = cx.new(|cx| {
15323            let mut multibuffer = MultiBuffer::new(capability);
15324            while let Some(location) = locations.next() {
15325                let buffer = location.buffer.read(cx);
15326                let mut ranges_for_buffer = Vec::new();
15327                let range = location.range.to_point(buffer);
15328                ranges_for_buffer.push(range.clone());
15329
15330                while let Some(next_location) = locations.peek() {
15331                    if next_location.buffer == location.buffer {
15332                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15333                        locations.next();
15334                    } else {
15335                        break;
15336                    }
15337                }
15338
15339                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15340                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15341                    PathKey::for_buffer(&location.buffer, cx),
15342                    location.buffer.clone(),
15343                    ranges_for_buffer,
15344                    DEFAULT_MULTIBUFFER_CONTEXT,
15345                    cx,
15346                );
15347                ranges.extend(new_ranges)
15348            }
15349
15350            multibuffer.with_title(title)
15351        });
15352
15353        let editor = cx.new(|cx| {
15354            Editor::for_multibuffer(
15355                excerpt_buffer,
15356                Some(workspace.project().clone()),
15357                window,
15358                cx,
15359            )
15360        });
15361        editor.update(cx, |editor, cx| {
15362            match multibuffer_selection_mode {
15363                MultibufferSelectionMode::First => {
15364                    if let Some(first_range) = ranges.first() {
15365                        editor.change_selections(None, window, cx, |selections| {
15366                            selections.clear_disjoint();
15367                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15368                        });
15369                    }
15370                    editor.highlight_background::<Self>(
15371                        &ranges,
15372                        |theme| theme.colors().editor_highlighted_line_background,
15373                        cx,
15374                    );
15375                }
15376                MultibufferSelectionMode::All => {
15377                    editor.change_selections(None, window, cx, |selections| {
15378                        selections.clear_disjoint();
15379                        selections.select_anchor_ranges(ranges);
15380                    });
15381                }
15382            }
15383            editor.register_buffers_with_language_servers(cx);
15384        });
15385
15386        let item = Box::new(editor);
15387        let item_id = item.item_id();
15388
15389        if split {
15390            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15391        } else {
15392            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15393                let (preview_item_id, preview_item_idx) =
15394                    workspace.active_pane().read_with(cx, |pane, _| {
15395                        (pane.preview_item_id(), pane.preview_item_idx())
15396                    });
15397
15398                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15399
15400                if let Some(preview_item_id) = preview_item_id {
15401                    workspace.active_pane().update(cx, |pane, cx| {
15402                        pane.remove_item(preview_item_id, false, false, window, cx);
15403                    });
15404                }
15405            } else {
15406                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15407            }
15408        }
15409        workspace.active_pane().update(cx, |pane, cx| {
15410            pane.set_preview_item_id(Some(item_id), cx);
15411        });
15412    }
15413
15414    pub fn rename(
15415        &mut self,
15416        _: &Rename,
15417        window: &mut Window,
15418        cx: &mut Context<Self>,
15419    ) -> Option<Task<Result<()>>> {
15420        use language::ToOffset as _;
15421
15422        let provider = self.semantics_provider.clone()?;
15423        let selection = self.selections.newest_anchor().clone();
15424        let (cursor_buffer, cursor_buffer_position) = self
15425            .buffer
15426            .read(cx)
15427            .text_anchor_for_position(selection.head(), cx)?;
15428        let (tail_buffer, cursor_buffer_position_end) = self
15429            .buffer
15430            .read(cx)
15431            .text_anchor_for_position(selection.tail(), cx)?;
15432        if tail_buffer != cursor_buffer {
15433            return None;
15434        }
15435
15436        let snapshot = cursor_buffer.read(cx).snapshot();
15437        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15438        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15439        let prepare_rename = provider
15440            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15441            .unwrap_or_else(|| Task::ready(Ok(None)));
15442        drop(snapshot);
15443
15444        Some(cx.spawn_in(window, async move |this, cx| {
15445            let rename_range = if let Some(range) = prepare_rename.await? {
15446                Some(range)
15447            } else {
15448                this.update(cx, |this, cx| {
15449                    let buffer = this.buffer.read(cx).snapshot(cx);
15450                    let mut buffer_highlights = this
15451                        .document_highlights_for_position(selection.head(), &buffer)
15452                        .filter(|highlight| {
15453                            highlight.start.excerpt_id == selection.head().excerpt_id
15454                                && highlight.end.excerpt_id == selection.head().excerpt_id
15455                        });
15456                    buffer_highlights
15457                        .next()
15458                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15459                })?
15460            };
15461            if let Some(rename_range) = rename_range {
15462                this.update_in(cx, |this, window, cx| {
15463                    let snapshot = cursor_buffer.read(cx).snapshot();
15464                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15465                    let cursor_offset_in_rename_range =
15466                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15467                    let cursor_offset_in_rename_range_end =
15468                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15469
15470                    this.take_rename(false, window, cx);
15471                    let buffer = this.buffer.read(cx).read(cx);
15472                    let cursor_offset = selection.head().to_offset(&buffer);
15473                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15474                    let rename_end = rename_start + rename_buffer_range.len();
15475                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15476                    let mut old_highlight_id = None;
15477                    let old_name: Arc<str> = buffer
15478                        .chunks(rename_start..rename_end, true)
15479                        .map(|chunk| {
15480                            if old_highlight_id.is_none() {
15481                                old_highlight_id = chunk.syntax_highlight_id;
15482                            }
15483                            chunk.text
15484                        })
15485                        .collect::<String>()
15486                        .into();
15487
15488                    drop(buffer);
15489
15490                    // Position the selection in the rename editor so that it matches the current selection.
15491                    this.show_local_selections = false;
15492                    let rename_editor = cx.new(|cx| {
15493                        let mut editor = Editor::single_line(window, cx);
15494                        editor.buffer.update(cx, |buffer, cx| {
15495                            buffer.edit([(0..0, old_name.clone())], None, cx)
15496                        });
15497                        let rename_selection_range = match cursor_offset_in_rename_range
15498                            .cmp(&cursor_offset_in_rename_range_end)
15499                        {
15500                            Ordering::Equal => {
15501                                editor.select_all(&SelectAll, window, cx);
15502                                return editor;
15503                            }
15504                            Ordering::Less => {
15505                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15506                            }
15507                            Ordering::Greater => {
15508                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15509                            }
15510                        };
15511                        if rename_selection_range.end > old_name.len() {
15512                            editor.select_all(&SelectAll, window, cx);
15513                        } else {
15514                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15515                                s.select_ranges([rename_selection_range]);
15516                            });
15517                        }
15518                        editor
15519                    });
15520                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15521                        if e == &EditorEvent::Focused {
15522                            cx.emit(EditorEvent::FocusedIn)
15523                        }
15524                    })
15525                    .detach();
15526
15527                    let write_highlights = this
15528                        .clear_background_highlights::<DocumentHighlightWrite>(cx)
15529                        .unwrap_or_default();
15530                    let read_highlights = this
15531                        .clear_background_highlights::<DocumentHighlightRead>(cx)
15532                        .unwrap_or_default();
15533                    let ranges = write_highlights
15534                        .iter()
15535                        .chain(read_highlights.iter())
15536                        .cloned()
15537                        .map(|highlight| {
15538                            (
15539                                highlight.range,
15540                                HighlightStyle {
15541                                    fade_out: Some(0.6),
15542                                    ..Default::default()
15543                                },
15544                            )
15545                        })
15546                        .collect();
15547
15548                    this.highlight_text::<Rename>(ranges, cx);
15549                    let rename_focus_handle = rename_editor.focus_handle(cx);
15550                    window.focus(&rename_focus_handle);
15551                    let block_id = this.insert_blocks(
15552                        [BlockProperties {
15553                            style: BlockStyle::Flex,
15554                            placement: BlockPlacement::Below(range.start),
15555                            height: Some(1),
15556                            render: Arc::new({
15557                                let rename_editor = rename_editor.clone();
15558                                move |cx: &mut BlockContext| {
15559                                    let mut text_style = cx.editor_style.text.clone();
15560                                    if let Some(highlight_style) = old_highlight_id
15561                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15562                                    {
15563                                        text_style = text_style.highlight(highlight_style);
15564                                    }
15565                                    div()
15566                                        .block_mouse_except_scroll()
15567                                        .pl(cx.anchor_x)
15568                                        .child(EditorElement::new(
15569                                            &rename_editor,
15570                                            EditorStyle {
15571                                                background: cx.theme().system().transparent,
15572                                                local_player: cx.editor_style.local_player,
15573                                                text: text_style,
15574                                                scrollbar_width: cx.editor_style.scrollbar_width,
15575                                                syntax: cx.editor_style.syntax.clone(),
15576                                                status: cx.editor_style.status.clone(),
15577                                                inlay_hints_style: HighlightStyle {
15578                                                    font_weight: Some(FontWeight::BOLD),
15579                                                    ..make_inlay_hints_style(cx.app)
15580                                                },
15581                                                inline_completion_styles: make_suggestion_styles(
15582                                                    cx.app,
15583                                                ),
15584                                                ..EditorStyle::default()
15585                                            },
15586                                        ))
15587                                        .into_any_element()
15588                                }
15589                            }),
15590                            priority: 0,
15591                            render_in_minimap: true,
15592                        }],
15593                        Some(Autoscroll::fit()),
15594                        cx,
15595                    )[0];
15596                    this.pending_rename = Some(RenameState {
15597                        range,
15598                        old_name,
15599                        editor: rename_editor,
15600                        block_id,
15601                    });
15602                })?;
15603            }
15604
15605            Ok(())
15606        }))
15607    }
15608
15609    pub fn confirm_rename(
15610        &mut self,
15611        _: &ConfirmRename,
15612        window: &mut Window,
15613        cx: &mut Context<Self>,
15614    ) -> Option<Task<Result<()>>> {
15615        let rename = self.take_rename(false, window, cx)?;
15616        let workspace = self.workspace()?.downgrade();
15617        let (buffer, start) = self
15618            .buffer
15619            .read(cx)
15620            .text_anchor_for_position(rename.range.start, cx)?;
15621        let (end_buffer, _) = self
15622            .buffer
15623            .read(cx)
15624            .text_anchor_for_position(rename.range.end, cx)?;
15625        if buffer != end_buffer {
15626            return None;
15627        }
15628
15629        let old_name = rename.old_name;
15630        let new_name = rename.editor.read(cx).text(cx);
15631
15632        let rename = self.semantics_provider.as_ref()?.perform_rename(
15633            &buffer,
15634            start,
15635            new_name.clone(),
15636            cx,
15637        )?;
15638
15639        Some(cx.spawn_in(window, async move |editor, cx| {
15640            let project_transaction = rename.await?;
15641            Self::open_project_transaction(
15642                &editor,
15643                workspace,
15644                project_transaction,
15645                format!("Rename: {}{}", old_name, new_name),
15646                cx,
15647            )
15648            .await?;
15649
15650            editor.update(cx, |editor, cx| {
15651                editor.refresh_document_highlights(cx);
15652            })?;
15653            Ok(())
15654        }))
15655    }
15656
15657    fn take_rename(
15658        &mut self,
15659        moving_cursor: bool,
15660        window: &mut Window,
15661        cx: &mut Context<Self>,
15662    ) -> Option<RenameState> {
15663        let rename = self.pending_rename.take()?;
15664        if rename.editor.focus_handle(cx).is_focused(window) {
15665            window.focus(&self.focus_handle);
15666        }
15667
15668        self.remove_blocks(
15669            [rename.block_id].into_iter().collect(),
15670            Some(Autoscroll::fit()),
15671            cx,
15672        );
15673        self.clear_highlights::<Rename>(cx);
15674        self.show_local_selections = true;
15675
15676        if moving_cursor {
15677            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15678                editor.selections.newest::<usize>(cx).head()
15679            });
15680
15681            // Update the selection to match the position of the selection inside
15682            // the rename editor.
15683            let snapshot = self.buffer.read(cx).read(cx);
15684            let rename_range = rename.range.to_offset(&snapshot);
15685            let cursor_in_editor = snapshot
15686                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15687                .min(rename_range.end);
15688            drop(snapshot);
15689
15690            self.change_selections(None, window, cx, |s| {
15691                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15692            });
15693        } else {
15694            self.refresh_document_highlights(cx);
15695        }
15696
15697        Some(rename)
15698    }
15699
15700    pub fn pending_rename(&self) -> Option<&RenameState> {
15701        self.pending_rename.as_ref()
15702    }
15703
15704    fn format(
15705        &mut self,
15706        _: &Format,
15707        window: &mut Window,
15708        cx: &mut Context<Self>,
15709    ) -> Option<Task<Result<()>>> {
15710        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15711
15712        let project = match &self.project {
15713            Some(project) => project.clone(),
15714            None => return None,
15715        };
15716
15717        Some(self.perform_format(
15718            project,
15719            FormatTrigger::Manual,
15720            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15721            window,
15722            cx,
15723        ))
15724    }
15725
15726    fn format_selections(
15727        &mut self,
15728        _: &FormatSelections,
15729        window: &mut Window,
15730        cx: &mut Context<Self>,
15731    ) -> Option<Task<Result<()>>> {
15732        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15733
15734        let project = match &self.project {
15735            Some(project) => project.clone(),
15736            None => return None,
15737        };
15738
15739        let ranges = self
15740            .selections
15741            .all_adjusted(cx)
15742            .into_iter()
15743            .map(|selection| selection.range())
15744            .collect_vec();
15745
15746        Some(self.perform_format(
15747            project,
15748            FormatTrigger::Manual,
15749            FormatTarget::Ranges(ranges),
15750            window,
15751            cx,
15752        ))
15753    }
15754
15755    fn perform_format(
15756        &mut self,
15757        project: Entity<Project>,
15758        trigger: FormatTrigger,
15759        target: FormatTarget,
15760        window: &mut Window,
15761        cx: &mut Context<Self>,
15762    ) -> Task<Result<()>> {
15763        let buffer = self.buffer.clone();
15764        let (buffers, target) = match target {
15765            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15766            FormatTarget::Ranges(selection_ranges) => {
15767                let multi_buffer = buffer.read(cx);
15768                let snapshot = multi_buffer.read(cx);
15769                let mut buffers = HashSet::default();
15770                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15771                    BTreeMap::new();
15772                for selection_range in selection_ranges {
15773                    for (buffer, buffer_range, _) in
15774                        snapshot.range_to_buffer_ranges(selection_range)
15775                    {
15776                        let buffer_id = buffer.remote_id();
15777                        let start = buffer.anchor_before(buffer_range.start);
15778                        let end = buffer.anchor_after(buffer_range.end);
15779                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15780                        buffer_id_to_ranges
15781                            .entry(buffer_id)
15782                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15783                            .or_insert_with(|| vec![start..end]);
15784                    }
15785                }
15786                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15787            }
15788        };
15789
15790        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15791        let selections_prev = transaction_id_prev
15792            .and_then(|transaction_id_prev| {
15793                // default to selections as they were after the last edit, if we have them,
15794                // instead of how they are now.
15795                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15796                // will take you back to where you made the last edit, instead of staying where you scrolled
15797                self.selection_history
15798                    .transaction(transaction_id_prev)
15799                    .map(|t| t.0.clone())
15800            })
15801            .unwrap_or_else(|| {
15802                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15803                self.selections.disjoint_anchors()
15804            });
15805
15806        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15807        let format = project.update(cx, |project, cx| {
15808            project.format(buffers, target, true, trigger, cx)
15809        });
15810
15811        cx.spawn_in(window, async move |editor, cx| {
15812            let transaction = futures::select_biased! {
15813                transaction = format.log_err().fuse() => transaction,
15814                () = timeout => {
15815                    log::warn!("timed out waiting for formatting");
15816                    None
15817                }
15818            };
15819
15820            buffer
15821                .update(cx, |buffer, cx| {
15822                    if let Some(transaction) = transaction {
15823                        if !buffer.is_singleton() {
15824                            buffer.push_transaction(&transaction.0, cx);
15825                        }
15826                    }
15827                    cx.notify();
15828                })
15829                .ok();
15830
15831            if let Some(transaction_id_now) =
15832                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15833            {
15834                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15835                if has_new_transaction {
15836                    _ = editor.update(cx, |editor, _| {
15837                        editor
15838                            .selection_history
15839                            .insert_transaction(transaction_id_now, selections_prev);
15840                    });
15841                }
15842            }
15843
15844            Ok(())
15845        })
15846    }
15847
15848    fn organize_imports(
15849        &mut self,
15850        _: &OrganizeImports,
15851        window: &mut Window,
15852        cx: &mut Context<Self>,
15853    ) -> Option<Task<Result<()>>> {
15854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15855        let project = match &self.project {
15856            Some(project) => project.clone(),
15857            None => return None,
15858        };
15859        Some(self.perform_code_action_kind(
15860            project,
15861            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15862            window,
15863            cx,
15864        ))
15865    }
15866
15867    fn perform_code_action_kind(
15868        &mut self,
15869        project: Entity<Project>,
15870        kind: CodeActionKind,
15871        window: &mut Window,
15872        cx: &mut Context<Self>,
15873    ) -> Task<Result<()>> {
15874        let buffer = self.buffer.clone();
15875        let buffers = buffer.read(cx).all_buffers();
15876        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15877        let apply_action = project.update(cx, |project, cx| {
15878            project.apply_code_action_kind(buffers, kind, true, cx)
15879        });
15880        cx.spawn_in(window, async move |_, cx| {
15881            let transaction = futures::select_biased! {
15882                () = timeout => {
15883                    log::warn!("timed out waiting for executing code action");
15884                    None
15885                }
15886                transaction = apply_action.log_err().fuse() => transaction,
15887            };
15888            buffer
15889                .update(cx, |buffer, cx| {
15890                    // check if we need this
15891                    if let Some(transaction) = transaction {
15892                        if !buffer.is_singleton() {
15893                            buffer.push_transaction(&transaction.0, cx);
15894                        }
15895                    }
15896                    cx.notify();
15897                })
15898                .ok();
15899            Ok(())
15900        })
15901    }
15902
15903    fn restart_language_server(
15904        &mut self,
15905        _: &RestartLanguageServer,
15906        _: &mut Window,
15907        cx: &mut Context<Self>,
15908    ) {
15909        if let Some(project) = self.project.clone() {
15910            self.buffer.update(cx, |multi_buffer, cx| {
15911                project.update(cx, |project, cx| {
15912                    project.restart_language_servers_for_buffers(
15913                        multi_buffer.all_buffers().into_iter().collect(),
15914                        cx,
15915                    );
15916                });
15917            })
15918        }
15919    }
15920
15921    fn stop_language_server(
15922        &mut self,
15923        _: &StopLanguageServer,
15924        _: &mut Window,
15925        cx: &mut Context<Self>,
15926    ) {
15927        if let Some(project) = self.project.clone() {
15928            self.buffer.update(cx, |multi_buffer, cx| {
15929                project.update(cx, |project, cx| {
15930                    project.stop_language_servers_for_buffers(
15931                        multi_buffer.all_buffers().into_iter().collect(),
15932                        cx,
15933                    );
15934                    cx.emit(project::Event::RefreshInlayHints);
15935                });
15936            });
15937        }
15938    }
15939
15940    fn cancel_language_server_work(
15941        workspace: &mut Workspace,
15942        _: &actions::CancelLanguageServerWork,
15943        _: &mut Window,
15944        cx: &mut Context<Workspace>,
15945    ) {
15946        let project = workspace.project();
15947        let buffers = workspace
15948            .active_item(cx)
15949            .and_then(|item| item.act_as::<Editor>(cx))
15950            .map_or(HashSet::default(), |editor| {
15951                editor.read(cx).buffer.read(cx).all_buffers()
15952            });
15953        project.update(cx, |project, cx| {
15954            project.cancel_language_server_work_for_buffers(buffers, cx);
15955        });
15956    }
15957
15958    fn show_character_palette(
15959        &mut self,
15960        _: &ShowCharacterPalette,
15961        window: &mut Window,
15962        _: &mut Context<Self>,
15963    ) {
15964        window.show_character_palette();
15965    }
15966
15967    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15968        if self.mode.is_minimap() {
15969            return;
15970        }
15971
15972        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15973            let buffer = self.buffer.read(cx).snapshot(cx);
15974            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15975            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15976            let is_valid = buffer
15977                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15978                .any(|entry| {
15979                    entry.diagnostic.is_primary
15980                        && !entry.range.is_empty()
15981                        && entry.range.start == primary_range_start
15982                        && entry.diagnostic.message == active_diagnostics.active_message
15983                });
15984
15985            if !is_valid {
15986                self.dismiss_diagnostics(cx);
15987            }
15988        }
15989    }
15990
15991    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15992        match &self.active_diagnostics {
15993            ActiveDiagnostic::Group(group) => Some(group),
15994            _ => None,
15995        }
15996    }
15997
15998    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15999        self.dismiss_diagnostics(cx);
16000        self.active_diagnostics = ActiveDiagnostic::All;
16001    }
16002
16003    fn activate_diagnostics(
16004        &mut self,
16005        buffer_id: BufferId,
16006        diagnostic: DiagnosticEntry<usize>,
16007        window: &mut Window,
16008        cx: &mut Context<Self>,
16009    ) {
16010        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16011            return;
16012        }
16013        self.dismiss_diagnostics(cx);
16014        let snapshot = self.snapshot(window, cx);
16015        let buffer = self.buffer.read(cx).snapshot(cx);
16016        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16017            return;
16018        };
16019
16020        let diagnostic_group = buffer
16021            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16022            .collect::<Vec<_>>();
16023
16024        let blocks =
16025            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16026
16027        let blocks = self.display_map.update(cx, |display_map, cx| {
16028            display_map.insert_blocks(blocks, cx).into_iter().collect()
16029        });
16030        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16031            active_range: buffer.anchor_before(diagnostic.range.start)
16032                ..buffer.anchor_after(diagnostic.range.end),
16033            active_message: diagnostic.diagnostic.message.clone(),
16034            group_id: diagnostic.diagnostic.group_id,
16035            blocks,
16036        });
16037        cx.notify();
16038    }
16039
16040    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16041        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16042            return;
16043        };
16044
16045        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16046        if let ActiveDiagnostic::Group(group) = prev {
16047            self.display_map.update(cx, |display_map, cx| {
16048                display_map.remove_blocks(group.blocks, cx);
16049            });
16050            cx.notify();
16051        }
16052    }
16053
16054    /// Disable inline diagnostics rendering for this editor.
16055    pub fn disable_inline_diagnostics(&mut self) {
16056        self.inline_diagnostics_enabled = false;
16057        self.inline_diagnostics_update = Task::ready(());
16058        self.inline_diagnostics.clear();
16059    }
16060
16061    pub fn diagnostics_enabled(&self) -> bool {
16062        self.mode.is_full()
16063    }
16064
16065    pub fn inline_diagnostics_enabled(&self) -> bool {
16066        self.diagnostics_enabled() && self.inline_diagnostics_enabled
16067    }
16068
16069    pub fn show_inline_diagnostics(&self) -> bool {
16070        self.show_inline_diagnostics
16071    }
16072
16073    pub fn toggle_inline_diagnostics(
16074        &mut self,
16075        _: &ToggleInlineDiagnostics,
16076        window: &mut Window,
16077        cx: &mut Context<Editor>,
16078    ) {
16079        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16080        self.refresh_inline_diagnostics(false, window, cx);
16081    }
16082
16083    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16084        self.diagnostics_max_severity = severity;
16085        self.display_map.update(cx, |display_map, _| {
16086            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16087        });
16088    }
16089
16090    pub fn toggle_diagnostics(
16091        &mut self,
16092        _: &ToggleDiagnostics,
16093        window: &mut Window,
16094        cx: &mut Context<Editor>,
16095    ) {
16096        if !self.diagnostics_enabled() {
16097            return;
16098        }
16099
16100        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16101            EditorSettings::get_global(cx)
16102                .diagnostics_max_severity
16103                .filter(|severity| severity != &DiagnosticSeverity::Off)
16104                .unwrap_or(DiagnosticSeverity::Hint)
16105        } else {
16106            DiagnosticSeverity::Off
16107        };
16108        self.set_max_diagnostics_severity(new_severity, cx);
16109        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16110            self.active_diagnostics = ActiveDiagnostic::None;
16111            self.inline_diagnostics_update = Task::ready(());
16112            self.inline_diagnostics.clear();
16113        } else {
16114            self.refresh_inline_diagnostics(false, window, cx);
16115        }
16116
16117        cx.notify();
16118    }
16119
16120    pub fn toggle_minimap(
16121        &mut self,
16122        _: &ToggleMinimap,
16123        window: &mut Window,
16124        cx: &mut Context<Editor>,
16125    ) {
16126        if self.supports_minimap(cx) {
16127            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16128        }
16129    }
16130
16131    fn refresh_inline_diagnostics(
16132        &mut self,
16133        debounce: bool,
16134        window: &mut Window,
16135        cx: &mut Context<Self>,
16136    ) {
16137        let max_severity = ProjectSettings::get_global(cx)
16138            .diagnostics
16139            .inline
16140            .max_severity
16141            .unwrap_or(self.diagnostics_max_severity);
16142
16143        if !self.inline_diagnostics_enabled()
16144            || !self.show_inline_diagnostics
16145            || max_severity == DiagnosticSeverity::Off
16146        {
16147            self.inline_diagnostics_update = Task::ready(());
16148            self.inline_diagnostics.clear();
16149            return;
16150        }
16151
16152        let debounce_ms = ProjectSettings::get_global(cx)
16153            .diagnostics
16154            .inline
16155            .update_debounce_ms;
16156        let debounce = if debounce && debounce_ms > 0 {
16157            Some(Duration::from_millis(debounce_ms))
16158        } else {
16159            None
16160        };
16161        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16162            if let Some(debounce) = debounce {
16163                cx.background_executor().timer(debounce).await;
16164            }
16165            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16166                editor
16167                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16168                    .ok()
16169            }) else {
16170                return;
16171            };
16172
16173            let new_inline_diagnostics = cx
16174                .background_spawn(async move {
16175                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16176                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16177                        let message = diagnostic_entry
16178                            .diagnostic
16179                            .message
16180                            .split_once('\n')
16181                            .map(|(line, _)| line)
16182                            .map(SharedString::new)
16183                            .unwrap_or_else(|| {
16184                                SharedString::from(diagnostic_entry.diagnostic.message)
16185                            });
16186                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16187                        let (Ok(i) | Err(i)) = inline_diagnostics
16188                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16189                        inline_diagnostics.insert(
16190                            i,
16191                            (
16192                                start_anchor,
16193                                InlineDiagnostic {
16194                                    message,
16195                                    group_id: diagnostic_entry.diagnostic.group_id,
16196                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16197                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16198                                    severity: diagnostic_entry.diagnostic.severity,
16199                                },
16200                            ),
16201                        );
16202                    }
16203                    inline_diagnostics
16204                })
16205                .await;
16206
16207            editor
16208                .update(cx, |editor, cx| {
16209                    editor.inline_diagnostics = new_inline_diagnostics;
16210                    cx.notify();
16211                })
16212                .ok();
16213        });
16214    }
16215
16216    fn pull_diagnostics(
16217        &mut self,
16218        buffer_id: Option<BufferId>,
16219        window: &Window,
16220        cx: &mut Context<Self>,
16221    ) -> Option<()> {
16222        if !self.mode().is_full() {
16223            return None;
16224        }
16225        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16226            .diagnostics
16227            .lsp_pull_diagnostics;
16228        if !pull_diagnostics_settings.enabled {
16229            return None;
16230        }
16231        let project = self.project.as_ref()?.downgrade();
16232        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16233        let mut buffers = self.buffer.read(cx).all_buffers();
16234        if let Some(buffer_id) = buffer_id {
16235            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16236        }
16237
16238        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16239            cx.background_executor().timer(debounce).await;
16240
16241            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16242                buffers
16243                    .into_iter()
16244                    .flat_map(|buffer| {
16245                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16246                    })
16247                    .collect::<FuturesUnordered<_>>()
16248            }) else {
16249                return;
16250            };
16251
16252            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16253                match pull_task {
16254                    Ok(()) => {
16255                        if editor
16256                            .update_in(cx, |editor, window, cx| {
16257                                editor.update_diagnostics_state(window, cx);
16258                            })
16259                            .is_err()
16260                        {
16261                            return;
16262                        }
16263                    }
16264                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16265                }
16266            }
16267        });
16268
16269        Some(())
16270    }
16271
16272    pub fn set_selections_from_remote(
16273        &mut self,
16274        selections: Vec<Selection<Anchor>>,
16275        pending_selection: Option<Selection<Anchor>>,
16276        window: &mut Window,
16277        cx: &mut Context<Self>,
16278    ) {
16279        let old_cursor_position = self.selections.newest_anchor().head();
16280        self.selections.change_with(cx, |s| {
16281            s.select_anchors(selections);
16282            if let Some(pending_selection) = pending_selection {
16283                s.set_pending(pending_selection, SelectMode::Character);
16284            } else {
16285                s.clear_pending();
16286            }
16287        });
16288        self.selections_did_change(
16289            false,
16290            &old_cursor_position,
16291            SelectionEffects::default(),
16292            window,
16293            cx,
16294        );
16295    }
16296
16297    pub fn transact(
16298        &mut self,
16299        window: &mut Window,
16300        cx: &mut Context<Self>,
16301        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16302    ) -> Option<TransactionId> {
16303        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16304            this.start_transaction_at(Instant::now(), window, cx);
16305            update(this, window, cx);
16306            this.end_transaction_at(Instant::now(), cx)
16307        })
16308    }
16309
16310    pub fn start_transaction_at(
16311        &mut self,
16312        now: Instant,
16313        window: &mut Window,
16314        cx: &mut Context<Self>,
16315    ) {
16316        self.end_selection(window, cx);
16317        if let Some(tx_id) = self
16318            .buffer
16319            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16320        {
16321            self.selection_history
16322                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16323            cx.emit(EditorEvent::TransactionBegun {
16324                transaction_id: tx_id,
16325            })
16326        }
16327    }
16328
16329    pub fn end_transaction_at(
16330        &mut self,
16331        now: Instant,
16332        cx: &mut Context<Self>,
16333    ) -> Option<TransactionId> {
16334        if let Some(transaction_id) = self
16335            .buffer
16336            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16337        {
16338            if let Some((_, end_selections)) =
16339                self.selection_history.transaction_mut(transaction_id)
16340            {
16341                *end_selections = Some(self.selections.disjoint_anchors());
16342            } else {
16343                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16344            }
16345
16346            cx.emit(EditorEvent::Edited { transaction_id });
16347            Some(transaction_id)
16348        } else {
16349            None
16350        }
16351    }
16352
16353    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16354        if self.selection_mark_mode {
16355            self.change_selections(None, window, cx, |s| {
16356                s.move_with(|_, sel| {
16357                    sel.collapse_to(sel.head(), SelectionGoal::None);
16358                });
16359            })
16360        }
16361        self.selection_mark_mode = true;
16362        cx.notify();
16363    }
16364
16365    pub fn swap_selection_ends(
16366        &mut self,
16367        _: &actions::SwapSelectionEnds,
16368        window: &mut Window,
16369        cx: &mut Context<Self>,
16370    ) {
16371        self.change_selections(None, window, cx, |s| {
16372            s.move_with(|_, sel| {
16373                if sel.start != sel.end {
16374                    sel.reversed = !sel.reversed
16375                }
16376            });
16377        });
16378        self.request_autoscroll(Autoscroll::newest(), cx);
16379        cx.notify();
16380    }
16381
16382    pub fn toggle_fold(
16383        &mut self,
16384        _: &actions::ToggleFold,
16385        window: &mut Window,
16386        cx: &mut Context<Self>,
16387    ) {
16388        if self.is_singleton(cx) {
16389            let selection = self.selections.newest::<Point>(cx);
16390
16391            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16392            let range = if selection.is_empty() {
16393                let point = selection.head().to_display_point(&display_map);
16394                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16395                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16396                    .to_point(&display_map);
16397                start..end
16398            } else {
16399                selection.range()
16400            };
16401            if display_map.folds_in_range(range).next().is_some() {
16402                self.unfold_lines(&Default::default(), window, cx)
16403            } else {
16404                self.fold(&Default::default(), window, cx)
16405            }
16406        } else {
16407            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16408            let buffer_ids: HashSet<_> = self
16409                .selections
16410                .disjoint_anchor_ranges()
16411                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16412                .collect();
16413
16414            let should_unfold = buffer_ids
16415                .iter()
16416                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16417
16418            for buffer_id in buffer_ids {
16419                if should_unfold {
16420                    self.unfold_buffer(buffer_id, cx);
16421                } else {
16422                    self.fold_buffer(buffer_id, cx);
16423                }
16424            }
16425        }
16426    }
16427
16428    pub fn toggle_fold_recursive(
16429        &mut self,
16430        _: &actions::ToggleFoldRecursive,
16431        window: &mut Window,
16432        cx: &mut Context<Self>,
16433    ) {
16434        let selection = self.selections.newest::<Point>(cx);
16435
16436        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16437        let range = if selection.is_empty() {
16438            let point = selection.head().to_display_point(&display_map);
16439            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16440            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16441                .to_point(&display_map);
16442            start..end
16443        } else {
16444            selection.range()
16445        };
16446        if display_map.folds_in_range(range).next().is_some() {
16447            self.unfold_recursive(&Default::default(), window, cx)
16448        } else {
16449            self.fold_recursive(&Default::default(), window, cx)
16450        }
16451    }
16452
16453    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16454        if self.is_singleton(cx) {
16455            let mut to_fold = Vec::new();
16456            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16457            let selections = self.selections.all_adjusted(cx);
16458
16459            for selection in selections {
16460                let range = selection.range().sorted();
16461                let buffer_start_row = range.start.row;
16462
16463                if range.start.row != range.end.row {
16464                    let mut found = false;
16465                    let mut row = range.start.row;
16466                    while row <= range.end.row {
16467                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16468                        {
16469                            found = true;
16470                            row = crease.range().end.row + 1;
16471                            to_fold.push(crease);
16472                        } else {
16473                            row += 1
16474                        }
16475                    }
16476                    if found {
16477                        continue;
16478                    }
16479                }
16480
16481                for row in (0..=range.start.row).rev() {
16482                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16483                        if crease.range().end.row >= buffer_start_row {
16484                            to_fold.push(crease);
16485                            if row <= range.start.row {
16486                                break;
16487                            }
16488                        }
16489                    }
16490                }
16491            }
16492
16493            self.fold_creases(to_fold, true, window, cx);
16494        } else {
16495            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16496            let buffer_ids = self
16497                .selections
16498                .disjoint_anchor_ranges()
16499                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16500                .collect::<HashSet<_>>();
16501            for buffer_id in buffer_ids {
16502                self.fold_buffer(buffer_id, cx);
16503            }
16504        }
16505    }
16506
16507    fn fold_at_level(
16508        &mut self,
16509        fold_at: &FoldAtLevel,
16510        window: &mut Window,
16511        cx: &mut Context<Self>,
16512    ) {
16513        if !self.buffer.read(cx).is_singleton() {
16514            return;
16515        }
16516
16517        let fold_at_level = fold_at.0;
16518        let snapshot = self.buffer.read(cx).snapshot(cx);
16519        let mut to_fold = Vec::new();
16520        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16521
16522        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16523            while start_row < end_row {
16524                match self
16525                    .snapshot(window, cx)
16526                    .crease_for_buffer_row(MultiBufferRow(start_row))
16527                {
16528                    Some(crease) => {
16529                        let nested_start_row = crease.range().start.row + 1;
16530                        let nested_end_row = crease.range().end.row;
16531
16532                        if current_level < fold_at_level {
16533                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16534                        } else if current_level == fold_at_level {
16535                            to_fold.push(crease);
16536                        }
16537
16538                        start_row = nested_end_row + 1;
16539                    }
16540                    None => start_row += 1,
16541                }
16542            }
16543        }
16544
16545        self.fold_creases(to_fold, true, window, cx);
16546    }
16547
16548    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16549        if self.buffer.read(cx).is_singleton() {
16550            let mut fold_ranges = Vec::new();
16551            let snapshot = self.buffer.read(cx).snapshot(cx);
16552
16553            for row in 0..snapshot.max_row().0 {
16554                if let Some(foldable_range) = self
16555                    .snapshot(window, cx)
16556                    .crease_for_buffer_row(MultiBufferRow(row))
16557                {
16558                    fold_ranges.push(foldable_range);
16559                }
16560            }
16561
16562            self.fold_creases(fold_ranges, true, window, cx);
16563        } else {
16564            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16565                editor
16566                    .update_in(cx, |editor, _, cx| {
16567                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16568                            editor.fold_buffer(buffer_id, cx);
16569                        }
16570                    })
16571                    .ok();
16572            });
16573        }
16574    }
16575
16576    pub fn fold_function_bodies(
16577        &mut self,
16578        _: &actions::FoldFunctionBodies,
16579        window: &mut Window,
16580        cx: &mut Context<Self>,
16581    ) {
16582        let snapshot = self.buffer.read(cx).snapshot(cx);
16583
16584        let ranges = snapshot
16585            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16586            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16587            .collect::<Vec<_>>();
16588
16589        let creases = ranges
16590            .into_iter()
16591            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16592            .collect();
16593
16594        self.fold_creases(creases, true, window, cx);
16595    }
16596
16597    pub fn fold_recursive(
16598        &mut self,
16599        _: &actions::FoldRecursive,
16600        window: &mut Window,
16601        cx: &mut Context<Self>,
16602    ) {
16603        let mut to_fold = Vec::new();
16604        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16605        let selections = self.selections.all_adjusted(cx);
16606
16607        for selection in selections {
16608            let range = selection.range().sorted();
16609            let buffer_start_row = range.start.row;
16610
16611            if range.start.row != range.end.row {
16612                let mut found = false;
16613                for row in range.start.row..=range.end.row {
16614                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16615                        found = true;
16616                        to_fold.push(crease);
16617                    }
16618                }
16619                if found {
16620                    continue;
16621                }
16622            }
16623
16624            for row in (0..=range.start.row).rev() {
16625                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16626                    if crease.range().end.row >= buffer_start_row {
16627                        to_fold.push(crease);
16628                    } else {
16629                        break;
16630                    }
16631                }
16632            }
16633        }
16634
16635        self.fold_creases(to_fold, true, window, cx);
16636    }
16637
16638    pub fn fold_at(
16639        &mut self,
16640        buffer_row: MultiBufferRow,
16641        window: &mut Window,
16642        cx: &mut Context<Self>,
16643    ) {
16644        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16645
16646        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16647            let autoscroll = self
16648                .selections
16649                .all::<Point>(cx)
16650                .iter()
16651                .any(|selection| crease.range().overlaps(&selection.range()));
16652
16653            self.fold_creases(vec![crease], autoscroll, window, cx);
16654        }
16655    }
16656
16657    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16658        if self.is_singleton(cx) {
16659            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16660            let buffer = &display_map.buffer_snapshot;
16661            let selections = self.selections.all::<Point>(cx);
16662            let ranges = selections
16663                .iter()
16664                .map(|s| {
16665                    let range = s.display_range(&display_map).sorted();
16666                    let mut start = range.start.to_point(&display_map);
16667                    let mut end = range.end.to_point(&display_map);
16668                    start.column = 0;
16669                    end.column = buffer.line_len(MultiBufferRow(end.row));
16670                    start..end
16671                })
16672                .collect::<Vec<_>>();
16673
16674            self.unfold_ranges(&ranges, true, true, cx);
16675        } else {
16676            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16677            let buffer_ids = self
16678                .selections
16679                .disjoint_anchor_ranges()
16680                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16681                .collect::<HashSet<_>>();
16682            for buffer_id in buffer_ids {
16683                self.unfold_buffer(buffer_id, cx);
16684            }
16685        }
16686    }
16687
16688    pub fn unfold_recursive(
16689        &mut self,
16690        _: &UnfoldRecursive,
16691        _window: &mut Window,
16692        cx: &mut Context<Self>,
16693    ) {
16694        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16695        let selections = self.selections.all::<Point>(cx);
16696        let ranges = selections
16697            .iter()
16698            .map(|s| {
16699                let mut range = s.display_range(&display_map).sorted();
16700                *range.start.column_mut() = 0;
16701                *range.end.column_mut() = display_map.line_len(range.end.row());
16702                let start = range.start.to_point(&display_map);
16703                let end = range.end.to_point(&display_map);
16704                start..end
16705            })
16706            .collect::<Vec<_>>();
16707
16708        self.unfold_ranges(&ranges, true, true, cx);
16709    }
16710
16711    pub fn unfold_at(
16712        &mut self,
16713        buffer_row: MultiBufferRow,
16714        _window: &mut Window,
16715        cx: &mut Context<Self>,
16716    ) {
16717        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16718
16719        let intersection_range = Point::new(buffer_row.0, 0)
16720            ..Point::new(
16721                buffer_row.0,
16722                display_map.buffer_snapshot.line_len(buffer_row),
16723            );
16724
16725        let autoscroll = self
16726            .selections
16727            .all::<Point>(cx)
16728            .iter()
16729            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16730
16731        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16732    }
16733
16734    pub fn unfold_all(
16735        &mut self,
16736        _: &actions::UnfoldAll,
16737        _window: &mut Window,
16738        cx: &mut Context<Self>,
16739    ) {
16740        if self.buffer.read(cx).is_singleton() {
16741            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16742            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16743        } else {
16744            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16745                editor
16746                    .update(cx, |editor, cx| {
16747                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16748                            editor.unfold_buffer(buffer_id, cx);
16749                        }
16750                    })
16751                    .ok();
16752            });
16753        }
16754    }
16755
16756    pub fn fold_selected_ranges(
16757        &mut self,
16758        _: &FoldSelectedRanges,
16759        window: &mut Window,
16760        cx: &mut Context<Self>,
16761    ) {
16762        let selections = self.selections.all_adjusted(cx);
16763        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16764        let ranges = selections
16765            .into_iter()
16766            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16767            .collect::<Vec<_>>();
16768        self.fold_creases(ranges, true, window, cx);
16769    }
16770
16771    pub fn fold_ranges<T: ToOffset + Clone>(
16772        &mut self,
16773        ranges: Vec<Range<T>>,
16774        auto_scroll: bool,
16775        window: &mut Window,
16776        cx: &mut Context<Self>,
16777    ) {
16778        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16779        let ranges = ranges
16780            .into_iter()
16781            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16782            .collect::<Vec<_>>();
16783        self.fold_creases(ranges, auto_scroll, window, cx);
16784    }
16785
16786    pub fn fold_creases<T: ToOffset + Clone>(
16787        &mut self,
16788        creases: Vec<Crease<T>>,
16789        auto_scroll: bool,
16790        _window: &mut Window,
16791        cx: &mut Context<Self>,
16792    ) {
16793        if creases.is_empty() {
16794            return;
16795        }
16796
16797        let mut buffers_affected = HashSet::default();
16798        let multi_buffer = self.buffer().read(cx);
16799        for crease in &creases {
16800            if let Some((_, buffer, _)) =
16801                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16802            {
16803                buffers_affected.insert(buffer.read(cx).remote_id());
16804            };
16805        }
16806
16807        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16808
16809        if auto_scroll {
16810            self.request_autoscroll(Autoscroll::fit(), cx);
16811        }
16812
16813        cx.notify();
16814
16815        self.scrollbar_marker_state.dirty = true;
16816        self.folds_did_change(cx);
16817    }
16818
16819    /// Removes any folds whose ranges intersect any of the given ranges.
16820    pub fn unfold_ranges<T: ToOffset + Clone>(
16821        &mut self,
16822        ranges: &[Range<T>],
16823        inclusive: bool,
16824        auto_scroll: bool,
16825        cx: &mut Context<Self>,
16826    ) {
16827        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16828            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16829        });
16830        self.folds_did_change(cx);
16831    }
16832
16833    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16834        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16835            return;
16836        }
16837        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16838        self.display_map.update(cx, |display_map, cx| {
16839            display_map.fold_buffers([buffer_id], cx)
16840        });
16841        cx.emit(EditorEvent::BufferFoldToggled {
16842            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16843            folded: true,
16844        });
16845        cx.notify();
16846    }
16847
16848    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16849        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16850            return;
16851        }
16852        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16853        self.display_map.update(cx, |display_map, cx| {
16854            display_map.unfold_buffers([buffer_id], cx);
16855        });
16856        cx.emit(EditorEvent::BufferFoldToggled {
16857            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16858            folded: false,
16859        });
16860        cx.notify();
16861    }
16862
16863    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16864        self.display_map.read(cx).is_buffer_folded(buffer)
16865    }
16866
16867    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16868        self.display_map.read(cx).folded_buffers()
16869    }
16870
16871    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16872        self.display_map.update(cx, |display_map, cx| {
16873            display_map.disable_header_for_buffer(buffer_id, cx);
16874        });
16875        cx.notify();
16876    }
16877
16878    /// Removes any folds with the given ranges.
16879    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16880        &mut self,
16881        ranges: &[Range<T>],
16882        type_id: TypeId,
16883        auto_scroll: bool,
16884        cx: &mut Context<Self>,
16885    ) {
16886        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16887            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16888        });
16889        self.folds_did_change(cx);
16890    }
16891
16892    fn remove_folds_with<T: ToOffset + Clone>(
16893        &mut self,
16894        ranges: &[Range<T>],
16895        auto_scroll: bool,
16896        cx: &mut Context<Self>,
16897        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16898    ) {
16899        if ranges.is_empty() {
16900            return;
16901        }
16902
16903        let mut buffers_affected = HashSet::default();
16904        let multi_buffer = self.buffer().read(cx);
16905        for range in ranges {
16906            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16907                buffers_affected.insert(buffer.read(cx).remote_id());
16908            };
16909        }
16910
16911        self.display_map.update(cx, update);
16912
16913        if auto_scroll {
16914            self.request_autoscroll(Autoscroll::fit(), cx);
16915        }
16916
16917        cx.notify();
16918        self.scrollbar_marker_state.dirty = true;
16919        self.active_indent_guides_state.dirty = true;
16920    }
16921
16922    pub fn update_fold_widths(
16923        &mut self,
16924        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16925        cx: &mut Context<Self>,
16926    ) -> bool {
16927        self.display_map
16928            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16929    }
16930
16931    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16932        self.display_map.read(cx).fold_placeholder.clone()
16933    }
16934
16935    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16936        self.buffer.update(cx, |buffer, cx| {
16937            buffer.set_all_diff_hunks_expanded(cx);
16938        });
16939    }
16940
16941    pub fn expand_all_diff_hunks(
16942        &mut self,
16943        _: &ExpandAllDiffHunks,
16944        _window: &mut Window,
16945        cx: &mut Context<Self>,
16946    ) {
16947        self.buffer.update(cx, |buffer, cx| {
16948            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16949        });
16950    }
16951
16952    pub fn toggle_selected_diff_hunks(
16953        &mut self,
16954        _: &ToggleSelectedDiffHunks,
16955        _window: &mut Window,
16956        cx: &mut Context<Self>,
16957    ) {
16958        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16959        self.toggle_diff_hunks_in_ranges(ranges, cx);
16960    }
16961
16962    pub fn diff_hunks_in_ranges<'a>(
16963        &'a self,
16964        ranges: &'a [Range<Anchor>],
16965        buffer: &'a MultiBufferSnapshot,
16966    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16967        ranges.iter().flat_map(move |range| {
16968            let end_excerpt_id = range.end.excerpt_id;
16969            let range = range.to_point(buffer);
16970            let mut peek_end = range.end;
16971            if range.end.row < buffer.max_row().0 {
16972                peek_end = Point::new(range.end.row + 1, 0);
16973            }
16974            buffer
16975                .diff_hunks_in_range(range.start..peek_end)
16976                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16977        })
16978    }
16979
16980    pub fn has_stageable_diff_hunks_in_ranges(
16981        &self,
16982        ranges: &[Range<Anchor>],
16983        snapshot: &MultiBufferSnapshot,
16984    ) -> bool {
16985        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16986        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16987    }
16988
16989    pub fn toggle_staged_selected_diff_hunks(
16990        &mut self,
16991        _: &::git::ToggleStaged,
16992        _: &mut Window,
16993        cx: &mut Context<Self>,
16994    ) {
16995        let snapshot = self.buffer.read(cx).snapshot(cx);
16996        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16997        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16998        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16999    }
17000
17001    pub fn set_render_diff_hunk_controls(
17002        &mut self,
17003        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17004        cx: &mut Context<Self>,
17005    ) {
17006        self.render_diff_hunk_controls = render_diff_hunk_controls;
17007        cx.notify();
17008    }
17009
17010    pub fn stage_and_next(
17011        &mut self,
17012        _: &::git::StageAndNext,
17013        window: &mut Window,
17014        cx: &mut Context<Self>,
17015    ) {
17016        self.do_stage_or_unstage_and_next(true, window, cx);
17017    }
17018
17019    pub fn unstage_and_next(
17020        &mut self,
17021        _: &::git::UnstageAndNext,
17022        window: &mut Window,
17023        cx: &mut Context<Self>,
17024    ) {
17025        self.do_stage_or_unstage_and_next(false, window, cx);
17026    }
17027
17028    pub fn stage_or_unstage_diff_hunks(
17029        &mut self,
17030        stage: bool,
17031        ranges: Vec<Range<Anchor>>,
17032        cx: &mut Context<Self>,
17033    ) {
17034        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17035        cx.spawn(async move |this, cx| {
17036            task.await?;
17037            this.update(cx, |this, cx| {
17038                let snapshot = this.buffer.read(cx).snapshot(cx);
17039                let chunk_by = this
17040                    .diff_hunks_in_ranges(&ranges, &snapshot)
17041                    .chunk_by(|hunk| hunk.buffer_id);
17042                for (buffer_id, hunks) in &chunk_by {
17043                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17044                }
17045            })
17046        })
17047        .detach_and_log_err(cx);
17048    }
17049
17050    fn save_buffers_for_ranges_if_needed(
17051        &mut self,
17052        ranges: &[Range<Anchor>],
17053        cx: &mut Context<Editor>,
17054    ) -> Task<Result<()>> {
17055        let multibuffer = self.buffer.read(cx);
17056        let snapshot = multibuffer.read(cx);
17057        let buffer_ids: HashSet<_> = ranges
17058            .iter()
17059            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17060            .collect();
17061        drop(snapshot);
17062
17063        let mut buffers = HashSet::default();
17064        for buffer_id in buffer_ids {
17065            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17066                let buffer = buffer_entity.read(cx);
17067                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17068                {
17069                    buffers.insert(buffer_entity);
17070                }
17071            }
17072        }
17073
17074        if let Some(project) = &self.project {
17075            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17076        } else {
17077            Task::ready(Ok(()))
17078        }
17079    }
17080
17081    fn do_stage_or_unstage_and_next(
17082        &mut self,
17083        stage: bool,
17084        window: &mut Window,
17085        cx: &mut Context<Self>,
17086    ) {
17087        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17088
17089        if ranges.iter().any(|range| range.start != range.end) {
17090            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17091            return;
17092        }
17093
17094        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17095        let snapshot = self.snapshot(window, cx);
17096        let position = self.selections.newest::<Point>(cx).head();
17097        let mut row = snapshot
17098            .buffer_snapshot
17099            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17100            .find(|hunk| hunk.row_range.start.0 > position.row)
17101            .map(|hunk| hunk.row_range.start);
17102
17103        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17104        // Outside of the project diff editor, wrap around to the beginning.
17105        if !all_diff_hunks_expanded {
17106            row = row.or_else(|| {
17107                snapshot
17108                    .buffer_snapshot
17109                    .diff_hunks_in_range(Point::zero()..position)
17110                    .find(|hunk| hunk.row_range.end.0 < position.row)
17111                    .map(|hunk| hunk.row_range.start)
17112            });
17113        }
17114
17115        if let Some(row) = row {
17116            let destination = Point::new(row.0, 0);
17117            let autoscroll = Autoscroll::center();
17118
17119            self.unfold_ranges(&[destination..destination], false, false, cx);
17120            self.change_selections(Some(autoscroll), window, cx, |s| {
17121                s.select_ranges([destination..destination]);
17122            });
17123        }
17124    }
17125
17126    fn do_stage_or_unstage(
17127        &self,
17128        stage: bool,
17129        buffer_id: BufferId,
17130        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17131        cx: &mut App,
17132    ) -> Option<()> {
17133        let project = self.project.as_ref()?;
17134        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17135        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17136        let buffer_snapshot = buffer.read(cx).snapshot();
17137        let file_exists = buffer_snapshot
17138            .file()
17139            .is_some_and(|file| file.disk_state().exists());
17140        diff.update(cx, |diff, cx| {
17141            diff.stage_or_unstage_hunks(
17142                stage,
17143                &hunks
17144                    .map(|hunk| buffer_diff::DiffHunk {
17145                        buffer_range: hunk.buffer_range,
17146                        diff_base_byte_range: hunk.diff_base_byte_range,
17147                        secondary_status: hunk.secondary_status,
17148                        range: Point::zero()..Point::zero(), // unused
17149                    })
17150                    .collect::<Vec<_>>(),
17151                &buffer_snapshot,
17152                file_exists,
17153                cx,
17154            )
17155        });
17156        None
17157    }
17158
17159    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17160        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17161        self.buffer
17162            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17163    }
17164
17165    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17166        self.buffer.update(cx, |buffer, cx| {
17167            let ranges = vec![Anchor::min()..Anchor::max()];
17168            if !buffer.all_diff_hunks_expanded()
17169                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17170            {
17171                buffer.collapse_diff_hunks(ranges, cx);
17172                true
17173            } else {
17174                false
17175            }
17176        })
17177    }
17178
17179    fn toggle_diff_hunks_in_ranges(
17180        &mut self,
17181        ranges: Vec<Range<Anchor>>,
17182        cx: &mut Context<Editor>,
17183    ) {
17184        self.buffer.update(cx, |buffer, cx| {
17185            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17186            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17187        })
17188    }
17189
17190    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17191        self.buffer.update(cx, |buffer, cx| {
17192            let snapshot = buffer.snapshot(cx);
17193            let excerpt_id = range.end.excerpt_id;
17194            let point_range = range.to_point(&snapshot);
17195            let expand = !buffer.single_hunk_is_expanded(range, cx);
17196            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17197        })
17198    }
17199
17200    pub(crate) fn apply_all_diff_hunks(
17201        &mut self,
17202        _: &ApplyAllDiffHunks,
17203        window: &mut Window,
17204        cx: &mut Context<Self>,
17205    ) {
17206        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17207
17208        let buffers = self.buffer.read(cx).all_buffers();
17209        for branch_buffer in buffers {
17210            branch_buffer.update(cx, |branch_buffer, cx| {
17211                branch_buffer.merge_into_base(Vec::new(), cx);
17212            });
17213        }
17214
17215        if let Some(project) = self.project.clone() {
17216            self.save(
17217                SaveOptions {
17218                    format: true,
17219                    autosave: false,
17220                },
17221                project,
17222                window,
17223                cx,
17224            )
17225            .detach_and_log_err(cx);
17226        }
17227    }
17228
17229    pub(crate) fn apply_selected_diff_hunks(
17230        &mut self,
17231        _: &ApplyDiffHunk,
17232        window: &mut Window,
17233        cx: &mut Context<Self>,
17234    ) {
17235        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17236        let snapshot = self.snapshot(window, cx);
17237        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17238        let mut ranges_by_buffer = HashMap::default();
17239        self.transact(window, cx, |editor, _window, cx| {
17240            for hunk in hunks {
17241                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17242                    ranges_by_buffer
17243                        .entry(buffer.clone())
17244                        .or_insert_with(Vec::new)
17245                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17246                }
17247            }
17248
17249            for (buffer, ranges) in ranges_by_buffer {
17250                buffer.update(cx, |buffer, cx| {
17251                    buffer.merge_into_base(ranges, cx);
17252                });
17253            }
17254        });
17255
17256        if let Some(project) = self.project.clone() {
17257            self.save(
17258                SaveOptions {
17259                    format: true,
17260                    autosave: false,
17261                },
17262                project,
17263                window,
17264                cx,
17265            )
17266            .detach_and_log_err(cx);
17267        }
17268    }
17269
17270    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17271        if hovered != self.gutter_hovered {
17272            self.gutter_hovered = hovered;
17273            cx.notify();
17274        }
17275    }
17276
17277    pub fn insert_blocks(
17278        &mut self,
17279        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17280        autoscroll: Option<Autoscroll>,
17281        cx: &mut Context<Self>,
17282    ) -> Vec<CustomBlockId> {
17283        let blocks = self
17284            .display_map
17285            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17286        if let Some(autoscroll) = autoscroll {
17287            self.request_autoscroll(autoscroll, cx);
17288        }
17289        cx.notify();
17290        blocks
17291    }
17292
17293    pub fn resize_blocks(
17294        &mut self,
17295        heights: HashMap<CustomBlockId, u32>,
17296        autoscroll: Option<Autoscroll>,
17297        cx: &mut Context<Self>,
17298    ) {
17299        self.display_map
17300            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17301        if let Some(autoscroll) = autoscroll {
17302            self.request_autoscroll(autoscroll, cx);
17303        }
17304        cx.notify();
17305    }
17306
17307    pub fn replace_blocks(
17308        &mut self,
17309        renderers: HashMap<CustomBlockId, RenderBlock>,
17310        autoscroll: Option<Autoscroll>,
17311        cx: &mut Context<Self>,
17312    ) {
17313        self.display_map
17314            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17315        if let Some(autoscroll) = autoscroll {
17316            self.request_autoscroll(autoscroll, cx);
17317        }
17318        cx.notify();
17319    }
17320
17321    pub fn remove_blocks(
17322        &mut self,
17323        block_ids: HashSet<CustomBlockId>,
17324        autoscroll: Option<Autoscroll>,
17325        cx: &mut Context<Self>,
17326    ) {
17327        self.display_map.update(cx, |display_map, cx| {
17328            display_map.remove_blocks(block_ids, cx)
17329        });
17330        if let Some(autoscroll) = autoscroll {
17331            self.request_autoscroll(autoscroll, cx);
17332        }
17333        cx.notify();
17334    }
17335
17336    pub fn row_for_block(
17337        &self,
17338        block_id: CustomBlockId,
17339        cx: &mut Context<Self>,
17340    ) -> Option<DisplayRow> {
17341        self.display_map
17342            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17343    }
17344
17345    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17346        self.focused_block = Some(focused_block);
17347    }
17348
17349    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17350        self.focused_block.take()
17351    }
17352
17353    pub fn insert_creases(
17354        &mut self,
17355        creases: impl IntoIterator<Item = Crease<Anchor>>,
17356        cx: &mut Context<Self>,
17357    ) -> Vec<CreaseId> {
17358        self.display_map
17359            .update(cx, |map, cx| map.insert_creases(creases, cx))
17360    }
17361
17362    pub fn remove_creases(
17363        &mut self,
17364        ids: impl IntoIterator<Item = CreaseId>,
17365        cx: &mut Context<Self>,
17366    ) -> Vec<(CreaseId, Range<Anchor>)> {
17367        self.display_map
17368            .update(cx, |map, cx| map.remove_creases(ids, cx))
17369    }
17370
17371    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17372        self.display_map
17373            .update(cx, |map, cx| map.snapshot(cx))
17374            .longest_row()
17375    }
17376
17377    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17378        self.display_map
17379            .update(cx, |map, cx| map.snapshot(cx))
17380            .max_point()
17381    }
17382
17383    pub fn text(&self, cx: &App) -> String {
17384        self.buffer.read(cx).read(cx).text()
17385    }
17386
17387    pub fn is_empty(&self, cx: &App) -> bool {
17388        self.buffer.read(cx).read(cx).is_empty()
17389    }
17390
17391    pub fn text_option(&self, cx: &App) -> Option<String> {
17392        let text = self.text(cx);
17393        let text = text.trim();
17394
17395        if text.is_empty() {
17396            return None;
17397        }
17398
17399        Some(text.to_string())
17400    }
17401
17402    pub fn set_text(
17403        &mut self,
17404        text: impl Into<Arc<str>>,
17405        window: &mut Window,
17406        cx: &mut Context<Self>,
17407    ) {
17408        self.transact(window, cx, |this, _, cx| {
17409            this.buffer
17410                .read(cx)
17411                .as_singleton()
17412                .expect("you can only call set_text on editors for singleton buffers")
17413                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17414        });
17415    }
17416
17417    pub fn display_text(&self, cx: &mut App) -> String {
17418        self.display_map
17419            .update(cx, |map, cx| map.snapshot(cx))
17420            .text()
17421    }
17422
17423    fn create_minimap(
17424        &self,
17425        minimap_settings: MinimapSettings,
17426        window: &mut Window,
17427        cx: &mut Context<Self>,
17428    ) -> Option<Entity<Self>> {
17429        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17430            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17431    }
17432
17433    fn initialize_new_minimap(
17434        &self,
17435        minimap_settings: MinimapSettings,
17436        window: &mut Window,
17437        cx: &mut Context<Self>,
17438    ) -> Entity<Self> {
17439        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17440
17441        let mut minimap = Editor::new_internal(
17442            EditorMode::Minimap {
17443                parent: cx.weak_entity(),
17444            },
17445            self.buffer.clone(),
17446            self.project.clone(),
17447            Some(self.display_map.clone()),
17448            window,
17449            cx,
17450        );
17451        minimap.scroll_manager.clone_state(&self.scroll_manager);
17452        minimap.set_text_style_refinement(TextStyleRefinement {
17453            font_size: Some(MINIMAP_FONT_SIZE),
17454            font_weight: Some(MINIMAP_FONT_WEIGHT),
17455            ..Default::default()
17456        });
17457        minimap.update_minimap_configuration(minimap_settings, cx);
17458        cx.new(|_| minimap)
17459    }
17460
17461    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17462        let current_line_highlight = minimap_settings
17463            .current_line_highlight
17464            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17465        self.set_current_line_highlight(Some(current_line_highlight));
17466    }
17467
17468    pub fn minimap(&self) -> Option<&Entity<Self>> {
17469        self.minimap
17470            .as_ref()
17471            .filter(|_| self.minimap_visibility.visible())
17472    }
17473
17474    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17475        let mut wrap_guides = smallvec![];
17476
17477        if self.show_wrap_guides == Some(false) {
17478            return wrap_guides;
17479        }
17480
17481        let settings = self.buffer.read(cx).language_settings(cx);
17482        if settings.show_wrap_guides {
17483            match self.soft_wrap_mode(cx) {
17484                SoftWrap::Column(soft_wrap) => {
17485                    wrap_guides.push((soft_wrap as usize, true));
17486                }
17487                SoftWrap::Bounded(soft_wrap) => {
17488                    wrap_guides.push((soft_wrap as usize, true));
17489                }
17490                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17491            }
17492            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17493        }
17494
17495        wrap_guides
17496    }
17497
17498    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17499        let settings = self.buffer.read(cx).language_settings(cx);
17500        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17501        match mode {
17502            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17503                SoftWrap::None
17504            }
17505            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17506            language_settings::SoftWrap::PreferredLineLength => {
17507                SoftWrap::Column(settings.preferred_line_length)
17508            }
17509            language_settings::SoftWrap::Bounded => {
17510                SoftWrap::Bounded(settings.preferred_line_length)
17511            }
17512        }
17513    }
17514
17515    pub fn set_soft_wrap_mode(
17516        &mut self,
17517        mode: language_settings::SoftWrap,
17518
17519        cx: &mut Context<Self>,
17520    ) {
17521        self.soft_wrap_mode_override = Some(mode);
17522        cx.notify();
17523    }
17524
17525    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17526        self.hard_wrap = hard_wrap;
17527        cx.notify();
17528    }
17529
17530    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17531        self.text_style_refinement = Some(style);
17532    }
17533
17534    /// called by the Element so we know what style we were most recently rendered with.
17535    pub(crate) fn set_style(
17536        &mut self,
17537        style: EditorStyle,
17538        window: &mut Window,
17539        cx: &mut Context<Self>,
17540    ) {
17541        // We intentionally do not inform the display map about the minimap style
17542        // so that wrapping is not recalculated and stays consistent for the editor
17543        // and its linked minimap.
17544        if !self.mode.is_minimap() {
17545            let rem_size = window.rem_size();
17546            self.display_map.update(cx, |map, cx| {
17547                map.set_font(
17548                    style.text.font(),
17549                    style.text.font_size.to_pixels(rem_size),
17550                    cx,
17551                )
17552            });
17553        }
17554        self.style = Some(style);
17555    }
17556
17557    pub fn style(&self) -> Option<&EditorStyle> {
17558        self.style.as_ref()
17559    }
17560
17561    // Called by the element. This method is not designed to be called outside of the editor
17562    // element's layout code because it does not notify when rewrapping is computed synchronously.
17563    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17564        self.display_map
17565            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17566    }
17567
17568    pub fn set_soft_wrap(&mut self) {
17569        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17570    }
17571
17572    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17573        if self.soft_wrap_mode_override.is_some() {
17574            self.soft_wrap_mode_override.take();
17575        } else {
17576            let soft_wrap = match self.soft_wrap_mode(cx) {
17577                SoftWrap::GitDiff => return,
17578                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17579                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17580                    language_settings::SoftWrap::None
17581                }
17582            };
17583            self.soft_wrap_mode_override = Some(soft_wrap);
17584        }
17585        cx.notify();
17586    }
17587
17588    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17589        let Some(workspace) = self.workspace() else {
17590            return;
17591        };
17592        let fs = workspace.read(cx).app_state().fs.clone();
17593        let current_show = TabBarSettings::get_global(cx).show;
17594        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17595            setting.show = Some(!current_show);
17596        });
17597    }
17598
17599    pub fn toggle_indent_guides(
17600        &mut self,
17601        _: &ToggleIndentGuides,
17602        _: &mut Window,
17603        cx: &mut Context<Self>,
17604    ) {
17605        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17606            self.buffer
17607                .read(cx)
17608                .language_settings(cx)
17609                .indent_guides
17610                .enabled
17611        });
17612        self.show_indent_guides = Some(!currently_enabled);
17613        cx.notify();
17614    }
17615
17616    fn should_show_indent_guides(&self) -> Option<bool> {
17617        self.show_indent_guides
17618    }
17619
17620    pub fn toggle_line_numbers(
17621        &mut self,
17622        _: &ToggleLineNumbers,
17623        _: &mut Window,
17624        cx: &mut Context<Self>,
17625    ) {
17626        let mut editor_settings = EditorSettings::get_global(cx).clone();
17627        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17628        EditorSettings::override_global(editor_settings, cx);
17629    }
17630
17631    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17632        if let Some(show_line_numbers) = self.show_line_numbers {
17633            return show_line_numbers;
17634        }
17635        EditorSettings::get_global(cx).gutter.line_numbers
17636    }
17637
17638    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17639        self.use_relative_line_numbers
17640            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17641    }
17642
17643    pub fn toggle_relative_line_numbers(
17644        &mut self,
17645        _: &ToggleRelativeLineNumbers,
17646        _: &mut Window,
17647        cx: &mut Context<Self>,
17648    ) {
17649        let is_relative = self.should_use_relative_line_numbers(cx);
17650        self.set_relative_line_number(Some(!is_relative), cx)
17651    }
17652
17653    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17654        self.use_relative_line_numbers = is_relative;
17655        cx.notify();
17656    }
17657
17658    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17659        self.show_gutter = show_gutter;
17660        cx.notify();
17661    }
17662
17663    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17664        self.show_scrollbars = ScrollbarAxes {
17665            horizontal: show,
17666            vertical: show,
17667        };
17668        cx.notify();
17669    }
17670
17671    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17672        self.show_scrollbars.vertical = show;
17673        cx.notify();
17674    }
17675
17676    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17677        self.show_scrollbars.horizontal = show;
17678        cx.notify();
17679    }
17680
17681    pub fn set_minimap_visibility(
17682        &mut self,
17683        minimap_visibility: MinimapVisibility,
17684        window: &mut Window,
17685        cx: &mut Context<Self>,
17686    ) {
17687        if self.minimap_visibility != minimap_visibility {
17688            if minimap_visibility.visible() && self.minimap.is_none() {
17689                let minimap_settings = EditorSettings::get_global(cx).minimap;
17690                self.minimap =
17691                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17692            }
17693            self.minimap_visibility = minimap_visibility;
17694            cx.notify();
17695        }
17696    }
17697
17698    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17699        self.set_show_scrollbars(false, cx);
17700        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17701    }
17702
17703    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17704        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17705    }
17706
17707    /// Normally the text in full mode and auto height editors is padded on the
17708    /// left side by roughly half a character width for improved hit testing.
17709    ///
17710    /// Use this method to disable this for cases where this is not wanted (e.g.
17711    /// if you want to align the editor text with some other text above or below)
17712    /// or if you want to add this padding to single-line editors.
17713    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17714        self.offset_content = offset_content;
17715        cx.notify();
17716    }
17717
17718    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17719        self.show_line_numbers = Some(show_line_numbers);
17720        cx.notify();
17721    }
17722
17723    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17724        self.disable_expand_excerpt_buttons = true;
17725        cx.notify();
17726    }
17727
17728    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17729        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17730        cx.notify();
17731    }
17732
17733    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17734        self.show_code_actions = Some(show_code_actions);
17735        cx.notify();
17736    }
17737
17738    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17739        self.show_runnables = Some(show_runnables);
17740        cx.notify();
17741    }
17742
17743    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17744        self.show_breakpoints = Some(show_breakpoints);
17745        cx.notify();
17746    }
17747
17748    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17749        if self.display_map.read(cx).masked != masked {
17750            self.display_map.update(cx, |map, _| map.masked = masked);
17751        }
17752        cx.notify()
17753    }
17754
17755    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17756        self.show_wrap_guides = Some(show_wrap_guides);
17757        cx.notify();
17758    }
17759
17760    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17761        self.show_indent_guides = Some(show_indent_guides);
17762        cx.notify();
17763    }
17764
17765    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17766        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17767            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17768                if let Some(dir) = file.abs_path(cx).parent() {
17769                    return Some(dir.to_owned());
17770                }
17771            }
17772
17773            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17774                return Some(project_path.path.to_path_buf());
17775            }
17776        }
17777
17778        None
17779    }
17780
17781    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17782        self.active_excerpt(cx)?
17783            .1
17784            .read(cx)
17785            .file()
17786            .and_then(|f| f.as_local())
17787    }
17788
17789    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17790        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17791            let buffer = buffer.read(cx);
17792            if let Some(project_path) = buffer.project_path(cx) {
17793                let project = self.project.as_ref()?.read(cx);
17794                project.absolute_path(&project_path, cx)
17795            } else {
17796                buffer
17797                    .file()
17798                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17799            }
17800        })
17801    }
17802
17803    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17804        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17805            let project_path = buffer.read(cx).project_path(cx)?;
17806            let project = self.project.as_ref()?.read(cx);
17807            let entry = project.entry_for_path(&project_path, cx)?;
17808            let path = entry.path.to_path_buf();
17809            Some(path)
17810        })
17811    }
17812
17813    pub fn reveal_in_finder(
17814        &mut self,
17815        _: &RevealInFileManager,
17816        _window: &mut Window,
17817        cx: &mut Context<Self>,
17818    ) {
17819        if let Some(target) = self.target_file(cx) {
17820            cx.reveal_path(&target.abs_path(cx));
17821        }
17822    }
17823
17824    pub fn copy_path(
17825        &mut self,
17826        _: &zed_actions::workspace::CopyPath,
17827        _window: &mut Window,
17828        cx: &mut Context<Self>,
17829    ) {
17830        if let Some(path) = self.target_file_abs_path(cx) {
17831            if let Some(path) = path.to_str() {
17832                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17833            }
17834        }
17835    }
17836
17837    pub fn copy_relative_path(
17838        &mut self,
17839        _: &zed_actions::workspace::CopyRelativePath,
17840        _window: &mut Window,
17841        cx: &mut Context<Self>,
17842    ) {
17843        if let Some(path) = self.target_file_path(cx) {
17844            if let Some(path) = path.to_str() {
17845                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17846            }
17847        }
17848    }
17849
17850    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17851        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17852            buffer.read(cx).project_path(cx)
17853        } else {
17854            None
17855        }
17856    }
17857
17858    // Returns true if the editor handled a go-to-line request
17859    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17860        maybe!({
17861            let breakpoint_store = self.breakpoint_store.as_ref()?;
17862
17863            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17864            else {
17865                self.clear_row_highlights::<ActiveDebugLine>();
17866                return None;
17867            };
17868
17869            let position = active_stack_frame.position;
17870            let buffer_id = position.buffer_id?;
17871            let snapshot = self
17872                .project
17873                .as_ref()?
17874                .read(cx)
17875                .buffer_for_id(buffer_id, cx)?
17876                .read(cx)
17877                .snapshot();
17878
17879            let mut handled = false;
17880            for (id, ExcerptRange { context, .. }) in
17881                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17882            {
17883                if context.start.cmp(&position, &snapshot).is_ge()
17884                    || context.end.cmp(&position, &snapshot).is_lt()
17885                {
17886                    continue;
17887                }
17888                let snapshot = self.buffer.read(cx).snapshot(cx);
17889                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17890
17891                handled = true;
17892                self.clear_row_highlights::<ActiveDebugLine>();
17893
17894                self.go_to_line::<ActiveDebugLine>(
17895                    multibuffer_anchor,
17896                    Some(cx.theme().colors().editor_debugger_active_line_background),
17897                    window,
17898                    cx,
17899                );
17900
17901                cx.notify();
17902            }
17903
17904            handled.then_some(())
17905        })
17906        .is_some()
17907    }
17908
17909    pub fn copy_file_name_without_extension(
17910        &mut self,
17911        _: &CopyFileNameWithoutExtension,
17912        _: &mut Window,
17913        cx: &mut Context<Self>,
17914    ) {
17915        if let Some(file) = self.target_file(cx) {
17916            if let Some(file_stem) = file.path().file_stem() {
17917                if let Some(name) = file_stem.to_str() {
17918                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17919                }
17920            }
17921        }
17922    }
17923
17924    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17925        if let Some(file) = self.target_file(cx) {
17926            if let Some(file_name) = file.path().file_name() {
17927                if let Some(name) = file_name.to_str() {
17928                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17929                }
17930            }
17931        }
17932    }
17933
17934    pub fn toggle_git_blame(
17935        &mut self,
17936        _: &::git::Blame,
17937        window: &mut Window,
17938        cx: &mut Context<Self>,
17939    ) {
17940        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17941
17942        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17943            self.start_git_blame(true, window, cx);
17944        }
17945
17946        cx.notify();
17947    }
17948
17949    pub fn toggle_git_blame_inline(
17950        &mut self,
17951        _: &ToggleGitBlameInline,
17952        window: &mut Window,
17953        cx: &mut Context<Self>,
17954    ) {
17955        self.toggle_git_blame_inline_internal(true, window, cx);
17956        cx.notify();
17957    }
17958
17959    pub fn open_git_blame_commit(
17960        &mut self,
17961        _: &OpenGitBlameCommit,
17962        window: &mut Window,
17963        cx: &mut Context<Self>,
17964    ) {
17965        self.open_git_blame_commit_internal(window, cx);
17966    }
17967
17968    fn open_git_blame_commit_internal(
17969        &mut self,
17970        window: &mut Window,
17971        cx: &mut Context<Self>,
17972    ) -> Option<()> {
17973        let blame = self.blame.as_ref()?;
17974        let snapshot = self.snapshot(window, cx);
17975        let cursor = self.selections.newest::<Point>(cx).head();
17976        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17977        let blame_entry = blame
17978            .update(cx, |blame, cx| {
17979                blame
17980                    .blame_for_rows(
17981                        &[RowInfo {
17982                            buffer_id: Some(buffer.remote_id()),
17983                            buffer_row: Some(point.row),
17984                            ..Default::default()
17985                        }],
17986                        cx,
17987                    )
17988                    .next()
17989            })
17990            .flatten()?;
17991        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17992        let repo = blame.read(cx).repository(cx)?;
17993        let workspace = self.workspace()?.downgrade();
17994        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17995        None
17996    }
17997
17998    pub fn git_blame_inline_enabled(&self) -> bool {
17999        self.git_blame_inline_enabled
18000    }
18001
18002    pub fn toggle_selection_menu(
18003        &mut self,
18004        _: &ToggleSelectionMenu,
18005        _: &mut Window,
18006        cx: &mut Context<Self>,
18007    ) {
18008        self.show_selection_menu = self
18009            .show_selection_menu
18010            .map(|show_selections_menu| !show_selections_menu)
18011            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18012
18013        cx.notify();
18014    }
18015
18016    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18017        self.show_selection_menu
18018            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18019    }
18020
18021    fn start_git_blame(
18022        &mut self,
18023        user_triggered: bool,
18024        window: &mut Window,
18025        cx: &mut Context<Self>,
18026    ) {
18027        if let Some(project) = self.project.as_ref() {
18028            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18029                return;
18030            };
18031
18032            if buffer.read(cx).file().is_none() {
18033                return;
18034            }
18035
18036            let focused = self.focus_handle(cx).contains_focused(window, cx);
18037
18038            let project = project.clone();
18039            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18040            self.blame_subscription =
18041                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18042            self.blame = Some(blame);
18043        }
18044    }
18045
18046    fn toggle_git_blame_inline_internal(
18047        &mut self,
18048        user_triggered: bool,
18049        window: &mut Window,
18050        cx: &mut Context<Self>,
18051    ) {
18052        if self.git_blame_inline_enabled {
18053            self.git_blame_inline_enabled = false;
18054            self.show_git_blame_inline = false;
18055            self.show_git_blame_inline_delay_task.take();
18056        } else {
18057            self.git_blame_inline_enabled = true;
18058            self.start_git_blame_inline(user_triggered, window, cx);
18059        }
18060
18061        cx.notify();
18062    }
18063
18064    fn start_git_blame_inline(
18065        &mut self,
18066        user_triggered: bool,
18067        window: &mut Window,
18068        cx: &mut Context<Self>,
18069    ) {
18070        self.start_git_blame(user_triggered, window, cx);
18071
18072        if ProjectSettings::get_global(cx)
18073            .git
18074            .inline_blame_delay()
18075            .is_some()
18076        {
18077            self.start_inline_blame_timer(window, cx);
18078        } else {
18079            self.show_git_blame_inline = true
18080        }
18081    }
18082
18083    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18084        self.blame.as_ref()
18085    }
18086
18087    pub fn show_git_blame_gutter(&self) -> bool {
18088        self.show_git_blame_gutter
18089    }
18090
18091    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18092        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18093    }
18094
18095    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18096        self.show_git_blame_inline
18097            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18098            && !self.newest_selection_head_on_empty_line(cx)
18099            && self.has_blame_entries(cx)
18100    }
18101
18102    fn has_blame_entries(&self, cx: &App) -> bool {
18103        self.blame()
18104            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18105    }
18106
18107    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18108        let cursor_anchor = self.selections.newest_anchor().head();
18109
18110        let snapshot = self.buffer.read(cx).snapshot(cx);
18111        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18112
18113        snapshot.line_len(buffer_row) == 0
18114    }
18115
18116    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18117        let buffer_and_selection = maybe!({
18118            let selection = self.selections.newest::<Point>(cx);
18119            let selection_range = selection.range();
18120
18121            let multi_buffer = self.buffer().read(cx);
18122            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18123            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18124
18125            let (buffer, range, _) = if selection.reversed {
18126                buffer_ranges.first()
18127            } else {
18128                buffer_ranges.last()
18129            }?;
18130
18131            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18132                ..text::ToPoint::to_point(&range.end, &buffer).row;
18133            Some((
18134                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18135                selection,
18136            ))
18137        });
18138
18139        let Some((buffer, selection)) = buffer_and_selection else {
18140            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18141        };
18142
18143        let Some(project) = self.project.as_ref() else {
18144            return Task::ready(Err(anyhow!("editor does not have project")));
18145        };
18146
18147        project.update(cx, |project, cx| {
18148            project.get_permalink_to_line(&buffer, selection, cx)
18149        })
18150    }
18151
18152    pub fn copy_permalink_to_line(
18153        &mut self,
18154        _: &CopyPermalinkToLine,
18155        window: &mut Window,
18156        cx: &mut Context<Self>,
18157    ) {
18158        let permalink_task = self.get_permalink_to_line(cx);
18159        let workspace = self.workspace();
18160
18161        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18162            Ok(permalink) => {
18163                cx.update(|_, cx| {
18164                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18165                })
18166                .ok();
18167            }
18168            Err(err) => {
18169                let message = format!("Failed to copy permalink: {err}");
18170
18171                anyhow::Result::<()>::Err(err).log_err();
18172
18173                if let Some(workspace) = workspace {
18174                    workspace
18175                        .update_in(cx, |workspace, _, cx| {
18176                            struct CopyPermalinkToLine;
18177
18178                            workspace.show_toast(
18179                                Toast::new(
18180                                    NotificationId::unique::<CopyPermalinkToLine>(),
18181                                    message,
18182                                ),
18183                                cx,
18184                            )
18185                        })
18186                        .ok();
18187                }
18188            }
18189        })
18190        .detach();
18191    }
18192
18193    pub fn copy_file_location(
18194        &mut self,
18195        _: &CopyFileLocation,
18196        _: &mut Window,
18197        cx: &mut Context<Self>,
18198    ) {
18199        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18200        if let Some(file) = self.target_file(cx) {
18201            if let Some(path) = file.path().to_str() {
18202                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18203            }
18204        }
18205    }
18206
18207    pub fn open_permalink_to_line(
18208        &mut self,
18209        _: &OpenPermalinkToLine,
18210        window: &mut Window,
18211        cx: &mut Context<Self>,
18212    ) {
18213        let permalink_task = self.get_permalink_to_line(cx);
18214        let workspace = self.workspace();
18215
18216        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18217            Ok(permalink) => {
18218                cx.update(|_, cx| {
18219                    cx.open_url(permalink.as_ref());
18220                })
18221                .ok();
18222            }
18223            Err(err) => {
18224                let message = format!("Failed to open permalink: {err}");
18225
18226                anyhow::Result::<()>::Err(err).log_err();
18227
18228                if let Some(workspace) = workspace {
18229                    workspace
18230                        .update(cx, |workspace, cx| {
18231                            struct OpenPermalinkToLine;
18232
18233                            workspace.show_toast(
18234                                Toast::new(
18235                                    NotificationId::unique::<OpenPermalinkToLine>(),
18236                                    message,
18237                                ),
18238                                cx,
18239                            )
18240                        })
18241                        .ok();
18242                }
18243            }
18244        })
18245        .detach();
18246    }
18247
18248    pub fn insert_uuid_v4(
18249        &mut self,
18250        _: &InsertUuidV4,
18251        window: &mut Window,
18252        cx: &mut Context<Self>,
18253    ) {
18254        self.insert_uuid(UuidVersion::V4, window, cx);
18255    }
18256
18257    pub fn insert_uuid_v7(
18258        &mut self,
18259        _: &InsertUuidV7,
18260        window: &mut Window,
18261        cx: &mut Context<Self>,
18262    ) {
18263        self.insert_uuid(UuidVersion::V7, window, cx);
18264    }
18265
18266    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18267        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18268        self.transact(window, cx, |this, window, cx| {
18269            let edits = this
18270                .selections
18271                .all::<Point>(cx)
18272                .into_iter()
18273                .map(|selection| {
18274                    let uuid = match version {
18275                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18276                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18277                    };
18278
18279                    (selection.range(), uuid.to_string())
18280                });
18281            this.edit(edits, cx);
18282            this.refresh_inline_completion(true, false, window, cx);
18283        });
18284    }
18285
18286    pub fn open_selections_in_multibuffer(
18287        &mut self,
18288        _: &OpenSelectionsInMultibuffer,
18289        window: &mut Window,
18290        cx: &mut Context<Self>,
18291    ) {
18292        let multibuffer = self.buffer.read(cx);
18293
18294        let Some(buffer) = multibuffer.as_singleton() else {
18295            return;
18296        };
18297
18298        let Some(workspace) = self.workspace() else {
18299            return;
18300        };
18301
18302        let title = multibuffer.title(cx).to_string();
18303
18304        let locations = self
18305            .selections
18306            .all_anchors(cx)
18307            .into_iter()
18308            .map(|selection| Location {
18309                buffer: buffer.clone(),
18310                range: selection.start.text_anchor..selection.end.text_anchor,
18311            })
18312            .collect::<Vec<_>>();
18313
18314        cx.spawn_in(window, async move |_, cx| {
18315            workspace.update_in(cx, |workspace, window, cx| {
18316                Self::open_locations_in_multibuffer(
18317                    workspace,
18318                    locations,
18319                    format!("Selections for '{title}'"),
18320                    false,
18321                    MultibufferSelectionMode::All,
18322                    window,
18323                    cx,
18324                );
18325            })
18326        })
18327        .detach();
18328    }
18329
18330    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18331    /// last highlight added will be used.
18332    ///
18333    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18334    pub fn highlight_rows<T: 'static>(
18335        &mut self,
18336        range: Range<Anchor>,
18337        color: Hsla,
18338        options: RowHighlightOptions,
18339        cx: &mut Context<Self>,
18340    ) {
18341        let snapshot = self.buffer().read(cx).snapshot(cx);
18342        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18343        let ix = row_highlights.binary_search_by(|highlight| {
18344            Ordering::Equal
18345                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18346                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18347        });
18348
18349        if let Err(mut ix) = ix {
18350            let index = post_inc(&mut self.highlight_order);
18351
18352            // If this range intersects with the preceding highlight, then merge it with
18353            // the preceding highlight. Otherwise insert a new highlight.
18354            let mut merged = false;
18355            if ix > 0 {
18356                let prev_highlight = &mut row_highlights[ix - 1];
18357                if prev_highlight
18358                    .range
18359                    .end
18360                    .cmp(&range.start, &snapshot)
18361                    .is_ge()
18362                {
18363                    ix -= 1;
18364                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18365                        prev_highlight.range.end = range.end;
18366                    }
18367                    merged = true;
18368                    prev_highlight.index = index;
18369                    prev_highlight.color = color;
18370                    prev_highlight.options = options;
18371                }
18372            }
18373
18374            if !merged {
18375                row_highlights.insert(
18376                    ix,
18377                    RowHighlight {
18378                        range: range.clone(),
18379                        index,
18380                        color,
18381                        options,
18382                        type_id: TypeId::of::<T>(),
18383                    },
18384                );
18385            }
18386
18387            // If any of the following highlights intersect with this one, merge them.
18388            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18389                let highlight = &row_highlights[ix];
18390                if next_highlight
18391                    .range
18392                    .start
18393                    .cmp(&highlight.range.end, &snapshot)
18394                    .is_le()
18395                {
18396                    if next_highlight
18397                        .range
18398                        .end
18399                        .cmp(&highlight.range.end, &snapshot)
18400                        .is_gt()
18401                    {
18402                        row_highlights[ix].range.end = next_highlight.range.end;
18403                    }
18404                    row_highlights.remove(ix + 1);
18405                } else {
18406                    break;
18407                }
18408            }
18409        }
18410    }
18411
18412    /// Remove any highlighted row ranges of the given type that intersect the
18413    /// given ranges.
18414    pub fn remove_highlighted_rows<T: 'static>(
18415        &mut self,
18416        ranges_to_remove: Vec<Range<Anchor>>,
18417        cx: &mut Context<Self>,
18418    ) {
18419        let snapshot = self.buffer().read(cx).snapshot(cx);
18420        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18421        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18422        row_highlights.retain(|highlight| {
18423            while let Some(range_to_remove) = ranges_to_remove.peek() {
18424                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18425                    Ordering::Less | Ordering::Equal => {
18426                        ranges_to_remove.next();
18427                    }
18428                    Ordering::Greater => {
18429                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18430                            Ordering::Less | Ordering::Equal => {
18431                                return false;
18432                            }
18433                            Ordering::Greater => break,
18434                        }
18435                    }
18436                }
18437            }
18438
18439            true
18440        })
18441    }
18442
18443    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18444    pub fn clear_row_highlights<T: 'static>(&mut self) {
18445        self.highlighted_rows.remove(&TypeId::of::<T>());
18446    }
18447
18448    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18449    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18450        self.highlighted_rows
18451            .get(&TypeId::of::<T>())
18452            .map_or(&[] as &[_], |vec| vec.as_slice())
18453            .iter()
18454            .map(|highlight| (highlight.range.clone(), highlight.color))
18455    }
18456
18457    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18458    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18459    /// Allows to ignore certain kinds of highlights.
18460    pub fn highlighted_display_rows(
18461        &self,
18462        window: &mut Window,
18463        cx: &mut App,
18464    ) -> BTreeMap<DisplayRow, LineHighlight> {
18465        let snapshot = self.snapshot(window, cx);
18466        let mut used_highlight_orders = HashMap::default();
18467        self.highlighted_rows
18468            .iter()
18469            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18470            .fold(
18471                BTreeMap::<DisplayRow, LineHighlight>::new(),
18472                |mut unique_rows, highlight| {
18473                    let start = highlight.range.start.to_display_point(&snapshot);
18474                    let end = highlight.range.end.to_display_point(&snapshot);
18475                    let start_row = start.row().0;
18476                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18477                        && end.column() == 0
18478                    {
18479                        end.row().0.saturating_sub(1)
18480                    } else {
18481                        end.row().0
18482                    };
18483                    for row in start_row..=end_row {
18484                        let used_index =
18485                            used_highlight_orders.entry(row).or_insert(highlight.index);
18486                        if highlight.index >= *used_index {
18487                            *used_index = highlight.index;
18488                            unique_rows.insert(
18489                                DisplayRow(row),
18490                                LineHighlight {
18491                                    include_gutter: highlight.options.include_gutter,
18492                                    border: None,
18493                                    background: highlight.color.into(),
18494                                    type_id: Some(highlight.type_id),
18495                                },
18496                            );
18497                        }
18498                    }
18499                    unique_rows
18500                },
18501            )
18502    }
18503
18504    pub fn highlighted_display_row_for_autoscroll(
18505        &self,
18506        snapshot: &DisplaySnapshot,
18507    ) -> Option<DisplayRow> {
18508        self.highlighted_rows
18509            .values()
18510            .flat_map(|highlighted_rows| highlighted_rows.iter())
18511            .filter_map(|highlight| {
18512                if highlight.options.autoscroll {
18513                    Some(highlight.range.start.to_display_point(snapshot).row())
18514                } else {
18515                    None
18516                }
18517            })
18518            .min()
18519    }
18520
18521    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18522        self.highlight_background::<SearchWithinRange>(
18523            ranges,
18524            |theme| theme.colors().editor_document_highlight_read_background,
18525            cx,
18526        )
18527    }
18528
18529    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18530        self.breadcrumb_header = Some(new_header);
18531    }
18532
18533    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18534        self.clear_background_highlights::<SearchWithinRange>(cx);
18535    }
18536
18537    pub fn highlight_background<T: 'static>(
18538        &mut self,
18539        ranges: &[Range<Anchor>],
18540        color_fetcher: fn(&Theme) -> Hsla,
18541        cx: &mut Context<Self>,
18542    ) {
18543        let highlights = ranges
18544            .iter()
18545            .map(|range| BackgroundHighlight {
18546                range: range.clone(),
18547                color_fetcher,
18548            })
18549            .collect();
18550        self.background_highlights
18551            .insert(TypeId::of::<T>(), highlights);
18552        self.scrollbar_marker_state.dirty = true;
18553        cx.notify();
18554    }
18555
18556    pub fn highlight_background_ranges<T: 'static>(
18557        &mut self,
18558        background_highlights: Vec<BackgroundHighlight>,
18559        cx: &mut Context<'_, Editor>,
18560    ) {
18561        self.background_highlights
18562            .insert(TypeId::of::<T>(), background_highlights);
18563        self.scrollbar_marker_state.dirty = true;
18564        cx.notify();
18565    }
18566
18567    pub fn clear_background_highlights<T: 'static>(
18568        &mut self,
18569        cx: &mut Context<Self>,
18570    ) -> Option<Vec<BackgroundHighlight>> {
18571        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18572        if !text_highlights.is_empty() {
18573            self.scrollbar_marker_state.dirty = true;
18574            cx.notify();
18575        }
18576        Some(text_highlights)
18577    }
18578
18579    pub fn highlight_gutter<T: 'static>(
18580        &mut self,
18581        ranges: impl Into<Vec<Range<Anchor>>>,
18582        color_fetcher: fn(&App) -> Hsla,
18583        cx: &mut Context<Self>,
18584    ) {
18585        self.gutter_highlights
18586            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18587        cx.notify();
18588    }
18589
18590    pub fn clear_gutter_highlights<T: 'static>(
18591        &mut self,
18592        cx: &mut Context<Self>,
18593    ) -> Option<GutterHighlight> {
18594        cx.notify();
18595        self.gutter_highlights.remove(&TypeId::of::<T>())
18596    }
18597
18598    pub fn insert_gutter_highlight<T: 'static>(
18599        &mut self,
18600        range: Range<Anchor>,
18601        color_fetcher: fn(&App) -> Hsla,
18602        cx: &mut Context<Self>,
18603    ) {
18604        let snapshot = self.buffer().read(cx).snapshot(cx);
18605        let mut highlights = self
18606            .gutter_highlights
18607            .remove(&TypeId::of::<T>())
18608            .map(|(_, highlights)| highlights)
18609            .unwrap_or_default();
18610        let ix = highlights.binary_search_by(|highlight| {
18611            Ordering::Equal
18612                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18613                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18614        });
18615        if let Err(ix) = ix {
18616            highlights.insert(ix, range);
18617        }
18618        self.gutter_highlights
18619            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18620    }
18621
18622    pub fn remove_gutter_highlights<T: 'static>(
18623        &mut self,
18624        ranges_to_remove: Vec<Range<Anchor>>,
18625        cx: &mut Context<Self>,
18626    ) {
18627        let snapshot = self.buffer().read(cx).snapshot(cx);
18628        let Some((color_fetcher, mut gutter_highlights)) =
18629            self.gutter_highlights.remove(&TypeId::of::<T>())
18630        else {
18631            return;
18632        };
18633        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18634        gutter_highlights.retain(|highlight| {
18635            while let Some(range_to_remove) = ranges_to_remove.peek() {
18636                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18637                    Ordering::Less | Ordering::Equal => {
18638                        ranges_to_remove.next();
18639                    }
18640                    Ordering::Greater => {
18641                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18642                            Ordering::Less | Ordering::Equal => {
18643                                return false;
18644                            }
18645                            Ordering::Greater => break,
18646                        }
18647                    }
18648                }
18649            }
18650
18651            true
18652        });
18653        self.gutter_highlights
18654            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18655    }
18656
18657    #[cfg(feature = "test-support")]
18658    pub fn all_text_background_highlights(
18659        &self,
18660        window: &mut Window,
18661        cx: &mut Context<Self>,
18662    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18663        let snapshot = self.snapshot(window, cx);
18664        let buffer = &snapshot.buffer_snapshot;
18665        let start = buffer.anchor_before(0);
18666        let end = buffer.anchor_after(buffer.len());
18667        let theme = cx.theme();
18668        self.background_highlights_in_range(start..end, &snapshot, theme)
18669    }
18670
18671    #[cfg(feature = "test-support")]
18672    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18673        let snapshot = self.buffer().read(cx).snapshot(cx);
18674
18675        let highlights = self
18676            .background_highlights
18677            .get(&TypeId::of::<items::BufferSearchHighlights>());
18678
18679        if let Some(highlights) = highlights {
18680            highlights
18681                .iter()
18682                .map(|highlight| {
18683                    highlight.range.start.to_point(&snapshot)
18684                        ..highlight.range.end.to_point(&snapshot)
18685                })
18686                .collect_vec()
18687        } else {
18688            vec![]
18689        }
18690    }
18691
18692    fn document_highlights_for_position<'a>(
18693        &'a self,
18694        position: Anchor,
18695        buffer: &'a MultiBufferSnapshot,
18696    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18697        let read_highlights = self
18698            .background_highlights
18699            .get(&TypeId::of::<DocumentHighlightRead>());
18700        let write_highlights = self
18701            .background_highlights
18702            .get(&TypeId::of::<DocumentHighlightWrite>());
18703        let left_position = position.bias_left(buffer);
18704        let right_position = position.bias_right(buffer);
18705        read_highlights
18706            .into_iter()
18707            .chain(write_highlights)
18708            .flat_map(move |highlights| {
18709                let start_ix = match highlights.binary_search_by(|probe| {
18710                    let cmp = probe.range.end.cmp(&left_position, buffer);
18711                    if cmp.is_ge() {
18712                        Ordering::Greater
18713                    } else {
18714                        Ordering::Less
18715                    }
18716                }) {
18717                    Ok(i) | Err(i) => i,
18718                };
18719
18720                highlights[start_ix..]
18721                    .iter()
18722                    .take_while(move |highlight| {
18723                        highlight.range.start.cmp(&right_position, buffer).is_le()
18724                    })
18725                    .map(|highlight| &highlight.range)
18726            })
18727    }
18728
18729    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18730        self.background_highlights
18731            .get(&TypeId::of::<T>())
18732            .map_or(false, |highlights| !highlights.is_empty())
18733    }
18734
18735    pub fn background_highlights_in_range(
18736        &self,
18737        search_range: Range<Anchor>,
18738        display_snapshot: &DisplaySnapshot,
18739        theme: &Theme,
18740    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18741        let mut results = Vec::new();
18742        for highlights in self.background_highlights.values() {
18743            let start_ix = match highlights.binary_search_by(|probe| {
18744                let cmp = probe
18745                    .range
18746                    .end
18747                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18748                if cmp.is_gt() {
18749                    Ordering::Greater
18750                } else {
18751                    Ordering::Less
18752                }
18753            }) {
18754                Ok(i) | Err(i) => i,
18755            };
18756            for highlight in &highlights[start_ix..] {
18757                if highlight
18758                    .range
18759                    .start
18760                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18761                    .is_ge()
18762                {
18763                    break;
18764                }
18765
18766                let start = highlight.range.start.to_display_point(display_snapshot);
18767                let end = highlight.range.end.to_display_point(display_snapshot);
18768                let color = (highlight.color_fetcher)(theme);
18769                results.push((start..end, color))
18770            }
18771        }
18772        results
18773    }
18774
18775    pub fn background_highlight_row_ranges<T: 'static>(
18776        &self,
18777        search_range: Range<Anchor>,
18778        display_snapshot: &DisplaySnapshot,
18779        count: usize,
18780    ) -> Vec<RangeInclusive<DisplayPoint>> {
18781        let mut results = Vec::new();
18782        let Some(highlights) = self.background_highlights.get(&TypeId::of::<T>()) else {
18783            return vec![];
18784        };
18785
18786        let start_ix = match highlights.binary_search_by(|probe| {
18787            let cmp = probe
18788                .range
18789                .end
18790                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18791            if cmp.is_gt() {
18792                Ordering::Greater
18793            } else {
18794                Ordering::Less
18795            }
18796        }) {
18797            Ok(i) | Err(i) => i,
18798        };
18799        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18800            if let (Some(start_display), Some(end_display)) = (start, end) {
18801                results.push(
18802                    start_display.to_display_point(display_snapshot)
18803                        ..=end_display.to_display_point(display_snapshot),
18804                );
18805            }
18806        };
18807        let mut start_row: Option<Point> = None;
18808        let mut end_row: Option<Point> = None;
18809        if highlights.len() > count {
18810            return Vec::new();
18811        }
18812        for highlight in &highlights[start_ix..] {
18813            if highlight
18814                .range
18815                .start
18816                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18817                .is_ge()
18818            {
18819                break;
18820            }
18821            let end = highlight
18822                .range
18823                .end
18824                .to_point(&display_snapshot.buffer_snapshot);
18825            if let Some(current_row) = &end_row {
18826                if end.row == current_row.row {
18827                    continue;
18828                }
18829            }
18830            let start = highlight
18831                .range
18832                .start
18833                .to_point(&display_snapshot.buffer_snapshot);
18834            if start_row.is_none() {
18835                assert_eq!(end_row, None);
18836                start_row = Some(start);
18837                end_row = Some(end);
18838                continue;
18839            }
18840            if let Some(current_end) = end_row.as_mut() {
18841                if start.row > current_end.row + 1 {
18842                    push_region(start_row, end_row);
18843                    start_row = Some(start);
18844                    end_row = Some(end);
18845                } else {
18846                    // Merge two hunks.
18847                    *current_end = end;
18848                }
18849            } else {
18850                unreachable!();
18851            }
18852        }
18853        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18854        push_region(start_row, end_row);
18855        results
18856    }
18857
18858    pub fn gutter_highlights_in_range(
18859        &self,
18860        search_range: Range<Anchor>,
18861        display_snapshot: &DisplaySnapshot,
18862        cx: &App,
18863    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18864        let mut results = Vec::new();
18865        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18866            let color = color_fetcher(cx);
18867            let start_ix = match ranges.binary_search_by(|probe| {
18868                let cmp = probe
18869                    .end
18870                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18871                if cmp.is_gt() {
18872                    Ordering::Greater
18873                } else {
18874                    Ordering::Less
18875                }
18876            }) {
18877                Ok(i) | Err(i) => i,
18878            };
18879            for range in &ranges[start_ix..] {
18880                if range
18881                    .start
18882                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18883                    .is_ge()
18884                {
18885                    break;
18886                }
18887
18888                let start = range.start.to_display_point(display_snapshot);
18889                let end = range.end.to_display_point(display_snapshot);
18890                results.push((start..end, color))
18891            }
18892        }
18893        results
18894    }
18895
18896    /// Get the text ranges corresponding to the redaction query
18897    pub fn redacted_ranges(
18898        &self,
18899        search_range: Range<Anchor>,
18900        display_snapshot: &DisplaySnapshot,
18901        cx: &App,
18902    ) -> Vec<Range<DisplayPoint>> {
18903        display_snapshot
18904            .buffer_snapshot
18905            .redacted_ranges(search_range, |file| {
18906                if let Some(file) = file {
18907                    file.is_private()
18908                        && EditorSettings::get(
18909                            Some(SettingsLocation {
18910                                worktree_id: file.worktree_id(cx),
18911                                path: file.path().as_ref(),
18912                            }),
18913                            cx,
18914                        )
18915                        .redact_private_values
18916                } else {
18917                    false
18918                }
18919            })
18920            .map(|range| {
18921                range.start.to_display_point(display_snapshot)
18922                    ..range.end.to_display_point(display_snapshot)
18923            })
18924            .collect()
18925    }
18926
18927    pub fn highlight_text<T: 'static>(
18928        &mut self,
18929        ranges: Vec<(Range<Anchor>, HighlightStyle)>,
18930        cx: &mut Context<Self>,
18931    ) {
18932        self.display_map
18933            .update(cx, |map, _| map.highlight_text(TypeId::of::<T>(), ranges));
18934        cx.notify();
18935    }
18936
18937    pub(crate) fn highlight_inlays<T: 'static>(
18938        &mut self,
18939        highlights: Vec<InlayHighlight>,
18940        style: HighlightStyle,
18941        cx: &mut Context<Self>,
18942    ) {
18943        self.display_map.update(cx, |map, _| {
18944            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18945        });
18946        cx.notify();
18947    }
18948
18949    pub fn text_highlights<'a, T: 'static>(
18950        &'a self,
18951        cx: &'a App,
18952    ) -> Option<&'a [(Range<Anchor>, HighlightStyle)]> {
18953        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18954    }
18955
18956    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18957        let cleared = self
18958            .display_map
18959            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18960        if cleared {
18961            cx.notify();
18962        }
18963    }
18964
18965    pub fn remove_text_highlights<T: 'static>(
18966        &mut self,
18967        cx: &mut Context<Self>,
18968    ) -> Option<Vec<(Range<Anchor>, HighlightStyle)>> {
18969        self.display_map
18970            .update(cx, |map, _| map.remove_text_highlights(TypeId::of::<T>()))
18971    }
18972
18973    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18974        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18975            && self.focus_handle.is_focused(window)
18976    }
18977
18978    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18979        self.show_cursor_when_unfocused = is_enabled;
18980        cx.notify();
18981    }
18982
18983    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18984        cx.notify();
18985    }
18986
18987    fn on_debug_session_event(
18988        &mut self,
18989        _session: Entity<Session>,
18990        event: &SessionEvent,
18991        cx: &mut Context<Self>,
18992    ) {
18993        match event {
18994            SessionEvent::InvalidateInlineValue => {
18995                self.refresh_inline_values(cx);
18996            }
18997            _ => {}
18998        }
18999    }
19000
19001    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19002        let Some(project) = self.project.clone() else {
19003            return;
19004        };
19005
19006        if !self.inline_value_cache.enabled {
19007            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19008            self.splice_inlays(&inlays, Vec::new(), cx);
19009            return;
19010        }
19011
19012        let current_execution_position = self
19013            .highlighted_rows
19014            .get(&TypeId::of::<ActiveDebugLine>())
19015            .and_then(|lines| lines.last().map(|line| line.range.start));
19016
19017        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19018            let inline_values = editor
19019                .update(cx, |editor, cx| {
19020                    let Some(current_execution_position) = current_execution_position else {
19021                        return Some(Task::ready(Ok(Vec::new())));
19022                    };
19023
19024                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19025                        let snapshot = buffer.snapshot(cx);
19026
19027                        let excerpt = snapshot.excerpt_containing(
19028                            current_execution_position..current_execution_position,
19029                        )?;
19030
19031                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19032                    })?;
19033
19034                    let range =
19035                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19036
19037                    project.inline_values(buffer, range, cx)
19038                })
19039                .ok()
19040                .flatten()?
19041                .await
19042                .context("refreshing debugger inlays")
19043                .log_err()?;
19044
19045            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19046
19047            for (buffer_id, inline_value) in inline_values
19048                .into_iter()
19049                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19050            {
19051                buffer_inline_values
19052                    .entry(buffer_id)
19053                    .or_default()
19054                    .push(inline_value);
19055            }
19056
19057            editor
19058                .update(cx, |editor, cx| {
19059                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19060                    let mut new_inlays = Vec::default();
19061
19062                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19063                        let buffer_id = buffer_snapshot.remote_id();
19064                        buffer_inline_values
19065                            .get(&buffer_id)
19066                            .into_iter()
19067                            .flatten()
19068                            .for_each(|hint| {
19069                                let inlay = Inlay::debugger_hint(
19070                                    post_inc(&mut editor.next_inlay_id),
19071                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19072                                    hint.text(),
19073                                );
19074
19075                                new_inlays.push(inlay);
19076                            });
19077                    }
19078
19079                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19080                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19081
19082                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19083                })
19084                .ok()?;
19085            Some(())
19086        });
19087    }
19088
19089    fn on_buffer_event(
19090        &mut self,
19091        multibuffer: &Entity<MultiBuffer>,
19092        event: &multi_buffer::Event,
19093        window: &mut Window,
19094        cx: &mut Context<Self>,
19095    ) {
19096        match event {
19097            multi_buffer::Event::Edited {
19098                singleton_buffer_edited,
19099                edited_buffer,
19100            } => {
19101                self.scrollbar_marker_state.dirty = true;
19102                self.active_indent_guides_state.dirty = true;
19103                self.refresh_active_diagnostics(cx);
19104                self.refresh_code_actions(window, cx);
19105                self.refresh_selected_text_highlights(true, window, cx);
19106                refresh_matching_bracket_highlights(self, window, cx);
19107                if self.has_active_inline_completion() {
19108                    self.update_visible_inline_completion(window, cx);
19109                }
19110                if let Some(project) = self.project.as_ref() {
19111                    if let Some(edited_buffer) = edited_buffer {
19112                        project.update(cx, |project, cx| {
19113                            self.registered_buffers
19114                                .entry(edited_buffer.read(cx).remote_id())
19115                                .or_insert_with(|| {
19116                                    project
19117                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19118                                });
19119                        });
19120                        if edited_buffer.read(cx).file().is_some() {
19121                            self.pull_diagnostics(
19122                                Some(edited_buffer.read(cx).remote_id()),
19123                                window,
19124                                cx,
19125                            );
19126                        }
19127                    }
19128                }
19129                cx.emit(EditorEvent::BufferEdited);
19130                cx.emit(SearchEvent::MatchesInvalidated);
19131                if *singleton_buffer_edited {
19132                    if let Some(buffer) = edited_buffer {
19133                        if buffer.read(cx).file().is_none() {
19134                            cx.emit(EditorEvent::TitleChanged);
19135                        }
19136                    }
19137                    if let Some(project) = &self.project {
19138                        #[allow(clippy::mutable_key_type)]
19139                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19140                            multibuffer
19141                                .all_buffers()
19142                                .into_iter()
19143                                .filter_map(|buffer| {
19144                                    buffer.update(cx, |buffer, cx| {
19145                                        let language = buffer.language()?;
19146                                        let should_discard = project.update(cx, |project, cx| {
19147                                            project.is_local()
19148                                                && !project.has_language_servers_for(buffer, cx)
19149                                        });
19150                                        should_discard.not().then_some(language.clone())
19151                                    })
19152                                })
19153                                .collect::<HashSet<_>>()
19154                        });
19155                        if !languages_affected.is_empty() {
19156                            self.refresh_inlay_hints(
19157                                InlayHintRefreshReason::BufferEdited(languages_affected),
19158                                cx,
19159                            );
19160                        }
19161                    }
19162                }
19163
19164                let Some(project) = &self.project else { return };
19165                let (telemetry, is_via_ssh) = {
19166                    let project = project.read(cx);
19167                    let telemetry = project.client().telemetry().clone();
19168                    let is_via_ssh = project.is_via_ssh();
19169                    (telemetry, is_via_ssh)
19170                };
19171                refresh_linked_ranges(self, window, cx);
19172                telemetry.log_edit_event("editor", is_via_ssh);
19173            }
19174            multi_buffer::Event::ExcerptsAdded {
19175                buffer,
19176                predecessor,
19177                excerpts,
19178            } => {
19179                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19180                let buffer_id = buffer.read(cx).remote_id();
19181                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19182                    if let Some(project) = &self.project {
19183                        update_uncommitted_diff_for_buffer(
19184                            cx.entity(),
19185                            project,
19186                            [buffer.clone()],
19187                            self.buffer.clone(),
19188                            cx,
19189                        )
19190                        .detach();
19191                    }
19192                }
19193                cx.emit(EditorEvent::ExcerptsAdded {
19194                    buffer: buffer.clone(),
19195                    predecessor: *predecessor,
19196                    excerpts: excerpts.clone(),
19197                });
19198                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19199            }
19200            multi_buffer::Event::ExcerptsRemoved {
19201                ids,
19202                removed_buffer_ids,
19203            } => {
19204                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19205                let buffer = self.buffer.read(cx);
19206                self.registered_buffers
19207                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19208                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19209                cx.emit(EditorEvent::ExcerptsRemoved {
19210                    ids: ids.clone(),
19211                    removed_buffer_ids: removed_buffer_ids.clone(),
19212                })
19213            }
19214            multi_buffer::Event::ExcerptsEdited {
19215                excerpt_ids,
19216                buffer_ids,
19217            } => {
19218                self.display_map.update(cx, |map, cx| {
19219                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19220                });
19221                cx.emit(EditorEvent::ExcerptsEdited {
19222                    ids: excerpt_ids.clone(),
19223                })
19224            }
19225            multi_buffer::Event::ExcerptsExpanded { ids } => {
19226                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19227                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19228            }
19229            multi_buffer::Event::Reparsed(buffer_id) => {
19230                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19231                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19232
19233                cx.emit(EditorEvent::Reparsed(*buffer_id));
19234            }
19235            multi_buffer::Event::DiffHunksToggled => {
19236                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19237            }
19238            multi_buffer::Event::LanguageChanged(buffer_id) => {
19239                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19240                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19241                cx.emit(EditorEvent::Reparsed(*buffer_id));
19242                cx.notify();
19243            }
19244            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19245            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19246            multi_buffer::Event::FileHandleChanged
19247            | multi_buffer::Event::Reloaded
19248            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19249            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19250            multi_buffer::Event::DiagnosticsUpdated => {
19251                self.update_diagnostics_state(window, cx);
19252            }
19253            _ => {}
19254        };
19255    }
19256
19257    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19258        self.refresh_active_diagnostics(cx);
19259        self.refresh_inline_diagnostics(true, window, cx);
19260        self.scrollbar_marker_state.dirty = true;
19261        cx.notify();
19262    }
19263
19264    pub fn start_temporary_diff_override(&mut self) {
19265        self.load_diff_task.take();
19266        self.temporary_diff_override = true;
19267    }
19268
19269    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19270        self.temporary_diff_override = false;
19271        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19272        self.buffer.update(cx, |buffer, cx| {
19273            buffer.set_all_diff_hunks_collapsed(cx);
19274        });
19275
19276        if let Some(project) = self.project.clone() {
19277            self.load_diff_task = Some(
19278                update_uncommitted_diff_for_buffer(
19279                    cx.entity(),
19280                    &project,
19281                    self.buffer.read(cx).all_buffers(),
19282                    self.buffer.clone(),
19283                    cx,
19284                )
19285                .shared(),
19286            );
19287        }
19288    }
19289
19290    fn on_display_map_changed(
19291        &mut self,
19292        _: Entity<DisplayMap>,
19293        _: &mut Window,
19294        cx: &mut Context<Self>,
19295    ) {
19296        cx.notify();
19297    }
19298
19299    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19300        let new_severity = if self.diagnostics_enabled() {
19301            EditorSettings::get_global(cx)
19302                .diagnostics_max_severity
19303                .unwrap_or(DiagnosticSeverity::Hint)
19304        } else {
19305            DiagnosticSeverity::Off
19306        };
19307        self.set_max_diagnostics_severity(new_severity, cx);
19308        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19309        self.update_edit_prediction_settings(cx);
19310        self.refresh_inline_completion(true, false, window, cx);
19311        self.refresh_inlay_hints(
19312            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19313                self.selections.newest_anchor().head(),
19314                &self.buffer.read(cx).snapshot(cx),
19315                cx,
19316            )),
19317            cx,
19318        );
19319
19320        let old_cursor_shape = self.cursor_shape;
19321
19322        {
19323            let editor_settings = EditorSettings::get_global(cx);
19324            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19325            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19326            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19327            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19328            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19329        }
19330
19331        if old_cursor_shape != self.cursor_shape {
19332            cx.emit(EditorEvent::CursorShapeChanged);
19333        }
19334
19335        let project_settings = ProjectSettings::get_global(cx);
19336        self.serialize_dirty_buffers =
19337            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19338
19339        if self.mode.is_full() {
19340            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19341            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19342            if self.show_inline_diagnostics != show_inline_diagnostics {
19343                self.show_inline_diagnostics = show_inline_diagnostics;
19344                self.refresh_inline_diagnostics(false, window, cx);
19345            }
19346
19347            if self.git_blame_inline_enabled != inline_blame_enabled {
19348                self.toggle_git_blame_inline_internal(false, window, cx);
19349            }
19350
19351            let minimap_settings = EditorSettings::get_global(cx).minimap;
19352            if self.minimap_visibility != MinimapVisibility::Disabled {
19353                if self.minimap_visibility.settings_visibility()
19354                    != minimap_settings.minimap_enabled()
19355                {
19356                    self.set_minimap_visibility(
19357                        MinimapVisibility::for_mode(self.mode(), cx),
19358                        window,
19359                        cx,
19360                    );
19361                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19362                    minimap_entity.update(cx, |minimap_editor, cx| {
19363                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19364                    })
19365                }
19366            }
19367        }
19368
19369        cx.notify();
19370    }
19371
19372    pub fn set_searchable(&mut self, searchable: bool) {
19373        self.searchable = searchable;
19374    }
19375
19376    pub fn searchable(&self) -> bool {
19377        self.searchable
19378    }
19379
19380    fn open_proposed_changes_editor(
19381        &mut self,
19382        _: &OpenProposedChangesEditor,
19383        window: &mut Window,
19384        cx: &mut Context<Self>,
19385    ) {
19386        let Some(workspace) = self.workspace() else {
19387            cx.propagate();
19388            return;
19389        };
19390
19391        let selections = self.selections.all::<usize>(cx);
19392        let multi_buffer = self.buffer.read(cx);
19393        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19394        let mut new_selections_by_buffer = HashMap::default();
19395        for selection in selections {
19396            for (buffer, range, _) in
19397                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19398            {
19399                let mut range = range.to_point(buffer);
19400                range.start.column = 0;
19401                range.end.column = buffer.line_len(range.end.row);
19402                new_selections_by_buffer
19403                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19404                    .or_insert(Vec::new())
19405                    .push(range)
19406            }
19407        }
19408
19409        let proposed_changes_buffers = new_selections_by_buffer
19410            .into_iter()
19411            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19412            .collect::<Vec<_>>();
19413        let proposed_changes_editor = cx.new(|cx| {
19414            ProposedChangesEditor::new(
19415                "Proposed changes",
19416                proposed_changes_buffers,
19417                self.project.clone(),
19418                window,
19419                cx,
19420            )
19421        });
19422
19423        window.defer(cx, move |window, cx| {
19424            workspace.update(cx, |workspace, cx| {
19425                workspace.active_pane().update(cx, |pane, cx| {
19426                    pane.add_item(
19427                        Box::new(proposed_changes_editor),
19428                        true,
19429                        true,
19430                        None,
19431                        window,
19432                        cx,
19433                    );
19434                });
19435            });
19436        });
19437    }
19438
19439    pub fn open_excerpts_in_split(
19440        &mut self,
19441        _: &OpenExcerptsSplit,
19442        window: &mut Window,
19443        cx: &mut Context<Self>,
19444    ) {
19445        self.open_excerpts_common(None, true, window, cx)
19446    }
19447
19448    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19449        self.open_excerpts_common(None, false, window, cx)
19450    }
19451
19452    fn open_excerpts_common(
19453        &mut self,
19454        jump_data: Option<JumpData>,
19455        split: bool,
19456        window: &mut Window,
19457        cx: &mut Context<Self>,
19458    ) {
19459        let Some(workspace) = self.workspace() else {
19460            cx.propagate();
19461            return;
19462        };
19463
19464        if self.buffer.read(cx).is_singleton() {
19465            cx.propagate();
19466            return;
19467        }
19468
19469        let mut new_selections_by_buffer = HashMap::default();
19470        match &jump_data {
19471            Some(JumpData::MultiBufferPoint {
19472                excerpt_id,
19473                position,
19474                anchor,
19475                line_offset_from_top,
19476            }) => {
19477                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19478                if let Some(buffer) = multi_buffer_snapshot
19479                    .buffer_id_for_excerpt(*excerpt_id)
19480                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19481                {
19482                    let buffer_snapshot = buffer.read(cx).snapshot();
19483                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19484                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19485                    } else {
19486                        buffer_snapshot.clip_point(*position, Bias::Left)
19487                    };
19488                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19489                    new_selections_by_buffer.insert(
19490                        buffer,
19491                        (
19492                            vec![jump_to_offset..jump_to_offset],
19493                            Some(*line_offset_from_top),
19494                        ),
19495                    );
19496                }
19497            }
19498            Some(JumpData::MultiBufferRow {
19499                row,
19500                line_offset_from_top,
19501            }) => {
19502                let point = MultiBufferPoint::new(row.0, 0);
19503                if let Some((buffer, buffer_point, _)) =
19504                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19505                {
19506                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19507                    new_selections_by_buffer
19508                        .entry(buffer)
19509                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19510                        .0
19511                        .push(buffer_offset..buffer_offset)
19512                }
19513            }
19514            None => {
19515                let selections = self.selections.all::<usize>(cx);
19516                let multi_buffer = self.buffer.read(cx);
19517                for selection in selections {
19518                    for (snapshot, range, _, anchor) in multi_buffer
19519                        .snapshot(cx)
19520                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19521                    {
19522                        if let Some(anchor) = anchor {
19523                            // selection is in a deleted hunk
19524                            let Some(buffer_id) = anchor.buffer_id else {
19525                                continue;
19526                            };
19527                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19528                                continue;
19529                            };
19530                            let offset = text::ToOffset::to_offset(
19531                                &anchor.text_anchor,
19532                                &buffer_handle.read(cx).snapshot(),
19533                            );
19534                            let range = offset..offset;
19535                            new_selections_by_buffer
19536                                .entry(buffer_handle)
19537                                .or_insert((Vec::new(), None))
19538                                .0
19539                                .push(range)
19540                        } else {
19541                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19542                            else {
19543                                continue;
19544                            };
19545                            new_selections_by_buffer
19546                                .entry(buffer_handle)
19547                                .or_insert((Vec::new(), None))
19548                                .0
19549                                .push(range)
19550                        }
19551                    }
19552                }
19553            }
19554        }
19555
19556        new_selections_by_buffer
19557            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19558
19559        if new_selections_by_buffer.is_empty() {
19560            return;
19561        }
19562
19563        // We defer the pane interaction because we ourselves are a workspace item
19564        // and activating a new item causes the pane to call a method on us reentrantly,
19565        // which panics if we're on the stack.
19566        window.defer(cx, move |window, cx| {
19567            workspace.update(cx, |workspace, cx| {
19568                let pane = if split {
19569                    workspace.adjacent_pane(window, cx)
19570                } else {
19571                    workspace.active_pane().clone()
19572                };
19573
19574                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19575                    let editor = buffer
19576                        .read(cx)
19577                        .file()
19578                        .is_none()
19579                        .then(|| {
19580                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19581                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19582                            // Instead, we try to activate the existing editor in the pane first.
19583                            let (editor, pane_item_index) =
19584                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19585                                    let editor = item.downcast::<Editor>()?;
19586                                    let singleton_buffer =
19587                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19588                                    if singleton_buffer == buffer {
19589                                        Some((editor, i))
19590                                    } else {
19591                                        None
19592                                    }
19593                                })?;
19594                            pane.update(cx, |pane, cx| {
19595                                pane.activate_item(pane_item_index, true, true, window, cx)
19596                            });
19597                            Some(editor)
19598                        })
19599                        .flatten()
19600                        .unwrap_or_else(|| {
19601                            workspace.open_project_item::<Self>(
19602                                pane.clone(),
19603                                buffer,
19604                                true,
19605                                true,
19606                                window,
19607                                cx,
19608                            )
19609                        });
19610
19611                    editor.update(cx, |editor, cx| {
19612                        let autoscroll = match scroll_offset {
19613                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19614                            None => Autoscroll::newest(),
19615                        };
19616                        let nav_history = editor.nav_history.take();
19617                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19618                            s.select_ranges(ranges);
19619                        });
19620                        editor.nav_history = nav_history;
19621                    });
19622                }
19623            })
19624        });
19625    }
19626
19627    // For now, don't allow opening excerpts in buffers that aren't backed by
19628    // regular project files.
19629    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19630        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19631    }
19632
19633    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19634        let snapshot = self.buffer.read(cx).read(cx);
19635        let ranges = self.text_highlights::<InputComposition>(cx)?;
19636        Some(
19637            ranges
19638                .iter()
19639                .map(move |(range, _)| {
19640                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19641                })
19642                .collect(),
19643        )
19644    }
19645
19646    fn selection_replacement_ranges(
19647        &self,
19648        range: Range<OffsetUtf16>,
19649        cx: &mut App,
19650    ) -> Vec<Range<OffsetUtf16>> {
19651        let selections = self.selections.all::<OffsetUtf16>(cx);
19652        let newest_selection = selections
19653            .iter()
19654            .max_by_key(|selection| selection.id)
19655            .unwrap();
19656        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19657        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19658        let snapshot = self.buffer.read(cx).read(cx);
19659        selections
19660            .into_iter()
19661            .map(|mut selection| {
19662                selection.start.0 =
19663                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19664                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19665                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19666                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19667            })
19668            .collect()
19669    }
19670
19671    fn report_editor_event(
19672        &self,
19673        event_type: &'static str,
19674        file_extension: Option<String>,
19675        cx: &App,
19676    ) {
19677        if cfg!(any(test, feature = "test-support")) {
19678            return;
19679        }
19680
19681        let Some(project) = &self.project else { return };
19682
19683        // If None, we are in a file without an extension
19684        let file = self
19685            .buffer
19686            .read(cx)
19687            .as_singleton()
19688            .and_then(|b| b.read(cx).file());
19689        let file_extension = file_extension.or(file
19690            .as_ref()
19691            .and_then(|file| Path::new(file.file_name(cx)).extension())
19692            .and_then(|e| e.to_str())
19693            .map(|a| a.to_string()));
19694
19695        let vim_mode = vim_enabled(cx);
19696
19697        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19698        let copilot_enabled = edit_predictions_provider
19699            == language::language_settings::EditPredictionProvider::Copilot;
19700        let copilot_enabled_for_language = self
19701            .buffer
19702            .read(cx)
19703            .language_settings(cx)
19704            .show_edit_predictions;
19705
19706        let project = project.read(cx);
19707        telemetry::event!(
19708            event_type,
19709            file_extension,
19710            vim_mode,
19711            copilot_enabled,
19712            copilot_enabled_for_language,
19713            edit_predictions_provider,
19714            is_via_ssh = project.is_via_ssh(),
19715        );
19716    }
19717
19718    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19719    /// with each line being an array of {text, highlight} objects.
19720    fn copy_highlight_json(
19721        &mut self,
19722        _: &CopyHighlightJson,
19723        window: &mut Window,
19724        cx: &mut Context<Self>,
19725    ) {
19726        #[derive(Serialize)]
19727        struct Chunk<'a> {
19728            text: String,
19729            highlight: Option<&'a str>,
19730        }
19731
19732        let snapshot = self.buffer.read(cx).snapshot(cx);
19733        let range = self
19734            .selected_text_range(false, window, cx)
19735            .and_then(|selection| {
19736                if selection.range.is_empty() {
19737                    None
19738                } else {
19739                    Some(selection.range)
19740                }
19741            })
19742            .unwrap_or_else(|| 0..snapshot.len());
19743
19744        let chunks = snapshot.chunks(range, true);
19745        let mut lines = Vec::new();
19746        let mut line: VecDeque<Chunk> = VecDeque::new();
19747
19748        let Some(style) = self.style.as_ref() else {
19749            return;
19750        };
19751
19752        for chunk in chunks {
19753            let highlight = chunk
19754                .syntax_highlight_id
19755                .and_then(|id| id.name(&style.syntax));
19756            let mut chunk_lines = chunk.text.split('\n').peekable();
19757            while let Some(text) = chunk_lines.next() {
19758                let mut merged_with_last_token = false;
19759                if let Some(last_token) = line.back_mut() {
19760                    if last_token.highlight == highlight {
19761                        last_token.text.push_str(text);
19762                        merged_with_last_token = true;
19763                    }
19764                }
19765
19766                if !merged_with_last_token {
19767                    line.push_back(Chunk {
19768                        text: text.into(),
19769                        highlight,
19770                    });
19771                }
19772
19773                if chunk_lines.peek().is_some() {
19774                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19775                        line.pop_front();
19776                    }
19777                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19778                        line.pop_back();
19779                    }
19780
19781                    lines.push(mem::take(&mut line));
19782                }
19783            }
19784        }
19785
19786        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19787            return;
19788        };
19789        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19790    }
19791
19792    pub fn open_context_menu(
19793        &mut self,
19794        _: &OpenContextMenu,
19795        window: &mut Window,
19796        cx: &mut Context<Self>,
19797    ) {
19798        self.request_autoscroll(Autoscroll::newest(), cx);
19799        let position = self.selections.newest_display(cx).start;
19800        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19801    }
19802
19803    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19804        &self.inlay_hint_cache
19805    }
19806
19807    pub fn replay_insert_event(
19808        &mut self,
19809        text: &str,
19810        relative_utf16_range: Option<Range<isize>>,
19811        window: &mut Window,
19812        cx: &mut Context<Self>,
19813    ) {
19814        if !self.input_enabled {
19815            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19816            return;
19817        }
19818        if let Some(relative_utf16_range) = relative_utf16_range {
19819            let selections = self.selections.all::<OffsetUtf16>(cx);
19820            self.change_selections(None, window, cx, |s| {
19821                let new_ranges = selections.into_iter().map(|range| {
19822                    let start = OffsetUtf16(
19823                        range
19824                            .head()
19825                            .0
19826                            .saturating_add_signed(relative_utf16_range.start),
19827                    );
19828                    let end = OffsetUtf16(
19829                        range
19830                            .head()
19831                            .0
19832                            .saturating_add_signed(relative_utf16_range.end),
19833                    );
19834                    start..end
19835                });
19836                s.select_ranges(new_ranges);
19837            });
19838        }
19839
19840        self.handle_input(text, window, cx);
19841    }
19842
19843    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19844        let Some(provider) = self.semantics_provider.as_ref() else {
19845            return false;
19846        };
19847
19848        let mut supports = false;
19849        self.buffer().update(cx, |this, cx| {
19850            this.for_each_buffer(|buffer| {
19851                supports |= provider.supports_inlay_hints(buffer, cx);
19852            });
19853        });
19854
19855        supports
19856    }
19857
19858    pub fn is_focused(&self, window: &Window) -> bool {
19859        self.focus_handle.is_focused(window)
19860    }
19861
19862    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19863        cx.emit(EditorEvent::Focused);
19864
19865        if let Some(descendant) = self
19866            .last_focused_descendant
19867            .take()
19868            .and_then(|descendant| descendant.upgrade())
19869        {
19870            window.focus(&descendant);
19871        } else {
19872            if let Some(blame) = self.blame.as_ref() {
19873                blame.update(cx, GitBlame::focus)
19874            }
19875
19876            self.blink_manager.update(cx, BlinkManager::enable);
19877            self.show_cursor_names(window, cx);
19878            self.buffer.update(cx, |buffer, cx| {
19879                buffer.finalize_last_transaction(cx);
19880                if self.leader_id.is_none() {
19881                    buffer.set_active_selections(
19882                        &self.selections.disjoint_anchors(),
19883                        self.selections.line_mode,
19884                        self.cursor_shape,
19885                        cx,
19886                    );
19887                }
19888            });
19889        }
19890    }
19891
19892    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19893        cx.emit(EditorEvent::FocusedIn)
19894    }
19895
19896    fn handle_focus_out(
19897        &mut self,
19898        event: FocusOutEvent,
19899        _window: &mut Window,
19900        cx: &mut Context<Self>,
19901    ) {
19902        if event.blurred != self.focus_handle {
19903            self.last_focused_descendant = Some(event.blurred);
19904        }
19905        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19906    }
19907
19908    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19909        self.blink_manager.update(cx, BlinkManager::disable);
19910        self.buffer
19911            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19912
19913        if let Some(blame) = self.blame.as_ref() {
19914            blame.update(cx, GitBlame::blur)
19915        }
19916        if !self.hover_state.focused(window, cx) {
19917            hide_hover(self, cx);
19918        }
19919        if !self
19920            .context_menu
19921            .borrow()
19922            .as_ref()
19923            .is_some_and(|context_menu| context_menu.focused(window, cx))
19924        {
19925            self.hide_context_menu(window, cx);
19926        }
19927        self.discard_inline_completion(false, cx);
19928        cx.emit(EditorEvent::Blurred);
19929        cx.notify();
19930    }
19931
19932    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19933        let mut pending: String = window
19934            .pending_input_keystrokes()
19935            .into_iter()
19936            .flatten()
19937            .filter_map(|keystroke| {
19938                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19939                    keystroke.key_char.clone()
19940                } else {
19941                    None
19942                }
19943            })
19944            .collect();
19945
19946        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19947            pending = "".to_string();
19948        }
19949
19950        let existing_pending = self.text_highlights::<PendingInput>(cx).map(|ranges| {
19951            ranges
19952                .iter()
19953                .map(|(range, _)| range.clone())
19954                .collect::<Vec<_>>()
19955        });
19956        if existing_pending.is_none() && pending.is_empty() {
19957            return;
19958        }
19959        let transaction =
19960            self.transact(window, cx, |this, window, cx| {
19961                let selections = this.selections.all::<usize>(cx);
19962                let edits = selections
19963                    .iter()
19964                    .map(|selection| (selection.end..selection.end, pending.clone()));
19965                this.edit(edits, cx);
19966                this.change_selections(None, window, cx, |s| {
19967                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19968                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19969                    }));
19970                });
19971                if let Some(existing_ranges) = existing_pending {
19972                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19973                    this.edit(edits, cx);
19974                }
19975            });
19976
19977        let snapshot = self.snapshot(window, cx);
19978        let ranges = self
19979            .selections
19980            .all::<usize>(cx)
19981            .into_iter()
19982            .map(|selection| {
19983                (
19984                    snapshot.buffer_snapshot.anchor_after(selection.end)
19985                        ..snapshot
19986                            .buffer_snapshot
19987                            .anchor_before(selection.end + pending.len()),
19988                    HighlightStyle {
19989                        underline: Some(UnderlineStyle {
19990                            thickness: px(1.),
19991                            color: None,
19992                            wavy: false,
19993                        }),
19994                        ..Default::default()
19995                    },
19996                )
19997            })
19998            .collect();
19999
20000        if pending.is_empty() {
20001            self.clear_highlights::<PendingInput>(cx);
20002        } else {
20003            self.highlight_text::<PendingInput>(ranges, cx);
20004        }
20005
20006        self.ime_transaction = self.ime_transaction.or(transaction);
20007        if let Some(transaction) = self.ime_transaction {
20008            self.buffer.update(cx, |buffer, cx| {
20009                buffer.group_until_transaction(transaction, cx);
20010            });
20011        }
20012
20013        if self.text_highlights::<PendingInput>(cx).is_none() {
20014            self.ime_transaction.take();
20015        }
20016    }
20017
20018    pub fn register_action_renderer(
20019        &mut self,
20020        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20021    ) -> Subscription {
20022        let id = self.next_editor_action_id.post_inc();
20023        self.editor_actions
20024            .borrow_mut()
20025            .insert(id, Box::new(listener));
20026
20027        let editor_actions = self.editor_actions.clone();
20028        Subscription::new(move || {
20029            editor_actions.borrow_mut().remove(&id);
20030        })
20031    }
20032
20033    pub fn register_action<A: Action>(
20034        &mut self,
20035        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20036    ) -> Subscription {
20037        let id = self.next_editor_action_id.post_inc();
20038        let listener = Arc::new(listener);
20039        self.editor_actions.borrow_mut().insert(
20040            id,
20041            Box::new(move |_, window, _| {
20042                let listener = listener.clone();
20043                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20044                    let action = action.downcast_ref().unwrap();
20045                    if phase == DispatchPhase::Bubble {
20046                        listener(action, window, cx)
20047                    }
20048                })
20049            }),
20050        );
20051
20052        let editor_actions = self.editor_actions.clone();
20053        Subscription::new(move || {
20054            editor_actions.borrow_mut().remove(&id);
20055        })
20056    }
20057
20058    pub fn file_header_size(&self) -> u32 {
20059        FILE_HEADER_HEIGHT
20060    }
20061
20062    pub fn restore(
20063        &mut self,
20064        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20065        window: &mut Window,
20066        cx: &mut Context<Self>,
20067    ) {
20068        let workspace = self.workspace();
20069        let project = self.project.as_ref();
20070        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20071            let mut tasks = Vec::new();
20072            for (buffer_id, changes) in revert_changes {
20073                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20074                    buffer.update(cx, |buffer, cx| {
20075                        buffer.edit(
20076                            changes
20077                                .into_iter()
20078                                .map(|(range, text)| (range, text.to_string())),
20079                            None,
20080                            cx,
20081                        );
20082                    });
20083
20084                    if let Some(project) =
20085                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20086                    {
20087                        project.update(cx, |project, cx| {
20088                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20089                        })
20090                    }
20091                }
20092            }
20093            tasks
20094        });
20095        cx.spawn_in(window, async move |_, cx| {
20096            for (buffer, task) in save_tasks {
20097                let result = task.await;
20098                if result.is_err() {
20099                    let Some(path) = buffer
20100                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20101                        .ok()
20102                    else {
20103                        continue;
20104                    };
20105                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20106                        let Some(task) = cx
20107                            .update_window_entity(&workspace, |workspace, window, cx| {
20108                                workspace
20109                                    .open_path_preview(path, None, false, false, false, window, cx)
20110                            })
20111                            .ok()
20112                        else {
20113                            continue;
20114                        };
20115                        task.await.log_err();
20116                    }
20117                }
20118            }
20119        })
20120        .detach();
20121        self.change_selections(None, window, cx, |selections| selections.refresh());
20122    }
20123
20124    pub fn to_pixel_point(
20125        &self,
20126        source: multi_buffer::Anchor,
20127        editor_snapshot: &EditorSnapshot,
20128        window: &mut Window,
20129    ) -> Option<gpui::Point<Pixels>> {
20130        let source_point = source.to_display_point(editor_snapshot);
20131        self.display_to_pixel_point(source_point, editor_snapshot, window)
20132    }
20133
20134    pub fn display_to_pixel_point(
20135        &self,
20136        source: DisplayPoint,
20137        editor_snapshot: &EditorSnapshot,
20138        window: &mut Window,
20139    ) -> Option<gpui::Point<Pixels>> {
20140        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20141        let text_layout_details = self.text_layout_details(window);
20142        let scroll_top = text_layout_details
20143            .scroll_anchor
20144            .scroll_position(editor_snapshot)
20145            .y;
20146
20147        if source.row().as_f32() < scroll_top.floor() {
20148            return None;
20149        }
20150        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20151        let source_y = line_height * (source.row().as_f32() - scroll_top);
20152        Some(gpui::Point::new(source_x, source_y))
20153    }
20154
20155    pub fn has_visible_completions_menu(&self) -> bool {
20156        !self.edit_prediction_preview_is_active()
20157            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20158                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20159            })
20160    }
20161
20162    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20163        if self.mode.is_minimap() {
20164            return;
20165        }
20166        self.addons
20167            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20168    }
20169
20170    pub fn unregister_addon<T: Addon>(&mut self) {
20171        self.addons.remove(&std::any::TypeId::of::<T>());
20172    }
20173
20174    pub fn addon<T: Addon>(&self) -> Option<&T> {
20175        let type_id = std::any::TypeId::of::<T>();
20176        self.addons
20177            .get(&type_id)
20178            .and_then(|item| item.to_any().downcast_ref::<T>())
20179    }
20180
20181    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20182        let type_id = std::any::TypeId::of::<T>();
20183        self.addons
20184            .get_mut(&type_id)
20185            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20186    }
20187
20188    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20189        let text_layout_details = self.text_layout_details(window);
20190        let style = &text_layout_details.editor_style;
20191        let font_id = window.text_system().resolve_font(&style.text.font());
20192        let font_size = style.text.font_size.to_pixels(window.rem_size());
20193        let line_height = style.text.line_height_in_pixels(window.rem_size());
20194        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20195
20196        gpui::Size::new(em_width, line_height)
20197    }
20198
20199    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20200        self.load_diff_task.clone()
20201    }
20202
20203    fn read_metadata_from_db(
20204        &mut self,
20205        item_id: u64,
20206        workspace_id: WorkspaceId,
20207        window: &mut Window,
20208        cx: &mut Context<Editor>,
20209    ) {
20210        if self.is_singleton(cx)
20211            && !self.mode.is_minimap()
20212            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20213        {
20214            let buffer_snapshot = OnceCell::new();
20215
20216            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20217                if !folds.is_empty() {
20218                    let snapshot =
20219                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20220                    self.fold_ranges(
20221                        folds
20222                            .into_iter()
20223                            .map(|(start, end)| {
20224                                snapshot.clip_offset(start, Bias::Left)
20225                                    ..snapshot.clip_offset(end, Bias::Right)
20226                            })
20227                            .collect(),
20228                        false,
20229                        window,
20230                        cx,
20231                    );
20232                }
20233            }
20234
20235            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20236                if !selections.is_empty() {
20237                    let snapshot =
20238                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20239                    // skip adding the initial selection to selection history
20240                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20241                    self.change_selections(None, window, cx, |s| {
20242                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20243                            snapshot.clip_offset(start, Bias::Left)
20244                                ..snapshot.clip_offset(end, Bias::Right)
20245                        }));
20246                    });
20247                    self.selection_history.mode = SelectionHistoryMode::Normal;
20248                }
20249            };
20250        }
20251
20252        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20253    }
20254}
20255
20256fn vim_enabled(cx: &App) -> bool {
20257    cx.global::<SettingsStore>()
20258        .raw_user_settings()
20259        .get("vim_mode")
20260        == Some(&serde_json::Value::Bool(true))
20261}
20262
20263fn process_completion_for_edit(
20264    completion: &Completion,
20265    intent: CompletionIntent,
20266    buffer: &Entity<Buffer>,
20267    cursor_position: &text::Anchor,
20268    cx: &mut Context<Editor>,
20269) -> CompletionEdit {
20270    let buffer = buffer.read(cx);
20271    let buffer_snapshot = buffer.snapshot();
20272    let (snippet, new_text) = if completion.is_snippet() {
20273        // Workaround for typescript language server issues so that methods don't expand within
20274        // strings and functions with type expressions. The previous point is used because the query
20275        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20276        let mut snippet_source = completion.new_text.clone();
20277        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20278        previous_point.column = previous_point.column.saturating_sub(1);
20279        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20280            if scope.prefers_label_for_snippet_in_completion() {
20281                if let Some(label) = completion.label() {
20282                    if matches!(
20283                        completion.kind(),
20284                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20285                    ) {
20286                        snippet_source = label;
20287                    }
20288                }
20289            }
20290        }
20291        match Snippet::parse(&snippet_source).log_err() {
20292            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20293            None => (None, completion.new_text.clone()),
20294        }
20295    } else {
20296        (None, completion.new_text.clone())
20297    };
20298
20299    let mut range_to_replace = {
20300        let replace_range = &completion.replace_range;
20301        if let CompletionSource::Lsp {
20302            insert_range: Some(insert_range),
20303            ..
20304        } = &completion.source
20305        {
20306            debug_assert_eq!(
20307                insert_range.start, replace_range.start,
20308                "insert_range and replace_range should start at the same position"
20309            );
20310            debug_assert!(
20311                insert_range
20312                    .start
20313                    .cmp(&cursor_position, &buffer_snapshot)
20314                    .is_le(),
20315                "insert_range should start before or at cursor position"
20316            );
20317            debug_assert!(
20318                replace_range
20319                    .start
20320                    .cmp(&cursor_position, &buffer_snapshot)
20321                    .is_le(),
20322                "replace_range should start before or at cursor position"
20323            );
20324            debug_assert!(
20325                insert_range
20326                    .end
20327                    .cmp(&cursor_position, &buffer_snapshot)
20328                    .is_le(),
20329                "insert_range should end before or at cursor position"
20330            );
20331
20332            let should_replace = match intent {
20333                CompletionIntent::CompleteWithInsert => false,
20334                CompletionIntent::CompleteWithReplace => true,
20335                CompletionIntent::Complete | CompletionIntent::Compose => {
20336                    let insert_mode =
20337                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20338                            .completions
20339                            .lsp_insert_mode;
20340                    match insert_mode {
20341                        LspInsertMode::Insert => false,
20342                        LspInsertMode::Replace => true,
20343                        LspInsertMode::ReplaceSubsequence => {
20344                            let mut text_to_replace = buffer.chars_for_range(
20345                                buffer.anchor_before(replace_range.start)
20346                                    ..buffer.anchor_after(replace_range.end),
20347                            );
20348                            let mut current_needle = text_to_replace.next();
20349                            for haystack_ch in completion.label.text.chars() {
20350                                if let Some(needle_ch) = current_needle {
20351                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20352                                        current_needle = text_to_replace.next();
20353                                    }
20354                                }
20355                            }
20356                            current_needle.is_none()
20357                        }
20358                        LspInsertMode::ReplaceSuffix => {
20359                            if replace_range
20360                                .end
20361                                .cmp(&cursor_position, &buffer_snapshot)
20362                                .is_gt()
20363                            {
20364                                let range_after_cursor = *cursor_position..replace_range.end;
20365                                let text_after_cursor = buffer
20366                                    .text_for_range(
20367                                        buffer.anchor_before(range_after_cursor.start)
20368                                            ..buffer.anchor_after(range_after_cursor.end),
20369                                    )
20370                                    .collect::<String>()
20371                                    .to_ascii_lowercase();
20372                                completion
20373                                    .label
20374                                    .text
20375                                    .to_ascii_lowercase()
20376                                    .ends_with(&text_after_cursor)
20377                            } else {
20378                                true
20379                            }
20380                        }
20381                    }
20382                }
20383            };
20384
20385            if should_replace {
20386                replace_range.clone()
20387            } else {
20388                insert_range.clone()
20389            }
20390        } else {
20391            replace_range.clone()
20392        }
20393    };
20394
20395    if range_to_replace
20396        .end
20397        .cmp(&cursor_position, &buffer_snapshot)
20398        .is_lt()
20399    {
20400        range_to_replace.end = *cursor_position;
20401    }
20402
20403    CompletionEdit {
20404        new_text,
20405        replace_range: range_to_replace.to_offset(&buffer),
20406        snippet,
20407    }
20408}
20409
20410struct CompletionEdit {
20411    new_text: String,
20412    replace_range: Range<usize>,
20413    snippet: Option<Snippet>,
20414}
20415
20416fn insert_extra_newline_brackets(
20417    buffer: &MultiBufferSnapshot,
20418    range: Range<usize>,
20419    language: &language::LanguageScope,
20420) -> bool {
20421    let leading_whitespace_len = buffer
20422        .reversed_chars_at(range.start)
20423        .take_while(|c| c.is_whitespace() && *c != '\n')
20424        .map(|c| c.len_utf8())
20425        .sum::<usize>();
20426    let trailing_whitespace_len = buffer
20427        .chars_at(range.end)
20428        .take_while(|c| c.is_whitespace() && *c != '\n')
20429        .map(|c| c.len_utf8())
20430        .sum::<usize>();
20431    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20432
20433    language.brackets().any(|(pair, enabled)| {
20434        let pair_start = pair.start.trim_end();
20435        let pair_end = pair.end.trim_start();
20436
20437        enabled
20438            && pair.newline
20439            && buffer.contains_str_at(range.end, pair_end)
20440            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20441    })
20442}
20443
20444fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20445    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20446        [(buffer, range, _)] => (*buffer, range.clone()),
20447        _ => return false,
20448    };
20449    let pair = {
20450        let mut result: Option<BracketMatch> = None;
20451
20452        for pair in buffer
20453            .all_bracket_ranges(range.clone())
20454            .filter(move |pair| {
20455                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20456            })
20457        {
20458            let len = pair.close_range.end - pair.open_range.start;
20459
20460            if let Some(existing) = &result {
20461                let existing_len = existing.close_range.end - existing.open_range.start;
20462                if len > existing_len {
20463                    continue;
20464                }
20465            }
20466
20467            result = Some(pair);
20468        }
20469
20470        result
20471    };
20472    let Some(pair) = pair else {
20473        return false;
20474    };
20475    pair.newline_only
20476        && buffer
20477            .chars_for_range(pair.open_range.end..range.start)
20478            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20479            .all(|c| c.is_whitespace() && c != '\n')
20480}
20481
20482fn update_uncommitted_diff_for_buffer(
20483    editor: Entity<Editor>,
20484    project: &Entity<Project>,
20485    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20486    buffer: Entity<MultiBuffer>,
20487    cx: &mut App,
20488) -> Task<()> {
20489    let mut tasks = Vec::new();
20490    project.update(cx, |project, cx| {
20491        for buffer in buffers {
20492            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20493                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20494            }
20495        }
20496    });
20497    cx.spawn(async move |cx| {
20498        let diffs = future::join_all(tasks).await;
20499        if editor
20500            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20501            .unwrap_or(false)
20502        {
20503            return;
20504        }
20505
20506        buffer
20507            .update(cx, |buffer, cx| {
20508                for diff in diffs.into_iter().flatten() {
20509                    buffer.add_diff(diff, cx);
20510                }
20511            })
20512            .ok();
20513    })
20514}
20515
20516fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20517    let tab_size = tab_size.get() as usize;
20518    let mut width = offset;
20519
20520    for ch in text.chars() {
20521        width += if ch == '\t' {
20522            tab_size - (width % tab_size)
20523        } else {
20524            1
20525        };
20526    }
20527
20528    width - offset
20529}
20530
20531#[cfg(test)]
20532mod tests {
20533    use super::*;
20534
20535    #[test]
20536    fn test_string_size_with_expanded_tabs() {
20537        let nz = |val| NonZeroU32::new(val).unwrap();
20538        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20539        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20540        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20541        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20542        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20543        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20544        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20545        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20546    }
20547}
20548
20549/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20550struct WordBreakingTokenizer<'a> {
20551    input: &'a str,
20552}
20553
20554impl<'a> WordBreakingTokenizer<'a> {
20555    fn new(input: &'a str) -> Self {
20556        Self { input }
20557    }
20558}
20559
20560fn is_char_ideographic(ch: char) -> bool {
20561    use unicode_script::Script::*;
20562    use unicode_script::UnicodeScript;
20563    matches!(ch.script(), Han | Tangut | Yi)
20564}
20565
20566fn is_grapheme_ideographic(text: &str) -> bool {
20567    text.chars().any(is_char_ideographic)
20568}
20569
20570fn is_grapheme_whitespace(text: &str) -> bool {
20571    text.chars().any(|x| x.is_whitespace())
20572}
20573
20574fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20575    text.chars().next().map_or(false, |ch| {
20576        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20577    })
20578}
20579
20580#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20581enum WordBreakToken<'a> {
20582    Word { token: &'a str, grapheme_len: usize },
20583    InlineWhitespace { token: &'a str, grapheme_len: usize },
20584    Newline,
20585}
20586
20587impl<'a> Iterator for WordBreakingTokenizer<'a> {
20588    /// Yields a span, the count of graphemes in the token, and whether it was
20589    /// whitespace. Note that it also breaks at word boundaries.
20590    type Item = WordBreakToken<'a>;
20591
20592    fn next(&mut self) -> Option<Self::Item> {
20593        use unicode_segmentation::UnicodeSegmentation;
20594        if self.input.is_empty() {
20595            return None;
20596        }
20597
20598        let mut iter = self.input.graphemes(true).peekable();
20599        let mut offset = 0;
20600        let mut grapheme_len = 0;
20601        if let Some(first_grapheme) = iter.next() {
20602            let is_newline = first_grapheme == "\n";
20603            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20604            offset += first_grapheme.len();
20605            grapheme_len += 1;
20606            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20607                if let Some(grapheme) = iter.peek().copied() {
20608                    if should_stay_with_preceding_ideograph(grapheme) {
20609                        offset += grapheme.len();
20610                        grapheme_len += 1;
20611                    }
20612                }
20613            } else {
20614                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20615                let mut next_word_bound = words.peek().copied();
20616                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20617                    next_word_bound = words.next();
20618                }
20619                while let Some(grapheme) = iter.peek().copied() {
20620                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20621                        break;
20622                    };
20623                    if is_grapheme_whitespace(grapheme) != is_whitespace
20624                        || (grapheme == "\n") != is_newline
20625                    {
20626                        break;
20627                    };
20628                    offset += grapheme.len();
20629                    grapheme_len += 1;
20630                    iter.next();
20631                }
20632            }
20633            let token = &self.input[..offset];
20634            self.input = &self.input[offset..];
20635            if token == "\n" {
20636                Some(WordBreakToken::Newline)
20637            } else if is_whitespace {
20638                Some(WordBreakToken::InlineWhitespace {
20639                    token,
20640                    grapheme_len,
20641                })
20642            } else {
20643                Some(WordBreakToken::Word {
20644                    token,
20645                    grapheme_len,
20646                })
20647            }
20648        } else {
20649            None
20650        }
20651    }
20652}
20653
20654#[test]
20655fn test_word_breaking_tokenizer() {
20656    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20657        ("", &[]),
20658        ("  ", &[whitespace("  ", 2)]),
20659        ("Ʒ", &[word("Ʒ", 1)]),
20660        ("Ǽ", &[word("Ǽ", 1)]),
20661        ("", &[word("", 1)]),
20662        ("⋑⋑", &[word("⋑⋑", 2)]),
20663        (
20664            "原理,进而",
20665            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20666        ),
20667        (
20668            "hello world",
20669            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20670        ),
20671        (
20672            "hello, world",
20673            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20674        ),
20675        (
20676            "  hello world",
20677            &[
20678                whitespace("  ", 2),
20679                word("hello", 5),
20680                whitespace(" ", 1),
20681                word("world", 5),
20682            ],
20683        ),
20684        (
20685            "这是什么 \n 钢笔",
20686            &[
20687                word("", 1),
20688                word("", 1),
20689                word("", 1),
20690                word("", 1),
20691                whitespace(" ", 1),
20692                newline(),
20693                whitespace(" ", 1),
20694                word("", 1),
20695                word("", 1),
20696            ],
20697        ),
20698        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20699    ];
20700
20701    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20702        WordBreakToken::Word {
20703            token,
20704            grapheme_len,
20705        }
20706    }
20707
20708    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20709        WordBreakToken::InlineWhitespace {
20710            token,
20711            grapheme_len,
20712        }
20713    }
20714
20715    fn newline() -> WordBreakToken<'static> {
20716        WordBreakToken::Newline
20717    }
20718
20719    for (input, result) in tests {
20720        assert_eq!(
20721            WordBreakingTokenizer::new(input)
20722                .collect::<Vec<_>>()
20723                .as_slice(),
20724            *result,
20725        );
20726    }
20727}
20728
20729fn wrap_with_prefix(
20730    line_prefix: String,
20731    unwrapped_text: String,
20732    wrap_column: usize,
20733    tab_size: NonZeroU32,
20734    preserve_existing_whitespace: bool,
20735) -> String {
20736    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20737    let mut wrapped_text = String::new();
20738    let mut current_line = line_prefix.clone();
20739
20740    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20741    let mut current_line_len = line_prefix_len;
20742    let mut in_whitespace = false;
20743    for token in tokenizer {
20744        let have_preceding_whitespace = in_whitespace;
20745        match token {
20746            WordBreakToken::Word {
20747                token,
20748                grapheme_len,
20749            } => {
20750                in_whitespace = false;
20751                if current_line_len + grapheme_len > wrap_column
20752                    && current_line_len != line_prefix_len
20753                {
20754                    wrapped_text.push_str(current_line.trim_end());
20755                    wrapped_text.push('\n');
20756                    current_line.truncate(line_prefix.len());
20757                    current_line_len = line_prefix_len;
20758                }
20759                current_line.push_str(token);
20760                current_line_len += grapheme_len;
20761            }
20762            WordBreakToken::InlineWhitespace {
20763                mut token,
20764                mut grapheme_len,
20765            } => {
20766                in_whitespace = true;
20767                if have_preceding_whitespace && !preserve_existing_whitespace {
20768                    continue;
20769                }
20770                if !preserve_existing_whitespace {
20771                    token = " ";
20772                    grapheme_len = 1;
20773                }
20774                if current_line_len + grapheme_len > wrap_column {
20775                    wrapped_text.push_str(current_line.trim_end());
20776                    wrapped_text.push('\n');
20777                    current_line.truncate(line_prefix.len());
20778                    current_line_len = line_prefix_len;
20779                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20780                    current_line.push_str(token);
20781                    current_line_len += grapheme_len;
20782                }
20783            }
20784            WordBreakToken::Newline => {
20785                in_whitespace = true;
20786                if preserve_existing_whitespace {
20787                    wrapped_text.push_str(current_line.trim_end());
20788                    wrapped_text.push('\n');
20789                    current_line.truncate(line_prefix.len());
20790                    current_line_len = line_prefix_len;
20791                } else if have_preceding_whitespace {
20792                    continue;
20793                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20794                {
20795                    wrapped_text.push_str(current_line.trim_end());
20796                    wrapped_text.push('\n');
20797                    current_line.truncate(line_prefix.len());
20798                    current_line_len = line_prefix_len;
20799                } else if current_line_len != line_prefix_len {
20800                    current_line.push(' ');
20801                    current_line_len += 1;
20802                }
20803            }
20804        }
20805    }
20806
20807    if !current_line.is_empty() {
20808        wrapped_text.push_str(&current_line);
20809    }
20810    wrapped_text
20811}
20812
20813#[test]
20814fn test_wrap_with_prefix() {
20815    assert_eq!(
20816        wrap_with_prefix(
20817            "# ".to_string(),
20818            "abcdefg".to_string(),
20819            4,
20820            NonZeroU32::new(4).unwrap(),
20821            false,
20822        ),
20823        "# abcdefg"
20824    );
20825    assert_eq!(
20826        wrap_with_prefix(
20827            "".to_string(),
20828            "\thello world".to_string(),
20829            8,
20830            NonZeroU32::new(4).unwrap(),
20831            false,
20832        ),
20833        "hello\nworld"
20834    );
20835    assert_eq!(
20836        wrap_with_prefix(
20837            "// ".to_string(),
20838            "xx \nyy zz aa bb cc".to_string(),
20839            12,
20840            NonZeroU32::new(4).unwrap(),
20841            false,
20842        ),
20843        "// xx yy zz\n// aa bb cc"
20844    );
20845    assert_eq!(
20846        wrap_with_prefix(
20847            String::new(),
20848            "这是什么 \n 钢笔".to_string(),
20849            3,
20850            NonZeroU32::new(4).unwrap(),
20851            false,
20852        ),
20853        "这是什\n么 钢\n"
20854    );
20855}
20856
20857pub trait CollaborationHub {
20858    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20859    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20860    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20861}
20862
20863impl CollaborationHub for Entity<Project> {
20864    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20865        self.read(cx).collaborators()
20866    }
20867
20868    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20869        self.read(cx).user_store().read(cx).participant_indices()
20870    }
20871
20872    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20873        let this = self.read(cx);
20874        let user_ids = this.collaborators().values().map(|c| c.user_id);
20875        this.user_store().read(cx).participant_names(user_ids, cx)
20876    }
20877}
20878
20879pub trait SemanticsProvider {
20880    fn hover(
20881        &self,
20882        buffer: &Entity<Buffer>,
20883        position: text::Anchor,
20884        cx: &mut App,
20885    ) -> Option<Task<Vec<project::Hover>>>;
20886
20887    fn inline_values(
20888        &self,
20889        buffer_handle: Entity<Buffer>,
20890        range: Range<text::Anchor>,
20891        cx: &mut App,
20892    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20893
20894    fn inlay_hints(
20895        &self,
20896        buffer_handle: Entity<Buffer>,
20897        range: Range<text::Anchor>,
20898        cx: &mut App,
20899    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20900
20901    fn resolve_inlay_hint(
20902        &self,
20903        hint: InlayHint,
20904        buffer_handle: Entity<Buffer>,
20905        server_id: LanguageServerId,
20906        cx: &mut App,
20907    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20908
20909    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20910
20911    fn document_highlights(
20912        &self,
20913        buffer: &Entity<Buffer>,
20914        position: text::Anchor,
20915        cx: &mut App,
20916    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20917
20918    fn definitions(
20919        &self,
20920        buffer: &Entity<Buffer>,
20921        position: text::Anchor,
20922        kind: GotoDefinitionKind,
20923        cx: &mut App,
20924    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20925
20926    fn range_for_rename(
20927        &self,
20928        buffer: &Entity<Buffer>,
20929        position: text::Anchor,
20930        cx: &mut App,
20931    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20932
20933    fn perform_rename(
20934        &self,
20935        buffer: &Entity<Buffer>,
20936        position: text::Anchor,
20937        new_name: String,
20938        cx: &mut App,
20939    ) -> Option<Task<Result<ProjectTransaction>>>;
20940
20941    fn pull_diagnostics_for_buffer(
20942        &self,
20943        buffer: Entity<Buffer>,
20944        cx: &mut App,
20945    ) -> Task<anyhow::Result<()>>;
20946}
20947
20948pub trait CompletionProvider {
20949    fn completions(
20950        &self,
20951        excerpt_id: ExcerptId,
20952        buffer: &Entity<Buffer>,
20953        buffer_position: text::Anchor,
20954        trigger: CompletionContext,
20955        window: &mut Window,
20956        cx: &mut Context<Editor>,
20957    ) -> Task<Result<Vec<CompletionResponse>>>;
20958
20959    fn resolve_completions(
20960        &self,
20961        _buffer: Entity<Buffer>,
20962        _completion_indices: Vec<usize>,
20963        _completions: Rc<RefCell<Box<[Completion]>>>,
20964        _cx: &mut Context<Editor>,
20965    ) -> Task<Result<bool>> {
20966        Task::ready(Ok(false))
20967    }
20968
20969    fn apply_additional_edits_for_completion(
20970        &self,
20971        _buffer: Entity<Buffer>,
20972        _completions: Rc<RefCell<Box<[Completion]>>>,
20973        _completion_index: usize,
20974        _push_to_history: bool,
20975        _cx: &mut Context<Editor>,
20976    ) -> Task<Result<Option<language::Transaction>>> {
20977        Task::ready(Ok(None))
20978    }
20979
20980    fn is_completion_trigger(
20981        &self,
20982        buffer: &Entity<Buffer>,
20983        position: language::Anchor,
20984        text: &str,
20985        trigger_in_words: bool,
20986        menu_is_open: bool,
20987        cx: &mut Context<Editor>,
20988    ) -> bool;
20989
20990    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20991
20992    fn sort_completions(&self) -> bool {
20993        true
20994    }
20995
20996    fn filter_completions(&self) -> bool {
20997        true
20998    }
20999}
21000
21001pub trait CodeActionProvider {
21002    fn id(&self) -> Arc<str>;
21003
21004    fn code_actions(
21005        &self,
21006        buffer: &Entity<Buffer>,
21007        range: Range<text::Anchor>,
21008        window: &mut Window,
21009        cx: &mut App,
21010    ) -> Task<Result<Vec<CodeAction>>>;
21011
21012    fn apply_code_action(
21013        &self,
21014        buffer_handle: Entity<Buffer>,
21015        action: CodeAction,
21016        excerpt_id: ExcerptId,
21017        push_to_history: bool,
21018        window: &mut Window,
21019        cx: &mut App,
21020    ) -> Task<Result<ProjectTransaction>>;
21021}
21022
21023impl CodeActionProvider for Entity<Project> {
21024    fn id(&self) -> Arc<str> {
21025        "project".into()
21026    }
21027
21028    fn code_actions(
21029        &self,
21030        buffer: &Entity<Buffer>,
21031        range: Range<text::Anchor>,
21032        _window: &mut Window,
21033        cx: &mut App,
21034    ) -> Task<Result<Vec<CodeAction>>> {
21035        self.update(cx, |project, cx| {
21036            let code_lens = project.code_lens(buffer, range.clone(), cx);
21037            let code_actions = project.code_actions(buffer, range, None, cx);
21038            cx.background_spawn(async move {
21039                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21040                Ok(code_lens
21041                    .context("code lens fetch")?
21042                    .into_iter()
21043                    .chain(code_actions.context("code action fetch")?)
21044                    .collect())
21045            })
21046        })
21047    }
21048
21049    fn apply_code_action(
21050        &self,
21051        buffer_handle: Entity<Buffer>,
21052        action: CodeAction,
21053        _excerpt_id: ExcerptId,
21054        push_to_history: bool,
21055        _window: &mut Window,
21056        cx: &mut App,
21057    ) -> Task<Result<ProjectTransaction>> {
21058        self.update(cx, |project, cx| {
21059            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21060        })
21061    }
21062}
21063
21064fn snippet_completions(
21065    project: &Project,
21066    buffer: &Entity<Buffer>,
21067    buffer_position: text::Anchor,
21068    cx: &mut App,
21069) -> Task<Result<CompletionResponse>> {
21070    let languages = buffer.read(cx).languages_at(buffer_position);
21071    let snippet_store = project.snippets().read(cx);
21072
21073    let scopes: Vec<_> = languages
21074        .iter()
21075        .filter_map(|language| {
21076            let language_name = language.lsp_id();
21077            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21078
21079            if snippets.is_empty() {
21080                None
21081            } else {
21082                Some((language.default_scope(), snippets))
21083            }
21084        })
21085        .collect();
21086
21087    if scopes.is_empty() {
21088        return Task::ready(Ok(CompletionResponse {
21089            completions: vec![],
21090            is_incomplete: false,
21091        }));
21092    }
21093
21094    let snapshot = buffer.read(cx).text_snapshot();
21095    let chars: String = snapshot
21096        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21097        .collect();
21098    let executor = cx.background_executor().clone();
21099
21100    cx.background_spawn(async move {
21101        let mut is_incomplete = false;
21102        let mut completions: Vec<Completion> = Vec::new();
21103        for (scope, snippets) in scopes.into_iter() {
21104            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21105            let mut last_word = chars
21106                .chars()
21107                .take_while(|c| classifier.is_word(*c))
21108                .collect::<String>();
21109            last_word = last_word.chars().rev().collect();
21110
21111            if last_word.is_empty() {
21112                return Ok(CompletionResponse {
21113                    completions: vec![],
21114                    is_incomplete: true,
21115                });
21116            }
21117
21118            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21119            let to_lsp = |point: &text::Anchor| {
21120                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21121                point_to_lsp(end)
21122            };
21123            let lsp_end = to_lsp(&buffer_position);
21124
21125            let candidates = snippets
21126                .iter()
21127                .enumerate()
21128                .flat_map(|(ix, snippet)| {
21129                    snippet
21130                        .prefix
21131                        .iter()
21132                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21133                })
21134                .collect::<Vec<StringMatchCandidate>>();
21135
21136            const MAX_RESULTS: usize = 100;
21137            let mut matches = fuzzy::match_strings(
21138                &candidates,
21139                &last_word,
21140                last_word.chars().any(|c| c.is_uppercase()),
21141                MAX_RESULTS,
21142                &Default::default(),
21143                executor.clone(),
21144            )
21145            .await;
21146
21147            if matches.len() >= MAX_RESULTS {
21148                is_incomplete = true;
21149            }
21150
21151            // Remove all candidates where the query's start does not match the start of any word in the candidate
21152            if let Some(query_start) = last_word.chars().next() {
21153                matches.retain(|string_match| {
21154                    split_words(&string_match.string).any(|word| {
21155                        // Check that the first codepoint of the word as lowercase matches the first
21156                        // codepoint of the query as lowercase
21157                        word.chars()
21158                            .flat_map(|codepoint| codepoint.to_lowercase())
21159                            .zip(query_start.to_lowercase())
21160                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21161                    })
21162                });
21163            }
21164
21165            let matched_strings = matches
21166                .into_iter()
21167                .map(|m| m.string)
21168                .collect::<HashSet<_>>();
21169
21170            completions.extend(snippets.iter().filter_map(|snippet| {
21171                let matching_prefix = snippet
21172                    .prefix
21173                    .iter()
21174                    .find(|prefix| matched_strings.contains(*prefix))?;
21175                let start = as_offset - last_word.len();
21176                let start = snapshot.anchor_before(start);
21177                let range = start..buffer_position;
21178                let lsp_start = to_lsp(&start);
21179                let lsp_range = lsp::Range {
21180                    start: lsp_start,
21181                    end: lsp_end,
21182                };
21183                Some(Completion {
21184                    replace_range: range,
21185                    new_text: snippet.body.clone(),
21186                    source: CompletionSource::Lsp {
21187                        insert_range: None,
21188                        server_id: LanguageServerId(usize::MAX),
21189                        resolved: true,
21190                        lsp_completion: Box::new(lsp::CompletionItem {
21191                            label: snippet.prefix.first().unwrap().clone(),
21192                            kind: Some(CompletionItemKind::SNIPPET),
21193                            label_details: snippet.description.as_ref().map(|description| {
21194                                lsp::CompletionItemLabelDetails {
21195                                    detail: Some(description.clone()),
21196                                    description: None,
21197                                }
21198                            }),
21199                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21200                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21201                                lsp::InsertReplaceEdit {
21202                                    new_text: snippet.body.clone(),
21203                                    insert: lsp_range,
21204                                    replace: lsp_range,
21205                                },
21206                            )),
21207                            filter_text: Some(snippet.body.clone()),
21208                            sort_text: Some(char::MAX.to_string()),
21209                            ..lsp::CompletionItem::default()
21210                        }),
21211                        lsp_defaults: None,
21212                    },
21213                    label: CodeLabel {
21214                        text: matching_prefix.clone(),
21215                        runs: Vec::new(),
21216                        filter_range: 0..matching_prefix.len(),
21217                    },
21218                    icon_path: None,
21219                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21220                        single_line: snippet.name.clone().into(),
21221                        plain_text: snippet
21222                            .description
21223                            .clone()
21224                            .map(|description| description.into()),
21225                    }),
21226                    insert_text_mode: None,
21227                    confirm: None,
21228                })
21229            }))
21230        }
21231
21232        Ok(CompletionResponse {
21233            completions,
21234            is_incomplete,
21235        })
21236    })
21237}
21238
21239impl CompletionProvider for Entity<Project> {
21240    fn completions(
21241        &self,
21242        _excerpt_id: ExcerptId,
21243        buffer: &Entity<Buffer>,
21244        buffer_position: text::Anchor,
21245        options: CompletionContext,
21246        _window: &mut Window,
21247        cx: &mut Context<Editor>,
21248    ) -> Task<Result<Vec<CompletionResponse>>> {
21249        self.update(cx, |project, cx| {
21250            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21251            let project_completions = project.completions(buffer, buffer_position, options, cx);
21252            cx.background_spawn(async move {
21253                let mut responses = project_completions.await?;
21254                let snippets = snippets.await?;
21255                if !snippets.completions.is_empty() {
21256                    responses.push(snippets);
21257                }
21258                Ok(responses)
21259            })
21260        })
21261    }
21262
21263    fn resolve_completions(
21264        &self,
21265        buffer: Entity<Buffer>,
21266        completion_indices: Vec<usize>,
21267        completions: Rc<RefCell<Box<[Completion]>>>,
21268        cx: &mut Context<Editor>,
21269    ) -> Task<Result<bool>> {
21270        self.update(cx, |project, cx| {
21271            project.lsp_store().update(cx, |lsp_store, cx| {
21272                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21273            })
21274        })
21275    }
21276
21277    fn apply_additional_edits_for_completion(
21278        &self,
21279        buffer: Entity<Buffer>,
21280        completions: Rc<RefCell<Box<[Completion]>>>,
21281        completion_index: usize,
21282        push_to_history: bool,
21283        cx: &mut Context<Editor>,
21284    ) -> Task<Result<Option<language::Transaction>>> {
21285        self.update(cx, |project, cx| {
21286            project.lsp_store().update(cx, |lsp_store, cx| {
21287                lsp_store.apply_additional_edits_for_completion(
21288                    buffer,
21289                    completions,
21290                    completion_index,
21291                    push_to_history,
21292                    cx,
21293                )
21294            })
21295        })
21296    }
21297
21298    fn is_completion_trigger(
21299        &self,
21300        buffer: &Entity<Buffer>,
21301        position: language::Anchor,
21302        text: &str,
21303        trigger_in_words: bool,
21304        menu_is_open: bool,
21305        cx: &mut Context<Editor>,
21306    ) -> bool {
21307        let mut chars = text.chars();
21308        let char = if let Some(char) = chars.next() {
21309            char
21310        } else {
21311            return false;
21312        };
21313        if chars.next().is_some() {
21314            return false;
21315        }
21316
21317        let buffer = buffer.read(cx);
21318        let snapshot = buffer.snapshot();
21319        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21320            return false;
21321        }
21322        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21323        if trigger_in_words && classifier.is_word(char) {
21324            return true;
21325        }
21326
21327        buffer.completion_triggers().contains(text)
21328    }
21329}
21330
21331impl SemanticsProvider for Entity<Project> {
21332    fn hover(
21333        &self,
21334        buffer: &Entity<Buffer>,
21335        position: text::Anchor,
21336        cx: &mut App,
21337    ) -> Option<Task<Vec<project::Hover>>> {
21338        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21339    }
21340
21341    fn document_highlights(
21342        &self,
21343        buffer: &Entity<Buffer>,
21344        position: text::Anchor,
21345        cx: &mut App,
21346    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21347        Some(self.update(cx, |project, cx| {
21348            project.document_highlights(buffer, position, cx)
21349        }))
21350    }
21351
21352    fn definitions(
21353        &self,
21354        buffer: &Entity<Buffer>,
21355        position: text::Anchor,
21356        kind: GotoDefinitionKind,
21357        cx: &mut App,
21358    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21359        Some(self.update(cx, |project, cx| match kind {
21360            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21361            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21362            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21363            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21364        }))
21365    }
21366
21367    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21368        // TODO: make this work for remote projects
21369        self.update(cx, |project, cx| {
21370            if project
21371                .active_debug_session(cx)
21372                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21373            {
21374                return true;
21375            }
21376
21377            buffer.update(cx, |buffer, cx| {
21378                project.any_language_server_supports_inlay_hints(buffer, cx)
21379            })
21380        })
21381    }
21382
21383    fn inline_values(
21384        &self,
21385        buffer_handle: Entity<Buffer>,
21386
21387        range: Range<text::Anchor>,
21388        cx: &mut App,
21389    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21390        self.update(cx, |project, cx| {
21391            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21392
21393            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21394        })
21395    }
21396
21397    fn inlay_hints(
21398        &self,
21399        buffer_handle: Entity<Buffer>,
21400        range: Range<text::Anchor>,
21401        cx: &mut App,
21402    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21403        Some(self.update(cx, |project, cx| {
21404            project.inlay_hints(buffer_handle, range, cx)
21405        }))
21406    }
21407
21408    fn resolve_inlay_hint(
21409        &self,
21410        hint: InlayHint,
21411        buffer_handle: Entity<Buffer>,
21412        server_id: LanguageServerId,
21413        cx: &mut App,
21414    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21415        Some(self.update(cx, |project, cx| {
21416            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21417        }))
21418    }
21419
21420    fn range_for_rename(
21421        &self,
21422        buffer: &Entity<Buffer>,
21423        position: text::Anchor,
21424        cx: &mut App,
21425    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21426        Some(self.update(cx, |project, cx| {
21427            let buffer = buffer.clone();
21428            let task = project.prepare_rename(buffer.clone(), position, cx);
21429            cx.spawn(async move |_, cx| {
21430                Ok(match task.await? {
21431                    PrepareRenameResponse::Success(range) => Some(range),
21432                    PrepareRenameResponse::InvalidPosition => None,
21433                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21434                        // Fallback on using TreeSitter info to determine identifier range
21435                        buffer.read_with(cx, |buffer, _| {
21436                            let snapshot = buffer.snapshot();
21437                            let (range, kind) = snapshot.surrounding_word(position);
21438                            if kind != Some(CharKind::Word) {
21439                                return None;
21440                            }
21441                            Some(
21442                                snapshot.anchor_before(range.start)
21443                                    ..snapshot.anchor_after(range.end),
21444                            )
21445                        })?
21446                    }
21447                })
21448            })
21449        }))
21450    }
21451
21452    fn perform_rename(
21453        &self,
21454        buffer: &Entity<Buffer>,
21455        position: text::Anchor,
21456        new_name: String,
21457        cx: &mut App,
21458    ) -> Option<Task<Result<ProjectTransaction>>> {
21459        Some(self.update(cx, |project, cx| {
21460            project.perform_rename(buffer.clone(), position, new_name, cx)
21461        }))
21462    }
21463
21464    fn pull_diagnostics_for_buffer(
21465        &self,
21466        buffer: Entity<Buffer>,
21467        cx: &mut App,
21468    ) -> Task<anyhow::Result<()>> {
21469        let diagnostics = self.update(cx, |project, cx| {
21470            project
21471                .lsp_store()
21472                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21473        });
21474        let project = self.clone();
21475        cx.spawn(async move |cx| {
21476            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21477            project.update(cx, |project, cx| {
21478                project.lsp_store().update(cx, |lsp_store, cx| {
21479                    for diagnostics_set in diagnostics {
21480                        let LspPullDiagnostics::Response {
21481                            server_id,
21482                            uri,
21483                            diagnostics,
21484                        } = diagnostics_set
21485                        else {
21486                            continue;
21487                        };
21488
21489                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21490                        let disk_based_sources = adapter
21491                            .as_ref()
21492                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21493                            .unwrap_or(&[]);
21494                        match diagnostics {
21495                            PulledDiagnostics::Unchanged { result_id } => {
21496                                lsp_store
21497                                    .merge_diagnostics(
21498                                        server_id,
21499                                        lsp::PublishDiagnosticsParams {
21500                                            uri: uri.clone(),
21501                                            diagnostics: Vec::new(),
21502                                            version: None,
21503                                        },
21504                                        Some(result_id),
21505                                        DiagnosticSourceKind::Pulled,
21506                                        disk_based_sources,
21507                                        |_, _| true,
21508                                        cx,
21509                                    )
21510                                    .log_err();
21511                            }
21512                            PulledDiagnostics::Changed {
21513                                diagnostics,
21514                                result_id,
21515                            } => {
21516                                lsp_store
21517                                    .merge_diagnostics(
21518                                        server_id,
21519                                        lsp::PublishDiagnosticsParams {
21520                                            uri: uri.clone(),
21521                                            diagnostics,
21522                                            version: None,
21523                                        },
21524                                        result_id,
21525                                        DiagnosticSourceKind::Pulled,
21526                                        disk_based_sources,
21527                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21528                                            DiagnosticSourceKind::Pulled => false,
21529                                            DiagnosticSourceKind::Other
21530                                            | DiagnosticSourceKind::Pushed => true,
21531                                        },
21532                                        cx,
21533                                    )
21534                                    .log_err();
21535                            }
21536                        }
21537                    }
21538                })
21539            })
21540        })
21541    }
21542}
21543
21544fn inlay_hint_settings(
21545    location: Anchor,
21546    snapshot: &MultiBufferSnapshot,
21547    cx: &mut Context<Editor>,
21548) -> InlayHintSettings {
21549    let file = snapshot.file_at(location);
21550    let language = snapshot.language_at(location).map(|l| l.name());
21551    language_settings(language, file, cx).inlay_hints
21552}
21553
21554fn consume_contiguous_rows(
21555    contiguous_row_selections: &mut Vec<Selection<Point>>,
21556    selection: &Selection<Point>,
21557    display_map: &DisplaySnapshot,
21558    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21559) -> (MultiBufferRow, MultiBufferRow) {
21560    contiguous_row_selections.push(selection.clone());
21561    let start_row = MultiBufferRow(selection.start.row);
21562    let mut end_row = ending_row(selection, display_map);
21563
21564    while let Some(next_selection) = selections.peek() {
21565        if next_selection.start.row <= end_row.0 {
21566            end_row = ending_row(next_selection, display_map);
21567            contiguous_row_selections.push(selections.next().unwrap().clone());
21568        } else {
21569            break;
21570        }
21571    }
21572    (start_row, end_row)
21573}
21574
21575fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21576    if next_selection.end.column > 0 || next_selection.is_empty() {
21577        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21578    } else {
21579        MultiBufferRow(next_selection.end.row)
21580    }
21581}
21582
21583impl EditorSnapshot {
21584    pub fn remote_selections_in_range<'a>(
21585        &'a self,
21586        range: &'a Range<Anchor>,
21587        collaboration_hub: &dyn CollaborationHub,
21588        cx: &'a App,
21589    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21590        let participant_names = collaboration_hub.user_names(cx);
21591        let participant_indices = collaboration_hub.user_participant_indices(cx);
21592        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21593        let collaborators_by_replica_id = collaborators_by_peer_id
21594            .values()
21595            .map(|collaborator| (collaborator.replica_id, collaborator))
21596            .collect::<HashMap<_, _>>();
21597        self.buffer_snapshot
21598            .selections_in_range(range, false)
21599            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21600                if replica_id == AGENT_REPLICA_ID {
21601                    Some(RemoteSelection {
21602                        replica_id,
21603                        selection,
21604                        cursor_shape,
21605                        line_mode,
21606                        collaborator_id: CollaboratorId::Agent,
21607                        user_name: Some("Agent".into()),
21608                        color: cx.theme().players().agent(),
21609                    })
21610                } else {
21611                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21612                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21613                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21614                    Some(RemoteSelection {
21615                        replica_id,
21616                        selection,
21617                        cursor_shape,
21618                        line_mode,
21619                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21620                        user_name,
21621                        color: if let Some(index) = participant_index {
21622                            cx.theme().players().color_for_participant(index.0)
21623                        } else {
21624                            cx.theme().players().absent()
21625                        },
21626                    })
21627                }
21628            })
21629    }
21630
21631    pub fn hunks_for_ranges(
21632        &self,
21633        ranges: impl IntoIterator<Item = Range<Point>>,
21634    ) -> Vec<MultiBufferDiffHunk> {
21635        let mut hunks = Vec::new();
21636        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21637            HashMap::default();
21638        for query_range in ranges {
21639            let query_rows =
21640                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21641            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21642                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21643            ) {
21644                // Include deleted hunks that are adjacent to the query range, because
21645                // otherwise they would be missed.
21646                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21647                if hunk.status().is_deleted() {
21648                    intersects_range |= hunk.row_range.start == query_rows.end;
21649                    intersects_range |= hunk.row_range.end == query_rows.start;
21650                }
21651                if intersects_range {
21652                    if !processed_buffer_rows
21653                        .entry(hunk.buffer_id)
21654                        .or_default()
21655                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21656                    {
21657                        continue;
21658                    }
21659                    hunks.push(hunk);
21660                }
21661            }
21662        }
21663
21664        hunks
21665    }
21666
21667    fn display_diff_hunks_for_rows<'a>(
21668        &'a self,
21669        display_rows: Range<DisplayRow>,
21670        folded_buffers: &'a HashSet<BufferId>,
21671    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21672        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21673        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21674
21675        self.buffer_snapshot
21676            .diff_hunks_in_range(buffer_start..buffer_end)
21677            .filter_map(|hunk| {
21678                if folded_buffers.contains(&hunk.buffer_id) {
21679                    return None;
21680                }
21681
21682                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21683                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21684
21685                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21686                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21687
21688                let display_hunk = if hunk_display_start.column() != 0 {
21689                    DisplayDiffHunk::Folded {
21690                        display_row: hunk_display_start.row(),
21691                    }
21692                } else {
21693                    let mut end_row = hunk_display_end.row();
21694                    if hunk_display_end.column() > 0 {
21695                        end_row.0 += 1;
21696                    }
21697                    let is_created_file = hunk.is_created_file();
21698                    DisplayDiffHunk::Unfolded {
21699                        status: hunk.status(),
21700                        diff_base_byte_range: hunk.diff_base_byte_range,
21701                        display_row_range: hunk_display_start.row()..end_row,
21702                        multi_buffer_range: Anchor::range_in_buffer(
21703                            hunk.excerpt_id,
21704                            hunk.buffer_id,
21705                            hunk.buffer_range,
21706                        ),
21707                        is_created_file,
21708                    }
21709                };
21710
21711                Some(display_hunk)
21712            })
21713    }
21714
21715    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21716        self.display_snapshot.buffer_snapshot.language_at(position)
21717    }
21718
21719    pub fn is_focused(&self) -> bool {
21720        self.is_focused
21721    }
21722
21723    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21724        self.placeholder_text.as_ref()
21725    }
21726
21727    pub fn scroll_position(&self) -> gpui::Point<f32> {
21728        self.scroll_anchor.scroll_position(&self.display_snapshot)
21729    }
21730
21731    fn gutter_dimensions(
21732        &self,
21733        font_id: FontId,
21734        font_size: Pixels,
21735        max_line_number_width: Pixels,
21736        cx: &App,
21737    ) -> Option<GutterDimensions> {
21738        if !self.show_gutter {
21739            return None;
21740        }
21741
21742        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21743        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21744
21745        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21746            matches!(
21747                ProjectSettings::get_global(cx).git.git_gutter,
21748                Some(GitGutterSetting::TrackedFiles)
21749            )
21750        });
21751        let gutter_settings = EditorSettings::get_global(cx).gutter;
21752        let show_line_numbers = self
21753            .show_line_numbers
21754            .unwrap_or(gutter_settings.line_numbers);
21755        let line_gutter_width = if show_line_numbers {
21756            // Avoid flicker-like gutter resizes when the line number gains another digit by
21757            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21758            let min_width_for_number_on_gutter =
21759                ch_advance * gutter_settings.min_line_number_digits as f32;
21760            max_line_number_width.max(min_width_for_number_on_gutter)
21761        } else {
21762            0.0.into()
21763        };
21764
21765        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21766        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21767
21768        let git_blame_entries_width =
21769            self.git_blame_gutter_max_author_length
21770                .map(|max_author_length| {
21771                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21772                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21773
21774                    /// The number of characters to dedicate to gaps and margins.
21775                    const SPACING_WIDTH: usize = 4;
21776
21777                    let max_char_count = max_author_length.min(renderer.max_author_length())
21778                        + ::git::SHORT_SHA_LENGTH
21779                        + MAX_RELATIVE_TIMESTAMP.len()
21780                        + SPACING_WIDTH;
21781
21782                    ch_advance * max_char_count
21783                });
21784
21785        let is_singleton = self.buffer_snapshot.is_singleton();
21786
21787        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21788        left_padding += if !is_singleton {
21789            ch_width * 4.0
21790        } else if show_runnables || show_breakpoints {
21791            ch_width * 3.0
21792        } else if show_git_gutter && show_line_numbers {
21793            ch_width * 2.0
21794        } else if show_git_gutter || show_line_numbers {
21795            ch_width
21796        } else {
21797            px(0.)
21798        };
21799
21800        let shows_folds = is_singleton && gutter_settings.folds;
21801
21802        let right_padding = if shows_folds && show_line_numbers {
21803            ch_width * 4.0
21804        } else if shows_folds || (!is_singleton && show_line_numbers) {
21805            ch_width * 3.0
21806        } else if show_line_numbers {
21807            ch_width
21808        } else {
21809            px(0.)
21810        };
21811
21812        Some(GutterDimensions {
21813            left_padding,
21814            right_padding,
21815            width: line_gutter_width + left_padding + right_padding,
21816            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21817            git_blame_entries_width,
21818        })
21819    }
21820
21821    pub fn render_crease_toggle(
21822        &self,
21823        buffer_row: MultiBufferRow,
21824        row_contains_cursor: bool,
21825        editor: Entity<Editor>,
21826        window: &mut Window,
21827        cx: &mut App,
21828    ) -> Option<AnyElement> {
21829        let folded = self.is_line_folded(buffer_row);
21830        let mut is_foldable = false;
21831
21832        if let Some(crease) = self
21833            .crease_snapshot
21834            .query_row(buffer_row, &self.buffer_snapshot)
21835        {
21836            is_foldable = true;
21837            match crease {
21838                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21839                    if let Some(render_toggle) = render_toggle {
21840                        let toggle_callback =
21841                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21842                                if folded {
21843                                    editor.update(cx, |editor, cx| {
21844                                        editor.fold_at(buffer_row, window, cx)
21845                                    });
21846                                } else {
21847                                    editor.update(cx, |editor, cx| {
21848                                        editor.unfold_at(buffer_row, window, cx)
21849                                    });
21850                                }
21851                            });
21852                        return Some((render_toggle)(
21853                            buffer_row,
21854                            folded,
21855                            toggle_callback,
21856                            window,
21857                            cx,
21858                        ));
21859                    }
21860                }
21861            }
21862        }
21863
21864        is_foldable |= self.starts_indent(buffer_row);
21865
21866        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21867            Some(
21868                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21869                    .toggle_state(folded)
21870                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21871                        if folded {
21872                            this.unfold_at(buffer_row, window, cx);
21873                        } else {
21874                            this.fold_at(buffer_row, window, cx);
21875                        }
21876                    }))
21877                    .into_any_element(),
21878            )
21879        } else {
21880            None
21881        }
21882    }
21883
21884    pub fn render_crease_trailer(
21885        &self,
21886        buffer_row: MultiBufferRow,
21887        window: &mut Window,
21888        cx: &mut App,
21889    ) -> Option<AnyElement> {
21890        let folded = self.is_line_folded(buffer_row);
21891        if let Crease::Inline { render_trailer, .. } = self
21892            .crease_snapshot
21893            .query_row(buffer_row, &self.buffer_snapshot)?
21894        {
21895            let render_trailer = render_trailer.as_ref()?;
21896            Some(render_trailer(buffer_row, folded, window, cx))
21897        } else {
21898            None
21899        }
21900    }
21901}
21902
21903impl Deref for EditorSnapshot {
21904    type Target = DisplaySnapshot;
21905
21906    fn deref(&self) -> &Self::Target {
21907        &self.display_snapshot
21908    }
21909}
21910
21911#[derive(Clone, Debug, PartialEq, Eq)]
21912pub enum EditorEvent {
21913    InputIgnored {
21914        text: Arc<str>,
21915    },
21916    InputHandled {
21917        utf16_range_to_replace: Option<Range<isize>>,
21918        text: Arc<str>,
21919    },
21920    ExcerptsAdded {
21921        buffer: Entity<Buffer>,
21922        predecessor: ExcerptId,
21923        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21924    },
21925    ExcerptsRemoved {
21926        ids: Vec<ExcerptId>,
21927        removed_buffer_ids: Vec<BufferId>,
21928    },
21929    BufferFoldToggled {
21930        ids: Vec<ExcerptId>,
21931        folded: bool,
21932    },
21933    ExcerptsEdited {
21934        ids: Vec<ExcerptId>,
21935    },
21936    ExcerptsExpanded {
21937        ids: Vec<ExcerptId>,
21938    },
21939    BufferEdited,
21940    Edited {
21941        transaction_id: clock::Lamport,
21942    },
21943    Reparsed(BufferId),
21944    Focused,
21945    FocusedIn,
21946    Blurred,
21947    DirtyChanged,
21948    Saved,
21949    TitleChanged,
21950    DiffBaseChanged,
21951    SelectionsChanged {
21952        local: bool,
21953    },
21954    ScrollPositionChanged {
21955        local: bool,
21956        autoscroll: bool,
21957    },
21958    Closed,
21959    TransactionUndone {
21960        transaction_id: clock::Lamport,
21961    },
21962    TransactionBegun {
21963        transaction_id: clock::Lamport,
21964    },
21965    Reloaded,
21966    CursorShapeChanged,
21967    PushedToNavHistory {
21968        anchor: Anchor,
21969        is_deactivate: bool,
21970    },
21971}
21972
21973impl EventEmitter<EditorEvent> for Editor {}
21974
21975impl Focusable for Editor {
21976    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21977        self.focus_handle.clone()
21978    }
21979}
21980
21981impl Render for Editor {
21982    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21983        let settings = ThemeSettings::get_global(cx);
21984
21985        let mut text_style = match self.mode {
21986            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21987                color: cx.theme().colors().editor_foreground,
21988                font_family: settings.ui_font.family.clone(),
21989                font_features: settings.ui_font.features.clone(),
21990                font_fallbacks: settings.ui_font.fallbacks.clone(),
21991                font_size: rems(0.875).into(),
21992                font_weight: settings.ui_font.weight,
21993                line_height: relative(settings.buffer_line_height.value()),
21994                ..Default::default()
21995            },
21996            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21997                color: cx.theme().colors().editor_foreground,
21998                font_family: settings.buffer_font.family.clone(),
21999                font_features: settings.buffer_font.features.clone(),
22000                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22001                font_size: settings.buffer_font_size(cx).into(),
22002                font_weight: settings.buffer_font.weight,
22003                line_height: relative(settings.buffer_line_height.value()),
22004                ..Default::default()
22005            },
22006        };
22007        if let Some(text_style_refinement) = &self.text_style_refinement {
22008            text_style.refine(text_style_refinement)
22009        }
22010
22011        let background = match self.mode {
22012            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22013            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22014            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22015            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22016        };
22017
22018        EditorElement::new(
22019            &cx.entity(),
22020            EditorStyle {
22021                background,
22022                local_player: cx.theme().players().local(),
22023                text: text_style,
22024                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22025                syntax: cx.theme().syntax().clone(),
22026                status: cx.theme().status().clone(),
22027                inlay_hints_style: make_inlay_hints_style(cx),
22028                inline_completion_styles: make_suggestion_styles(cx),
22029                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22030                show_underlines: !self.mode.is_minimap(),
22031            },
22032        )
22033    }
22034}
22035
22036impl EntityInputHandler for Editor {
22037    fn text_for_range(
22038        &mut self,
22039        range_utf16: Range<usize>,
22040        adjusted_range: &mut Option<Range<usize>>,
22041        _: &mut Window,
22042        cx: &mut Context<Self>,
22043    ) -> Option<String> {
22044        let snapshot = self.buffer.read(cx).read(cx);
22045        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22046        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22047        if (start.0..end.0) != range_utf16 {
22048            adjusted_range.replace(start.0..end.0);
22049        }
22050        Some(snapshot.text_for_range(start..end).collect())
22051    }
22052
22053    fn selected_text_range(
22054        &mut self,
22055        ignore_disabled_input: bool,
22056        _: &mut Window,
22057        cx: &mut Context<Self>,
22058    ) -> Option<UTF16Selection> {
22059        // Prevent the IME menu from appearing when holding down an alphabetic key
22060        // while input is disabled.
22061        if !ignore_disabled_input && !self.input_enabled {
22062            return None;
22063        }
22064
22065        let selection = self.selections.newest::<OffsetUtf16>(cx);
22066        let range = selection.range();
22067
22068        Some(UTF16Selection {
22069            range: range.start.0..range.end.0,
22070            reversed: selection.reversed,
22071        })
22072    }
22073
22074    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22075        let snapshot = self.buffer.read(cx).read(cx);
22076        let (range, _) = self.text_highlights::<InputComposition>(cx)?.first()?;
22077        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22078    }
22079
22080    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22081        self.clear_highlights::<InputComposition>(cx);
22082        self.ime_transaction.take();
22083    }
22084
22085    fn replace_text_in_range(
22086        &mut self,
22087        range_utf16: Option<Range<usize>>,
22088        text: &str,
22089        window: &mut Window,
22090        cx: &mut Context<Self>,
22091    ) {
22092        if !self.input_enabled {
22093            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22094            return;
22095        }
22096
22097        self.transact(window, cx, |this, window, cx| {
22098            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22099                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22100                Some(this.selection_replacement_ranges(range_utf16, cx))
22101            } else {
22102                this.marked_text_ranges(cx)
22103            };
22104
22105            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22106                let newest_selection_id = this.selections.newest_anchor().id;
22107                this.selections
22108                    .all::<OffsetUtf16>(cx)
22109                    .iter()
22110                    .zip(ranges_to_replace.iter())
22111                    .find_map(|(selection, range)| {
22112                        if selection.id == newest_selection_id {
22113                            Some(
22114                                (range.start.0 as isize - selection.head().0 as isize)
22115                                    ..(range.end.0 as isize - selection.head().0 as isize),
22116                            )
22117                        } else {
22118                            None
22119                        }
22120                    })
22121            });
22122
22123            cx.emit(EditorEvent::InputHandled {
22124                utf16_range_to_replace: range_to_replace,
22125                text: text.into(),
22126            });
22127
22128            if let Some(new_selected_ranges) = new_selected_ranges {
22129                this.change_selections(None, window, cx, |selections| {
22130                    selections.select_ranges(new_selected_ranges)
22131                });
22132                this.backspace(&Default::default(), window, cx);
22133            }
22134
22135            this.handle_input(text, window, cx);
22136        });
22137
22138        if let Some(transaction) = self.ime_transaction {
22139            self.buffer.update(cx, |buffer, cx| {
22140                buffer.group_until_transaction(transaction, cx);
22141            });
22142        }
22143
22144        self.unmark_text(window, cx);
22145    }
22146
22147    fn replace_and_mark_text_in_range(
22148        &mut self,
22149        range_utf16: Option<Range<usize>>,
22150        text: &str,
22151        new_selected_range_utf16: Option<Range<usize>>,
22152        window: &mut Window,
22153        cx: &mut Context<Self>,
22154    ) {
22155        if !self.input_enabled {
22156            return;
22157        }
22158
22159        let transaction = self.transact(window, cx, |this, window, cx| {
22160            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22161                let snapshot = this.buffer.read(cx).read(cx);
22162                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22163                    for marked_range in &mut marked_ranges {
22164                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22165                        marked_range.start.0 += relative_range_utf16.start;
22166                        marked_range.start =
22167                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22168                        marked_range.end =
22169                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22170                    }
22171                }
22172                Some(marked_ranges)
22173            } else if let Some(range_utf16) = range_utf16 {
22174                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22175                Some(this.selection_replacement_ranges(range_utf16, cx))
22176            } else {
22177                None
22178            };
22179
22180            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22181                let newest_selection_id = this.selections.newest_anchor().id;
22182                this.selections
22183                    .all::<OffsetUtf16>(cx)
22184                    .iter()
22185                    .zip(ranges_to_replace.iter())
22186                    .find_map(|(selection, range)| {
22187                        if selection.id == newest_selection_id {
22188                            Some(
22189                                (range.start.0 as isize - selection.head().0 as isize)
22190                                    ..(range.end.0 as isize - selection.head().0 as isize),
22191                            )
22192                        } else {
22193                            None
22194                        }
22195                    })
22196            });
22197
22198            cx.emit(EditorEvent::InputHandled {
22199                utf16_range_to_replace: range_to_replace,
22200                text: text.into(),
22201            });
22202
22203            if let Some(ranges) = ranges_to_replace {
22204                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22205            }
22206
22207            let marked_ranges = {
22208                let snapshot = this.buffer.read(cx).read(cx);
22209                this.selections
22210                    .disjoint_anchors()
22211                    .iter()
22212                    .map(|selection| {
22213                        (
22214                            selection.start.bias_left(&snapshot)
22215                                ..selection.end.bias_right(&snapshot),
22216                            HighlightStyle {
22217                                underline: Some(UnderlineStyle {
22218                                    thickness: px(1.),
22219                                    color: None,
22220                                    wavy: false,
22221                                }),
22222                                ..Default::default()
22223                            },
22224                        )
22225                    })
22226                    .collect::<Vec<_>>()
22227            };
22228
22229            if text.is_empty() {
22230                this.unmark_text(window, cx);
22231            } else {
22232                this.highlight_text::<InputComposition>(marked_ranges.clone(), cx);
22233            }
22234
22235            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22236            let use_autoclose = this.use_autoclose;
22237            let use_auto_surround = this.use_auto_surround;
22238            this.set_use_autoclose(false);
22239            this.set_use_auto_surround(false);
22240            this.handle_input(text, window, cx);
22241            this.set_use_autoclose(use_autoclose);
22242            this.set_use_auto_surround(use_auto_surround);
22243
22244            if let Some(new_selected_range) = new_selected_range_utf16 {
22245                let snapshot = this.buffer.read(cx).read(cx);
22246                let new_selected_ranges = marked_ranges
22247                    .into_iter()
22248                    .map(|(marked_range, _)| {
22249                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22250                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22251                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22252                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22253                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22254                    })
22255                    .collect::<Vec<_>>();
22256
22257                drop(snapshot);
22258                this.change_selections(None, window, cx, |selections| {
22259                    selections.select_ranges(new_selected_ranges)
22260                });
22261            }
22262        });
22263
22264        self.ime_transaction = self.ime_transaction.or(transaction);
22265        if let Some(transaction) = self.ime_transaction {
22266            self.buffer.update(cx, |buffer, cx| {
22267                buffer.group_until_transaction(transaction, cx);
22268            });
22269        }
22270
22271        if self.text_highlights::<InputComposition>(cx).is_none() {
22272            self.ime_transaction.take();
22273        }
22274    }
22275
22276    fn bounds_for_range(
22277        &mut self,
22278        range_utf16: Range<usize>,
22279        element_bounds: gpui::Bounds<Pixels>,
22280        window: &mut Window,
22281        cx: &mut Context<Self>,
22282    ) -> Option<gpui::Bounds<Pixels>> {
22283        let text_layout_details = self.text_layout_details(window);
22284        let gpui::Size {
22285            width: em_width,
22286            height: line_height,
22287        } = self.character_size(window);
22288
22289        let snapshot = self.snapshot(window, cx);
22290        let scroll_position = snapshot.scroll_position();
22291        let scroll_left = scroll_position.x * em_width;
22292
22293        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22294        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22295            + self.gutter_dimensions.width
22296            + self.gutter_dimensions.margin;
22297        let y = line_height * (start.row().as_f32() - scroll_position.y);
22298
22299        Some(Bounds {
22300            origin: element_bounds.origin + point(x, y),
22301            size: size(em_width, line_height),
22302        })
22303    }
22304
22305    fn character_index_for_point(
22306        &mut self,
22307        point: gpui::Point<Pixels>,
22308        _window: &mut Window,
22309        _cx: &mut Context<Self>,
22310    ) -> Option<usize> {
22311        let position_map = self.last_position_map.as_ref()?;
22312        if !position_map.text_hitbox.contains(&point) {
22313            return None;
22314        }
22315        let display_point = position_map.point_for_position(point).previous_valid;
22316        let anchor = position_map
22317            .snapshot
22318            .display_point_to_anchor(display_point, Bias::Left);
22319        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22320        Some(utf16_offset.0)
22321    }
22322}
22323
22324trait SelectionExt {
22325    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22326    fn spanned_rows(
22327        &self,
22328        include_end_if_at_line_start: bool,
22329        map: &DisplaySnapshot,
22330    ) -> Range<MultiBufferRow>;
22331}
22332
22333impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22334    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22335        let start = self
22336            .start
22337            .to_point(&map.buffer_snapshot)
22338            .to_display_point(map);
22339        let end = self
22340            .end
22341            .to_point(&map.buffer_snapshot)
22342            .to_display_point(map);
22343        if self.reversed {
22344            end..start
22345        } else {
22346            start..end
22347        }
22348    }
22349
22350    fn spanned_rows(
22351        &self,
22352        include_end_if_at_line_start: bool,
22353        map: &DisplaySnapshot,
22354    ) -> Range<MultiBufferRow> {
22355        let start = self.start.to_point(&map.buffer_snapshot);
22356        let mut end = self.end.to_point(&map.buffer_snapshot);
22357        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22358            end.row -= 1;
22359        }
22360
22361        let buffer_start = map.prev_line_boundary(start).0;
22362        let buffer_end = map.next_line_boundary(end).0;
22363        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22364    }
22365}
22366
22367impl<T: InvalidationRegion> InvalidationStack<T> {
22368    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22369    where
22370        S: Clone + ToOffset,
22371    {
22372        while let Some(region) = self.last() {
22373            let all_selections_inside_invalidation_ranges =
22374                if selections.len() == region.ranges().len() {
22375                    selections
22376                        .iter()
22377                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22378                        .all(|(selection, invalidation_range)| {
22379                            let head = selection.head().to_offset(buffer);
22380                            invalidation_range.start <= head && invalidation_range.end >= head
22381                        })
22382                } else {
22383                    false
22384                };
22385
22386            if all_selections_inside_invalidation_ranges {
22387                break;
22388            } else {
22389                self.pop();
22390            }
22391        }
22392    }
22393}
22394
22395impl<T> Default for InvalidationStack<T> {
22396    fn default() -> Self {
22397        Self(Default::default())
22398    }
22399}
22400
22401impl<T> Deref for InvalidationStack<T> {
22402    type Target = Vec<T>;
22403
22404    fn deref(&self) -> &Self::Target {
22405        &self.0
22406    }
22407}
22408
22409impl<T> DerefMut for InvalidationStack<T> {
22410    fn deref_mut(&mut self) -> &mut Self::Target {
22411        &mut self.0
22412    }
22413}
22414
22415impl InvalidationRegion for SnippetState {
22416    fn ranges(&self) -> &[Range<Anchor>] {
22417        &self.ranges[self.active_index]
22418    }
22419}
22420
22421fn inline_completion_edit_text(
22422    current_snapshot: &BufferSnapshot,
22423    edits: &[(Range<Anchor>, String)],
22424    edit_preview: &EditPreview,
22425    include_deletions: bool,
22426    cx: &App,
22427) -> HighlightedText {
22428    let edits = edits
22429        .iter()
22430        .map(|(anchor, text)| {
22431            (
22432                anchor.start.text_anchor..anchor.end.text_anchor,
22433                text.clone(),
22434            )
22435        })
22436        .collect::<Vec<_>>();
22437
22438    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22439}
22440
22441pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22442    match severity {
22443        lsp::DiagnosticSeverity::ERROR => colors.error,
22444        lsp::DiagnosticSeverity::WARNING => colors.warning,
22445        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22446        lsp::DiagnosticSeverity::HINT => colors.info,
22447        _ => colors.ignored,
22448    }
22449}
22450
22451pub fn styled_runs_for_code_label<'a>(
22452    label: &'a CodeLabel,
22453    syntax_theme: &'a theme::SyntaxTheme,
22454) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22455    let fade_out = HighlightStyle {
22456        fade_out: Some(0.35),
22457        ..Default::default()
22458    };
22459
22460    let mut prev_end = label.filter_range.end;
22461    label
22462        .runs
22463        .iter()
22464        .enumerate()
22465        .flat_map(move |(ix, (range, highlight_id))| {
22466            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22467                style
22468            } else {
22469                return Default::default();
22470            };
22471            let mut muted_style = style;
22472            muted_style.highlight(fade_out);
22473
22474            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22475            if range.start >= label.filter_range.end {
22476                if range.start > prev_end {
22477                    runs.push((prev_end..range.start, fade_out));
22478                }
22479                runs.push((range.clone(), muted_style));
22480            } else if range.end <= label.filter_range.end {
22481                runs.push((range.clone(), style));
22482            } else {
22483                runs.push((range.start..label.filter_range.end, style));
22484                runs.push((label.filter_range.end..range.end, muted_style));
22485            }
22486            prev_end = cmp::max(prev_end, range.end);
22487
22488            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22489                runs.push((prev_end..label.text.len(), fade_out));
22490            }
22491
22492            runs
22493        })
22494}
22495
22496pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22497    let mut prev_index = 0;
22498    let mut prev_codepoint: Option<char> = None;
22499    text.char_indices()
22500        .chain([(text.len(), '\0')])
22501        .filter_map(move |(index, codepoint)| {
22502            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22503            let is_boundary = index == text.len()
22504                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22505                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22506            if is_boundary {
22507                let chunk = &text[prev_index..index];
22508                prev_index = index;
22509                Some(chunk)
22510            } else {
22511                None
22512            }
22513        })
22514}
22515
22516pub trait RangeToAnchorExt: Sized {
22517    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22518
22519    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22520        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22521        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22522    }
22523}
22524
22525impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22526    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22527        let start_offset = self.start.to_offset(snapshot);
22528        let end_offset = self.end.to_offset(snapshot);
22529        if start_offset == end_offset {
22530            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22531        } else {
22532            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22533        }
22534    }
22535}
22536
22537pub trait RowExt {
22538    fn as_f32(&self) -> f32;
22539
22540    fn next_row(&self) -> Self;
22541
22542    fn previous_row(&self) -> Self;
22543
22544    fn minus(&self, other: Self) -> u32;
22545}
22546
22547impl RowExt for DisplayRow {
22548    fn as_f32(&self) -> f32 {
22549        self.0 as f32
22550    }
22551
22552    fn next_row(&self) -> Self {
22553        Self(self.0 + 1)
22554    }
22555
22556    fn previous_row(&self) -> Self {
22557        Self(self.0.saturating_sub(1))
22558    }
22559
22560    fn minus(&self, other: Self) -> u32 {
22561        self.0 - other.0
22562    }
22563}
22564
22565impl RowExt for MultiBufferRow {
22566    fn as_f32(&self) -> f32 {
22567        self.0 as f32
22568    }
22569
22570    fn next_row(&self) -> Self {
22571        Self(self.0 + 1)
22572    }
22573
22574    fn previous_row(&self) -> Self {
22575        Self(self.0.saturating_sub(1))
22576    }
22577
22578    fn minus(&self, other: Self) -> u32 {
22579        self.0 - other.0
22580    }
22581}
22582
22583trait RowRangeExt {
22584    type Row;
22585
22586    fn len(&self) -> usize;
22587
22588    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22589}
22590
22591impl RowRangeExt for Range<MultiBufferRow> {
22592    type Row = MultiBufferRow;
22593
22594    fn len(&self) -> usize {
22595        (self.end.0 - self.start.0) as usize
22596    }
22597
22598    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22599        (self.start.0..self.end.0).map(MultiBufferRow)
22600    }
22601}
22602
22603impl RowRangeExt for Range<DisplayRow> {
22604    type Row = DisplayRow;
22605
22606    fn len(&self) -> usize {
22607        (self.end.0 - self.start.0) as usize
22608    }
22609
22610    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22611        (self.start.0..self.end.0).map(DisplayRow)
22612    }
22613}
22614
22615/// If select range has more than one line, we
22616/// just point the cursor to range.start.
22617fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22618    if range.start.row == range.end.row {
22619        range
22620    } else {
22621        range.start..range.start
22622    }
22623}
22624pub struct KillRing(ClipboardItem);
22625impl Global for KillRing {}
22626
22627const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22628
22629enum BreakpointPromptEditAction {
22630    Log,
22631    Condition,
22632    HitCondition,
22633}
22634
22635struct BreakpointPromptEditor {
22636    pub(crate) prompt: Entity<Editor>,
22637    editor: WeakEntity<Editor>,
22638    breakpoint_anchor: Anchor,
22639    breakpoint: Breakpoint,
22640    edit_action: BreakpointPromptEditAction,
22641    block_ids: HashSet<CustomBlockId>,
22642    editor_margins: Arc<Mutex<EditorMargins>>,
22643    _subscriptions: Vec<Subscription>,
22644}
22645
22646impl BreakpointPromptEditor {
22647    const MAX_LINES: u8 = 4;
22648
22649    fn new(
22650        editor: WeakEntity<Editor>,
22651        breakpoint_anchor: Anchor,
22652        breakpoint: Breakpoint,
22653        edit_action: BreakpointPromptEditAction,
22654        window: &mut Window,
22655        cx: &mut Context<Self>,
22656    ) -> Self {
22657        let base_text = match edit_action {
22658            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22659            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22660            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22661        }
22662        .map(|msg| msg.to_string())
22663        .unwrap_or_default();
22664
22665        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22666        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22667
22668        let prompt = cx.new(|cx| {
22669            let mut prompt = Editor::new(
22670                EditorMode::AutoHeight {
22671                    min_lines: 1,
22672                    max_lines: Self::MAX_LINES as usize,
22673                },
22674                buffer,
22675                None,
22676                window,
22677                cx,
22678            );
22679            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22680            prompt.set_show_cursor_when_unfocused(false, cx);
22681            prompt.set_placeholder_text(
22682                match edit_action {
22683                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22684                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22685                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22686                },
22687                cx,
22688            );
22689
22690            prompt
22691        });
22692
22693        Self {
22694            prompt,
22695            editor,
22696            breakpoint_anchor,
22697            breakpoint,
22698            edit_action,
22699            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22700            block_ids: Default::default(),
22701            _subscriptions: vec![],
22702        }
22703    }
22704
22705    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22706        self.block_ids.extend(block_ids)
22707    }
22708
22709    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22710        if let Some(editor) = self.editor.upgrade() {
22711            let message = self
22712                .prompt
22713                .read(cx)
22714                .buffer
22715                .read(cx)
22716                .as_singleton()
22717                .expect("A multi buffer in breakpoint prompt isn't possible")
22718                .read(cx)
22719                .as_rope()
22720                .to_string();
22721
22722            editor.update(cx, |editor, cx| {
22723                editor.edit_breakpoint_at_anchor(
22724                    self.breakpoint_anchor,
22725                    self.breakpoint.clone(),
22726                    match self.edit_action {
22727                        BreakpointPromptEditAction::Log => {
22728                            BreakpointEditAction::EditLogMessage(message.into())
22729                        }
22730                        BreakpointPromptEditAction::Condition => {
22731                            BreakpointEditAction::EditCondition(message.into())
22732                        }
22733                        BreakpointPromptEditAction::HitCondition => {
22734                            BreakpointEditAction::EditHitCondition(message.into())
22735                        }
22736                    },
22737                    cx,
22738                );
22739
22740                editor.remove_blocks(self.block_ids.clone(), None, cx);
22741                cx.focus_self(window);
22742            });
22743        }
22744    }
22745
22746    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22747        self.editor
22748            .update(cx, |editor, cx| {
22749                editor.remove_blocks(self.block_ids.clone(), None, cx);
22750                window.focus(&editor.focus_handle);
22751            })
22752            .log_err();
22753    }
22754
22755    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22756        let settings = ThemeSettings::get_global(cx);
22757        let text_style = TextStyle {
22758            color: if self.prompt.read(cx).read_only(cx) {
22759                cx.theme().colors().text_disabled
22760            } else {
22761                cx.theme().colors().text
22762            },
22763            font_family: settings.buffer_font.family.clone(),
22764            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22765            font_size: settings.buffer_font_size(cx).into(),
22766            font_weight: settings.buffer_font.weight,
22767            line_height: relative(settings.buffer_line_height.value()),
22768            ..Default::default()
22769        };
22770        EditorElement::new(
22771            &self.prompt,
22772            EditorStyle {
22773                background: cx.theme().colors().editor_background,
22774                local_player: cx.theme().players().local(),
22775                text: text_style,
22776                ..Default::default()
22777            },
22778        )
22779    }
22780}
22781
22782impl Render for BreakpointPromptEditor {
22783    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22784        let editor_margins = *self.editor_margins.lock();
22785        let gutter_dimensions = editor_margins.gutter;
22786        h_flex()
22787            .key_context("Editor")
22788            .bg(cx.theme().colors().editor_background)
22789            .border_y_1()
22790            .border_color(cx.theme().status().info_border)
22791            .size_full()
22792            .py(window.line_height() / 2.5)
22793            .on_action(cx.listener(Self::confirm))
22794            .on_action(cx.listener(Self::cancel))
22795            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22796            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22797    }
22798}
22799
22800impl Focusable for BreakpointPromptEditor {
22801    fn focus_handle(&self, cx: &App) -> FocusHandle {
22802        self.prompt.focus_handle(cx)
22803    }
22804}
22805
22806fn all_edits_insertions_or_deletions(
22807    edits: &Vec<(Range<Anchor>, String)>,
22808    snapshot: &MultiBufferSnapshot,
22809) -> bool {
22810    let mut all_insertions = true;
22811    let mut all_deletions = true;
22812
22813    for (range, new_text) in edits.iter() {
22814        let range_is_empty = range.to_offset(&snapshot).is_empty();
22815        let text_is_empty = new_text.is_empty();
22816
22817        if range_is_empty != text_is_empty {
22818            if range_is_empty {
22819                all_deletions = false;
22820            } else {
22821                all_insertions = false;
22822            }
22823        } else {
22824            return false;
22825        }
22826
22827        if !all_insertions && !all_deletions {
22828            return false;
22829        }
22830    }
22831    all_insertions || all_deletions
22832}
22833
22834struct MissingEditPredictionKeybindingTooltip;
22835
22836impl Render for MissingEditPredictionKeybindingTooltip {
22837    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22838        ui::tooltip_container(window, cx, |container, _, cx| {
22839            container
22840                .flex_shrink_0()
22841                .max_w_80()
22842                .min_h(rems_from_px(124.))
22843                .justify_between()
22844                .child(
22845                    v_flex()
22846                        .flex_1()
22847                        .text_ui_sm(cx)
22848                        .child(Label::new("Conflict with Accept Keybinding"))
22849                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22850                )
22851                .child(
22852                    h_flex()
22853                        .pb_1()
22854                        .gap_1()
22855                        .items_end()
22856                        .w_full()
22857                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22858                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22859                        }))
22860                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22861                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22862                        })),
22863                )
22864        })
22865    }
22866}
22867
22868#[derive(Debug, Clone, Copy, PartialEq)]
22869pub struct LineHighlight {
22870    pub background: Background,
22871    pub border: Option<gpui::Hsla>,
22872    pub include_gutter: bool,
22873    pub type_id: Option<TypeId>,
22874}
22875
22876fn render_diff_hunk_controls(
22877    row: u32,
22878    status: &DiffHunkStatus,
22879    hunk_range: Range<Anchor>,
22880    is_created_file: bool,
22881    line_height: Pixels,
22882    editor: &Entity<Editor>,
22883    _window: &mut Window,
22884    cx: &mut App,
22885) -> AnyElement {
22886    h_flex()
22887        .h(line_height)
22888        .mr_1()
22889        .gap_1()
22890        .px_0p5()
22891        .pb_1()
22892        .border_x_1()
22893        .border_b_1()
22894        .border_color(cx.theme().colors().border_variant)
22895        .rounded_b_lg()
22896        .bg(cx.theme().colors().editor_background)
22897        .gap_1()
22898        .block_mouse_except_scroll()
22899        .shadow_md()
22900        .child(if status.has_secondary_hunk() {
22901            Button::new(("stage", row as u64), "Stage")
22902                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22903                .tooltip({
22904                    let focus_handle = editor.focus_handle(cx);
22905                    move |window, cx| {
22906                        Tooltip::for_action_in(
22907                            "Stage Hunk",
22908                            &::git::ToggleStaged,
22909                            &focus_handle,
22910                            window,
22911                            cx,
22912                        )
22913                    }
22914                })
22915                .on_click({
22916                    let editor = editor.clone();
22917                    move |_event, _window, cx| {
22918                        editor.update(cx, |editor, cx| {
22919                            editor.stage_or_unstage_diff_hunks(
22920                                true,
22921                                vec![hunk_range.start..hunk_range.start],
22922                                cx,
22923                            );
22924                        });
22925                    }
22926                })
22927        } else {
22928            Button::new(("unstage", row as u64), "Unstage")
22929                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22930                .tooltip({
22931                    let focus_handle = editor.focus_handle(cx);
22932                    move |window, cx| {
22933                        Tooltip::for_action_in(
22934                            "Unstage Hunk",
22935                            &::git::ToggleStaged,
22936                            &focus_handle,
22937                            window,
22938                            cx,
22939                        )
22940                    }
22941                })
22942                .on_click({
22943                    let editor = editor.clone();
22944                    move |_event, _window, cx| {
22945                        editor.update(cx, |editor, cx| {
22946                            editor.stage_or_unstage_diff_hunks(
22947                                false,
22948                                vec![hunk_range.start..hunk_range.start],
22949                                cx,
22950                            );
22951                        });
22952                    }
22953                })
22954        })
22955        .child(
22956            Button::new(("restore", row as u64), "Restore")
22957                .tooltip({
22958                    let focus_handle = editor.focus_handle(cx);
22959                    move |window, cx| {
22960                        Tooltip::for_action_in(
22961                            "Restore Hunk",
22962                            &::git::Restore,
22963                            &focus_handle,
22964                            window,
22965                            cx,
22966                        )
22967                    }
22968                })
22969                .on_click({
22970                    let editor = editor.clone();
22971                    move |_event, window, cx| {
22972                        editor.update(cx, |editor, cx| {
22973                            let snapshot = editor.snapshot(window, cx);
22974                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22975                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22976                        });
22977                    }
22978                })
22979                .disabled(is_created_file),
22980        )
22981        .when(
22982            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22983            |el| {
22984                el.child(
22985                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22986                        .shape(IconButtonShape::Square)
22987                        .icon_size(IconSize::Small)
22988                        // .disabled(!has_multiple_hunks)
22989                        .tooltip({
22990                            let focus_handle = editor.focus_handle(cx);
22991                            move |window, cx| {
22992                                Tooltip::for_action_in(
22993                                    "Next Hunk",
22994                                    &GoToHunk,
22995                                    &focus_handle,
22996                                    window,
22997                                    cx,
22998                                )
22999                            }
23000                        })
23001                        .on_click({
23002                            let editor = editor.clone();
23003                            move |_event, window, cx| {
23004                                editor.update(cx, |editor, cx| {
23005                                    let snapshot = editor.snapshot(window, cx);
23006                                    let position =
23007                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23008                                    editor.go_to_hunk_before_or_after_position(
23009                                        &snapshot,
23010                                        position,
23011                                        Direction::Next,
23012                                        window,
23013                                        cx,
23014                                    );
23015                                    editor.expand_selected_diff_hunks(cx);
23016                                });
23017                            }
23018                        }),
23019                )
23020                .child(
23021                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23022                        .shape(IconButtonShape::Square)
23023                        .icon_size(IconSize::Small)
23024                        // .disabled(!has_multiple_hunks)
23025                        .tooltip({
23026                            let focus_handle = editor.focus_handle(cx);
23027                            move |window, cx| {
23028                                Tooltip::for_action_in(
23029                                    "Previous Hunk",
23030                                    &GoToPreviousHunk,
23031                                    &focus_handle,
23032                                    window,
23033                                    cx,
23034                                )
23035                            }
23036                        })
23037                        .on_click({
23038                            let editor = editor.clone();
23039                            move |_event, window, cx| {
23040                                editor.update(cx, |editor, cx| {
23041                                    let snapshot = editor.snapshot(window, cx);
23042                                    let point =
23043                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23044                                    editor.go_to_hunk_before_or_after_position(
23045                                        &snapshot,
23046                                        point,
23047                                        Direction::Prev,
23048                                        window,
23049                                        cx,
23050                                    );
23051                                    editor.expand_selected_diff_hunks(cx);
23052                                });
23053                            }
23054                        }),
23055                )
23056            },
23057        )
23058        .into_any_element()
23059}