editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82
   83use ::git::blame::BlameEntry;
   84use ::git::{Restore, blame::ParsedCommitMessage};
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use git::blame::{GitBlame, GlobalBlameRenderer};
   90use gpui::{
   91    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   92    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   93    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   94    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   95    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   96    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   97    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   98    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   99};
  100use highlight_matching_bracket::refresh_matching_bracket_highlights;
  101use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  102pub use hover_popover::hover_markdown_style;
  103use hover_popover::{HoverState, hide_hover};
  104use indent_guides::ActiveIndentGuidesState;
  105use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  106pub use inline_completion::Direction;
  107use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  108pub use items::MAX_TAB_TITLE_LEN;
  109use itertools::Itertools;
  110use language::{
  111    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  112    CursorShape, DiagnosticEntry, DiagnosticSourceKind, DiffOptions, DocumentationConfig,
  113    EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language,
  114    OffsetRangeExt, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  115    WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, LspPullDiagnostics, ProjectPath, PulledDiagnostics,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    project_settings::DiagnosticSeverity,
  137};
  138
  139pub use git::blame::BlameRenderer;
  140pub use proposed_changes_editor::{
  141    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  142};
  143use std::{cell::OnceCell, iter::Peekable, ops::Not};
  144use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  145
  146pub use lsp::CompletionContext;
  147use lsp::{
  148    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  149    LanguageServerId, LanguageServerName,
  150};
  151
  152use language::BufferSnapshot;
  153pub use lsp_ext::lsp_tasks;
  154use movement::TextLayoutDetails;
  155pub use multi_buffer::{
  156    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  157    RowInfo, ToOffset, ToPoint,
  158};
  159use multi_buffer::{
  160    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  161    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  162};
  163use parking_lot::Mutex;
  164use project::{
  165    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  166    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  167    TaskSourceKind,
  168    debugger::breakpoint_store::Breakpoint,
  169    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  170    project_settings::{GitGutterSetting, ProjectSettings},
  171};
  172use rand::prelude::*;
  173use rpc::{ErrorExt, proto::*};
  174use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  175use selections_collection::{
  176    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  177};
  178use serde::{Deserialize, Serialize};
  179use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  180use smallvec::{SmallVec, smallvec};
  181use snippet::Snippet;
  182use std::sync::Arc;
  183use std::{
  184    any::TypeId,
  185    borrow::Cow,
  186    cell::RefCell,
  187    cmp::{self, Ordering, Reverse},
  188    mem,
  189    num::NonZeroU32,
  190    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  191    path::{Path, PathBuf},
  192    rc::Rc,
  193    time::{Duration, Instant},
  194};
  195pub use sum_tree::Bias;
  196use sum_tree::TreeMap;
  197use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  198use theme::{
  199    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  200    observe_buffer_font_size_adjustment,
  201};
  202use ui::{
  203    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  204    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  205};
  206use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  207use workspace::{
  208    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  209    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  210    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  211    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  212    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  213    searchable::SearchEvent,
  214};
  215
  216use crate::{
  217    code_context_menus::CompletionsMenuSource,
  218    hover_links::{find_url, find_url_from_range},
  219};
  220use crate::{
  221    editor_settings::MultiCursorModifier,
  222    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  223};
  224
  225pub const FILE_HEADER_HEIGHT: u32 = 2;
  226pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  227pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  228const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  229const MAX_LINE_LEN: usize = 1024;
  230const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  231const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  232pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  233#[doc(hidden)]
  234pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  235const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  236
  237pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  240
  241pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  242pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  243pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  244
  245pub type RenderDiffHunkControlsFn = Arc<
  246    dyn Fn(
  247        u32,
  248        &DiffHunkStatus,
  249        Range<Anchor>,
  250        bool,
  251        Pixels,
  252        &Entity<Editor>,
  253        &mut Window,
  254        &mut App,
  255    ) -> AnyElement,
  256>;
  257
  258struct InlineValueCache {
  259    enabled: bool,
  260    inlays: Vec<InlayId>,
  261    refresh_task: Task<Option<()>>,
  262}
  263
  264impl InlineValueCache {
  265    fn new(enabled: bool) -> Self {
  266        Self {
  267            enabled,
  268            inlays: Vec::new(),
  269            refresh_task: Task::ready(None),
  270        }
  271    }
  272}
  273
  274#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  275pub enum InlayId {
  276    InlineCompletion(usize),
  277    Hint(usize),
  278    DebuggerValue(usize),
  279}
  280
  281impl InlayId {
  282    fn id(&self) -> usize {
  283        match self {
  284            Self::InlineCompletion(id) => *id,
  285            Self::Hint(id) => *id,
  286            Self::DebuggerValue(id) => *id,
  287        }
  288    }
  289}
  290
  291pub enum ActiveDebugLine {}
  292pub enum DebugStackFrameLine {}
  293enum DocumentHighlightRead {}
  294enum DocumentHighlightWrite {}
  295enum InputComposition {}
  296pub enum PendingInput {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        mode: ColumnarMode,
  451        goal_column: u32,
  452    },
  453    Extend {
  454        position: DisplayPoint,
  455        click_count: usize,
  456    },
  457    Update {
  458        position: DisplayPoint,
  459        goal_column: u32,
  460        scroll_delta: gpui::Point<f32>,
  461    },
  462    End,
  463}
  464
  465#[derive(Clone, Debug, PartialEq)]
  466pub enum ColumnarMode {
  467    FromMouse,
  468    FromSelection,
  469}
  470
  471#[derive(Clone, Debug)]
  472pub enum SelectMode {
  473    Character,
  474    Word(Range<Anchor>),
  475    Line(Range<Anchor>),
  476    All,
  477}
  478
  479#[derive(Clone, PartialEq, Eq, Debug)]
  480pub enum EditorMode {
  481    SingleLine {
  482        auto_width: bool,
  483    },
  484    AutoHeight {
  485        min_lines: usize,
  486        max_lines: usize,
  487    },
  488    Full {
  489        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  490        scale_ui_elements_with_buffer_font_size: bool,
  491        /// When set to `true`, the editor will render a background for the active line.
  492        show_active_line_background: bool,
  493        /// When set to `true`, the editor's height will be determined by its content.
  494        sized_by_content: bool,
  495    },
  496    Minimap {
  497        parent: WeakEntity<Editor>,
  498    },
  499}
  500
  501impl EditorMode {
  502    pub fn full() -> Self {
  503        Self::Full {
  504            scale_ui_elements_with_buffer_font_size: true,
  505            show_active_line_background: true,
  506            sized_by_content: false,
  507        }
  508    }
  509
  510    pub fn is_full(&self) -> bool {
  511        matches!(self, Self::Full { .. })
  512    }
  513
  514    fn is_minimap(&self) -> bool {
  515        matches!(self, Self::Minimap { .. })
  516    }
  517}
  518
  519#[derive(Copy, Clone, Debug)]
  520pub enum SoftWrap {
  521    /// Prefer not to wrap at all.
  522    ///
  523    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  524    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  525    GitDiff,
  526    /// Prefer a single line generally, unless an overly long line is encountered.
  527    None,
  528    /// Soft wrap lines that exceed the editor width.
  529    EditorWidth,
  530    /// Soft wrap lines at the preferred line length.
  531    Column(u32),
  532    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  533    Bounded(u32),
  534}
  535
  536#[derive(Clone)]
  537pub struct EditorStyle {
  538    pub background: Hsla,
  539    pub local_player: PlayerColor,
  540    pub text: TextStyle,
  541    pub scrollbar_width: Pixels,
  542    pub syntax: Arc<SyntaxTheme>,
  543    pub status: StatusColors,
  544    pub inlay_hints_style: HighlightStyle,
  545    pub inline_completion_styles: InlineCompletionStyles,
  546    pub unnecessary_code_fade: f32,
  547    pub show_underlines: bool,
  548}
  549
  550impl Default for EditorStyle {
  551    fn default() -> Self {
  552        Self {
  553            background: Hsla::default(),
  554            local_player: PlayerColor::default(),
  555            text: TextStyle::default(),
  556            scrollbar_width: Pixels::default(),
  557            syntax: Default::default(),
  558            // HACK: Status colors don't have a real default.
  559            // We should look into removing the status colors from the editor
  560            // style and retrieve them directly from the theme.
  561            status: StatusColors::dark(),
  562            inlay_hints_style: HighlightStyle::default(),
  563            inline_completion_styles: InlineCompletionStyles {
  564                insertion: HighlightStyle::default(),
  565                whitespace: HighlightStyle::default(),
  566            },
  567            unnecessary_code_fade: Default::default(),
  568            show_underlines: true,
  569        }
  570    }
  571}
  572
  573pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  574    let show_background = language_settings::language_settings(None, None, cx)
  575        .inlay_hints
  576        .show_background;
  577
  578    HighlightStyle {
  579        color: Some(cx.theme().status().hint),
  580        background_color: show_background.then(|| cx.theme().status().hint_background),
  581        ..HighlightStyle::default()
  582    }
  583}
  584
  585pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  586    InlineCompletionStyles {
  587        insertion: HighlightStyle {
  588            color: Some(cx.theme().status().predictive),
  589            ..HighlightStyle::default()
  590        },
  591        whitespace: HighlightStyle {
  592            background_color: Some(cx.theme().status().created_background),
  593            ..HighlightStyle::default()
  594        },
  595    }
  596}
  597
  598type CompletionId = usize;
  599
  600pub(crate) enum EditDisplayMode {
  601    TabAccept,
  602    DiffPopover,
  603    Inline,
  604}
  605
  606enum InlineCompletion {
  607    Edit {
  608        edits: Vec<(Range<Anchor>, String)>,
  609        edit_preview: Option<EditPreview>,
  610        display_mode: EditDisplayMode,
  611        snapshot: BufferSnapshot,
  612    },
  613    Move {
  614        target: Anchor,
  615        snapshot: BufferSnapshot,
  616    },
  617}
  618
  619struct InlineCompletionState {
  620    inlay_ids: Vec<InlayId>,
  621    completion: InlineCompletion,
  622    completion_id: Option<SharedString>,
  623    invalidation_range: Range<Anchor>,
  624}
  625
  626enum EditPredictionSettings {
  627    Disabled,
  628    Enabled {
  629        show_in_menu: bool,
  630        preview_requires_modifier: bool,
  631    },
  632}
  633
  634enum InlineCompletionHighlight {}
  635
  636#[derive(Debug, Clone)]
  637struct InlineDiagnostic {
  638    message: SharedString,
  639    group_id: usize,
  640    is_primary: bool,
  641    start: Point,
  642    severity: lsp::DiagnosticSeverity,
  643}
  644
  645pub enum MenuInlineCompletionsPolicy {
  646    Never,
  647    ByProvider,
  648}
  649
  650pub enum EditPredictionPreview {
  651    /// Modifier is not pressed
  652    Inactive { released_too_fast: bool },
  653    /// Modifier pressed
  654    Active {
  655        since: Instant,
  656        previous_scroll_position: Option<ScrollAnchor>,
  657    },
  658}
  659
  660impl EditPredictionPreview {
  661    pub fn released_too_fast(&self) -> bool {
  662        match self {
  663            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  664            EditPredictionPreview::Active { .. } => false,
  665        }
  666    }
  667
  668    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  669        if let EditPredictionPreview::Active {
  670            previous_scroll_position,
  671            ..
  672        } = self
  673        {
  674            *previous_scroll_position = scroll_position;
  675        }
  676    }
  677}
  678
  679pub struct ContextMenuOptions {
  680    pub min_entries_visible: usize,
  681    pub max_entries_visible: usize,
  682    pub placement: Option<ContextMenuPlacement>,
  683}
  684
  685#[derive(Debug, Clone, PartialEq, Eq)]
  686pub enum ContextMenuPlacement {
  687    Above,
  688    Below,
  689}
  690
  691#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  692struct EditorActionId(usize);
  693
  694impl EditorActionId {
  695    pub fn post_inc(&mut self) -> Self {
  696        let answer = self.0;
  697
  698        *self = Self(answer + 1);
  699
  700        Self(answer)
  701    }
  702}
  703
  704// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  705// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  706
  707type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  708type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  709
  710#[derive(Default)]
  711struct ScrollbarMarkerState {
  712    scrollbar_size: Size<Pixels>,
  713    dirty: bool,
  714    markers: Arc<[PaintQuad]>,
  715    pending_refresh: Option<Task<Result<()>>>,
  716}
  717
  718impl ScrollbarMarkerState {
  719    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  720        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  721    }
  722}
  723
  724#[derive(Clone, Copy, PartialEq, Eq)]
  725pub enum MinimapVisibility {
  726    Disabled,
  727    Enabled {
  728        /// The configuration currently present in the users settings.
  729        setting_configuration: bool,
  730        /// Whether to override the currently set visibility from the users setting.
  731        toggle_override: bool,
  732    },
  733}
  734
  735impl MinimapVisibility {
  736    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  737        if mode.is_full() {
  738            Self::Enabled {
  739                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  740                toggle_override: false,
  741            }
  742        } else {
  743            Self::Disabled
  744        }
  745    }
  746
  747    fn hidden(&self) -> Self {
  748        match *self {
  749            Self::Enabled {
  750                setting_configuration,
  751                ..
  752            } => Self::Enabled {
  753                setting_configuration,
  754                toggle_override: setting_configuration,
  755            },
  756            Self::Disabled => Self::Disabled,
  757        }
  758    }
  759
  760    fn disabled(&self) -> bool {
  761        match *self {
  762            Self::Disabled => true,
  763            _ => false,
  764        }
  765    }
  766
  767    fn settings_visibility(&self) -> bool {
  768        match *self {
  769            Self::Enabled {
  770                setting_configuration,
  771                ..
  772            } => setting_configuration,
  773            _ => false,
  774        }
  775    }
  776
  777    fn visible(&self) -> bool {
  778        match *self {
  779            Self::Enabled {
  780                setting_configuration,
  781                toggle_override,
  782            } => setting_configuration ^ toggle_override,
  783            _ => false,
  784        }
  785    }
  786
  787    fn toggle_visibility(&self) -> Self {
  788        match *self {
  789            Self::Enabled {
  790                toggle_override,
  791                setting_configuration,
  792            } => Self::Enabled {
  793                setting_configuration,
  794                toggle_override: !toggle_override,
  795            },
  796            Self::Disabled => Self::Disabled,
  797        }
  798    }
  799}
  800
  801#[derive(Clone, Debug)]
  802struct RunnableTasks {
  803    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  804    offset: multi_buffer::Anchor,
  805    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  806    column: u32,
  807    // Values of all named captures, including those starting with '_'
  808    extra_variables: HashMap<String, String>,
  809    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  810    context_range: Range<BufferOffset>,
  811}
  812
  813impl RunnableTasks {
  814    fn resolve<'a>(
  815        &'a self,
  816        cx: &'a task::TaskContext,
  817    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  818        self.templates.iter().filter_map(|(kind, template)| {
  819            template
  820                .resolve_task(&kind.to_id_base(), cx)
  821                .map(|task| (kind.clone(), task))
  822        })
  823    }
  824}
  825
  826#[derive(Clone)]
  827pub struct ResolvedTasks {
  828    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  829    position: Anchor,
  830}
  831
  832#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  833struct BufferOffset(usize);
  834
  835// Addons allow storing per-editor state in other crates (e.g. Vim)
  836pub trait Addon: 'static {
  837    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  838
  839    fn render_buffer_header_controls(
  840        &self,
  841        _: &ExcerptInfo,
  842        _: &Window,
  843        _: &App,
  844    ) -> Option<AnyElement> {
  845        None
  846    }
  847
  848    fn to_any(&self) -> &dyn std::any::Any;
  849
  850    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  851        None
  852    }
  853}
  854
  855/// A set of caret positions, registered when the editor was edited.
  856pub struct ChangeList {
  857    changes: Vec<Vec<Anchor>>,
  858    /// Currently "selected" change.
  859    position: Option<usize>,
  860}
  861
  862impl ChangeList {
  863    pub fn new() -> Self {
  864        Self {
  865            changes: Vec::new(),
  866            position: None,
  867        }
  868    }
  869
  870    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  871    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  872    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  873        if self.changes.is_empty() {
  874            return None;
  875        }
  876
  877        let prev = self.position.unwrap_or(self.changes.len());
  878        let next = if direction == Direction::Prev {
  879            prev.saturating_sub(count)
  880        } else {
  881            (prev + count).min(self.changes.len() - 1)
  882        };
  883        self.position = Some(next);
  884        self.changes.get(next).map(|anchors| anchors.as_slice())
  885    }
  886
  887    /// Adds a new change to the list, resetting the change list position.
  888    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  889        self.position.take();
  890        if pop_state {
  891            self.changes.pop();
  892        }
  893        self.changes.push(new_positions.clone());
  894    }
  895
  896    pub fn last(&self) -> Option<&[Anchor]> {
  897        self.changes.last().map(|anchors| anchors.as_slice())
  898    }
  899}
  900
  901#[derive(Clone)]
  902struct InlineBlamePopoverState {
  903    scroll_handle: ScrollHandle,
  904    commit_message: Option<ParsedCommitMessage>,
  905    markdown: Entity<Markdown>,
  906}
  907
  908struct InlineBlamePopover {
  909    position: gpui::Point<Pixels>,
  910    hide_task: Option<Task<()>>,
  911    popover_bounds: Option<Bounds<Pixels>>,
  912    popover_state: InlineBlamePopoverState,
  913}
  914
  915enum SelectionDragState {
  916    /// State when no drag related activity is detected.
  917    None,
  918    /// State when the mouse is down on a selection that is about to be dragged.
  919    ReadyToDrag {
  920        selection: Selection<Anchor>,
  921        click_position: gpui::Point<Pixels>,
  922        mouse_down_time: Instant,
  923    },
  924    /// State when the mouse is dragging the selection in the editor.
  925    Dragging {
  926        selection: Selection<Anchor>,
  927        drop_cursor: Selection<Anchor>,
  928        hide_drop_cursor: bool,
  929    },
  930}
  931
  932enum ColumnarSelectionState {
  933    FromMouse {
  934        selection_tail: Anchor,
  935        display_point: Option<DisplayPoint>,
  936    },
  937    FromSelection {
  938        selection_tail: Anchor,
  939    },
  940}
  941
  942/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  943/// a breakpoint on them.
  944#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  945struct PhantomBreakpointIndicator {
  946    display_row: DisplayRow,
  947    /// There's a small debounce between hovering over the line and showing the indicator.
  948    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  949    is_active: bool,
  950    collides_with_existing_breakpoint: bool,
  951}
  952
  953/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  954///
  955/// See the [module level documentation](self) for more information.
  956pub struct Editor {
  957    focus_handle: FocusHandle,
  958    last_focused_descendant: Option<WeakFocusHandle>,
  959    /// The text buffer being edited
  960    buffer: Entity<MultiBuffer>,
  961    /// Map of how text in the buffer should be displayed.
  962    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  963    pub display_map: Entity<DisplayMap>,
  964    pub selections: SelectionsCollection,
  965    pub scroll_manager: ScrollManager,
  966    /// When inline assist editors are linked, they all render cursors because
  967    /// typing enters text into each of them, even the ones that aren't focused.
  968    pub(crate) show_cursor_when_unfocused: bool,
  969    columnar_selection_state: Option<ColumnarSelectionState>,
  970    add_selections_state: Option<AddSelectionsState>,
  971    select_next_state: Option<SelectNextState>,
  972    select_prev_state: Option<SelectNextState>,
  973    selection_history: SelectionHistory,
  974    defer_selection_effects: bool,
  975    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  976    autoclose_regions: Vec<AutocloseRegion>,
  977    snippet_stack: InvalidationStack<SnippetState>,
  978    select_syntax_node_history: SelectSyntaxNodeHistory,
  979    ime_transaction: Option<TransactionId>,
  980    pub diagnostics_max_severity: DiagnosticSeverity,
  981    active_diagnostics: ActiveDiagnostic,
  982    show_inline_diagnostics: bool,
  983    inline_diagnostics_update: Task<()>,
  984    inline_diagnostics_enabled: bool,
  985    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  986    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  987    hard_wrap: Option<usize>,
  988
  989    // TODO: make this a access method
  990    pub project: Option<Entity<Project>>,
  991    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  992    completion_provider: Option<Rc<dyn CompletionProvider>>,
  993    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  994    blink_manager: Entity<BlinkManager>,
  995    show_cursor_names: bool,
  996    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  997    pub show_local_selections: bool,
  998    mode: EditorMode,
  999    show_breadcrumbs: bool,
 1000    show_gutter: bool,
 1001    show_scrollbars: ScrollbarAxes,
 1002    minimap_visibility: MinimapVisibility,
 1003    offset_content: bool,
 1004    disable_expand_excerpt_buttons: bool,
 1005    show_line_numbers: Option<bool>,
 1006    use_relative_line_numbers: Option<bool>,
 1007    show_git_diff_gutter: Option<bool>,
 1008    show_code_actions: Option<bool>,
 1009    show_runnables: Option<bool>,
 1010    show_breakpoints: Option<bool>,
 1011    show_wrap_guides: Option<bool>,
 1012    show_indent_guides: Option<bool>,
 1013    placeholder_text: Option<Arc<str>>,
 1014    highlight_order: usize,
 1015    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1016    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1017    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1018    scrollbar_marker_state: ScrollbarMarkerState,
 1019    active_indent_guides_state: ActiveIndentGuidesState,
 1020    nav_history: Option<ItemNavHistory>,
 1021    context_menu: RefCell<Option<CodeContextMenu>>,
 1022    context_menu_options: Option<ContextMenuOptions>,
 1023    mouse_context_menu: Option<MouseContextMenu>,
 1024    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1025    inline_blame_popover: Option<InlineBlamePopover>,
 1026    inline_blame_popover_show_task: Option<Task<()>>,
 1027    signature_help_state: SignatureHelpState,
 1028    auto_signature_help: Option<bool>,
 1029    find_all_references_task_sources: Vec<Anchor>,
 1030    next_completion_id: CompletionId,
 1031    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1032    code_actions_task: Option<Task<Result<()>>>,
 1033    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1034    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1035    document_highlights_task: Option<Task<()>>,
 1036    linked_editing_range_task: Option<Task<Option<()>>>,
 1037    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1038    pending_rename: Option<RenameState>,
 1039    searchable: bool,
 1040    cursor_shape: CursorShape,
 1041    current_line_highlight: Option<CurrentLineHighlight>,
 1042    collapse_matches: bool,
 1043    autoindent_mode: Option<AutoindentMode>,
 1044    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1045    input_enabled: bool,
 1046    use_modal_editing: bool,
 1047    read_only: bool,
 1048    leader_id: Option<CollaboratorId>,
 1049    remote_id: Option<ViewId>,
 1050    pub hover_state: HoverState,
 1051    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1052    gutter_hovered: bool,
 1053    hovered_link_state: Option<HoveredLinkState>,
 1054    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1055    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1056    active_inline_completion: Option<InlineCompletionState>,
 1057    /// Used to prevent flickering as the user types while the menu is open
 1058    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1059    edit_prediction_settings: EditPredictionSettings,
 1060    inline_completions_hidden_for_vim_mode: bool,
 1061    show_inline_completions_override: Option<bool>,
 1062    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1063    edit_prediction_preview: EditPredictionPreview,
 1064    edit_prediction_indent_conflict: bool,
 1065    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1066    inlay_hint_cache: InlayHintCache,
 1067    next_inlay_id: usize,
 1068    _subscriptions: Vec<Subscription>,
 1069    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1070    gutter_dimensions: GutterDimensions,
 1071    style: Option<EditorStyle>,
 1072    text_style_refinement: Option<TextStyleRefinement>,
 1073    next_editor_action_id: EditorActionId,
 1074    editor_actions: Rc<
 1075        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1076    >,
 1077    use_autoclose: bool,
 1078    use_auto_surround: bool,
 1079    auto_replace_emoji_shortcode: bool,
 1080    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1081    show_git_blame_gutter: bool,
 1082    show_git_blame_inline: bool,
 1083    show_git_blame_inline_delay_task: Option<Task<()>>,
 1084    git_blame_inline_enabled: bool,
 1085    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1086    serialize_dirty_buffers: bool,
 1087    show_selection_menu: Option<bool>,
 1088    blame: Option<Entity<GitBlame>>,
 1089    blame_subscription: Option<Subscription>,
 1090    custom_context_menu: Option<
 1091        Box<
 1092            dyn 'static
 1093                + Fn(
 1094                    &mut Self,
 1095                    DisplayPoint,
 1096                    &mut Window,
 1097                    &mut Context<Self>,
 1098                ) -> Option<Entity<ui::ContextMenu>>,
 1099        >,
 1100    >,
 1101    last_bounds: Option<Bounds<Pixels>>,
 1102    last_position_map: Option<Rc<PositionMap>>,
 1103    expect_bounds_change: Option<Bounds<Pixels>>,
 1104    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1105    tasks_update_task: Option<Task<()>>,
 1106    breakpoint_store: Option<Entity<BreakpointStore>>,
 1107    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1108    hovered_diff_hunk_row: Option<DisplayRow>,
 1109    pull_diagnostics_task: Task<()>,
 1110    in_project_search: bool,
 1111    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1112    breadcrumb_header: Option<String>,
 1113    focused_block: Option<FocusedBlock>,
 1114    next_scroll_position: NextScrollCursorCenterTopBottom,
 1115    addons: HashMap<TypeId, Box<dyn Addon>>,
 1116    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1117    load_diff_task: Option<Shared<Task<()>>>,
 1118    /// Whether we are temporarily displaying a diff other than git's
 1119    temporary_diff_override: bool,
 1120    selection_mark_mode: bool,
 1121    toggle_fold_multiple_buffers: Task<()>,
 1122    _scroll_cursor_center_top_bottom_task: Task<()>,
 1123    serialize_selections: Task<()>,
 1124    serialize_folds: Task<()>,
 1125    mouse_cursor_hidden: bool,
 1126    minimap: Option<Entity<Self>>,
 1127    hide_mouse_mode: HideMouseMode,
 1128    pub change_list: ChangeList,
 1129    inline_value_cache: InlineValueCache,
 1130    selection_drag_state: SelectionDragState,
 1131    drag_and_drop_selection_enabled: bool,
 1132}
 1133
 1134#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1135enum NextScrollCursorCenterTopBottom {
 1136    #[default]
 1137    Center,
 1138    Top,
 1139    Bottom,
 1140}
 1141
 1142impl NextScrollCursorCenterTopBottom {
 1143    fn next(&self) -> Self {
 1144        match self {
 1145            Self::Center => Self::Top,
 1146            Self::Top => Self::Bottom,
 1147            Self::Bottom => Self::Center,
 1148        }
 1149    }
 1150}
 1151
 1152#[derive(Clone)]
 1153pub struct EditorSnapshot {
 1154    pub mode: EditorMode,
 1155    show_gutter: bool,
 1156    show_line_numbers: Option<bool>,
 1157    show_git_diff_gutter: Option<bool>,
 1158    show_code_actions: Option<bool>,
 1159    show_runnables: Option<bool>,
 1160    show_breakpoints: Option<bool>,
 1161    git_blame_gutter_max_author_length: Option<usize>,
 1162    pub display_snapshot: DisplaySnapshot,
 1163    pub placeholder_text: Option<Arc<str>>,
 1164    is_focused: bool,
 1165    scroll_anchor: ScrollAnchor,
 1166    ongoing_scroll: OngoingScroll,
 1167    current_line_highlight: CurrentLineHighlight,
 1168    gutter_hovered: bool,
 1169}
 1170
 1171#[derive(Default, Debug, Clone, Copy)]
 1172pub struct GutterDimensions {
 1173    pub left_padding: Pixels,
 1174    pub right_padding: Pixels,
 1175    pub width: Pixels,
 1176    pub margin: Pixels,
 1177    pub git_blame_entries_width: Option<Pixels>,
 1178}
 1179
 1180impl GutterDimensions {
 1181    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1182        Self {
 1183            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1184            ..Default::default()
 1185        }
 1186    }
 1187
 1188    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1189        -cx.text_system().descent(font_id, font_size)
 1190    }
 1191    /// The full width of the space taken up by the gutter.
 1192    pub fn full_width(&self) -> Pixels {
 1193        self.margin + self.width
 1194    }
 1195
 1196    /// The width of the space reserved for the fold indicators,
 1197    /// use alongside 'justify_end' and `gutter_width` to
 1198    /// right align content with the line numbers
 1199    pub fn fold_area_width(&self) -> Pixels {
 1200        self.margin + self.right_padding
 1201    }
 1202}
 1203
 1204#[derive(Debug)]
 1205pub struct RemoteSelection {
 1206    pub replica_id: ReplicaId,
 1207    pub selection: Selection<Anchor>,
 1208    pub cursor_shape: CursorShape,
 1209    pub collaborator_id: CollaboratorId,
 1210    pub line_mode: bool,
 1211    pub user_name: Option<SharedString>,
 1212    pub color: PlayerColor,
 1213}
 1214
 1215#[derive(Clone, Debug)]
 1216struct SelectionHistoryEntry {
 1217    selections: Arc<[Selection<Anchor>]>,
 1218    select_next_state: Option<SelectNextState>,
 1219    select_prev_state: Option<SelectNextState>,
 1220    add_selections_state: Option<AddSelectionsState>,
 1221}
 1222
 1223#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1224enum SelectionHistoryMode {
 1225    Normal,
 1226    Undoing,
 1227    Redoing,
 1228    Skipping,
 1229}
 1230
 1231#[derive(Clone, PartialEq, Eq, Hash)]
 1232struct HoveredCursor {
 1233    replica_id: u16,
 1234    selection_id: usize,
 1235}
 1236
 1237impl Default for SelectionHistoryMode {
 1238    fn default() -> Self {
 1239        Self::Normal
 1240    }
 1241}
 1242
 1243#[derive(Debug)]
 1244pub struct SelectionEffects {
 1245    nav_history: bool,
 1246    completions: bool,
 1247    scroll: Option<Autoscroll>,
 1248}
 1249
 1250impl Default for SelectionEffects {
 1251    fn default() -> Self {
 1252        Self {
 1253            nav_history: true,
 1254            completions: true,
 1255            scroll: Some(Autoscroll::fit()),
 1256        }
 1257    }
 1258}
 1259impl SelectionEffects {
 1260    pub fn scroll(scroll: Autoscroll) -> Self {
 1261        Self {
 1262            scroll: Some(scroll),
 1263            ..Default::default()
 1264        }
 1265    }
 1266
 1267    pub fn no_scroll() -> Self {
 1268        Self {
 1269            scroll: None,
 1270            ..Default::default()
 1271        }
 1272    }
 1273
 1274    pub fn completions(self, completions: bool) -> Self {
 1275        Self {
 1276            completions,
 1277            ..self
 1278        }
 1279    }
 1280
 1281    pub fn nav_history(self, nav_history: bool) -> Self {
 1282        Self {
 1283            nav_history,
 1284            ..self
 1285        }
 1286    }
 1287}
 1288
 1289struct DeferredSelectionEffectsState {
 1290    changed: bool,
 1291    effects: SelectionEffects,
 1292    old_cursor_position: Anchor,
 1293    history_entry: SelectionHistoryEntry,
 1294}
 1295
 1296#[derive(Default)]
 1297struct SelectionHistory {
 1298    #[allow(clippy::type_complexity)]
 1299    selections_by_transaction:
 1300        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1301    mode: SelectionHistoryMode,
 1302    undo_stack: VecDeque<SelectionHistoryEntry>,
 1303    redo_stack: VecDeque<SelectionHistoryEntry>,
 1304}
 1305
 1306impl SelectionHistory {
 1307    #[track_caller]
 1308    fn insert_transaction(
 1309        &mut self,
 1310        transaction_id: TransactionId,
 1311        selections: Arc<[Selection<Anchor>]>,
 1312    ) {
 1313        if selections.is_empty() {
 1314            log::error!(
 1315                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1316                std::panic::Location::caller()
 1317            );
 1318            return;
 1319        }
 1320        self.selections_by_transaction
 1321            .insert(transaction_id, (selections, None));
 1322    }
 1323
 1324    #[allow(clippy::type_complexity)]
 1325    fn transaction(
 1326        &self,
 1327        transaction_id: TransactionId,
 1328    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1329        self.selections_by_transaction.get(&transaction_id)
 1330    }
 1331
 1332    #[allow(clippy::type_complexity)]
 1333    fn transaction_mut(
 1334        &mut self,
 1335        transaction_id: TransactionId,
 1336    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1337        self.selections_by_transaction.get_mut(&transaction_id)
 1338    }
 1339
 1340    fn push(&mut self, entry: SelectionHistoryEntry) {
 1341        if !entry.selections.is_empty() {
 1342            match self.mode {
 1343                SelectionHistoryMode::Normal => {
 1344                    self.push_undo(entry);
 1345                    self.redo_stack.clear();
 1346                }
 1347                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1348                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1349                SelectionHistoryMode::Skipping => {}
 1350            }
 1351        }
 1352    }
 1353
 1354    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1355        if self
 1356            .undo_stack
 1357            .back()
 1358            .map_or(true, |e| e.selections != entry.selections)
 1359        {
 1360            self.undo_stack.push_back(entry);
 1361            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1362                self.undo_stack.pop_front();
 1363            }
 1364        }
 1365    }
 1366
 1367    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1368        if self
 1369            .redo_stack
 1370            .back()
 1371            .map_or(true, |e| e.selections != entry.selections)
 1372        {
 1373            self.redo_stack.push_back(entry);
 1374            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1375                self.redo_stack.pop_front();
 1376            }
 1377        }
 1378    }
 1379}
 1380
 1381#[derive(Clone, Copy)]
 1382pub struct RowHighlightOptions {
 1383    pub autoscroll: bool,
 1384    pub include_gutter: bool,
 1385}
 1386
 1387impl Default for RowHighlightOptions {
 1388    fn default() -> Self {
 1389        Self {
 1390            autoscroll: Default::default(),
 1391            include_gutter: true,
 1392        }
 1393    }
 1394}
 1395
 1396struct RowHighlight {
 1397    index: usize,
 1398    range: Range<Anchor>,
 1399    color: Hsla,
 1400    options: RowHighlightOptions,
 1401    type_id: TypeId,
 1402}
 1403
 1404#[derive(Clone, Debug)]
 1405struct AddSelectionsState {
 1406    groups: Vec<AddSelectionsGroup>,
 1407}
 1408
 1409#[derive(Clone, Debug)]
 1410struct AddSelectionsGroup {
 1411    above: bool,
 1412    stack: Vec<usize>,
 1413}
 1414
 1415#[derive(Clone)]
 1416struct SelectNextState {
 1417    query: AhoCorasick,
 1418    wordwise: bool,
 1419    done: bool,
 1420}
 1421
 1422impl std::fmt::Debug for SelectNextState {
 1423    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1424        f.debug_struct(std::any::type_name::<Self>())
 1425            .field("wordwise", &self.wordwise)
 1426            .field("done", &self.done)
 1427            .finish()
 1428    }
 1429}
 1430
 1431#[derive(Debug)]
 1432struct AutocloseRegion {
 1433    selection_id: usize,
 1434    range: Range<Anchor>,
 1435    pair: BracketPair,
 1436}
 1437
 1438#[derive(Debug)]
 1439struct SnippetState {
 1440    ranges: Vec<Vec<Range<Anchor>>>,
 1441    active_index: usize,
 1442    choices: Vec<Option<Vec<String>>>,
 1443}
 1444
 1445#[doc(hidden)]
 1446pub struct RenameState {
 1447    pub range: Range<Anchor>,
 1448    pub old_name: Arc<str>,
 1449    pub editor: Entity<Editor>,
 1450    block_id: CustomBlockId,
 1451}
 1452
 1453struct InvalidationStack<T>(Vec<T>);
 1454
 1455struct RegisteredInlineCompletionProvider {
 1456    provider: Arc<dyn InlineCompletionProviderHandle>,
 1457    _subscription: Subscription,
 1458}
 1459
 1460#[derive(Debug, PartialEq, Eq)]
 1461pub struct ActiveDiagnosticGroup {
 1462    pub active_range: Range<Anchor>,
 1463    pub active_message: String,
 1464    pub group_id: usize,
 1465    pub blocks: HashSet<CustomBlockId>,
 1466}
 1467
 1468#[derive(Debug, PartialEq, Eq)]
 1469
 1470pub(crate) enum ActiveDiagnostic {
 1471    None,
 1472    All,
 1473    Group(ActiveDiagnosticGroup),
 1474}
 1475
 1476#[derive(Serialize, Deserialize, Clone, Debug)]
 1477pub struct ClipboardSelection {
 1478    /// The number of bytes in this selection.
 1479    pub len: usize,
 1480    /// Whether this was a full-line selection.
 1481    pub is_entire_line: bool,
 1482    /// The indentation of the first line when this content was originally copied.
 1483    pub first_line_indent: u32,
 1484}
 1485
 1486// selections, scroll behavior, was newest selection reversed
 1487type SelectSyntaxNodeHistoryState = (
 1488    Box<[Selection<usize>]>,
 1489    SelectSyntaxNodeScrollBehavior,
 1490    bool,
 1491);
 1492
 1493#[derive(Default)]
 1494struct SelectSyntaxNodeHistory {
 1495    stack: Vec<SelectSyntaxNodeHistoryState>,
 1496    // disable temporarily to allow changing selections without losing the stack
 1497    pub disable_clearing: bool,
 1498}
 1499
 1500impl SelectSyntaxNodeHistory {
 1501    pub fn try_clear(&mut self) {
 1502        if !self.disable_clearing {
 1503            self.stack.clear();
 1504        }
 1505    }
 1506
 1507    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1508        self.stack.push(selection);
 1509    }
 1510
 1511    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1512        self.stack.pop()
 1513    }
 1514}
 1515
 1516enum SelectSyntaxNodeScrollBehavior {
 1517    CursorTop,
 1518    FitSelection,
 1519    CursorBottom,
 1520}
 1521
 1522#[derive(Debug)]
 1523pub(crate) struct NavigationData {
 1524    cursor_anchor: Anchor,
 1525    cursor_position: Point,
 1526    scroll_anchor: ScrollAnchor,
 1527    scroll_top_row: u32,
 1528}
 1529
 1530#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1531pub enum GotoDefinitionKind {
 1532    Symbol,
 1533    Declaration,
 1534    Type,
 1535    Implementation,
 1536}
 1537
 1538#[derive(Debug, Clone)]
 1539enum InlayHintRefreshReason {
 1540    ModifiersChanged(bool),
 1541    Toggle(bool),
 1542    SettingsChange(InlayHintSettings),
 1543    NewLinesShown,
 1544    BufferEdited(HashSet<Arc<Language>>),
 1545    RefreshRequested,
 1546    ExcerptsRemoved(Vec<ExcerptId>),
 1547}
 1548
 1549impl InlayHintRefreshReason {
 1550    fn description(&self) -> &'static str {
 1551        match self {
 1552            Self::ModifiersChanged(_) => "modifiers changed",
 1553            Self::Toggle(_) => "toggle",
 1554            Self::SettingsChange(_) => "settings change",
 1555            Self::NewLinesShown => "new lines shown",
 1556            Self::BufferEdited(_) => "buffer edited",
 1557            Self::RefreshRequested => "refresh requested",
 1558            Self::ExcerptsRemoved(_) => "excerpts removed",
 1559        }
 1560    }
 1561}
 1562
 1563pub enum FormatTarget {
 1564    Buffers(HashSet<Entity<Buffer>>),
 1565    Ranges(Vec<Range<MultiBufferPoint>>),
 1566}
 1567
 1568pub(crate) struct FocusedBlock {
 1569    id: BlockId,
 1570    focus_handle: WeakFocusHandle,
 1571}
 1572
 1573#[derive(Clone)]
 1574enum JumpData {
 1575    MultiBufferRow {
 1576        row: MultiBufferRow,
 1577        line_offset_from_top: u32,
 1578    },
 1579    MultiBufferPoint {
 1580        excerpt_id: ExcerptId,
 1581        position: Point,
 1582        anchor: text::Anchor,
 1583        line_offset_from_top: u32,
 1584    },
 1585}
 1586
 1587pub enum MultibufferSelectionMode {
 1588    First,
 1589    All,
 1590}
 1591
 1592#[derive(Clone, Copy, Debug, Default)]
 1593pub struct RewrapOptions {
 1594    pub override_language_settings: bool,
 1595    pub preserve_existing_whitespace: bool,
 1596}
 1597
 1598impl Editor {
 1599    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1600        let buffer = cx.new(|cx| Buffer::local("", cx));
 1601        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1602        Self::new(
 1603            EditorMode::SingleLine { auto_width: false },
 1604            buffer,
 1605            None,
 1606            window,
 1607            cx,
 1608        )
 1609    }
 1610
 1611    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1612        let buffer = cx.new(|cx| Buffer::local("", cx));
 1613        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1614        Self::new(EditorMode::full(), buffer, None, window, cx)
 1615    }
 1616
 1617    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1618        let buffer = cx.new(|cx| Buffer::local("", cx));
 1619        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1620        Self::new(
 1621            EditorMode::SingleLine { auto_width: true },
 1622            buffer,
 1623            None,
 1624            window,
 1625            cx,
 1626        )
 1627    }
 1628
 1629    pub fn auto_height(
 1630        min_lines: usize,
 1631        max_lines: usize,
 1632        window: &mut Window,
 1633        cx: &mut Context<Self>,
 1634    ) -> Self {
 1635        let buffer = cx.new(|cx| Buffer::local("", cx));
 1636        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1637        Self::new(
 1638            EditorMode::AutoHeight {
 1639                min_lines,
 1640                max_lines,
 1641            },
 1642            buffer,
 1643            None,
 1644            window,
 1645            cx,
 1646        )
 1647    }
 1648
 1649    pub fn for_buffer(
 1650        buffer: Entity<Buffer>,
 1651        project: Option<Entity<Project>>,
 1652        window: &mut Window,
 1653        cx: &mut Context<Self>,
 1654    ) -> Self {
 1655        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1656        Self::new(EditorMode::full(), buffer, project, window, cx)
 1657    }
 1658
 1659    pub fn for_multibuffer(
 1660        buffer: Entity<MultiBuffer>,
 1661        project: Option<Entity<Project>>,
 1662        window: &mut Window,
 1663        cx: &mut Context<Self>,
 1664    ) -> Self {
 1665        Self::new(EditorMode::full(), buffer, project, window, cx)
 1666    }
 1667
 1668    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1669        let mut clone = Self::new(
 1670            self.mode.clone(),
 1671            self.buffer.clone(),
 1672            self.project.clone(),
 1673            window,
 1674            cx,
 1675        );
 1676        self.display_map.update(cx, |display_map, cx| {
 1677            let snapshot = display_map.snapshot(cx);
 1678            clone.display_map.update(cx, |display_map, cx| {
 1679                display_map.set_state(&snapshot, cx);
 1680            });
 1681        });
 1682        clone.folds_did_change(cx);
 1683        clone.selections.clone_state(&self.selections);
 1684        clone.scroll_manager.clone_state(&self.scroll_manager);
 1685        clone.searchable = self.searchable;
 1686        clone.read_only = self.read_only;
 1687        clone
 1688    }
 1689
 1690    pub fn new(
 1691        mode: EditorMode,
 1692        buffer: Entity<MultiBuffer>,
 1693        project: Option<Entity<Project>>,
 1694        window: &mut Window,
 1695        cx: &mut Context<Self>,
 1696    ) -> Self {
 1697        Editor::new_internal(mode, buffer, project, None, window, cx)
 1698    }
 1699
 1700    fn new_internal(
 1701        mode: EditorMode,
 1702        buffer: Entity<MultiBuffer>,
 1703        project: Option<Entity<Project>>,
 1704        display_map: Option<Entity<DisplayMap>>,
 1705        window: &mut Window,
 1706        cx: &mut Context<Self>,
 1707    ) -> Self {
 1708        debug_assert!(
 1709            display_map.is_none() || mode.is_minimap(),
 1710            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1711        );
 1712
 1713        let full_mode = mode.is_full();
 1714        let diagnostics_max_severity = if full_mode {
 1715            EditorSettings::get_global(cx)
 1716                .diagnostics_max_severity
 1717                .unwrap_or(DiagnosticSeverity::Hint)
 1718        } else {
 1719            DiagnosticSeverity::Off
 1720        };
 1721        let style = window.text_style();
 1722        let font_size = style.font_size.to_pixels(window.rem_size());
 1723        let editor = cx.entity().downgrade();
 1724        let fold_placeholder = FoldPlaceholder {
 1725            constrain_width: true,
 1726            render: Arc::new(move |fold_id, fold_range, cx| {
 1727                let editor = editor.clone();
 1728                div()
 1729                    .id(fold_id)
 1730                    .bg(cx.theme().colors().ghost_element_background)
 1731                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1732                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1733                    .rounded_xs()
 1734                    .size_full()
 1735                    .cursor_pointer()
 1736                    .child("")
 1737                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1738                    .on_click(move |_, _window, cx| {
 1739                        editor
 1740                            .update(cx, |editor, cx| {
 1741                                editor.unfold_ranges(
 1742                                    &[fold_range.start..fold_range.end],
 1743                                    true,
 1744                                    false,
 1745                                    cx,
 1746                                );
 1747                                cx.stop_propagation();
 1748                            })
 1749                            .ok();
 1750                    })
 1751                    .into_any()
 1752            }),
 1753            merge_adjacent: true,
 1754            ..FoldPlaceholder::default()
 1755        };
 1756        let display_map = display_map.unwrap_or_else(|| {
 1757            cx.new(|cx| {
 1758                DisplayMap::new(
 1759                    buffer.clone(),
 1760                    style.font(),
 1761                    font_size,
 1762                    None,
 1763                    FILE_HEADER_HEIGHT,
 1764                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1765                    fold_placeholder,
 1766                    diagnostics_max_severity,
 1767                    cx,
 1768                )
 1769            })
 1770        });
 1771
 1772        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1773
 1774        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1775
 1776        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1777            .then(|| language_settings::SoftWrap::None);
 1778
 1779        let mut project_subscriptions = Vec::new();
 1780        if mode.is_full() {
 1781            if let Some(project) = project.as_ref() {
 1782                project_subscriptions.push(cx.subscribe_in(
 1783                    project,
 1784                    window,
 1785                    |editor, _, event, window, cx| match event {
 1786                        project::Event::RefreshCodeLens => {
 1787                            // we always query lens with actions, without storing them, always refreshing them
 1788                        }
 1789                        project::Event::RefreshInlayHints => {
 1790                            editor
 1791                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1792                        }
 1793                        project::Event::LanguageServerAdded(..)
 1794                        | project::Event::LanguageServerRemoved(..) => {
 1795                            if editor.tasks_update_task.is_none() {
 1796                                editor.tasks_update_task =
 1797                                    Some(editor.refresh_runnables(window, cx));
 1798                            }
 1799                            editor.pull_diagnostics(None, window, cx);
 1800                        }
 1801                        project::Event::SnippetEdit(id, snippet_edits) => {
 1802                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1803                                let focus_handle = editor.focus_handle(cx);
 1804                                if focus_handle.is_focused(window) {
 1805                                    let snapshot = buffer.read(cx).snapshot();
 1806                                    for (range, snippet) in snippet_edits {
 1807                                        let editor_range =
 1808                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1809                                        editor
 1810                                            .insert_snippet(
 1811                                                &[editor_range],
 1812                                                snippet.clone(),
 1813                                                window,
 1814                                                cx,
 1815                                            )
 1816                                            .ok();
 1817                                    }
 1818                                }
 1819                            }
 1820                        }
 1821                        _ => {}
 1822                    },
 1823                ));
 1824                if let Some(task_inventory) = project
 1825                    .read(cx)
 1826                    .task_store()
 1827                    .read(cx)
 1828                    .task_inventory()
 1829                    .cloned()
 1830                {
 1831                    project_subscriptions.push(cx.observe_in(
 1832                        &task_inventory,
 1833                        window,
 1834                        |editor, _, window, cx| {
 1835                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1836                        },
 1837                    ));
 1838                };
 1839
 1840                project_subscriptions.push(cx.subscribe_in(
 1841                    &project.read(cx).breakpoint_store(),
 1842                    window,
 1843                    |editor, _, event, window, cx| match event {
 1844                        BreakpointStoreEvent::ClearDebugLines => {
 1845                            editor.clear_row_highlights::<ActiveDebugLine>();
 1846                            editor.refresh_inline_values(cx);
 1847                        }
 1848                        BreakpointStoreEvent::SetDebugLine => {
 1849                            if editor.go_to_active_debug_line(window, cx) {
 1850                                cx.stop_propagation();
 1851                            }
 1852
 1853                            editor.refresh_inline_values(cx);
 1854                        }
 1855                        _ => {}
 1856                    },
 1857                ));
 1858            }
 1859        }
 1860
 1861        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1862
 1863        let inlay_hint_settings =
 1864            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1865        let focus_handle = cx.focus_handle();
 1866        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1867            .detach();
 1868        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1869            .detach();
 1870        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1871            .detach();
 1872        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1873            .detach();
 1874        cx.observe_pending_input(window, Self::observe_pending_input)
 1875            .detach();
 1876
 1877        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1878            Some(false)
 1879        } else {
 1880            None
 1881        };
 1882
 1883        let breakpoint_store = match (&mode, project.as_ref()) {
 1884            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1885            _ => None,
 1886        };
 1887
 1888        let mut code_action_providers = Vec::new();
 1889        let mut load_uncommitted_diff = None;
 1890        if let Some(project) = project.clone() {
 1891            load_uncommitted_diff = Some(
 1892                update_uncommitted_diff_for_buffer(
 1893                    cx.entity(),
 1894                    &project,
 1895                    buffer.read(cx).all_buffers(),
 1896                    buffer.clone(),
 1897                    cx,
 1898                )
 1899                .shared(),
 1900            );
 1901            code_action_providers.push(Rc::new(project) as Rc<_>);
 1902        }
 1903
 1904        let mut editor = Self {
 1905            focus_handle,
 1906            show_cursor_when_unfocused: false,
 1907            last_focused_descendant: None,
 1908            buffer: buffer.clone(),
 1909            display_map: display_map.clone(),
 1910            selections,
 1911            scroll_manager: ScrollManager::new(cx),
 1912            columnar_selection_state: None,
 1913            add_selections_state: None,
 1914            select_next_state: None,
 1915            select_prev_state: None,
 1916            selection_history: SelectionHistory::default(),
 1917            defer_selection_effects: false,
 1918            deferred_selection_effects_state: None,
 1919            autoclose_regions: Vec::new(),
 1920            snippet_stack: InvalidationStack::default(),
 1921            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1922            ime_transaction: None,
 1923            active_diagnostics: ActiveDiagnostic::None,
 1924            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1925            inline_diagnostics_update: Task::ready(()),
 1926            inline_diagnostics: Vec::new(),
 1927            soft_wrap_mode_override,
 1928            diagnostics_max_severity,
 1929            hard_wrap: None,
 1930            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1931            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1932            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1933            project,
 1934            blink_manager: blink_manager.clone(),
 1935            show_local_selections: true,
 1936            show_scrollbars: ScrollbarAxes {
 1937                horizontal: full_mode,
 1938                vertical: full_mode,
 1939            },
 1940            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1941            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1942            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1943            show_gutter: mode.is_full(),
 1944            show_line_numbers: None,
 1945            use_relative_line_numbers: None,
 1946            disable_expand_excerpt_buttons: false,
 1947            show_git_diff_gutter: None,
 1948            show_code_actions: None,
 1949            show_runnables: None,
 1950            show_breakpoints: None,
 1951            show_wrap_guides: None,
 1952            show_indent_guides,
 1953            placeholder_text: None,
 1954            highlight_order: 0,
 1955            highlighted_rows: HashMap::default(),
 1956            background_highlights: TreeMap::default(),
 1957            gutter_highlights: TreeMap::default(),
 1958            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1959            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1960            nav_history: None,
 1961            context_menu: RefCell::new(None),
 1962            context_menu_options: None,
 1963            mouse_context_menu: None,
 1964            completion_tasks: Vec::new(),
 1965            inline_blame_popover: None,
 1966            inline_blame_popover_show_task: None,
 1967            signature_help_state: SignatureHelpState::default(),
 1968            auto_signature_help: None,
 1969            find_all_references_task_sources: Vec::new(),
 1970            next_completion_id: 0,
 1971            next_inlay_id: 0,
 1972            code_action_providers,
 1973            available_code_actions: None,
 1974            code_actions_task: None,
 1975            quick_selection_highlight_task: None,
 1976            debounced_selection_highlight_task: None,
 1977            document_highlights_task: None,
 1978            linked_editing_range_task: None,
 1979            pending_rename: None,
 1980            searchable: true,
 1981            cursor_shape: EditorSettings::get_global(cx)
 1982                .cursor_shape
 1983                .unwrap_or_default(),
 1984            current_line_highlight: None,
 1985            autoindent_mode: Some(AutoindentMode::EachLine),
 1986            collapse_matches: false,
 1987            workspace: None,
 1988            input_enabled: true,
 1989            use_modal_editing: mode.is_full(),
 1990            read_only: mode.is_minimap(),
 1991            use_autoclose: true,
 1992            use_auto_surround: true,
 1993            auto_replace_emoji_shortcode: false,
 1994            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1995            leader_id: None,
 1996            remote_id: None,
 1997            hover_state: HoverState::default(),
 1998            pending_mouse_down: None,
 1999            hovered_link_state: None,
 2000            edit_prediction_provider: None,
 2001            active_inline_completion: None,
 2002            stale_inline_completion_in_menu: None,
 2003            edit_prediction_preview: EditPredictionPreview::Inactive {
 2004                released_too_fast: false,
 2005            },
 2006            inline_diagnostics_enabled: mode.is_full(),
 2007            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2008            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2009
 2010            gutter_hovered: false,
 2011            pixel_position_of_newest_cursor: None,
 2012            last_bounds: None,
 2013            last_position_map: None,
 2014            expect_bounds_change: None,
 2015            gutter_dimensions: GutterDimensions::default(),
 2016            style: None,
 2017            show_cursor_names: false,
 2018            hovered_cursors: HashMap::default(),
 2019            next_editor_action_id: EditorActionId::default(),
 2020            editor_actions: Rc::default(),
 2021            inline_completions_hidden_for_vim_mode: false,
 2022            show_inline_completions_override: None,
 2023            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2024            edit_prediction_settings: EditPredictionSettings::Disabled,
 2025            edit_prediction_indent_conflict: false,
 2026            edit_prediction_requires_modifier_in_indent_conflict: true,
 2027            custom_context_menu: None,
 2028            show_git_blame_gutter: false,
 2029            show_git_blame_inline: false,
 2030            show_selection_menu: None,
 2031            show_git_blame_inline_delay_task: None,
 2032            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2033            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2034            serialize_dirty_buffers: !mode.is_minimap()
 2035                && ProjectSettings::get_global(cx)
 2036                    .session
 2037                    .restore_unsaved_buffers,
 2038            blame: None,
 2039            blame_subscription: None,
 2040            tasks: BTreeMap::default(),
 2041
 2042            breakpoint_store,
 2043            gutter_breakpoint_indicator: (None, None),
 2044            hovered_diff_hunk_row: None,
 2045            _subscriptions: vec![
 2046                cx.observe(&buffer, Self::on_buffer_changed),
 2047                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2048                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2049                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2050                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2051                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2052                cx.observe_window_activation(window, |editor, window, cx| {
 2053                    let active = window.is_window_active();
 2054                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2055                        if active {
 2056                            blink_manager.enable(cx);
 2057                        } else {
 2058                            blink_manager.disable(cx);
 2059                        }
 2060                    });
 2061                    if active {
 2062                        editor.show_mouse_cursor();
 2063                    }
 2064                }),
 2065            ],
 2066            tasks_update_task: None,
 2067            pull_diagnostics_task: Task::ready(()),
 2068            linked_edit_ranges: Default::default(),
 2069            in_project_search: false,
 2070            previous_search_ranges: None,
 2071            breadcrumb_header: None,
 2072            focused_block: None,
 2073            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2074            addons: HashMap::default(),
 2075            registered_buffers: HashMap::default(),
 2076            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2077            selection_mark_mode: false,
 2078            toggle_fold_multiple_buffers: Task::ready(()),
 2079            serialize_selections: Task::ready(()),
 2080            serialize_folds: Task::ready(()),
 2081            text_style_refinement: None,
 2082            load_diff_task: load_uncommitted_diff,
 2083            temporary_diff_override: false,
 2084            mouse_cursor_hidden: false,
 2085            minimap: None,
 2086            hide_mouse_mode: EditorSettings::get_global(cx)
 2087                .hide_mouse
 2088                .unwrap_or_default(),
 2089            change_list: ChangeList::new(),
 2090            mode,
 2091            selection_drag_state: SelectionDragState::None,
 2092            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2093        };
 2094        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2095            editor
 2096                ._subscriptions
 2097                .push(cx.observe(breakpoints, |_, _, cx| {
 2098                    cx.notify();
 2099                }));
 2100        }
 2101        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2102        editor._subscriptions.extend(project_subscriptions);
 2103
 2104        editor._subscriptions.push(cx.subscribe_in(
 2105            &cx.entity(),
 2106            window,
 2107            |editor, _, e: &EditorEvent, window, cx| match e {
 2108                EditorEvent::ScrollPositionChanged { local, .. } => {
 2109                    if *local {
 2110                        let new_anchor = editor.scroll_manager.anchor();
 2111                        let snapshot = editor.snapshot(window, cx);
 2112                        editor.update_restoration_data(cx, move |data| {
 2113                            data.scroll_position = (
 2114                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2115                                new_anchor.offset,
 2116                            );
 2117                        });
 2118                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2119                        editor.inline_blame_popover.take();
 2120                    }
 2121                }
 2122                EditorEvent::Edited { .. } => {
 2123                    if !vim_enabled(cx) {
 2124                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2125                        let pop_state = editor
 2126                            .change_list
 2127                            .last()
 2128                            .map(|previous| {
 2129                                previous.len() == selections.len()
 2130                                    && previous.iter().enumerate().all(|(ix, p)| {
 2131                                        p.to_display_point(&map).row()
 2132                                            == selections[ix].head().row()
 2133                                    })
 2134                            })
 2135                            .unwrap_or(false);
 2136                        let new_positions = selections
 2137                            .into_iter()
 2138                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2139                            .collect();
 2140                        editor
 2141                            .change_list
 2142                            .push_to_change_list(pop_state, new_positions);
 2143                    }
 2144                }
 2145                _ => (),
 2146            },
 2147        ));
 2148
 2149        if let Some(dap_store) = editor
 2150            .project
 2151            .as_ref()
 2152            .map(|project| project.read(cx).dap_store())
 2153        {
 2154            let weak_editor = cx.weak_entity();
 2155
 2156            editor
 2157                ._subscriptions
 2158                .push(
 2159                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2160                        let session_entity = cx.entity();
 2161                        weak_editor
 2162                            .update(cx, |editor, cx| {
 2163                                editor._subscriptions.push(
 2164                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2165                                );
 2166                            })
 2167                            .ok();
 2168                    }),
 2169                );
 2170
 2171            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2172                editor
 2173                    ._subscriptions
 2174                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2175            }
 2176        }
 2177
 2178        // skip adding the initial selection to selection history
 2179        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2180        editor.end_selection(window, cx);
 2181        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2182
 2183        editor.scroll_manager.show_scrollbars(window, cx);
 2184        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2185
 2186        if full_mode {
 2187            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2188            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2189
 2190            if editor.git_blame_inline_enabled {
 2191                editor.start_git_blame_inline(false, window, cx);
 2192            }
 2193
 2194            editor.go_to_active_debug_line(window, cx);
 2195
 2196            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2197                if let Some(project) = editor.project.as_ref() {
 2198                    let handle = project.update(cx, |project, cx| {
 2199                        project.register_buffer_with_language_servers(&buffer, cx)
 2200                    });
 2201                    editor
 2202                        .registered_buffers
 2203                        .insert(buffer.read(cx).remote_id(), handle);
 2204                }
 2205            }
 2206
 2207            editor.minimap =
 2208                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2209            editor.pull_diagnostics(None, window, cx);
 2210        }
 2211
 2212        editor.report_editor_event("Editor Opened", None, cx);
 2213        editor
 2214    }
 2215
 2216    pub fn deploy_mouse_context_menu(
 2217        &mut self,
 2218        position: gpui::Point<Pixels>,
 2219        context_menu: Entity<ContextMenu>,
 2220        window: &mut Window,
 2221        cx: &mut Context<Self>,
 2222    ) {
 2223        self.mouse_context_menu = Some(MouseContextMenu::new(
 2224            self,
 2225            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2226            context_menu,
 2227            window,
 2228            cx,
 2229        ));
 2230    }
 2231
 2232    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2233        self.mouse_context_menu
 2234            .as_ref()
 2235            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2236    }
 2237
 2238    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2239        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2240    }
 2241
 2242    fn key_context_internal(
 2243        &self,
 2244        has_active_edit_prediction: bool,
 2245        window: &Window,
 2246        cx: &App,
 2247    ) -> KeyContext {
 2248        let mut key_context = KeyContext::new_with_defaults();
 2249        key_context.add("Editor");
 2250        let mode = match self.mode {
 2251            EditorMode::SingleLine { .. } => "single_line",
 2252            EditorMode::AutoHeight { .. } => "auto_height",
 2253            EditorMode::Minimap { .. } => "minimap",
 2254            EditorMode::Full { .. } => "full",
 2255        };
 2256
 2257        if EditorSettings::jupyter_enabled(cx) {
 2258            key_context.add("jupyter");
 2259        }
 2260
 2261        key_context.set("mode", mode);
 2262        if self.pending_rename.is_some() {
 2263            key_context.add("renaming");
 2264        }
 2265
 2266        match self.context_menu.borrow().as_ref() {
 2267            Some(CodeContextMenu::Completions(_)) => {
 2268                key_context.add("menu");
 2269                key_context.add("showing_completions");
 2270            }
 2271            Some(CodeContextMenu::CodeActions(_)) => {
 2272                key_context.add("menu");
 2273                key_context.add("showing_code_actions")
 2274            }
 2275            None => {}
 2276        }
 2277
 2278        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2279        if !self.focus_handle(cx).contains_focused(window, cx)
 2280            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2281        {
 2282            for addon in self.addons.values() {
 2283                addon.extend_key_context(&mut key_context, cx)
 2284            }
 2285        }
 2286
 2287        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2288            if let Some(extension) = singleton_buffer
 2289                .read(cx)
 2290                .file()
 2291                .and_then(|file| file.path().extension()?.to_str())
 2292            {
 2293                key_context.set("extension", extension.to_string());
 2294            }
 2295        } else {
 2296            key_context.add("multibuffer");
 2297        }
 2298
 2299        if has_active_edit_prediction {
 2300            if self.edit_prediction_in_conflict() {
 2301                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2302            } else {
 2303                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2304                key_context.add("copilot_suggestion");
 2305            }
 2306        }
 2307
 2308        if self.selection_mark_mode {
 2309            key_context.add("selection_mode");
 2310        }
 2311
 2312        key_context
 2313    }
 2314
 2315    fn show_mouse_cursor(&mut self) {
 2316        self.mouse_cursor_hidden = false;
 2317    }
 2318
 2319    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2320        self.mouse_cursor_hidden = match origin {
 2321            HideMouseCursorOrigin::TypingAction => {
 2322                matches!(
 2323                    self.hide_mouse_mode,
 2324                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2325                )
 2326            }
 2327            HideMouseCursorOrigin::MovementAction => {
 2328                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2329            }
 2330        };
 2331    }
 2332
 2333    pub fn edit_prediction_in_conflict(&self) -> bool {
 2334        if !self.show_edit_predictions_in_menu() {
 2335            return false;
 2336        }
 2337
 2338        let showing_completions = self
 2339            .context_menu
 2340            .borrow()
 2341            .as_ref()
 2342            .map_or(false, |context| {
 2343                matches!(context, CodeContextMenu::Completions(_))
 2344            });
 2345
 2346        showing_completions
 2347            || self.edit_prediction_requires_modifier()
 2348            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2349            // bindings to insert tab characters.
 2350            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2351    }
 2352
 2353    pub fn accept_edit_prediction_keybind(
 2354        &self,
 2355        accept_partial: bool,
 2356        window: &Window,
 2357        cx: &App,
 2358    ) -> AcceptEditPredictionBinding {
 2359        let key_context = self.key_context_internal(true, window, cx);
 2360        let in_conflict = self.edit_prediction_in_conflict();
 2361
 2362        let bindings = if accept_partial {
 2363            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2364        } else {
 2365            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2366        };
 2367
 2368        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2369        // just the first one.
 2370        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2371            !in_conflict
 2372                || binding
 2373                    .keystrokes()
 2374                    .first()
 2375                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2376        }))
 2377    }
 2378
 2379    pub fn new_file(
 2380        workspace: &mut Workspace,
 2381        _: &workspace::NewFile,
 2382        window: &mut Window,
 2383        cx: &mut Context<Workspace>,
 2384    ) {
 2385        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2386            "Failed to create buffer",
 2387            window,
 2388            cx,
 2389            |e, _, _| match e.error_code() {
 2390                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2391                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2392                e.error_tag("required").unwrap_or("the latest version")
 2393            )),
 2394                _ => None,
 2395            },
 2396        );
 2397    }
 2398
 2399    pub fn new_in_workspace(
 2400        workspace: &mut Workspace,
 2401        window: &mut Window,
 2402        cx: &mut Context<Workspace>,
 2403    ) -> Task<Result<Entity<Editor>>> {
 2404        let project = workspace.project().clone();
 2405        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2406
 2407        cx.spawn_in(window, async move |workspace, cx| {
 2408            let buffer = create.await?;
 2409            workspace.update_in(cx, |workspace, window, cx| {
 2410                let editor =
 2411                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2412                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2413                editor
 2414            })
 2415        })
 2416    }
 2417
 2418    fn new_file_vertical(
 2419        workspace: &mut Workspace,
 2420        _: &workspace::NewFileSplitVertical,
 2421        window: &mut Window,
 2422        cx: &mut Context<Workspace>,
 2423    ) {
 2424        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2425    }
 2426
 2427    fn new_file_horizontal(
 2428        workspace: &mut Workspace,
 2429        _: &workspace::NewFileSplitHorizontal,
 2430        window: &mut Window,
 2431        cx: &mut Context<Workspace>,
 2432    ) {
 2433        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2434    }
 2435
 2436    fn new_file_in_direction(
 2437        workspace: &mut Workspace,
 2438        direction: SplitDirection,
 2439        window: &mut Window,
 2440        cx: &mut Context<Workspace>,
 2441    ) {
 2442        let project = workspace.project().clone();
 2443        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2444
 2445        cx.spawn_in(window, async move |workspace, cx| {
 2446            let buffer = create.await?;
 2447            workspace.update_in(cx, move |workspace, window, cx| {
 2448                workspace.split_item(
 2449                    direction,
 2450                    Box::new(
 2451                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2452                    ),
 2453                    window,
 2454                    cx,
 2455                )
 2456            })?;
 2457            anyhow::Ok(())
 2458        })
 2459        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2460            match e.error_code() {
 2461                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2462                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2463                e.error_tag("required").unwrap_or("the latest version")
 2464            )),
 2465                _ => None,
 2466            }
 2467        });
 2468    }
 2469
 2470    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2471        self.leader_id
 2472    }
 2473
 2474    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2475        &self.buffer
 2476    }
 2477
 2478    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2479        self.workspace.as_ref()?.0.upgrade()
 2480    }
 2481
 2482    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2483        self.buffer().read(cx).title(cx)
 2484    }
 2485
 2486    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2487        let git_blame_gutter_max_author_length = self
 2488            .render_git_blame_gutter(cx)
 2489            .then(|| {
 2490                if let Some(blame) = self.blame.as_ref() {
 2491                    let max_author_length =
 2492                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2493                    Some(max_author_length)
 2494                } else {
 2495                    None
 2496                }
 2497            })
 2498            .flatten();
 2499
 2500        EditorSnapshot {
 2501            mode: self.mode.clone(),
 2502            show_gutter: self.show_gutter,
 2503            show_line_numbers: self.show_line_numbers,
 2504            show_git_diff_gutter: self.show_git_diff_gutter,
 2505            show_code_actions: self.show_code_actions,
 2506            show_runnables: self.show_runnables,
 2507            show_breakpoints: self.show_breakpoints,
 2508            git_blame_gutter_max_author_length,
 2509            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2510            scroll_anchor: self.scroll_manager.anchor(),
 2511            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2512            placeholder_text: self.placeholder_text.clone(),
 2513            is_focused: self.focus_handle.is_focused(window),
 2514            current_line_highlight: self
 2515                .current_line_highlight
 2516                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2517            gutter_hovered: self.gutter_hovered,
 2518        }
 2519    }
 2520
 2521    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2522        self.buffer.read(cx).language_at(point, cx)
 2523    }
 2524
 2525    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2526        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2527    }
 2528
 2529    pub fn active_excerpt(
 2530        &self,
 2531        cx: &App,
 2532    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2533        self.buffer
 2534            .read(cx)
 2535            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2536    }
 2537
 2538    pub fn mode(&self) -> &EditorMode {
 2539        &self.mode
 2540    }
 2541
 2542    pub fn set_mode(&mut self, mode: EditorMode) {
 2543        self.mode = mode;
 2544    }
 2545
 2546    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2547        self.collaboration_hub.as_deref()
 2548    }
 2549
 2550    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2551        self.collaboration_hub = Some(hub);
 2552    }
 2553
 2554    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2555        self.in_project_search = in_project_search;
 2556    }
 2557
 2558    pub fn set_custom_context_menu(
 2559        &mut self,
 2560        f: impl 'static
 2561        + Fn(
 2562            &mut Self,
 2563            DisplayPoint,
 2564            &mut Window,
 2565            &mut Context<Self>,
 2566        ) -> Option<Entity<ui::ContextMenu>>,
 2567    ) {
 2568        self.custom_context_menu = Some(Box::new(f))
 2569    }
 2570
 2571    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2572        self.completion_provider = provider;
 2573    }
 2574
 2575    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2576        self.semantics_provider.clone()
 2577    }
 2578
 2579    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2580        self.semantics_provider = provider;
 2581    }
 2582
 2583    pub fn set_edit_prediction_provider<T>(
 2584        &mut self,
 2585        provider: Option<Entity<T>>,
 2586        window: &mut Window,
 2587        cx: &mut Context<Self>,
 2588    ) where
 2589        T: EditPredictionProvider,
 2590    {
 2591        self.edit_prediction_provider =
 2592            provider.map(|provider| RegisteredInlineCompletionProvider {
 2593                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2594                    if this.focus_handle.is_focused(window) {
 2595                        this.update_visible_inline_completion(window, cx);
 2596                    }
 2597                }),
 2598                provider: Arc::new(provider),
 2599            });
 2600        self.update_edit_prediction_settings(cx);
 2601        self.refresh_inline_completion(false, false, window, cx);
 2602    }
 2603
 2604    pub fn placeholder_text(&self) -> Option<&str> {
 2605        self.placeholder_text.as_deref()
 2606    }
 2607
 2608    pub fn set_placeholder_text(
 2609        &mut self,
 2610        placeholder_text: impl Into<Arc<str>>,
 2611        cx: &mut Context<Self>,
 2612    ) {
 2613        let placeholder_text = Some(placeholder_text.into());
 2614        if self.placeholder_text != placeholder_text {
 2615            self.placeholder_text = placeholder_text;
 2616            cx.notify();
 2617        }
 2618    }
 2619
 2620    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2621        self.cursor_shape = cursor_shape;
 2622
 2623        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2624        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2625
 2626        cx.notify();
 2627    }
 2628
 2629    pub fn set_current_line_highlight(
 2630        &mut self,
 2631        current_line_highlight: Option<CurrentLineHighlight>,
 2632    ) {
 2633        self.current_line_highlight = current_line_highlight;
 2634    }
 2635
 2636    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2637        self.collapse_matches = collapse_matches;
 2638    }
 2639
 2640    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2641        let buffers = self.buffer.read(cx).all_buffers();
 2642        let Some(project) = self.project.as_ref() else {
 2643            return;
 2644        };
 2645        project.update(cx, |project, cx| {
 2646            for buffer in buffers {
 2647                self.registered_buffers
 2648                    .entry(buffer.read(cx).remote_id())
 2649                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2650            }
 2651        })
 2652    }
 2653
 2654    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2655        if self.collapse_matches {
 2656            return range.start..range.start;
 2657        }
 2658        range.clone()
 2659    }
 2660
 2661    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2662        if self.display_map.read(cx).clip_at_line_ends != clip {
 2663            self.display_map
 2664                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2665        }
 2666    }
 2667
 2668    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2669        self.input_enabled = input_enabled;
 2670    }
 2671
 2672    pub fn set_inline_completions_hidden_for_vim_mode(
 2673        &mut self,
 2674        hidden: bool,
 2675        window: &mut Window,
 2676        cx: &mut Context<Self>,
 2677    ) {
 2678        if hidden != self.inline_completions_hidden_for_vim_mode {
 2679            self.inline_completions_hidden_for_vim_mode = hidden;
 2680            if hidden {
 2681                self.update_visible_inline_completion(window, cx);
 2682            } else {
 2683                self.refresh_inline_completion(true, false, window, cx);
 2684            }
 2685        }
 2686    }
 2687
 2688    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2689        self.menu_inline_completions_policy = value;
 2690    }
 2691
 2692    pub fn set_autoindent(&mut self, autoindent: bool) {
 2693        if autoindent {
 2694            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2695        } else {
 2696            self.autoindent_mode = None;
 2697        }
 2698    }
 2699
 2700    pub fn read_only(&self, cx: &App) -> bool {
 2701        self.read_only || self.buffer.read(cx).read_only()
 2702    }
 2703
 2704    pub fn set_read_only(&mut self, read_only: bool) {
 2705        self.read_only = read_only;
 2706    }
 2707
 2708    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2709        self.use_autoclose = autoclose;
 2710    }
 2711
 2712    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2713        self.use_auto_surround = auto_surround;
 2714    }
 2715
 2716    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2717        self.auto_replace_emoji_shortcode = auto_replace;
 2718    }
 2719
 2720    pub fn toggle_edit_predictions(
 2721        &mut self,
 2722        _: &ToggleEditPrediction,
 2723        window: &mut Window,
 2724        cx: &mut Context<Self>,
 2725    ) {
 2726        if self.show_inline_completions_override.is_some() {
 2727            self.set_show_edit_predictions(None, window, cx);
 2728        } else {
 2729            let show_edit_predictions = !self.edit_predictions_enabled();
 2730            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2731        }
 2732    }
 2733
 2734    pub fn set_show_edit_predictions(
 2735        &mut self,
 2736        show_edit_predictions: Option<bool>,
 2737        window: &mut Window,
 2738        cx: &mut Context<Self>,
 2739    ) {
 2740        self.show_inline_completions_override = show_edit_predictions;
 2741        self.update_edit_prediction_settings(cx);
 2742
 2743        if let Some(false) = show_edit_predictions {
 2744            self.discard_inline_completion(false, cx);
 2745        } else {
 2746            self.refresh_inline_completion(false, true, window, cx);
 2747        }
 2748    }
 2749
 2750    fn inline_completions_disabled_in_scope(
 2751        &self,
 2752        buffer: &Entity<Buffer>,
 2753        buffer_position: language::Anchor,
 2754        cx: &App,
 2755    ) -> bool {
 2756        let snapshot = buffer.read(cx).snapshot();
 2757        let settings = snapshot.settings_at(buffer_position, cx);
 2758
 2759        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2760            return false;
 2761        };
 2762
 2763        scope.override_name().map_or(false, |scope_name| {
 2764            settings
 2765                .edit_predictions_disabled_in
 2766                .iter()
 2767                .any(|s| s == scope_name)
 2768        })
 2769    }
 2770
 2771    pub fn set_use_modal_editing(&mut self, to: bool) {
 2772        self.use_modal_editing = to;
 2773    }
 2774
 2775    pub fn use_modal_editing(&self) -> bool {
 2776        self.use_modal_editing
 2777    }
 2778
 2779    fn selections_did_change(
 2780        &mut self,
 2781        local: bool,
 2782        old_cursor_position: &Anchor,
 2783        effects: SelectionEffects,
 2784        window: &mut Window,
 2785        cx: &mut Context<Self>,
 2786    ) {
 2787        window.invalidate_character_coordinates();
 2788
 2789        // Copy selections to primary selection buffer
 2790        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2791        if local {
 2792            let selections = self.selections.all::<usize>(cx);
 2793            let buffer_handle = self.buffer.read(cx).read(cx);
 2794
 2795            let mut text = String::new();
 2796            for (index, selection) in selections.iter().enumerate() {
 2797                let text_for_selection = buffer_handle
 2798                    .text_for_range(selection.start..selection.end)
 2799                    .collect::<String>();
 2800
 2801                text.push_str(&text_for_selection);
 2802                if index != selections.len() - 1 {
 2803                    text.push('\n');
 2804                }
 2805            }
 2806
 2807            if !text.is_empty() {
 2808                cx.write_to_primary(ClipboardItem::new_string(text));
 2809            }
 2810        }
 2811
 2812        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2813            self.buffer.update(cx, |buffer, cx| {
 2814                buffer.set_active_selections(
 2815                    &self.selections.disjoint_anchors(),
 2816                    self.selections.line_mode,
 2817                    self.cursor_shape,
 2818                    cx,
 2819                )
 2820            });
 2821        }
 2822        let display_map = self
 2823            .display_map
 2824            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2825        let buffer = &display_map.buffer_snapshot;
 2826        if self.selections.count() == 1 {
 2827            self.add_selections_state = None;
 2828        }
 2829        self.select_next_state = None;
 2830        self.select_prev_state = None;
 2831        self.select_syntax_node_history.try_clear();
 2832        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2833        self.snippet_stack
 2834            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2835        self.take_rename(false, window, cx);
 2836
 2837        let newest_selection = self.selections.newest_anchor();
 2838        let new_cursor_position = newest_selection.head();
 2839        let selection_start = newest_selection.start;
 2840
 2841        if effects.nav_history {
 2842            self.push_to_nav_history(
 2843                *old_cursor_position,
 2844                Some(new_cursor_position.to_point(buffer)),
 2845                false,
 2846                cx,
 2847            );
 2848        }
 2849
 2850        if local {
 2851            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2852                if !self.registered_buffers.contains_key(&buffer_id) {
 2853                    if let Some(project) = self.project.as_ref() {
 2854                        project.update(cx, |project, cx| {
 2855                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2856                                return;
 2857                            };
 2858                            self.registered_buffers.insert(
 2859                                buffer_id,
 2860                                project.register_buffer_with_language_servers(&buffer, cx),
 2861                            );
 2862                        })
 2863                    }
 2864                }
 2865            }
 2866
 2867            let mut context_menu = self.context_menu.borrow_mut();
 2868            let completion_menu = match context_menu.as_ref() {
 2869                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2870                Some(CodeContextMenu::CodeActions(_)) => {
 2871                    *context_menu = None;
 2872                    None
 2873                }
 2874                None => None,
 2875            };
 2876            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2877            drop(context_menu);
 2878
 2879            if effects.completions {
 2880                if let Some(completion_position) = completion_position {
 2881                    let start_offset = selection_start.to_offset(buffer);
 2882                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2883                    let continue_showing = if position_matches {
 2884                        if self.snippet_stack.is_empty() {
 2885                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2886                        } else {
 2887                            // Snippet choices can be shown even when the cursor is in whitespace.
 2888                            // Dismissing the menu with actions like backspace is handled by
 2889                            // invalidation regions.
 2890                            true
 2891                        }
 2892                    } else {
 2893                        false
 2894                    };
 2895
 2896                    if continue_showing {
 2897                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2898                    } else {
 2899                        self.hide_context_menu(window, cx);
 2900                    }
 2901                }
 2902            }
 2903
 2904            hide_hover(self, cx);
 2905
 2906            if old_cursor_position.to_display_point(&display_map).row()
 2907                != new_cursor_position.to_display_point(&display_map).row()
 2908            {
 2909                self.available_code_actions.take();
 2910            }
 2911            self.refresh_code_actions(window, cx);
 2912            self.refresh_document_highlights(cx);
 2913            self.refresh_selected_text_highlights(false, window, cx);
 2914            refresh_matching_bracket_highlights(self, window, cx);
 2915            self.update_visible_inline_completion(window, cx);
 2916            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2917            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2918            self.inline_blame_popover.take();
 2919            if self.git_blame_inline_enabled {
 2920                self.start_inline_blame_timer(window, cx);
 2921            }
 2922        }
 2923
 2924        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2925        cx.emit(EditorEvent::SelectionsChanged { local });
 2926
 2927        let selections = &self.selections.disjoint;
 2928        if selections.len() == 1 {
 2929            cx.emit(SearchEvent::ActiveMatchChanged)
 2930        }
 2931        if local {
 2932            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2933                let inmemory_selections = selections
 2934                    .iter()
 2935                    .map(|s| {
 2936                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2937                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2938                    })
 2939                    .collect();
 2940                self.update_restoration_data(cx, |data| {
 2941                    data.selections = inmemory_selections;
 2942                });
 2943
 2944                if WorkspaceSettings::get(None, cx).restore_on_startup
 2945                    != RestoreOnStartupBehavior::None
 2946                {
 2947                    if let Some(workspace_id) =
 2948                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2949                    {
 2950                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2951                        let selections = selections.clone();
 2952                        let background_executor = cx.background_executor().clone();
 2953                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2954                        self.serialize_selections = cx.background_spawn(async move {
 2955                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2956                            let db_selections = selections
 2957                                .iter()
 2958                                .map(|selection| {
 2959                                    (
 2960                                        selection.start.to_offset(&snapshot),
 2961                                        selection.end.to_offset(&snapshot),
 2962                                    )
 2963                                })
 2964                                .collect();
 2965
 2966                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2967                                .await
 2968                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2969                                .log_err();
 2970                        });
 2971                    }
 2972                }
 2973            }
 2974        }
 2975
 2976        cx.notify();
 2977    }
 2978
 2979    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2980        use text::ToOffset as _;
 2981        use text::ToPoint as _;
 2982
 2983        if self.mode.is_minimap()
 2984            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2985        {
 2986            return;
 2987        }
 2988
 2989        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2990            return;
 2991        };
 2992
 2993        let snapshot = singleton.read(cx).snapshot();
 2994        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2995            let display_snapshot = display_map.snapshot(cx);
 2996
 2997            display_snapshot
 2998                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2999                .map(|fold| {
 3000                    fold.range.start.text_anchor.to_point(&snapshot)
 3001                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3002                })
 3003                .collect()
 3004        });
 3005        self.update_restoration_data(cx, |data| {
 3006            data.folds = inmemory_folds;
 3007        });
 3008
 3009        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3010            return;
 3011        };
 3012        let background_executor = cx.background_executor().clone();
 3013        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3014        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3015            display_map
 3016                .snapshot(cx)
 3017                .folds_in_range(0..snapshot.len())
 3018                .map(|fold| {
 3019                    (
 3020                        fold.range.start.text_anchor.to_offset(&snapshot),
 3021                        fold.range.end.text_anchor.to_offset(&snapshot),
 3022                    )
 3023                })
 3024                .collect()
 3025        });
 3026        self.serialize_folds = cx.background_spawn(async move {
 3027            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3028            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3029                .await
 3030                .with_context(|| {
 3031                    format!(
 3032                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3033                    )
 3034                })
 3035                .log_err();
 3036        });
 3037    }
 3038
 3039    pub fn sync_selections(
 3040        &mut self,
 3041        other: Entity<Editor>,
 3042        cx: &mut Context<Self>,
 3043    ) -> gpui::Subscription {
 3044        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3045        self.selections.change_with(cx, |selections| {
 3046            selections.select_anchors(other_selections);
 3047        });
 3048
 3049        let other_subscription =
 3050            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3051                EditorEvent::SelectionsChanged { local: true } => {
 3052                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3053                    if other_selections.is_empty() {
 3054                        return;
 3055                    }
 3056                    this.selections.change_with(cx, |selections| {
 3057                        selections.select_anchors(other_selections);
 3058                    });
 3059                }
 3060                _ => {}
 3061            });
 3062
 3063        let this_subscription =
 3064            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3065                EditorEvent::SelectionsChanged { local: true } => {
 3066                    let these_selections = this.selections.disjoint.to_vec();
 3067                    if these_selections.is_empty() {
 3068                        return;
 3069                    }
 3070                    other.update(cx, |other_editor, cx| {
 3071                        other_editor.selections.change_with(cx, |selections| {
 3072                            selections.select_anchors(these_selections);
 3073                        })
 3074                    });
 3075                }
 3076                _ => {}
 3077            });
 3078
 3079        Subscription::join(other_subscription, this_subscription)
 3080    }
 3081
 3082    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3083    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3084    /// effects of selection change occur at the end of the transaction.
 3085    pub fn change_selections<R>(
 3086        &mut self,
 3087        effects: impl Into<SelectionEffects>,
 3088        window: &mut Window,
 3089        cx: &mut Context<Self>,
 3090        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3091    ) -> R {
 3092        let effects = effects.into();
 3093        if let Some(state) = &mut self.deferred_selection_effects_state {
 3094            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3095            state.effects.completions = effects.completions;
 3096            state.effects.nav_history |= effects.nav_history;
 3097            let (changed, result) = self.selections.change_with(cx, change);
 3098            state.changed |= changed;
 3099            return result;
 3100        }
 3101        let mut state = DeferredSelectionEffectsState {
 3102            changed: false,
 3103            effects,
 3104            old_cursor_position: self.selections.newest_anchor().head(),
 3105            history_entry: SelectionHistoryEntry {
 3106                selections: self.selections.disjoint_anchors(),
 3107                select_next_state: self.select_next_state.clone(),
 3108                select_prev_state: self.select_prev_state.clone(),
 3109                add_selections_state: self.add_selections_state.clone(),
 3110            },
 3111        };
 3112        let (changed, result) = self.selections.change_with(cx, change);
 3113        state.changed = state.changed || changed;
 3114        if self.defer_selection_effects {
 3115            self.deferred_selection_effects_state = Some(state);
 3116        } else {
 3117            self.apply_selection_effects(state, window, cx);
 3118        }
 3119        result
 3120    }
 3121
 3122    /// Defers the effects of selection change, so that the effects of multiple calls to
 3123    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3124    /// to selection history and the state of popovers based on selection position aren't
 3125    /// erroneously updated.
 3126    pub fn with_selection_effects_deferred<R>(
 3127        &mut self,
 3128        window: &mut Window,
 3129        cx: &mut Context<Self>,
 3130        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3131    ) -> R {
 3132        let already_deferred = self.defer_selection_effects;
 3133        self.defer_selection_effects = true;
 3134        let result = update(self, window, cx);
 3135        if !already_deferred {
 3136            self.defer_selection_effects = false;
 3137            if let Some(state) = self.deferred_selection_effects_state.take() {
 3138                self.apply_selection_effects(state, window, cx);
 3139            }
 3140        }
 3141        result
 3142    }
 3143
 3144    fn apply_selection_effects(
 3145        &mut self,
 3146        state: DeferredSelectionEffectsState,
 3147        window: &mut Window,
 3148        cx: &mut Context<Self>,
 3149    ) {
 3150        if state.changed {
 3151            self.selection_history.push(state.history_entry);
 3152
 3153            if let Some(autoscroll) = state.effects.scroll {
 3154                self.request_autoscroll(autoscroll, cx);
 3155            }
 3156
 3157            let old_cursor_position = &state.old_cursor_position;
 3158
 3159            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3160
 3161            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3162                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3163            }
 3164        }
 3165    }
 3166
 3167    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3168    where
 3169        I: IntoIterator<Item = (Range<S>, T)>,
 3170        S: ToOffset,
 3171        T: Into<Arc<str>>,
 3172    {
 3173        if self.read_only(cx) {
 3174            return;
 3175        }
 3176
 3177        self.buffer
 3178            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3179    }
 3180
 3181    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3182    where
 3183        I: IntoIterator<Item = (Range<S>, T)>,
 3184        S: ToOffset,
 3185        T: Into<Arc<str>>,
 3186    {
 3187        if self.read_only(cx) {
 3188            return;
 3189        }
 3190
 3191        self.buffer.update(cx, |buffer, cx| {
 3192            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3193        });
 3194    }
 3195
 3196    pub fn edit_with_block_indent<I, S, T>(
 3197        &mut self,
 3198        edits: I,
 3199        original_indent_columns: Vec<Option<u32>>,
 3200        cx: &mut Context<Self>,
 3201    ) where
 3202        I: IntoIterator<Item = (Range<S>, T)>,
 3203        S: ToOffset,
 3204        T: Into<Arc<str>>,
 3205    {
 3206        if self.read_only(cx) {
 3207            return;
 3208        }
 3209
 3210        self.buffer.update(cx, |buffer, cx| {
 3211            buffer.edit(
 3212                edits,
 3213                Some(AutoindentMode::Block {
 3214                    original_indent_columns,
 3215                }),
 3216                cx,
 3217            )
 3218        });
 3219    }
 3220
 3221    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3222        self.hide_context_menu(window, cx);
 3223
 3224        match phase {
 3225            SelectPhase::Begin {
 3226                position,
 3227                add,
 3228                click_count,
 3229            } => self.begin_selection(position, add, click_count, window, cx),
 3230            SelectPhase::BeginColumnar {
 3231                position,
 3232                goal_column,
 3233                reset,
 3234                mode,
 3235            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3236            SelectPhase::Extend {
 3237                position,
 3238                click_count,
 3239            } => self.extend_selection(position, click_count, window, cx),
 3240            SelectPhase::Update {
 3241                position,
 3242                goal_column,
 3243                scroll_delta,
 3244            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3245            SelectPhase::End => self.end_selection(window, cx),
 3246        }
 3247    }
 3248
 3249    fn extend_selection(
 3250        &mut self,
 3251        position: DisplayPoint,
 3252        click_count: usize,
 3253        window: &mut Window,
 3254        cx: &mut Context<Self>,
 3255    ) {
 3256        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3257        let tail = self.selections.newest::<usize>(cx).tail();
 3258        self.begin_selection(position, false, click_count, window, cx);
 3259
 3260        let position = position.to_offset(&display_map, Bias::Left);
 3261        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3262
 3263        let mut pending_selection = self
 3264            .selections
 3265            .pending_anchor()
 3266            .expect("extend_selection not called with pending selection");
 3267        if position >= tail {
 3268            pending_selection.start = tail_anchor;
 3269        } else {
 3270            pending_selection.end = tail_anchor;
 3271            pending_selection.reversed = true;
 3272        }
 3273
 3274        let mut pending_mode = self.selections.pending_mode().unwrap();
 3275        match &mut pending_mode {
 3276            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3277            _ => {}
 3278        }
 3279
 3280        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3281            SelectionEffects::scroll(Autoscroll::fit())
 3282        } else {
 3283            SelectionEffects::no_scroll()
 3284        };
 3285
 3286        self.change_selections(effects, window, cx, |s| {
 3287            s.set_pending(pending_selection, pending_mode)
 3288        });
 3289    }
 3290
 3291    fn begin_selection(
 3292        &mut self,
 3293        position: DisplayPoint,
 3294        add: bool,
 3295        click_count: usize,
 3296        window: &mut Window,
 3297        cx: &mut Context<Self>,
 3298    ) {
 3299        if !self.focus_handle.is_focused(window) {
 3300            self.last_focused_descendant = None;
 3301            window.focus(&self.focus_handle);
 3302        }
 3303
 3304        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3305        let buffer = &display_map.buffer_snapshot;
 3306        let position = display_map.clip_point(position, Bias::Left);
 3307
 3308        let start;
 3309        let end;
 3310        let mode;
 3311        let mut auto_scroll;
 3312        match click_count {
 3313            1 => {
 3314                start = buffer.anchor_before(position.to_point(&display_map));
 3315                end = start;
 3316                mode = SelectMode::Character;
 3317                auto_scroll = true;
 3318            }
 3319            2 => {
 3320                let range = movement::surrounding_word(&display_map, position);
 3321                start = buffer.anchor_before(range.start.to_point(&display_map));
 3322                end = buffer.anchor_before(range.end.to_point(&display_map));
 3323                mode = SelectMode::Word(start..end);
 3324                auto_scroll = true;
 3325            }
 3326            3 => {
 3327                let position = display_map
 3328                    .clip_point(position, Bias::Left)
 3329                    .to_point(&display_map);
 3330                let line_start = display_map.prev_line_boundary(position).0;
 3331                let next_line_start = buffer.clip_point(
 3332                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3333                    Bias::Left,
 3334                );
 3335                start = buffer.anchor_before(line_start);
 3336                end = buffer.anchor_before(next_line_start);
 3337                mode = SelectMode::Line(start..end);
 3338                auto_scroll = true;
 3339            }
 3340            _ => {
 3341                start = buffer.anchor_before(0);
 3342                end = buffer.anchor_before(buffer.len());
 3343                mode = SelectMode::All;
 3344                auto_scroll = false;
 3345            }
 3346        }
 3347        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3348
 3349        let point_to_delete: Option<usize> = {
 3350            let selected_points: Vec<Selection<Point>> =
 3351                self.selections.disjoint_in_range(start..end, cx);
 3352
 3353            if !add || click_count > 1 {
 3354                None
 3355            } else if !selected_points.is_empty() {
 3356                Some(selected_points[0].id)
 3357            } else {
 3358                let clicked_point_already_selected =
 3359                    self.selections.disjoint.iter().find(|selection| {
 3360                        selection.start.to_point(buffer) == start.to_point(buffer)
 3361                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3362                    });
 3363
 3364                clicked_point_already_selected.map(|selection| selection.id)
 3365            }
 3366        };
 3367
 3368        let selections_count = self.selections.count();
 3369
 3370        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3371            if let Some(point_to_delete) = point_to_delete {
 3372                s.delete(point_to_delete);
 3373
 3374                if selections_count == 1 {
 3375                    s.set_pending_anchor_range(start..end, mode);
 3376                }
 3377            } else {
 3378                if !add {
 3379                    s.clear_disjoint();
 3380                }
 3381
 3382                s.set_pending_anchor_range(start..end, mode);
 3383            }
 3384        });
 3385    }
 3386
 3387    fn begin_columnar_selection(
 3388        &mut self,
 3389        position: DisplayPoint,
 3390        goal_column: u32,
 3391        reset: bool,
 3392        mode: ColumnarMode,
 3393        window: &mut Window,
 3394        cx: &mut Context<Self>,
 3395    ) {
 3396        if !self.focus_handle.is_focused(window) {
 3397            self.last_focused_descendant = None;
 3398            window.focus(&self.focus_handle);
 3399        }
 3400
 3401        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3402
 3403        if reset {
 3404            let pointer_position = display_map
 3405                .buffer_snapshot
 3406                .anchor_before(position.to_point(&display_map));
 3407
 3408            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3409                s.clear_disjoint();
 3410                s.set_pending_anchor_range(
 3411                    pointer_position..pointer_position,
 3412                    SelectMode::Character,
 3413                );
 3414            });
 3415        };
 3416
 3417        let tail = self.selections.newest::<Point>(cx).tail();
 3418        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3419        self.columnar_selection_state = match mode {
 3420            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3421                selection_tail: selection_anchor,
 3422                display_point: if reset {
 3423                    if position.column() != goal_column {
 3424                        Some(DisplayPoint::new(position.row(), goal_column))
 3425                    } else {
 3426                        None
 3427                    }
 3428                } else {
 3429                    None
 3430                },
 3431            }),
 3432            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3433                selection_tail: selection_anchor,
 3434            }),
 3435        };
 3436
 3437        if !reset {
 3438            self.select_columns(position, goal_column, &display_map, window, cx);
 3439        }
 3440    }
 3441
 3442    fn update_selection(
 3443        &mut self,
 3444        position: DisplayPoint,
 3445        goal_column: u32,
 3446        scroll_delta: gpui::Point<f32>,
 3447        window: &mut Window,
 3448        cx: &mut Context<Self>,
 3449    ) {
 3450        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3451
 3452        if self.columnar_selection_state.is_some() {
 3453            self.select_columns(position, goal_column, &display_map, window, cx);
 3454        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3455            let buffer = self.buffer.read(cx).snapshot(cx);
 3456            let head;
 3457            let tail;
 3458            let mode = self.selections.pending_mode().unwrap();
 3459            match &mode {
 3460                SelectMode::Character => {
 3461                    head = position.to_point(&display_map);
 3462                    tail = pending.tail().to_point(&buffer);
 3463                }
 3464                SelectMode::Word(original_range) => {
 3465                    let original_display_range = original_range.start.to_display_point(&display_map)
 3466                        ..original_range.end.to_display_point(&display_map);
 3467                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3468                        ..original_display_range.end.to_point(&display_map);
 3469                    if movement::is_inside_word(&display_map, position)
 3470                        || original_display_range.contains(&position)
 3471                    {
 3472                        let word_range = movement::surrounding_word(&display_map, position);
 3473                        if word_range.start < original_display_range.start {
 3474                            head = word_range.start.to_point(&display_map);
 3475                        } else {
 3476                            head = word_range.end.to_point(&display_map);
 3477                        }
 3478                    } else {
 3479                        head = position.to_point(&display_map);
 3480                    }
 3481
 3482                    if head <= original_buffer_range.start {
 3483                        tail = original_buffer_range.end;
 3484                    } else {
 3485                        tail = original_buffer_range.start;
 3486                    }
 3487                }
 3488                SelectMode::Line(original_range) => {
 3489                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3490
 3491                    let position = display_map
 3492                        .clip_point(position, Bias::Left)
 3493                        .to_point(&display_map);
 3494                    let line_start = display_map.prev_line_boundary(position).0;
 3495                    let next_line_start = buffer.clip_point(
 3496                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3497                        Bias::Left,
 3498                    );
 3499
 3500                    if line_start < original_range.start {
 3501                        head = line_start
 3502                    } else {
 3503                        head = next_line_start
 3504                    }
 3505
 3506                    if head <= original_range.start {
 3507                        tail = original_range.end;
 3508                    } else {
 3509                        tail = original_range.start;
 3510                    }
 3511                }
 3512                SelectMode::All => {
 3513                    return;
 3514                }
 3515            };
 3516
 3517            if head < tail {
 3518                pending.start = buffer.anchor_before(head);
 3519                pending.end = buffer.anchor_before(tail);
 3520                pending.reversed = true;
 3521            } else {
 3522                pending.start = buffer.anchor_before(tail);
 3523                pending.end = buffer.anchor_before(head);
 3524                pending.reversed = false;
 3525            }
 3526
 3527            self.change_selections(None, window, cx, |s| {
 3528                s.set_pending(pending, mode);
 3529            });
 3530        } else {
 3531            log::error!("update_selection dispatched with no pending selection");
 3532            return;
 3533        }
 3534
 3535        self.apply_scroll_delta(scroll_delta, window, cx);
 3536        cx.notify();
 3537    }
 3538
 3539    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3540        self.columnar_selection_state.take();
 3541        if self.selections.pending_anchor().is_some() {
 3542            let selections = self.selections.all::<usize>(cx);
 3543            self.change_selections(None, window, cx, |s| {
 3544                s.select(selections);
 3545                s.clear_pending();
 3546            });
 3547        }
 3548    }
 3549
 3550    fn select_columns(
 3551        &mut self,
 3552        head: DisplayPoint,
 3553        goal_column: u32,
 3554        display_map: &DisplaySnapshot,
 3555        window: &mut Window,
 3556        cx: &mut Context<Self>,
 3557    ) {
 3558        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3559            return;
 3560        };
 3561
 3562        let tail = match columnar_state {
 3563            ColumnarSelectionState::FromMouse {
 3564                selection_tail,
 3565                display_point,
 3566            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3567            ColumnarSelectionState::FromSelection { selection_tail } => {
 3568                selection_tail.to_display_point(&display_map)
 3569            }
 3570        };
 3571
 3572        let start_row = cmp::min(tail.row(), head.row());
 3573        let end_row = cmp::max(tail.row(), head.row());
 3574        let start_column = cmp::min(tail.column(), goal_column);
 3575        let end_column = cmp::max(tail.column(), goal_column);
 3576        let reversed = start_column < tail.column();
 3577
 3578        let selection_ranges = (start_row.0..=end_row.0)
 3579            .map(DisplayRow)
 3580            .filter_map(|row| {
 3581                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3582                    || start_column <= display_map.line_len(row))
 3583                    && !display_map.is_block_line(row)
 3584                {
 3585                    let start = display_map
 3586                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3587                        .to_point(display_map);
 3588                    let end = display_map
 3589                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3590                        .to_point(display_map);
 3591                    if reversed {
 3592                        Some(end..start)
 3593                    } else {
 3594                        Some(start..end)
 3595                    }
 3596                } else {
 3597                    None
 3598                }
 3599            })
 3600            .collect::<Vec<_>>();
 3601
 3602        let ranges = match columnar_state {
 3603            ColumnarSelectionState::FromMouse { .. } => {
 3604                let mut non_empty_ranges = selection_ranges
 3605                    .iter()
 3606                    .filter(|selection_range| selection_range.start != selection_range.end)
 3607                    .peekable();
 3608                if non_empty_ranges.peek().is_some() {
 3609                    non_empty_ranges.cloned().collect()
 3610                } else {
 3611                    selection_ranges
 3612                }
 3613            }
 3614            _ => selection_ranges,
 3615        };
 3616
 3617        self.change_selections(None, window, cx, |s| {
 3618            s.select_ranges(ranges);
 3619        });
 3620        cx.notify();
 3621    }
 3622
 3623    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3624        self.selections
 3625            .all_adjusted(cx)
 3626            .iter()
 3627            .any(|selection| !selection.is_empty())
 3628    }
 3629
 3630    pub fn has_pending_nonempty_selection(&self) -> bool {
 3631        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3632            Some(Selection { start, end, .. }) => start != end,
 3633            None => false,
 3634        };
 3635
 3636        pending_nonempty_selection
 3637            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3638    }
 3639
 3640    pub fn has_pending_selection(&self) -> bool {
 3641        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3642    }
 3643
 3644    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3645        self.selection_mark_mode = false;
 3646        self.selection_drag_state = SelectionDragState::None;
 3647
 3648        if self.clear_expanded_diff_hunks(cx) {
 3649            cx.notify();
 3650            return;
 3651        }
 3652        if self.dismiss_menus_and_popups(true, window, cx) {
 3653            return;
 3654        }
 3655
 3656        if self.mode.is_full()
 3657            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3658        {
 3659            return;
 3660        }
 3661
 3662        cx.propagate();
 3663    }
 3664
 3665    pub fn dismiss_menus_and_popups(
 3666        &mut self,
 3667        is_user_requested: bool,
 3668        window: &mut Window,
 3669        cx: &mut Context<Self>,
 3670    ) -> bool {
 3671        if self.take_rename(false, window, cx).is_some() {
 3672            return true;
 3673        }
 3674
 3675        if hide_hover(self, cx) {
 3676            return true;
 3677        }
 3678
 3679        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3680            return true;
 3681        }
 3682
 3683        if self.hide_context_menu(window, cx).is_some() {
 3684            return true;
 3685        }
 3686
 3687        if self.mouse_context_menu.take().is_some() {
 3688            return true;
 3689        }
 3690
 3691        if is_user_requested && self.discard_inline_completion(true, cx) {
 3692            return true;
 3693        }
 3694
 3695        if self.snippet_stack.pop().is_some() {
 3696            return true;
 3697        }
 3698
 3699        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3700            self.dismiss_diagnostics(cx);
 3701            return true;
 3702        }
 3703
 3704        false
 3705    }
 3706
 3707    fn linked_editing_ranges_for(
 3708        &self,
 3709        selection: Range<text::Anchor>,
 3710        cx: &App,
 3711    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3712        if self.linked_edit_ranges.is_empty() {
 3713            return None;
 3714        }
 3715        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3716            selection.end.buffer_id.and_then(|end_buffer_id| {
 3717                if selection.start.buffer_id != Some(end_buffer_id) {
 3718                    return None;
 3719                }
 3720                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3721                let snapshot = buffer.read(cx).snapshot();
 3722                self.linked_edit_ranges
 3723                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3724                    .map(|ranges| (ranges, snapshot, buffer))
 3725            })?;
 3726        use text::ToOffset as TO;
 3727        // find offset from the start of current range to current cursor position
 3728        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3729
 3730        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3731        let start_difference = start_offset - start_byte_offset;
 3732        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3733        let end_difference = end_offset - start_byte_offset;
 3734        // Current range has associated linked ranges.
 3735        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3736        for range in linked_ranges.iter() {
 3737            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3738            let end_offset = start_offset + end_difference;
 3739            let start_offset = start_offset + start_difference;
 3740            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3741                continue;
 3742            }
 3743            if self.selections.disjoint_anchor_ranges().any(|s| {
 3744                if s.start.buffer_id != selection.start.buffer_id
 3745                    || s.end.buffer_id != selection.end.buffer_id
 3746                {
 3747                    return false;
 3748                }
 3749                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3750                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3751            }) {
 3752                continue;
 3753            }
 3754            let start = buffer_snapshot.anchor_after(start_offset);
 3755            let end = buffer_snapshot.anchor_after(end_offset);
 3756            linked_edits
 3757                .entry(buffer.clone())
 3758                .or_default()
 3759                .push(start..end);
 3760        }
 3761        Some(linked_edits)
 3762    }
 3763
 3764    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3765        let text: Arc<str> = text.into();
 3766
 3767        if self.read_only(cx) {
 3768            return;
 3769        }
 3770
 3771        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3772
 3773        let selections = self.selections.all_adjusted(cx);
 3774        let mut bracket_inserted = false;
 3775        let mut edits = Vec::new();
 3776        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3777        let mut new_selections = Vec::with_capacity(selections.len());
 3778        let mut new_autoclose_regions = Vec::new();
 3779        let snapshot = self.buffer.read(cx).read(cx);
 3780        let mut clear_linked_edit_ranges = false;
 3781
 3782        for (selection, autoclose_region) in
 3783            self.selections_with_autoclose_regions(selections, &snapshot)
 3784        {
 3785            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3786                // Determine if the inserted text matches the opening or closing
 3787                // bracket of any of this language's bracket pairs.
 3788                let mut bracket_pair = None;
 3789                let mut is_bracket_pair_start = false;
 3790                let mut is_bracket_pair_end = false;
 3791                if !text.is_empty() {
 3792                    let mut bracket_pair_matching_end = None;
 3793                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3794                    //  and they are removing the character that triggered IME popup.
 3795                    for (pair, enabled) in scope.brackets() {
 3796                        if !pair.close && !pair.surround {
 3797                            continue;
 3798                        }
 3799
 3800                        if enabled && pair.start.ends_with(text.as_ref()) {
 3801                            let prefix_len = pair.start.len() - text.len();
 3802                            let preceding_text_matches_prefix = prefix_len == 0
 3803                                || (selection.start.column >= (prefix_len as u32)
 3804                                    && snapshot.contains_str_at(
 3805                                        Point::new(
 3806                                            selection.start.row,
 3807                                            selection.start.column - (prefix_len as u32),
 3808                                        ),
 3809                                        &pair.start[..prefix_len],
 3810                                    ));
 3811                            if preceding_text_matches_prefix {
 3812                                bracket_pair = Some(pair.clone());
 3813                                is_bracket_pair_start = true;
 3814                                break;
 3815                            }
 3816                        }
 3817                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3818                        {
 3819                            // take first bracket pair matching end, but don't break in case a later bracket
 3820                            // pair matches start
 3821                            bracket_pair_matching_end = Some(pair.clone());
 3822                        }
 3823                    }
 3824                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3825                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3826                        is_bracket_pair_end = true;
 3827                    }
 3828                }
 3829
 3830                if let Some(bracket_pair) = bracket_pair {
 3831                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3832                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3833                    let auto_surround =
 3834                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3835                    if selection.is_empty() {
 3836                        if is_bracket_pair_start {
 3837                            // If the inserted text is a suffix of an opening bracket and the
 3838                            // selection is preceded by the rest of the opening bracket, then
 3839                            // insert the closing bracket.
 3840                            let following_text_allows_autoclose = snapshot
 3841                                .chars_at(selection.start)
 3842                                .next()
 3843                                .map_or(true, |c| scope.should_autoclose_before(c));
 3844
 3845                            let preceding_text_allows_autoclose = selection.start.column == 0
 3846                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3847                                    true,
 3848                                    |c| {
 3849                                        bracket_pair.start != bracket_pair.end
 3850                                            || !snapshot
 3851                                                .char_classifier_at(selection.start)
 3852                                                .is_word(c)
 3853                                    },
 3854                                );
 3855
 3856                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3857                                && bracket_pair.start.len() == 1
 3858                            {
 3859                                let target = bracket_pair.start.chars().next().unwrap();
 3860                                let current_line_count = snapshot
 3861                                    .reversed_chars_at(selection.start)
 3862                                    .take_while(|&c| c != '\n')
 3863                                    .filter(|&c| c == target)
 3864                                    .count();
 3865                                current_line_count % 2 == 1
 3866                            } else {
 3867                                false
 3868                            };
 3869
 3870                            if autoclose
 3871                                && bracket_pair.close
 3872                                && following_text_allows_autoclose
 3873                                && preceding_text_allows_autoclose
 3874                                && !is_closing_quote
 3875                            {
 3876                                let anchor = snapshot.anchor_before(selection.end);
 3877                                new_selections.push((selection.map(|_| anchor), text.len()));
 3878                                new_autoclose_regions.push((
 3879                                    anchor,
 3880                                    text.len(),
 3881                                    selection.id,
 3882                                    bracket_pair.clone(),
 3883                                ));
 3884                                edits.push((
 3885                                    selection.range(),
 3886                                    format!("{}{}", text, bracket_pair.end).into(),
 3887                                ));
 3888                                bracket_inserted = true;
 3889                                continue;
 3890                            }
 3891                        }
 3892
 3893                        if let Some(region) = autoclose_region {
 3894                            // If the selection is followed by an auto-inserted closing bracket,
 3895                            // then don't insert that closing bracket again; just move the selection
 3896                            // past the closing bracket.
 3897                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3898                                && text.as_ref() == region.pair.end.as_str();
 3899                            if should_skip {
 3900                                let anchor = snapshot.anchor_after(selection.end);
 3901                                new_selections
 3902                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3903                                continue;
 3904                            }
 3905                        }
 3906
 3907                        let always_treat_brackets_as_autoclosed = snapshot
 3908                            .language_settings_at(selection.start, cx)
 3909                            .always_treat_brackets_as_autoclosed;
 3910                        if always_treat_brackets_as_autoclosed
 3911                            && is_bracket_pair_end
 3912                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3913                        {
 3914                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3915                            // and the inserted text is a closing bracket and the selection is followed
 3916                            // by the closing bracket then move the selection past the closing bracket.
 3917                            let anchor = snapshot.anchor_after(selection.end);
 3918                            new_selections.push((selection.map(|_| anchor), text.len()));
 3919                            continue;
 3920                        }
 3921                    }
 3922                    // If an opening bracket is 1 character long and is typed while
 3923                    // text is selected, then surround that text with the bracket pair.
 3924                    else if auto_surround
 3925                        && bracket_pair.surround
 3926                        && is_bracket_pair_start
 3927                        && bracket_pair.start.chars().count() == 1
 3928                    {
 3929                        edits.push((selection.start..selection.start, text.clone()));
 3930                        edits.push((
 3931                            selection.end..selection.end,
 3932                            bracket_pair.end.as_str().into(),
 3933                        ));
 3934                        bracket_inserted = true;
 3935                        new_selections.push((
 3936                            Selection {
 3937                                id: selection.id,
 3938                                start: snapshot.anchor_after(selection.start),
 3939                                end: snapshot.anchor_before(selection.end),
 3940                                reversed: selection.reversed,
 3941                                goal: selection.goal,
 3942                            },
 3943                            0,
 3944                        ));
 3945                        continue;
 3946                    }
 3947                }
 3948            }
 3949
 3950            if self.auto_replace_emoji_shortcode
 3951                && selection.is_empty()
 3952                && text.as_ref().ends_with(':')
 3953            {
 3954                if let Some(possible_emoji_short_code) =
 3955                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3956                {
 3957                    if !possible_emoji_short_code.is_empty() {
 3958                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3959                            let emoji_shortcode_start = Point::new(
 3960                                selection.start.row,
 3961                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3962                            );
 3963
 3964                            // Remove shortcode from buffer
 3965                            edits.push((
 3966                                emoji_shortcode_start..selection.start,
 3967                                "".to_string().into(),
 3968                            ));
 3969                            new_selections.push((
 3970                                Selection {
 3971                                    id: selection.id,
 3972                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3973                                    end: snapshot.anchor_before(selection.start),
 3974                                    reversed: selection.reversed,
 3975                                    goal: selection.goal,
 3976                                },
 3977                                0,
 3978                            ));
 3979
 3980                            // Insert emoji
 3981                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3982                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3983                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3984
 3985                            continue;
 3986                        }
 3987                    }
 3988                }
 3989            }
 3990
 3991            // If not handling any auto-close operation, then just replace the selected
 3992            // text with the given input and move the selection to the end of the
 3993            // newly inserted text.
 3994            let anchor = snapshot.anchor_after(selection.end);
 3995            if !self.linked_edit_ranges.is_empty() {
 3996                let start_anchor = snapshot.anchor_before(selection.start);
 3997
 3998                let is_word_char = text.chars().next().map_or(true, |char| {
 3999                    let classifier = snapshot
 4000                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4001                        .ignore_punctuation(true);
 4002                    classifier.is_word(char)
 4003                });
 4004
 4005                if is_word_char {
 4006                    if let Some(ranges) = self
 4007                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4008                    {
 4009                        for (buffer, edits) in ranges {
 4010                            linked_edits
 4011                                .entry(buffer.clone())
 4012                                .or_default()
 4013                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4014                        }
 4015                    }
 4016                } else {
 4017                    clear_linked_edit_ranges = true;
 4018                }
 4019            }
 4020
 4021            new_selections.push((selection.map(|_| anchor), 0));
 4022            edits.push((selection.start..selection.end, text.clone()));
 4023        }
 4024
 4025        drop(snapshot);
 4026
 4027        self.transact(window, cx, |this, window, cx| {
 4028            if clear_linked_edit_ranges {
 4029                this.linked_edit_ranges.clear();
 4030            }
 4031            let initial_buffer_versions =
 4032                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4033
 4034            this.buffer.update(cx, |buffer, cx| {
 4035                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4036            });
 4037            for (buffer, edits) in linked_edits {
 4038                buffer.update(cx, |buffer, cx| {
 4039                    let snapshot = buffer.snapshot();
 4040                    let edits = edits
 4041                        .into_iter()
 4042                        .map(|(range, text)| {
 4043                            use text::ToPoint as TP;
 4044                            let end_point = TP::to_point(&range.end, &snapshot);
 4045                            let start_point = TP::to_point(&range.start, &snapshot);
 4046                            (start_point..end_point, text)
 4047                        })
 4048                        .sorted_by_key(|(range, _)| range.start);
 4049                    buffer.edit(edits, None, cx);
 4050                })
 4051            }
 4052            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4053            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4054            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4055            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4056                .zip(new_selection_deltas)
 4057                .map(|(selection, delta)| Selection {
 4058                    id: selection.id,
 4059                    start: selection.start + delta,
 4060                    end: selection.end + delta,
 4061                    reversed: selection.reversed,
 4062                    goal: SelectionGoal::None,
 4063                })
 4064                .collect::<Vec<_>>();
 4065
 4066            let mut i = 0;
 4067            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4068                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4069                let start = map.buffer_snapshot.anchor_before(position);
 4070                let end = map.buffer_snapshot.anchor_after(position);
 4071                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4072                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4073                        Ordering::Less => i += 1,
 4074                        Ordering::Greater => break,
 4075                        Ordering::Equal => {
 4076                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4077                                Ordering::Less => i += 1,
 4078                                Ordering::Equal => break,
 4079                                Ordering::Greater => break,
 4080                            }
 4081                        }
 4082                    }
 4083                }
 4084                this.autoclose_regions.insert(
 4085                    i,
 4086                    AutocloseRegion {
 4087                        selection_id,
 4088                        range: start..end,
 4089                        pair,
 4090                    },
 4091                );
 4092            }
 4093
 4094            let had_active_inline_completion = this.has_active_inline_completion();
 4095            this.change_selections(
 4096                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4097                window,
 4098                cx,
 4099                |s| s.select(new_selections),
 4100            );
 4101
 4102            if !bracket_inserted {
 4103                if let Some(on_type_format_task) =
 4104                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4105                {
 4106                    on_type_format_task.detach_and_log_err(cx);
 4107                }
 4108            }
 4109
 4110            let editor_settings = EditorSettings::get_global(cx);
 4111            if bracket_inserted
 4112                && (editor_settings.auto_signature_help
 4113                    || editor_settings.show_signature_help_after_edits)
 4114            {
 4115                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4116            }
 4117
 4118            let trigger_in_words =
 4119                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4120            if this.hard_wrap.is_some() {
 4121                let latest: Range<Point> = this.selections.newest(cx).range();
 4122                if latest.is_empty()
 4123                    && this
 4124                        .buffer()
 4125                        .read(cx)
 4126                        .snapshot(cx)
 4127                        .line_len(MultiBufferRow(latest.start.row))
 4128                        == latest.start.column
 4129                {
 4130                    this.rewrap_impl(
 4131                        RewrapOptions {
 4132                            override_language_settings: true,
 4133                            preserve_existing_whitespace: true,
 4134                        },
 4135                        cx,
 4136                    )
 4137                }
 4138            }
 4139            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4140            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4141            this.refresh_inline_completion(true, false, window, cx);
 4142            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4143        });
 4144    }
 4145
 4146    fn find_possible_emoji_shortcode_at_position(
 4147        snapshot: &MultiBufferSnapshot,
 4148        position: Point,
 4149    ) -> Option<String> {
 4150        let mut chars = Vec::new();
 4151        let mut found_colon = false;
 4152        for char in snapshot.reversed_chars_at(position).take(100) {
 4153            // Found a possible emoji shortcode in the middle of the buffer
 4154            if found_colon {
 4155                if char.is_whitespace() {
 4156                    chars.reverse();
 4157                    return Some(chars.iter().collect());
 4158                }
 4159                // If the previous character is not a whitespace, we are in the middle of a word
 4160                // and we only want to complete the shortcode if the word is made up of other emojis
 4161                let mut containing_word = String::new();
 4162                for ch in snapshot
 4163                    .reversed_chars_at(position)
 4164                    .skip(chars.len() + 1)
 4165                    .take(100)
 4166                {
 4167                    if ch.is_whitespace() {
 4168                        break;
 4169                    }
 4170                    containing_word.push(ch);
 4171                }
 4172                let containing_word = containing_word.chars().rev().collect::<String>();
 4173                if util::word_consists_of_emojis(containing_word.as_str()) {
 4174                    chars.reverse();
 4175                    return Some(chars.iter().collect());
 4176                }
 4177            }
 4178
 4179            if char.is_whitespace() || !char.is_ascii() {
 4180                return None;
 4181            }
 4182            if char == ':' {
 4183                found_colon = true;
 4184            } else {
 4185                chars.push(char);
 4186            }
 4187        }
 4188        // Found a possible emoji shortcode at the beginning of the buffer
 4189        chars.reverse();
 4190        Some(chars.iter().collect())
 4191    }
 4192
 4193    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4194        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4195        self.transact(window, cx, |this, window, cx| {
 4196            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4197                let selections = this.selections.all::<usize>(cx);
 4198                let multi_buffer = this.buffer.read(cx);
 4199                let buffer = multi_buffer.snapshot(cx);
 4200                selections
 4201                    .iter()
 4202                    .map(|selection| {
 4203                        let start_point = selection.start.to_point(&buffer);
 4204                        let mut existing_indent =
 4205                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4206                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4207                        let start = selection.start;
 4208                        let end = selection.end;
 4209                        let selection_is_empty = start == end;
 4210                        let language_scope = buffer.language_scope_at(start);
 4211                        let (
 4212                            comment_delimiter,
 4213                            doc_delimiter,
 4214                            insert_extra_newline,
 4215                            indent_on_newline,
 4216                            indent_on_extra_newline,
 4217                        ) = if let Some(language) = &language_scope {
 4218                            let mut insert_extra_newline =
 4219                                insert_extra_newline_brackets(&buffer, start..end, language)
 4220                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4221
 4222                            // Comment extension on newline is allowed only for cursor selections
 4223                            let comment_delimiter = maybe!({
 4224                                if !selection_is_empty {
 4225                                    return None;
 4226                                }
 4227
 4228                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4229                                    return None;
 4230                                }
 4231
 4232                                let delimiters = language.line_comment_prefixes();
 4233                                let max_len_of_delimiter =
 4234                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4235                                let (snapshot, range) =
 4236                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4237
 4238                                let num_of_whitespaces = snapshot
 4239                                    .chars_for_range(range.clone())
 4240                                    .take_while(|c| c.is_whitespace())
 4241                                    .count();
 4242                                let comment_candidate = snapshot
 4243                                    .chars_for_range(range)
 4244                                    .skip(num_of_whitespaces)
 4245                                    .take(max_len_of_delimiter)
 4246                                    .collect::<String>();
 4247                                let (delimiter, trimmed_len) = delimiters
 4248                                    .iter()
 4249                                    .filter_map(|delimiter| {
 4250                                        let prefix = delimiter.trim_end();
 4251                                        if comment_candidate.starts_with(prefix) {
 4252                                            Some((delimiter, prefix.len()))
 4253                                        } else {
 4254                                            None
 4255                                        }
 4256                                    })
 4257                                    .max_by_key(|(_, len)| *len)?;
 4258
 4259                                let cursor_is_placed_after_comment_marker =
 4260                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4261                                if cursor_is_placed_after_comment_marker {
 4262                                    Some(delimiter.clone())
 4263                                } else {
 4264                                    None
 4265                                }
 4266                            });
 4267
 4268                            let mut indent_on_newline = IndentSize::spaces(0);
 4269                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4270
 4271                            let doc_delimiter = maybe!({
 4272                                if !selection_is_empty {
 4273                                    return None;
 4274                                }
 4275
 4276                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4277                                    return None;
 4278                                }
 4279
 4280                                let DocumentationConfig {
 4281                                    start: start_tag,
 4282                                    end: end_tag,
 4283                                    prefix: delimiter,
 4284                                    tab_size: len,
 4285                                } = language.documentation()?;
 4286
 4287                                let is_within_block_comment = buffer
 4288                                    .language_scope_at(start_point)
 4289                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4290                                if !is_within_block_comment {
 4291                                    return None;
 4292                                }
 4293
 4294                                let (snapshot, range) =
 4295                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4296
 4297                                let num_of_whitespaces = snapshot
 4298                                    .chars_for_range(range.clone())
 4299                                    .take_while(|c| c.is_whitespace())
 4300                                    .count();
 4301
 4302                                // 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.
 4303                                let column = start_point.column;
 4304                                let cursor_is_after_start_tag = {
 4305                                    let start_tag_len = start_tag.len();
 4306                                    let start_tag_line = snapshot
 4307                                        .chars_for_range(range.clone())
 4308                                        .skip(num_of_whitespaces)
 4309                                        .take(start_tag_len)
 4310                                        .collect::<String>();
 4311                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4312                                        num_of_whitespaces + start_tag_len <= column as usize
 4313                                    } else {
 4314                                        false
 4315                                    }
 4316                                };
 4317
 4318                                let cursor_is_after_delimiter = {
 4319                                    let delimiter_trim = delimiter.trim_end();
 4320                                    let delimiter_line = snapshot
 4321                                        .chars_for_range(range.clone())
 4322                                        .skip(num_of_whitespaces)
 4323                                        .take(delimiter_trim.len())
 4324                                        .collect::<String>();
 4325                                    if delimiter_line.starts_with(delimiter_trim) {
 4326                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4327                                    } else {
 4328                                        false
 4329                                    }
 4330                                };
 4331
 4332                                let cursor_is_before_end_tag_if_exists = {
 4333                                    let mut char_position = 0u32;
 4334                                    let mut end_tag_offset = None;
 4335
 4336                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4337                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4338                                            let chars_before_match =
 4339                                                chunk[..byte_pos].chars().count() as u32;
 4340                                            end_tag_offset =
 4341                                                Some(char_position + chars_before_match);
 4342                                            break 'outer;
 4343                                        }
 4344                                        char_position += chunk.chars().count() as u32;
 4345                                    }
 4346
 4347                                    if let Some(end_tag_offset) = end_tag_offset {
 4348                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4349                                        if cursor_is_after_start_tag {
 4350                                            if cursor_is_before_end_tag {
 4351                                                insert_extra_newline = true;
 4352                                            }
 4353                                            let cursor_is_at_start_of_end_tag =
 4354                                                column == end_tag_offset;
 4355                                            if cursor_is_at_start_of_end_tag {
 4356                                                indent_on_extra_newline.len = (*len).into();
 4357                                            }
 4358                                        }
 4359                                        cursor_is_before_end_tag
 4360                                    } else {
 4361                                        true
 4362                                    }
 4363                                };
 4364
 4365                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4366                                    && cursor_is_before_end_tag_if_exists
 4367                                {
 4368                                    if cursor_is_after_start_tag {
 4369                                        indent_on_newline.len = (*len).into();
 4370                                    }
 4371                                    Some(delimiter.clone())
 4372                                } else {
 4373                                    None
 4374                                }
 4375                            });
 4376
 4377                            (
 4378                                comment_delimiter,
 4379                                doc_delimiter,
 4380                                insert_extra_newline,
 4381                                indent_on_newline,
 4382                                indent_on_extra_newline,
 4383                            )
 4384                        } else {
 4385                            (
 4386                                None,
 4387                                None,
 4388                                false,
 4389                                IndentSize::default(),
 4390                                IndentSize::default(),
 4391                            )
 4392                        };
 4393
 4394                        let prevent_auto_indent = doc_delimiter.is_some();
 4395                        let delimiter = comment_delimiter.or(doc_delimiter);
 4396
 4397                        let capacity_for_delimiter =
 4398                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4399                        let mut new_text = String::with_capacity(
 4400                            1 + capacity_for_delimiter
 4401                                + existing_indent.len as usize
 4402                                + indent_on_newline.len as usize
 4403                                + indent_on_extra_newline.len as usize,
 4404                        );
 4405                        new_text.push('\n');
 4406                        new_text.extend(existing_indent.chars());
 4407                        new_text.extend(indent_on_newline.chars());
 4408
 4409                        if let Some(delimiter) = &delimiter {
 4410                            new_text.push_str(delimiter);
 4411                        }
 4412
 4413                        if insert_extra_newline {
 4414                            new_text.push('\n');
 4415                            new_text.extend(existing_indent.chars());
 4416                            new_text.extend(indent_on_extra_newline.chars());
 4417                        }
 4418
 4419                        let anchor = buffer.anchor_after(end);
 4420                        let new_selection = selection.map(|_| anchor);
 4421                        (
 4422                            ((start..end, new_text), prevent_auto_indent),
 4423                            (insert_extra_newline, new_selection),
 4424                        )
 4425                    })
 4426                    .unzip()
 4427            };
 4428
 4429            let mut auto_indent_edits = Vec::new();
 4430            let mut edits = Vec::new();
 4431            for (edit, prevent_auto_indent) in edits_with_flags {
 4432                if prevent_auto_indent {
 4433                    edits.push(edit);
 4434                } else {
 4435                    auto_indent_edits.push(edit);
 4436                }
 4437            }
 4438            if !edits.is_empty() {
 4439                this.edit(edits, cx);
 4440            }
 4441            if !auto_indent_edits.is_empty() {
 4442                this.edit_with_autoindent(auto_indent_edits, cx);
 4443            }
 4444
 4445            let buffer = this.buffer.read(cx).snapshot(cx);
 4446            let new_selections = selection_info
 4447                .into_iter()
 4448                .map(|(extra_newline_inserted, new_selection)| {
 4449                    let mut cursor = new_selection.end.to_point(&buffer);
 4450                    if extra_newline_inserted {
 4451                        cursor.row -= 1;
 4452                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4453                    }
 4454                    new_selection.map(|_| cursor)
 4455                })
 4456                .collect();
 4457
 4458            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4459                s.select(new_selections)
 4460            });
 4461            this.refresh_inline_completion(true, false, window, cx);
 4462        });
 4463    }
 4464
 4465    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4466        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4467
 4468        let buffer = self.buffer.read(cx);
 4469        let snapshot = buffer.snapshot(cx);
 4470
 4471        let mut edits = Vec::new();
 4472        let mut rows = Vec::new();
 4473
 4474        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4475            let cursor = selection.head();
 4476            let row = cursor.row;
 4477
 4478            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4479
 4480            let newline = "\n".to_string();
 4481            edits.push((start_of_line..start_of_line, newline));
 4482
 4483            rows.push(row + rows_inserted as u32);
 4484        }
 4485
 4486        self.transact(window, cx, |editor, window, cx| {
 4487            editor.edit(edits, cx);
 4488
 4489            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4490                let mut index = 0;
 4491                s.move_cursors_with(|map, _, _| {
 4492                    let row = rows[index];
 4493                    index += 1;
 4494
 4495                    let point = Point::new(row, 0);
 4496                    let boundary = map.next_line_boundary(point).1;
 4497                    let clipped = map.clip_point(boundary, Bias::Left);
 4498
 4499                    (clipped, SelectionGoal::None)
 4500                });
 4501            });
 4502
 4503            let mut indent_edits = Vec::new();
 4504            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4505            for row in rows {
 4506                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4507                for (row, indent) in indents {
 4508                    if indent.len == 0 {
 4509                        continue;
 4510                    }
 4511
 4512                    let text = match indent.kind {
 4513                        IndentKind::Space => " ".repeat(indent.len as usize),
 4514                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4515                    };
 4516                    let point = Point::new(row.0, 0);
 4517                    indent_edits.push((point..point, text));
 4518                }
 4519            }
 4520            editor.edit(indent_edits, cx);
 4521        });
 4522    }
 4523
 4524    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4525        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4526
 4527        let buffer = self.buffer.read(cx);
 4528        let snapshot = buffer.snapshot(cx);
 4529
 4530        let mut edits = Vec::new();
 4531        let mut rows = Vec::new();
 4532        let mut rows_inserted = 0;
 4533
 4534        for selection in self.selections.all_adjusted(cx) {
 4535            let cursor = selection.head();
 4536            let row = cursor.row;
 4537
 4538            let point = Point::new(row + 1, 0);
 4539            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4540
 4541            let newline = "\n".to_string();
 4542            edits.push((start_of_line..start_of_line, newline));
 4543
 4544            rows_inserted += 1;
 4545            rows.push(row + rows_inserted);
 4546        }
 4547
 4548        self.transact(window, cx, |editor, window, cx| {
 4549            editor.edit(edits, cx);
 4550
 4551            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4552                let mut index = 0;
 4553                s.move_cursors_with(|map, _, _| {
 4554                    let row = rows[index];
 4555                    index += 1;
 4556
 4557                    let point = Point::new(row, 0);
 4558                    let boundary = map.next_line_boundary(point).1;
 4559                    let clipped = map.clip_point(boundary, Bias::Left);
 4560
 4561                    (clipped, SelectionGoal::None)
 4562                });
 4563            });
 4564
 4565            let mut indent_edits = Vec::new();
 4566            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4567            for row in rows {
 4568                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4569                for (row, indent) in indents {
 4570                    if indent.len == 0 {
 4571                        continue;
 4572                    }
 4573
 4574                    let text = match indent.kind {
 4575                        IndentKind::Space => " ".repeat(indent.len as usize),
 4576                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4577                    };
 4578                    let point = Point::new(row.0, 0);
 4579                    indent_edits.push((point..point, text));
 4580                }
 4581            }
 4582            editor.edit(indent_edits, cx);
 4583        });
 4584    }
 4585
 4586    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4587        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4588            original_indent_columns: Vec::new(),
 4589        });
 4590        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4591    }
 4592
 4593    fn insert_with_autoindent_mode(
 4594        &mut self,
 4595        text: &str,
 4596        autoindent_mode: Option<AutoindentMode>,
 4597        window: &mut Window,
 4598        cx: &mut Context<Self>,
 4599    ) {
 4600        if self.read_only(cx) {
 4601            return;
 4602        }
 4603
 4604        let text: Arc<str> = text.into();
 4605        self.transact(window, cx, |this, window, cx| {
 4606            let old_selections = this.selections.all_adjusted(cx);
 4607            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4608                let anchors = {
 4609                    let snapshot = buffer.read(cx);
 4610                    old_selections
 4611                        .iter()
 4612                        .map(|s| {
 4613                            let anchor = snapshot.anchor_after(s.head());
 4614                            s.map(|_| anchor)
 4615                        })
 4616                        .collect::<Vec<_>>()
 4617                };
 4618                buffer.edit(
 4619                    old_selections
 4620                        .iter()
 4621                        .map(|s| (s.start..s.end, text.clone())),
 4622                    autoindent_mode,
 4623                    cx,
 4624                );
 4625                anchors
 4626            });
 4627
 4628            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4629                s.select_anchors(selection_anchors);
 4630            });
 4631
 4632            cx.notify();
 4633        });
 4634    }
 4635
 4636    fn trigger_completion_on_input(
 4637        &mut self,
 4638        text: &str,
 4639        trigger_in_words: bool,
 4640        window: &mut Window,
 4641        cx: &mut Context<Self>,
 4642    ) {
 4643        let completions_source = self
 4644            .context_menu
 4645            .borrow()
 4646            .as_ref()
 4647            .and_then(|menu| match menu {
 4648                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4649                CodeContextMenu::CodeActions(_) => None,
 4650            });
 4651
 4652        match completions_source {
 4653            Some(CompletionsMenuSource::Words) => {
 4654                self.show_word_completions(&ShowWordCompletions, window, cx)
 4655            }
 4656            Some(CompletionsMenuSource::Normal)
 4657            | Some(CompletionsMenuSource::SnippetChoices)
 4658            | None
 4659                if self.is_completion_trigger(
 4660                    text,
 4661                    trigger_in_words,
 4662                    completions_source.is_some(),
 4663                    cx,
 4664                ) =>
 4665            {
 4666                self.show_completions(
 4667                    &ShowCompletions {
 4668                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4669                    },
 4670                    window,
 4671                    cx,
 4672                )
 4673            }
 4674            _ => {
 4675                self.hide_context_menu(window, cx);
 4676            }
 4677        }
 4678    }
 4679
 4680    fn is_completion_trigger(
 4681        &self,
 4682        text: &str,
 4683        trigger_in_words: bool,
 4684        menu_is_open: bool,
 4685        cx: &mut Context<Self>,
 4686    ) -> bool {
 4687        let position = self.selections.newest_anchor().head();
 4688        let multibuffer = self.buffer.read(cx);
 4689        let Some(buffer) = position
 4690            .buffer_id
 4691            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4692        else {
 4693            return false;
 4694        };
 4695
 4696        if let Some(completion_provider) = &self.completion_provider {
 4697            completion_provider.is_completion_trigger(
 4698                &buffer,
 4699                position.text_anchor,
 4700                text,
 4701                trigger_in_words,
 4702                menu_is_open,
 4703                cx,
 4704            )
 4705        } else {
 4706            false
 4707        }
 4708    }
 4709
 4710    /// If any empty selections is touching the start of its innermost containing autoclose
 4711    /// region, expand it to select the brackets.
 4712    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4713        let selections = self.selections.all::<usize>(cx);
 4714        let buffer = self.buffer.read(cx).read(cx);
 4715        let new_selections = self
 4716            .selections_with_autoclose_regions(selections, &buffer)
 4717            .map(|(mut selection, region)| {
 4718                if !selection.is_empty() {
 4719                    return selection;
 4720                }
 4721
 4722                if let Some(region) = region {
 4723                    let mut range = region.range.to_offset(&buffer);
 4724                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4725                        range.start -= region.pair.start.len();
 4726                        if buffer.contains_str_at(range.start, &region.pair.start)
 4727                            && buffer.contains_str_at(range.end, &region.pair.end)
 4728                        {
 4729                            range.end += region.pair.end.len();
 4730                            selection.start = range.start;
 4731                            selection.end = range.end;
 4732
 4733                            return selection;
 4734                        }
 4735                    }
 4736                }
 4737
 4738                let always_treat_brackets_as_autoclosed = buffer
 4739                    .language_settings_at(selection.start, cx)
 4740                    .always_treat_brackets_as_autoclosed;
 4741
 4742                if !always_treat_brackets_as_autoclosed {
 4743                    return selection;
 4744                }
 4745
 4746                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4747                    for (pair, enabled) in scope.brackets() {
 4748                        if !enabled || !pair.close {
 4749                            continue;
 4750                        }
 4751
 4752                        if buffer.contains_str_at(selection.start, &pair.end) {
 4753                            let pair_start_len = pair.start.len();
 4754                            if buffer.contains_str_at(
 4755                                selection.start.saturating_sub(pair_start_len),
 4756                                &pair.start,
 4757                            ) {
 4758                                selection.start -= pair_start_len;
 4759                                selection.end += pair.end.len();
 4760
 4761                                return selection;
 4762                            }
 4763                        }
 4764                    }
 4765                }
 4766
 4767                selection
 4768            })
 4769            .collect();
 4770
 4771        drop(buffer);
 4772        self.change_selections(None, window, cx, |selections| {
 4773            selections.select(new_selections)
 4774        });
 4775    }
 4776
 4777    /// Iterate the given selections, and for each one, find the smallest surrounding
 4778    /// autoclose region. This uses the ordering of the selections and the autoclose
 4779    /// regions to avoid repeated comparisons.
 4780    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4781        &'a self,
 4782        selections: impl IntoIterator<Item = Selection<D>>,
 4783        buffer: &'a MultiBufferSnapshot,
 4784    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4785        let mut i = 0;
 4786        let mut regions = self.autoclose_regions.as_slice();
 4787        selections.into_iter().map(move |selection| {
 4788            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4789
 4790            let mut enclosing = None;
 4791            while let Some(pair_state) = regions.get(i) {
 4792                if pair_state.range.end.to_offset(buffer) < range.start {
 4793                    regions = &regions[i + 1..];
 4794                    i = 0;
 4795                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4796                    break;
 4797                } else {
 4798                    if pair_state.selection_id == selection.id {
 4799                        enclosing = Some(pair_state);
 4800                    }
 4801                    i += 1;
 4802                }
 4803            }
 4804
 4805            (selection, enclosing)
 4806        })
 4807    }
 4808
 4809    /// Remove any autoclose regions that no longer contain their selection.
 4810    fn invalidate_autoclose_regions(
 4811        &mut self,
 4812        mut selections: &[Selection<Anchor>],
 4813        buffer: &MultiBufferSnapshot,
 4814    ) {
 4815        self.autoclose_regions.retain(|state| {
 4816            let mut i = 0;
 4817            while let Some(selection) = selections.get(i) {
 4818                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4819                    selections = &selections[1..];
 4820                    continue;
 4821                }
 4822                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4823                    break;
 4824                }
 4825                if selection.id == state.selection_id {
 4826                    return true;
 4827                } else {
 4828                    i += 1;
 4829                }
 4830            }
 4831            false
 4832        });
 4833    }
 4834
 4835    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4836        let offset = position.to_offset(buffer);
 4837        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4838        if offset > word_range.start && kind == Some(CharKind::Word) {
 4839            Some(
 4840                buffer
 4841                    .text_for_range(word_range.start..offset)
 4842                    .collect::<String>(),
 4843            )
 4844        } else {
 4845            None
 4846        }
 4847    }
 4848
 4849    pub fn toggle_inline_values(
 4850        &mut self,
 4851        _: &ToggleInlineValues,
 4852        _: &mut Window,
 4853        cx: &mut Context<Self>,
 4854    ) {
 4855        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4856
 4857        self.refresh_inline_values(cx);
 4858    }
 4859
 4860    pub fn toggle_inlay_hints(
 4861        &mut self,
 4862        _: &ToggleInlayHints,
 4863        _: &mut Window,
 4864        cx: &mut Context<Self>,
 4865    ) {
 4866        self.refresh_inlay_hints(
 4867            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4868            cx,
 4869        );
 4870    }
 4871
 4872    pub fn inlay_hints_enabled(&self) -> bool {
 4873        self.inlay_hint_cache.enabled
 4874    }
 4875
 4876    pub fn inline_values_enabled(&self) -> bool {
 4877        self.inline_value_cache.enabled
 4878    }
 4879
 4880    #[cfg(any(test, feature = "test-support"))]
 4881    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4882        self.display_map
 4883            .read(cx)
 4884            .current_inlays()
 4885            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4886            .cloned()
 4887            .collect()
 4888    }
 4889
 4890    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4891        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4892            return;
 4893        }
 4894
 4895        let reason_description = reason.description();
 4896        let ignore_debounce = matches!(
 4897            reason,
 4898            InlayHintRefreshReason::SettingsChange(_)
 4899                | InlayHintRefreshReason::Toggle(_)
 4900                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4901                | InlayHintRefreshReason::ModifiersChanged(_)
 4902        );
 4903        let (invalidate_cache, required_languages) = match reason {
 4904            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4905                match self.inlay_hint_cache.modifiers_override(enabled) {
 4906                    Some(enabled) => {
 4907                        if enabled {
 4908                            (InvalidationStrategy::RefreshRequested, None)
 4909                        } else {
 4910                            self.splice_inlays(
 4911                                &self
 4912                                    .visible_inlay_hints(cx)
 4913                                    .iter()
 4914                                    .map(|inlay| inlay.id)
 4915                                    .collect::<Vec<InlayId>>(),
 4916                                Vec::new(),
 4917                                cx,
 4918                            );
 4919                            return;
 4920                        }
 4921                    }
 4922                    None => return,
 4923                }
 4924            }
 4925            InlayHintRefreshReason::Toggle(enabled) => {
 4926                if self.inlay_hint_cache.toggle(enabled) {
 4927                    if enabled {
 4928                        (InvalidationStrategy::RefreshRequested, None)
 4929                    } else {
 4930                        self.splice_inlays(
 4931                            &self
 4932                                .visible_inlay_hints(cx)
 4933                                .iter()
 4934                                .map(|inlay| inlay.id)
 4935                                .collect::<Vec<InlayId>>(),
 4936                            Vec::new(),
 4937                            cx,
 4938                        );
 4939                        return;
 4940                    }
 4941                } else {
 4942                    return;
 4943                }
 4944            }
 4945            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4946                match self.inlay_hint_cache.update_settings(
 4947                    &self.buffer,
 4948                    new_settings,
 4949                    self.visible_inlay_hints(cx),
 4950                    cx,
 4951                ) {
 4952                    ControlFlow::Break(Some(InlaySplice {
 4953                        to_remove,
 4954                        to_insert,
 4955                    })) => {
 4956                        self.splice_inlays(&to_remove, to_insert, cx);
 4957                        return;
 4958                    }
 4959                    ControlFlow::Break(None) => return,
 4960                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4961                }
 4962            }
 4963            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4964                if let Some(InlaySplice {
 4965                    to_remove,
 4966                    to_insert,
 4967                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4968                {
 4969                    self.splice_inlays(&to_remove, to_insert, cx);
 4970                }
 4971                self.display_map.update(cx, |display_map, _| {
 4972                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4973                });
 4974                return;
 4975            }
 4976            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4977            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4978                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4979            }
 4980            InlayHintRefreshReason::RefreshRequested => {
 4981                (InvalidationStrategy::RefreshRequested, None)
 4982            }
 4983        };
 4984
 4985        if let Some(InlaySplice {
 4986            to_remove,
 4987            to_insert,
 4988        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4989            reason_description,
 4990            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4991            invalidate_cache,
 4992            ignore_debounce,
 4993            cx,
 4994        ) {
 4995            self.splice_inlays(&to_remove, to_insert, cx);
 4996        }
 4997    }
 4998
 4999    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5000        self.display_map
 5001            .read(cx)
 5002            .current_inlays()
 5003            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5004            .cloned()
 5005            .collect()
 5006    }
 5007
 5008    pub fn excerpts_for_inlay_hints_query(
 5009        &self,
 5010        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5011        cx: &mut Context<Editor>,
 5012    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5013        let Some(project) = self.project.as_ref() else {
 5014            return HashMap::default();
 5015        };
 5016        let project = project.read(cx);
 5017        let multi_buffer = self.buffer().read(cx);
 5018        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5019        let multi_buffer_visible_start = self
 5020            .scroll_manager
 5021            .anchor()
 5022            .anchor
 5023            .to_point(&multi_buffer_snapshot);
 5024        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5025            multi_buffer_visible_start
 5026                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5027            Bias::Left,
 5028        );
 5029        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5030        multi_buffer_snapshot
 5031            .range_to_buffer_ranges(multi_buffer_visible_range)
 5032            .into_iter()
 5033            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5034            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5035                let buffer_file = project::File::from_dyn(buffer.file())?;
 5036                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5037                let worktree_entry = buffer_worktree
 5038                    .read(cx)
 5039                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5040                if worktree_entry.is_ignored {
 5041                    return None;
 5042                }
 5043
 5044                let language = buffer.language()?;
 5045                if let Some(restrict_to_languages) = restrict_to_languages {
 5046                    if !restrict_to_languages.contains(language) {
 5047                        return None;
 5048                    }
 5049                }
 5050                Some((
 5051                    excerpt_id,
 5052                    (
 5053                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5054                        buffer.version().clone(),
 5055                        excerpt_visible_range,
 5056                    ),
 5057                ))
 5058            })
 5059            .collect()
 5060    }
 5061
 5062    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5063        TextLayoutDetails {
 5064            text_system: window.text_system().clone(),
 5065            editor_style: self.style.clone().unwrap(),
 5066            rem_size: window.rem_size(),
 5067            scroll_anchor: self.scroll_manager.anchor(),
 5068            visible_rows: self.visible_line_count(),
 5069            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5070        }
 5071    }
 5072
 5073    pub fn splice_inlays(
 5074        &self,
 5075        to_remove: &[InlayId],
 5076        to_insert: Vec<Inlay>,
 5077        cx: &mut Context<Self>,
 5078    ) {
 5079        self.display_map.update(cx, |display_map, cx| {
 5080            display_map.splice_inlays(to_remove, to_insert, cx)
 5081        });
 5082        cx.notify();
 5083    }
 5084
 5085    fn trigger_on_type_formatting(
 5086        &self,
 5087        input: String,
 5088        window: &mut Window,
 5089        cx: &mut Context<Self>,
 5090    ) -> Option<Task<Result<()>>> {
 5091        if input.len() != 1 {
 5092            return None;
 5093        }
 5094
 5095        let project = self.project.as_ref()?;
 5096        let position = self.selections.newest_anchor().head();
 5097        let (buffer, buffer_position) = self
 5098            .buffer
 5099            .read(cx)
 5100            .text_anchor_for_position(position, cx)?;
 5101
 5102        let settings = language_settings::language_settings(
 5103            buffer
 5104                .read(cx)
 5105                .language_at(buffer_position)
 5106                .map(|l| l.name()),
 5107            buffer.read(cx).file(),
 5108            cx,
 5109        );
 5110        if !settings.use_on_type_format {
 5111            return None;
 5112        }
 5113
 5114        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5115        // hence we do LSP request & edit on host side only — add formats to host's history.
 5116        let push_to_lsp_host_history = true;
 5117        // If this is not the host, append its history with new edits.
 5118        let push_to_client_history = project.read(cx).is_via_collab();
 5119
 5120        let on_type_formatting = project.update(cx, |project, cx| {
 5121            project.on_type_format(
 5122                buffer.clone(),
 5123                buffer_position,
 5124                input,
 5125                push_to_lsp_host_history,
 5126                cx,
 5127            )
 5128        });
 5129        Some(cx.spawn_in(window, async move |editor, cx| {
 5130            if let Some(transaction) = on_type_formatting.await? {
 5131                if push_to_client_history {
 5132                    buffer
 5133                        .update(cx, |buffer, _| {
 5134                            buffer.push_transaction(transaction, Instant::now());
 5135                            buffer.finalize_last_transaction();
 5136                        })
 5137                        .ok();
 5138                }
 5139                editor.update(cx, |editor, cx| {
 5140                    editor.refresh_document_highlights(cx);
 5141                })?;
 5142            }
 5143            Ok(())
 5144        }))
 5145    }
 5146
 5147    pub fn show_word_completions(
 5148        &mut self,
 5149        _: &ShowWordCompletions,
 5150        window: &mut Window,
 5151        cx: &mut Context<Self>,
 5152    ) {
 5153        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5154    }
 5155
 5156    pub fn show_completions(
 5157        &mut self,
 5158        options: &ShowCompletions,
 5159        window: &mut Window,
 5160        cx: &mut Context<Self>,
 5161    ) {
 5162        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5163    }
 5164
 5165    fn open_or_update_completions_menu(
 5166        &mut self,
 5167        requested_source: Option<CompletionsMenuSource>,
 5168        trigger: Option<&str>,
 5169        window: &mut Window,
 5170        cx: &mut Context<Self>,
 5171    ) {
 5172        if self.pending_rename.is_some() {
 5173            return;
 5174        }
 5175
 5176        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5177
 5178        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5179        // inserted and selected. To handle that case, the start of the selection is used so that
 5180        // the menu starts with all choices.
 5181        let position = self
 5182            .selections
 5183            .newest_anchor()
 5184            .start
 5185            .bias_right(&multibuffer_snapshot);
 5186        if position.diff_base_anchor.is_some() {
 5187            return;
 5188        }
 5189        let (buffer, buffer_position) =
 5190            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5191                output
 5192            } else {
 5193                return;
 5194            };
 5195        let buffer_snapshot = buffer.read(cx).snapshot();
 5196
 5197        let query: Option<Arc<String>> =
 5198            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5199
 5200        drop(multibuffer_snapshot);
 5201
 5202        let provider = match requested_source {
 5203            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5204            Some(CompletionsMenuSource::Words) => None,
 5205            Some(CompletionsMenuSource::SnippetChoices) => {
 5206                log::error!("bug: SnippetChoices requested_source is not handled");
 5207                None
 5208            }
 5209        };
 5210
 5211        let sort_completions = provider
 5212            .as_ref()
 5213            .map_or(false, |provider| provider.sort_completions());
 5214
 5215        let filter_completions = provider
 5216            .as_ref()
 5217            .map_or(true, |provider| provider.filter_completions());
 5218
 5219        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5220            if filter_completions {
 5221                menu.filter(query.clone(), provider.clone(), window, cx);
 5222            }
 5223            // When `is_incomplete` is false, no need to re-query completions when the current query
 5224            // is a suffix of the initial query.
 5225            if !menu.is_incomplete {
 5226                // If the new query is a suffix of the old query (typing more characters) and
 5227                // the previous result was complete, the existing completions can be filtered.
 5228                //
 5229                // Note that this is always true for snippet completions.
 5230                let query_matches = match (&menu.initial_query, &query) {
 5231                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5232                    (None, _) => true,
 5233                    _ => false,
 5234                };
 5235                if query_matches {
 5236                    let position_matches = if menu.initial_position == position {
 5237                        true
 5238                    } else {
 5239                        let snapshot = self.buffer.read(cx).read(cx);
 5240                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5241                    };
 5242                    if position_matches {
 5243                        return;
 5244                    }
 5245                }
 5246            }
 5247        };
 5248
 5249        let trigger_kind = match trigger {
 5250            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5251                CompletionTriggerKind::TRIGGER_CHARACTER
 5252            }
 5253            _ => CompletionTriggerKind::INVOKED,
 5254        };
 5255        let completion_context = CompletionContext {
 5256            trigger_character: trigger.and_then(|trigger| {
 5257                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5258                    Some(String::from(trigger))
 5259                } else {
 5260                    None
 5261                }
 5262            }),
 5263            trigger_kind,
 5264        };
 5265
 5266        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5267            buffer_snapshot.surrounding_word(buffer_position)
 5268        {
 5269            let word_to_exclude = buffer_snapshot
 5270                .text_for_range(word_range.clone())
 5271                .collect::<String>();
 5272            (
 5273                buffer_snapshot.anchor_before(word_range.start)
 5274                    ..buffer_snapshot.anchor_after(buffer_position),
 5275                Some(word_to_exclude),
 5276            )
 5277        } else {
 5278            (buffer_position..buffer_position, None)
 5279        };
 5280
 5281        let language = buffer_snapshot
 5282            .language_at(buffer_position)
 5283            .map(|language| language.name());
 5284
 5285        let completion_settings =
 5286            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5287
 5288        let show_completion_documentation = buffer_snapshot
 5289            .settings_at(buffer_position, cx)
 5290            .show_completion_documentation;
 5291
 5292        // The document can be large, so stay in reasonable bounds when searching for words,
 5293        // otherwise completion pop-up might be slow to appear.
 5294        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5295        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5296        let min_word_search = buffer_snapshot.clip_point(
 5297            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5298            Bias::Left,
 5299        );
 5300        let max_word_search = buffer_snapshot.clip_point(
 5301            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5302            Bias::Right,
 5303        );
 5304        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5305            ..buffer_snapshot.point_to_offset(max_word_search);
 5306
 5307        let skip_digits = query
 5308            .as_ref()
 5309            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5310
 5311        let (mut words, provider_responses) = match &provider {
 5312            Some(provider) => {
 5313                let provider_responses = provider.completions(
 5314                    position.excerpt_id,
 5315                    &buffer,
 5316                    buffer_position,
 5317                    completion_context,
 5318                    window,
 5319                    cx,
 5320                );
 5321
 5322                let words = match completion_settings.words {
 5323                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5324                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5325                        .background_spawn(async move {
 5326                            buffer_snapshot.words_in_range(WordsQuery {
 5327                                fuzzy_contents: None,
 5328                                range: word_search_range,
 5329                                skip_digits,
 5330                            })
 5331                        }),
 5332                };
 5333
 5334                (words, provider_responses)
 5335            }
 5336            None => (
 5337                cx.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                Task::ready(Ok(Vec::new())),
 5345            ),
 5346        };
 5347
 5348        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5349
 5350        let id = post_inc(&mut self.next_completion_id);
 5351        let task = cx.spawn_in(window, async move |editor, cx| {
 5352            let Ok(()) = editor.update(cx, |this, _| {
 5353                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5354            }) else {
 5355                return;
 5356            };
 5357
 5358            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5359            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5360            let mut completions = Vec::new();
 5361            let mut is_incomplete = false;
 5362            if let Some(provider_responses) = provider_responses.await.log_err() {
 5363                if !provider_responses.is_empty() {
 5364                    for response in provider_responses {
 5365                        completions.extend(response.completions);
 5366                        is_incomplete = is_incomplete || response.is_incomplete;
 5367                    }
 5368                    if completion_settings.words == WordsCompletionMode::Fallback {
 5369                        words = Task::ready(BTreeMap::default());
 5370                    }
 5371                }
 5372            }
 5373
 5374            let mut words = words.await;
 5375            if let Some(word_to_exclude) = &word_to_exclude {
 5376                words.remove(word_to_exclude);
 5377            }
 5378            for lsp_completion in &completions {
 5379                words.remove(&lsp_completion.new_text);
 5380            }
 5381            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5382                replace_range: word_replace_range.clone(),
 5383                new_text: word.clone(),
 5384                label: CodeLabel::plain(word, None),
 5385                icon_path: None,
 5386                documentation: None,
 5387                source: CompletionSource::BufferWord {
 5388                    word_range,
 5389                    resolved: false,
 5390                },
 5391                insert_text_mode: Some(InsertTextMode::AS_IS),
 5392                confirm: None,
 5393            }));
 5394
 5395            let menu = if completions.is_empty() {
 5396                None
 5397            } else {
 5398                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5399                    let languages = editor
 5400                        .workspace
 5401                        .as_ref()
 5402                        .and_then(|(workspace, _)| workspace.upgrade())
 5403                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5404                    let menu = CompletionsMenu::new(
 5405                        id,
 5406                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5407                        sort_completions,
 5408                        show_completion_documentation,
 5409                        position,
 5410                        query.clone(),
 5411                        is_incomplete,
 5412                        buffer.clone(),
 5413                        completions.into(),
 5414                        snippet_sort_order,
 5415                        languages,
 5416                        language,
 5417                        cx,
 5418                    );
 5419
 5420                    let query = if filter_completions { query } else { None };
 5421                    let matches_task = if let Some(query) = query {
 5422                        menu.do_async_filtering(query, cx)
 5423                    } else {
 5424                        Task::ready(menu.unfiltered_matches())
 5425                    };
 5426                    (menu, matches_task)
 5427                }) else {
 5428                    return;
 5429                };
 5430
 5431                let matches = matches_task.await;
 5432
 5433                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5434                    // Newer menu already set, so exit.
 5435                    match editor.context_menu.borrow().as_ref() {
 5436                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5437                            if prev_menu.id > id {
 5438                                return;
 5439                            }
 5440                        }
 5441                        _ => {}
 5442                    };
 5443
 5444                    // Only valid to take prev_menu because it the new menu is immediately set
 5445                    // below, or the menu is hidden.
 5446                    match editor.context_menu.borrow_mut().take() {
 5447                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5448                            let position_matches =
 5449                                if prev_menu.initial_position == menu.initial_position {
 5450                                    true
 5451                                } else {
 5452                                    let snapshot = editor.buffer.read(cx).read(cx);
 5453                                    prev_menu.initial_position.to_offset(&snapshot)
 5454                                        == menu.initial_position.to_offset(&snapshot)
 5455                                };
 5456                            if position_matches {
 5457                                // Preserve markdown cache before `set_filter_results` because it will
 5458                                // try to populate the documentation cache.
 5459                                menu.preserve_markdown_cache(prev_menu);
 5460                            }
 5461                        }
 5462                        _ => {}
 5463                    };
 5464
 5465                    menu.set_filter_results(matches, provider, window, cx);
 5466                }) else {
 5467                    return;
 5468                };
 5469
 5470                menu.visible().then_some(menu)
 5471            };
 5472
 5473            editor
 5474                .update_in(cx, |editor, window, cx| {
 5475                    if editor.focus_handle.is_focused(window) {
 5476                        if let Some(menu) = menu {
 5477                            *editor.context_menu.borrow_mut() =
 5478                                Some(CodeContextMenu::Completions(menu));
 5479
 5480                            crate::hover_popover::hide_hover(editor, cx);
 5481                            if editor.show_edit_predictions_in_menu() {
 5482                                editor.update_visible_inline_completion(window, cx);
 5483                            } else {
 5484                                editor.discard_inline_completion(false, cx);
 5485                            }
 5486
 5487                            cx.notify();
 5488                            return;
 5489                        }
 5490                    }
 5491
 5492                    if editor.completion_tasks.len() <= 1 {
 5493                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5494                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5495                        // If it was already hidden and we don't show inline completions in the menu, we should
 5496                        // also show the inline-completion when available.
 5497                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5498                            editor.update_visible_inline_completion(window, cx);
 5499                        }
 5500                    }
 5501                })
 5502                .ok();
 5503        });
 5504
 5505        self.completion_tasks.push((id, task));
 5506    }
 5507
 5508    #[cfg(feature = "test-support")]
 5509    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5510        let menu = self.context_menu.borrow();
 5511        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5512            let completions = menu.completions.borrow();
 5513            Some(completions.to_vec())
 5514        } else {
 5515            None
 5516        }
 5517    }
 5518
 5519    pub fn with_completions_menu_matching_id<R>(
 5520        &self,
 5521        id: CompletionId,
 5522        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5523    ) -> R {
 5524        let mut context_menu = self.context_menu.borrow_mut();
 5525        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5526            return f(None);
 5527        };
 5528        if completions_menu.id != id {
 5529            return f(None);
 5530        }
 5531        f(Some(completions_menu))
 5532    }
 5533
 5534    pub fn confirm_completion(
 5535        &mut self,
 5536        action: &ConfirmCompletion,
 5537        window: &mut Window,
 5538        cx: &mut Context<Self>,
 5539    ) -> Option<Task<Result<()>>> {
 5540        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5541        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5542    }
 5543
 5544    pub fn confirm_completion_insert(
 5545        &mut self,
 5546        _: &ConfirmCompletionInsert,
 5547        window: &mut Window,
 5548        cx: &mut Context<Self>,
 5549    ) -> Option<Task<Result<()>>> {
 5550        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5551        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5552    }
 5553
 5554    pub fn confirm_completion_replace(
 5555        &mut self,
 5556        _: &ConfirmCompletionReplace,
 5557        window: &mut Window,
 5558        cx: &mut Context<Self>,
 5559    ) -> Option<Task<Result<()>>> {
 5560        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5561        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5562    }
 5563
 5564    pub fn compose_completion(
 5565        &mut self,
 5566        action: &ComposeCompletion,
 5567        window: &mut Window,
 5568        cx: &mut Context<Self>,
 5569    ) -> Option<Task<Result<()>>> {
 5570        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5571        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5572    }
 5573
 5574    fn do_completion(
 5575        &mut self,
 5576        item_ix: Option<usize>,
 5577        intent: CompletionIntent,
 5578        window: &mut Window,
 5579        cx: &mut Context<Editor>,
 5580    ) -> Option<Task<Result<()>>> {
 5581        use language::ToOffset as _;
 5582
 5583        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5584        else {
 5585            return None;
 5586        };
 5587
 5588        let candidate_id = {
 5589            let entries = completions_menu.entries.borrow();
 5590            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5591            if self.show_edit_predictions_in_menu() {
 5592                self.discard_inline_completion(true, cx);
 5593            }
 5594            mat.candidate_id
 5595        };
 5596
 5597        let completion = completions_menu
 5598            .completions
 5599            .borrow()
 5600            .get(candidate_id)?
 5601            .clone();
 5602        cx.stop_propagation();
 5603
 5604        let buffer_handle = completions_menu.buffer.clone();
 5605
 5606        let CompletionEdit {
 5607            new_text,
 5608            snippet,
 5609            replace_range,
 5610        } = process_completion_for_edit(
 5611            &completion,
 5612            intent,
 5613            &buffer_handle,
 5614            &completions_menu.initial_position.text_anchor,
 5615            cx,
 5616        );
 5617
 5618        let buffer = buffer_handle.read(cx);
 5619        let snapshot = self.buffer.read(cx).snapshot(cx);
 5620        let newest_anchor = self.selections.newest_anchor();
 5621        let replace_range_multibuffer = {
 5622            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5623            let multibuffer_anchor = snapshot
 5624                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5625                .unwrap()
 5626                ..snapshot
 5627                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5628                    .unwrap();
 5629            multibuffer_anchor.start.to_offset(&snapshot)
 5630                ..multibuffer_anchor.end.to_offset(&snapshot)
 5631        };
 5632        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5633            return None;
 5634        }
 5635
 5636        let old_text = buffer
 5637            .text_for_range(replace_range.clone())
 5638            .collect::<String>();
 5639        let lookbehind = newest_anchor
 5640            .start
 5641            .text_anchor
 5642            .to_offset(buffer)
 5643            .saturating_sub(replace_range.start);
 5644        let lookahead = replace_range
 5645            .end
 5646            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5647        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5648        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5649
 5650        let selections = self.selections.all::<usize>(cx);
 5651        let mut ranges = Vec::new();
 5652        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5653
 5654        for selection in &selections {
 5655            let range = if selection.id == newest_anchor.id {
 5656                replace_range_multibuffer.clone()
 5657            } else {
 5658                let mut range = selection.range();
 5659
 5660                // if prefix is present, don't duplicate it
 5661                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5662                    range.start = range.start.saturating_sub(lookbehind);
 5663
 5664                    // if suffix is also present, mimic the newest cursor and replace it
 5665                    if selection.id != newest_anchor.id
 5666                        && snapshot.contains_str_at(range.end, suffix)
 5667                    {
 5668                        range.end += lookahead;
 5669                    }
 5670                }
 5671                range
 5672            };
 5673
 5674            ranges.push(range.clone());
 5675
 5676            if !self.linked_edit_ranges.is_empty() {
 5677                let start_anchor = snapshot.anchor_before(range.start);
 5678                let end_anchor = snapshot.anchor_after(range.end);
 5679                if let Some(ranges) = self
 5680                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5681                {
 5682                    for (buffer, edits) in ranges {
 5683                        linked_edits
 5684                            .entry(buffer.clone())
 5685                            .or_default()
 5686                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5687                    }
 5688                }
 5689            }
 5690        }
 5691
 5692        let common_prefix_len = old_text
 5693            .chars()
 5694            .zip(new_text.chars())
 5695            .take_while(|(a, b)| a == b)
 5696            .map(|(a, _)| a.len_utf8())
 5697            .sum::<usize>();
 5698
 5699        cx.emit(EditorEvent::InputHandled {
 5700            utf16_range_to_replace: None,
 5701            text: new_text[common_prefix_len..].into(),
 5702        });
 5703
 5704        self.transact(window, cx, |this, window, cx| {
 5705            if let Some(mut snippet) = snippet {
 5706                snippet.text = new_text.to_string();
 5707                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5708            } else {
 5709                this.buffer.update(cx, |buffer, cx| {
 5710                    let auto_indent = match completion.insert_text_mode {
 5711                        Some(InsertTextMode::AS_IS) => None,
 5712                        _ => this.autoindent_mode.clone(),
 5713                    };
 5714                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5715                    buffer.edit(edits, auto_indent, cx);
 5716                });
 5717            }
 5718            for (buffer, edits) in linked_edits {
 5719                buffer.update(cx, |buffer, cx| {
 5720                    let snapshot = buffer.snapshot();
 5721                    let edits = edits
 5722                        .into_iter()
 5723                        .map(|(range, text)| {
 5724                            use text::ToPoint as TP;
 5725                            let end_point = TP::to_point(&range.end, &snapshot);
 5726                            let start_point = TP::to_point(&range.start, &snapshot);
 5727                            (start_point..end_point, text)
 5728                        })
 5729                        .sorted_by_key(|(range, _)| range.start);
 5730                    buffer.edit(edits, None, cx);
 5731                })
 5732            }
 5733
 5734            this.refresh_inline_completion(true, false, window, cx);
 5735        });
 5736
 5737        let show_new_completions_on_confirm = completion
 5738            .confirm
 5739            .as_ref()
 5740            .map_or(false, |confirm| confirm(intent, window, cx));
 5741        if show_new_completions_on_confirm {
 5742            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5743        }
 5744
 5745        let provider = self.completion_provider.as_ref()?;
 5746        drop(completion);
 5747        let apply_edits = provider.apply_additional_edits_for_completion(
 5748            buffer_handle,
 5749            completions_menu.completions.clone(),
 5750            candidate_id,
 5751            true,
 5752            cx,
 5753        );
 5754
 5755        let editor_settings = EditorSettings::get_global(cx);
 5756        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5757            // After the code completion is finished, users often want to know what signatures are needed.
 5758            // so we should automatically call signature_help
 5759            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5760        }
 5761
 5762        Some(cx.foreground_executor().spawn(async move {
 5763            apply_edits.await?;
 5764            Ok(())
 5765        }))
 5766    }
 5767
 5768    pub fn toggle_code_actions(
 5769        &mut self,
 5770        action: &ToggleCodeActions,
 5771        window: &mut Window,
 5772        cx: &mut Context<Self>,
 5773    ) {
 5774        let quick_launch = action.quick_launch;
 5775        let mut context_menu = self.context_menu.borrow_mut();
 5776        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5777            if code_actions.deployed_from == action.deployed_from {
 5778                // Toggle if we're selecting the same one
 5779                *context_menu = None;
 5780                cx.notify();
 5781                return;
 5782            } else {
 5783                // Otherwise, clear it and start a new one
 5784                *context_menu = None;
 5785                cx.notify();
 5786            }
 5787        }
 5788        drop(context_menu);
 5789        let snapshot = self.snapshot(window, cx);
 5790        let deployed_from = action.deployed_from.clone();
 5791        let action = action.clone();
 5792        self.completion_tasks.clear();
 5793        self.discard_inline_completion(false, cx);
 5794
 5795        let multibuffer_point = match &action.deployed_from {
 5796            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5797                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5798            }
 5799            _ => self.selections.newest::<Point>(cx).head(),
 5800        };
 5801        let Some((buffer, buffer_row)) = snapshot
 5802            .buffer_snapshot
 5803            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5804            .and_then(|(buffer_snapshot, range)| {
 5805                self.buffer()
 5806                    .read(cx)
 5807                    .buffer(buffer_snapshot.remote_id())
 5808                    .map(|buffer| (buffer, range.start.row))
 5809            })
 5810        else {
 5811            return;
 5812        };
 5813        let buffer_id = buffer.read(cx).remote_id();
 5814        let tasks = self
 5815            .tasks
 5816            .get(&(buffer_id, buffer_row))
 5817            .map(|t| Arc::new(t.to_owned()));
 5818
 5819        if !self.focus_handle.is_focused(window) {
 5820            return;
 5821        }
 5822        let project = self.project.clone();
 5823
 5824        let code_actions_task = match deployed_from {
 5825            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5826            _ => self.code_actions(buffer_row, window, cx),
 5827        };
 5828
 5829        let runnable_task = match deployed_from {
 5830            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5831            _ => {
 5832                let mut task_context_task = Task::ready(None);
 5833                if let Some(tasks) = &tasks {
 5834                    if let Some(project) = project {
 5835                        task_context_task =
 5836                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5837                    }
 5838                }
 5839
 5840                cx.spawn_in(window, {
 5841                    let buffer = buffer.clone();
 5842                    async move |editor, cx| {
 5843                        let task_context = task_context_task.await;
 5844
 5845                        let resolved_tasks =
 5846                            tasks
 5847                                .zip(task_context.clone())
 5848                                .map(|(tasks, task_context)| ResolvedTasks {
 5849                                    templates: tasks.resolve(&task_context).collect(),
 5850                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5851                                        multibuffer_point.row,
 5852                                        tasks.column,
 5853                                    )),
 5854                                });
 5855                        let debug_scenarios = editor
 5856                            .update(cx, |editor, cx| {
 5857                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5858                            })?
 5859                            .await;
 5860                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5861                    }
 5862                })
 5863            }
 5864        };
 5865
 5866        cx.spawn_in(window, async move |editor, cx| {
 5867            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5868            let code_actions = code_actions_task.await;
 5869            let spawn_straight_away = quick_launch
 5870                && resolved_tasks
 5871                    .as_ref()
 5872                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5873                && code_actions
 5874                    .as_ref()
 5875                    .map_or(true, |actions| actions.is_empty())
 5876                && debug_scenarios.is_empty();
 5877
 5878            editor.update_in(cx, |editor, window, cx| {
 5879                crate::hover_popover::hide_hover(editor, cx);
 5880                *editor.context_menu.borrow_mut() =
 5881                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5882                        buffer,
 5883                        actions: CodeActionContents::new(
 5884                            resolved_tasks,
 5885                            code_actions,
 5886                            debug_scenarios,
 5887                            task_context.unwrap_or_default(),
 5888                        ),
 5889                        selected_item: Default::default(),
 5890                        scroll_handle: UniformListScrollHandle::default(),
 5891                        deployed_from,
 5892                    }));
 5893                if spawn_straight_away {
 5894                    if let Some(task) = editor.confirm_code_action(
 5895                        &ConfirmCodeAction { item_ix: Some(0) },
 5896                        window,
 5897                        cx,
 5898                    ) {
 5899                        cx.notify();
 5900                        return task;
 5901                    }
 5902                }
 5903
 5904                Task::ready(Ok(()))
 5905            })
 5906        })
 5907        .detach_and_log_err(cx);
 5908    }
 5909
 5910    fn debug_scenarios(
 5911        &mut self,
 5912        resolved_tasks: &Option<ResolvedTasks>,
 5913        buffer: &Entity<Buffer>,
 5914        cx: &mut App,
 5915    ) -> Task<Vec<task::DebugScenario>> {
 5916        if cx.has_flag::<DebuggerFeatureFlag>() {
 5917            maybe!({
 5918                let project = self.project.as_ref()?;
 5919                let dap_store = project.read(cx).dap_store();
 5920                let mut scenarios = vec![];
 5921                let resolved_tasks = resolved_tasks.as_ref()?;
 5922                let buffer = buffer.read(cx);
 5923                let language = buffer.language()?;
 5924                let file = buffer.file();
 5925                let debug_adapter = language_settings(language.name().into(), file, cx)
 5926                    .debuggers
 5927                    .first()
 5928                    .map(SharedString::from)
 5929                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5930
 5931                dap_store.update(cx, |dap_store, cx| {
 5932                    for (_, task) in &resolved_tasks.templates {
 5933                        let maybe_scenario = dap_store.debug_scenario_for_build_task(
 5934                            task.original_task().clone(),
 5935                            debug_adapter.clone().into(),
 5936                            task.display_label().to_owned().into(),
 5937                            cx,
 5938                        );
 5939                        scenarios.push(maybe_scenario);
 5940                    }
 5941                });
 5942                Some(cx.background_spawn(async move {
 5943                    let scenarios = futures::future::join_all(scenarios)
 5944                        .await
 5945                        .into_iter()
 5946                        .flatten()
 5947                        .collect::<Vec<_>>();
 5948                    scenarios
 5949                }))
 5950            })
 5951            .unwrap_or_else(|| Task::ready(vec![]))
 5952        } else {
 5953            Task::ready(vec![])
 5954        }
 5955    }
 5956
 5957    fn code_actions(
 5958        &mut self,
 5959        buffer_row: u32,
 5960        window: &mut Window,
 5961        cx: &mut Context<Self>,
 5962    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5963        let mut task = self.code_actions_task.take();
 5964        cx.spawn_in(window, async move |editor, cx| {
 5965            while let Some(prev_task) = task {
 5966                prev_task.await.log_err();
 5967                task = editor
 5968                    .update(cx, |this, _| this.code_actions_task.take())
 5969                    .ok()?;
 5970            }
 5971
 5972            editor
 5973                .update(cx, |editor, cx| {
 5974                    editor
 5975                        .available_code_actions
 5976                        .clone()
 5977                        .and_then(|(location, code_actions)| {
 5978                            let snapshot = location.buffer.read(cx).snapshot();
 5979                            let point_range = location.range.to_point(&snapshot);
 5980                            let point_range = point_range.start.row..=point_range.end.row;
 5981                            if point_range.contains(&buffer_row) {
 5982                                Some(code_actions)
 5983                            } else {
 5984                                None
 5985                            }
 5986                        })
 5987                })
 5988                .ok()
 5989                .flatten()
 5990        })
 5991    }
 5992
 5993    pub fn confirm_code_action(
 5994        &mut self,
 5995        action: &ConfirmCodeAction,
 5996        window: &mut Window,
 5997        cx: &mut Context<Self>,
 5998    ) -> Option<Task<Result<()>>> {
 5999        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 6000
 6001        let actions_menu =
 6002            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6003                menu
 6004            } else {
 6005                return None;
 6006            };
 6007
 6008        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6009        let action = actions_menu.actions.get(action_ix)?;
 6010        let title = action.label();
 6011        let buffer = actions_menu.buffer;
 6012        let workspace = self.workspace()?;
 6013
 6014        match action {
 6015            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6016                workspace.update(cx, |workspace, cx| {
 6017                    workspace.schedule_resolved_task(
 6018                        task_source_kind,
 6019                        resolved_task,
 6020                        false,
 6021                        window,
 6022                        cx,
 6023                    );
 6024
 6025                    Some(Task::ready(Ok(())))
 6026                })
 6027            }
 6028            CodeActionsItem::CodeAction {
 6029                excerpt_id,
 6030                action,
 6031                provider,
 6032            } => {
 6033                let apply_code_action =
 6034                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6035                let workspace = workspace.downgrade();
 6036                Some(cx.spawn_in(window, async move |editor, cx| {
 6037                    let project_transaction = apply_code_action.await?;
 6038                    Self::open_project_transaction(
 6039                        &editor,
 6040                        workspace,
 6041                        project_transaction,
 6042                        title,
 6043                        cx,
 6044                    )
 6045                    .await
 6046                }))
 6047            }
 6048            CodeActionsItem::DebugScenario(scenario) => {
 6049                let context = actions_menu.actions.context.clone();
 6050
 6051                workspace.update(cx, |workspace, cx| {
 6052                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6053                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6054                });
 6055                Some(Task::ready(Ok(())))
 6056            }
 6057        }
 6058    }
 6059
 6060    pub async fn open_project_transaction(
 6061        this: &WeakEntity<Editor>,
 6062        workspace: WeakEntity<Workspace>,
 6063        transaction: ProjectTransaction,
 6064        title: String,
 6065        cx: &mut AsyncWindowContext,
 6066    ) -> Result<()> {
 6067        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6068        cx.update(|_, cx| {
 6069            entries.sort_unstable_by_key(|(buffer, _)| {
 6070                buffer.read(cx).file().map(|f| f.path().clone())
 6071            });
 6072        })?;
 6073
 6074        // If the project transaction's edits are all contained within this editor, then
 6075        // avoid opening a new editor to display them.
 6076
 6077        if let Some((buffer, transaction)) = entries.first() {
 6078            if entries.len() == 1 {
 6079                let excerpt = this.update(cx, |editor, cx| {
 6080                    editor
 6081                        .buffer()
 6082                        .read(cx)
 6083                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6084                })?;
 6085                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6086                    if excerpted_buffer == *buffer {
 6087                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6088                            let excerpt_range = excerpt_range.to_offset(buffer);
 6089                            buffer
 6090                                .edited_ranges_for_transaction::<usize>(transaction)
 6091                                .all(|range| {
 6092                                    excerpt_range.start <= range.start
 6093                                        && excerpt_range.end >= range.end
 6094                                })
 6095                        })?;
 6096
 6097                        if all_edits_within_excerpt {
 6098                            return Ok(());
 6099                        }
 6100                    }
 6101                }
 6102            }
 6103        } else {
 6104            return Ok(());
 6105        }
 6106
 6107        let mut ranges_to_highlight = Vec::new();
 6108        let excerpt_buffer = cx.new(|cx| {
 6109            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6110            for (buffer_handle, transaction) in &entries {
 6111                let edited_ranges = buffer_handle
 6112                    .read(cx)
 6113                    .edited_ranges_for_transaction::<Point>(transaction)
 6114                    .collect::<Vec<_>>();
 6115                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6116                    PathKey::for_buffer(buffer_handle, cx),
 6117                    buffer_handle.clone(),
 6118                    edited_ranges,
 6119                    DEFAULT_MULTIBUFFER_CONTEXT,
 6120                    cx,
 6121                );
 6122
 6123                ranges_to_highlight.extend(ranges);
 6124            }
 6125            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6126            multibuffer
 6127        })?;
 6128
 6129        workspace.update_in(cx, |workspace, window, cx| {
 6130            let project = workspace.project().clone();
 6131            let editor =
 6132                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6133            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6134            editor.update(cx, |editor, cx| {
 6135                editor.highlight_background::<Self>(
 6136                    &ranges_to_highlight,
 6137                    |theme| theme.editor_highlighted_line_background,
 6138                    cx,
 6139                );
 6140            });
 6141        })?;
 6142
 6143        Ok(())
 6144    }
 6145
 6146    pub fn clear_code_action_providers(&mut self) {
 6147        self.code_action_providers.clear();
 6148        self.available_code_actions.take();
 6149    }
 6150
 6151    pub fn add_code_action_provider(
 6152        &mut self,
 6153        provider: Rc<dyn CodeActionProvider>,
 6154        window: &mut Window,
 6155        cx: &mut Context<Self>,
 6156    ) {
 6157        if self
 6158            .code_action_providers
 6159            .iter()
 6160            .any(|existing_provider| existing_provider.id() == provider.id())
 6161        {
 6162            return;
 6163        }
 6164
 6165        self.code_action_providers.push(provider);
 6166        self.refresh_code_actions(window, cx);
 6167    }
 6168
 6169    pub fn remove_code_action_provider(
 6170        &mut self,
 6171        id: Arc<str>,
 6172        window: &mut Window,
 6173        cx: &mut Context<Self>,
 6174    ) {
 6175        self.code_action_providers
 6176            .retain(|provider| provider.id() != id);
 6177        self.refresh_code_actions(window, cx);
 6178    }
 6179
 6180    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6181        !self.code_action_providers.is_empty()
 6182            && EditorSettings::get_global(cx).toolbar.code_actions
 6183    }
 6184
 6185    pub fn has_available_code_actions(&self) -> bool {
 6186        self.available_code_actions
 6187            .as_ref()
 6188            .is_some_and(|(_, actions)| !actions.is_empty())
 6189    }
 6190
 6191    fn render_inline_code_actions(
 6192        &self,
 6193        icon_size: ui::IconSize,
 6194        display_row: DisplayRow,
 6195        is_active: bool,
 6196        cx: &mut Context<Self>,
 6197    ) -> AnyElement {
 6198        let show_tooltip = !self.context_menu_visible();
 6199        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6200            .icon_size(icon_size)
 6201            .shape(ui::IconButtonShape::Square)
 6202            .style(ButtonStyle::Transparent)
 6203            .icon_color(ui::Color::Hidden)
 6204            .toggle_state(is_active)
 6205            .when(show_tooltip, |this| {
 6206                this.tooltip({
 6207                    let focus_handle = self.focus_handle.clone();
 6208                    move |window, cx| {
 6209                        Tooltip::for_action_in(
 6210                            "Toggle Code Actions",
 6211                            &ToggleCodeActions {
 6212                                deployed_from: None,
 6213                                quick_launch: false,
 6214                            },
 6215                            &focus_handle,
 6216                            window,
 6217                            cx,
 6218                        )
 6219                    }
 6220                })
 6221            })
 6222            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6223                window.focus(&editor.focus_handle(cx));
 6224                editor.toggle_code_actions(
 6225                    &crate::actions::ToggleCodeActions {
 6226                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6227                            display_row,
 6228                        )),
 6229                        quick_launch: false,
 6230                    },
 6231                    window,
 6232                    cx,
 6233                );
 6234            }))
 6235            .into_any_element()
 6236    }
 6237
 6238    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6239        &self.context_menu
 6240    }
 6241
 6242    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6243        let newest_selection = self.selections.newest_anchor().clone();
 6244        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6245        let buffer = self.buffer.read(cx);
 6246        if newest_selection.head().diff_base_anchor.is_some() {
 6247            return None;
 6248        }
 6249        let (start_buffer, start) =
 6250            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6251        let (end_buffer, end) =
 6252            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6253        if start_buffer != end_buffer {
 6254            return None;
 6255        }
 6256
 6257        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6258            cx.background_executor()
 6259                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6260                .await;
 6261
 6262            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6263                let providers = this.code_action_providers.clone();
 6264                let tasks = this
 6265                    .code_action_providers
 6266                    .iter()
 6267                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6268                    .collect::<Vec<_>>();
 6269                (providers, tasks)
 6270            })?;
 6271
 6272            let mut actions = Vec::new();
 6273            for (provider, provider_actions) in
 6274                providers.into_iter().zip(future::join_all(tasks).await)
 6275            {
 6276                if let Some(provider_actions) = provider_actions.log_err() {
 6277                    actions.extend(provider_actions.into_iter().map(|action| {
 6278                        AvailableCodeAction {
 6279                            excerpt_id: newest_selection.start.excerpt_id,
 6280                            action,
 6281                            provider: provider.clone(),
 6282                        }
 6283                    }));
 6284                }
 6285            }
 6286
 6287            this.update(cx, |this, cx| {
 6288                this.available_code_actions = if actions.is_empty() {
 6289                    None
 6290                } else {
 6291                    Some((
 6292                        Location {
 6293                            buffer: start_buffer,
 6294                            range: start..end,
 6295                        },
 6296                        actions.into(),
 6297                    ))
 6298                };
 6299                cx.notify();
 6300            })
 6301        }));
 6302        None
 6303    }
 6304
 6305    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6306        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6307            self.show_git_blame_inline = false;
 6308
 6309            self.show_git_blame_inline_delay_task =
 6310                Some(cx.spawn_in(window, async move |this, cx| {
 6311                    cx.background_executor().timer(delay).await;
 6312
 6313                    this.update(cx, |this, cx| {
 6314                        this.show_git_blame_inline = true;
 6315                        cx.notify();
 6316                    })
 6317                    .log_err();
 6318                }));
 6319        }
 6320    }
 6321
 6322    fn show_blame_popover(
 6323        &mut self,
 6324        blame_entry: &BlameEntry,
 6325        position: gpui::Point<Pixels>,
 6326        cx: &mut Context<Self>,
 6327    ) {
 6328        if let Some(state) = &mut self.inline_blame_popover {
 6329            state.hide_task.take();
 6330        } else {
 6331            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6332            let blame_entry = blame_entry.clone();
 6333            let show_task = cx.spawn(async move |editor, cx| {
 6334                cx.background_executor()
 6335                    .timer(std::time::Duration::from_millis(delay))
 6336                    .await;
 6337                editor
 6338                    .update(cx, |editor, cx| {
 6339                        editor.inline_blame_popover_show_task.take();
 6340                        let Some(blame) = editor.blame.as_ref() else {
 6341                            return;
 6342                        };
 6343                        let blame = blame.read(cx);
 6344                        let details = blame.details_for_entry(&blame_entry);
 6345                        let markdown = cx.new(|cx| {
 6346                            Markdown::new(
 6347                                details
 6348                                    .as_ref()
 6349                                    .map(|message| message.message.clone())
 6350                                    .unwrap_or_default(),
 6351                                None,
 6352                                None,
 6353                                cx,
 6354                            )
 6355                        });
 6356                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6357                            position,
 6358                            hide_task: None,
 6359                            popover_bounds: None,
 6360                            popover_state: InlineBlamePopoverState {
 6361                                scroll_handle: ScrollHandle::new(),
 6362                                commit_message: details,
 6363                                markdown,
 6364                            },
 6365                        });
 6366                        cx.notify();
 6367                    })
 6368                    .ok();
 6369            });
 6370            self.inline_blame_popover_show_task = Some(show_task);
 6371        }
 6372    }
 6373
 6374    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6375        self.inline_blame_popover_show_task.take();
 6376        if let Some(state) = &mut self.inline_blame_popover {
 6377            let hide_task = cx.spawn(async move |editor, cx| {
 6378                cx.background_executor()
 6379                    .timer(std::time::Duration::from_millis(100))
 6380                    .await;
 6381                editor
 6382                    .update(cx, |editor, cx| {
 6383                        editor.inline_blame_popover.take();
 6384                        cx.notify();
 6385                    })
 6386                    .ok();
 6387            });
 6388            state.hide_task = Some(hide_task);
 6389        }
 6390    }
 6391
 6392    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6393        if self.pending_rename.is_some() {
 6394            return None;
 6395        }
 6396
 6397        let provider = self.semantics_provider.clone()?;
 6398        let buffer = self.buffer.read(cx);
 6399        let newest_selection = self.selections.newest_anchor().clone();
 6400        let cursor_position = newest_selection.head();
 6401        let (cursor_buffer, cursor_buffer_position) =
 6402            buffer.text_anchor_for_position(cursor_position, cx)?;
 6403        let (tail_buffer, tail_buffer_position) =
 6404            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6405        if cursor_buffer != tail_buffer {
 6406            return None;
 6407        }
 6408
 6409        let snapshot = cursor_buffer.read(cx).snapshot();
 6410        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6411        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6412        if start_word_range != end_word_range {
 6413            self.document_highlights_task.take();
 6414            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6415            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6416            return None;
 6417        }
 6418
 6419        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6420        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6421            cx.background_executor()
 6422                .timer(Duration::from_millis(debounce))
 6423                .await;
 6424
 6425            let highlights = if let Some(highlights) = cx
 6426                .update(|cx| {
 6427                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6428                })
 6429                .ok()
 6430                .flatten()
 6431            {
 6432                highlights.await.log_err()
 6433            } else {
 6434                None
 6435            };
 6436
 6437            if let Some(highlights) = highlights {
 6438                this.update(cx, |this, cx| {
 6439                    if this.pending_rename.is_some() {
 6440                        return;
 6441                    }
 6442
 6443                    let buffer_id = cursor_position.buffer_id;
 6444                    let buffer = this.buffer.read(cx);
 6445                    if !buffer
 6446                        .text_anchor_for_position(cursor_position, cx)
 6447                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6448                    {
 6449                        return;
 6450                    }
 6451
 6452                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6453                    let mut write_ranges = Vec::new();
 6454                    let mut read_ranges = Vec::new();
 6455                    for highlight in highlights {
 6456                        for (excerpt_id, excerpt_range) in
 6457                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6458                        {
 6459                            let start = highlight
 6460                                .range
 6461                                .start
 6462                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6463                            let end = highlight
 6464                                .range
 6465                                .end
 6466                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6467                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6468                                continue;
 6469                            }
 6470
 6471                            let range = Anchor {
 6472                                buffer_id,
 6473                                excerpt_id,
 6474                                text_anchor: start,
 6475                                diff_base_anchor: None,
 6476                            }..Anchor {
 6477                                buffer_id,
 6478                                excerpt_id,
 6479                                text_anchor: end,
 6480                                diff_base_anchor: None,
 6481                            };
 6482                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6483                                write_ranges.push(range);
 6484                            } else {
 6485                                read_ranges.push(range);
 6486                            }
 6487                        }
 6488                    }
 6489
 6490                    this.highlight_background::<DocumentHighlightRead>(
 6491                        &read_ranges,
 6492                        |theme| theme.editor_document_highlight_read_background,
 6493                        cx,
 6494                    );
 6495                    this.highlight_background::<DocumentHighlightWrite>(
 6496                        &write_ranges,
 6497                        |theme| theme.editor_document_highlight_write_background,
 6498                        cx,
 6499                    );
 6500                    cx.notify();
 6501                })
 6502                .log_err();
 6503            }
 6504        }));
 6505        None
 6506    }
 6507
 6508    fn prepare_highlight_query_from_selection(
 6509        &mut self,
 6510        cx: &mut Context<Editor>,
 6511    ) -> Option<(String, Range<Anchor>)> {
 6512        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6513            return None;
 6514        }
 6515        if !EditorSettings::get_global(cx).selection_highlight {
 6516            return None;
 6517        }
 6518        if self.selections.count() != 1 || self.selections.line_mode {
 6519            return None;
 6520        }
 6521        let selection = self.selections.newest::<Point>(cx);
 6522        if selection.is_empty() || selection.start.row != selection.end.row {
 6523            return None;
 6524        }
 6525        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6526        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6527        let query = multi_buffer_snapshot
 6528            .text_for_range(selection_anchor_range.clone())
 6529            .collect::<String>();
 6530        if query.trim().is_empty() {
 6531            return None;
 6532        }
 6533        Some((query, selection_anchor_range))
 6534    }
 6535
 6536    fn update_selection_occurrence_highlights(
 6537        &mut self,
 6538        query_text: String,
 6539        query_range: Range<Anchor>,
 6540        multi_buffer_range_to_query: Range<Point>,
 6541        use_debounce: bool,
 6542        window: &mut Window,
 6543        cx: &mut Context<Editor>,
 6544    ) -> Task<()> {
 6545        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6546        cx.spawn_in(window, async move |editor, cx| {
 6547            if use_debounce {
 6548                cx.background_executor()
 6549                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6550                    .await;
 6551            }
 6552            let match_task = cx.background_spawn(async move {
 6553                let buffer_ranges = multi_buffer_snapshot
 6554                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6555                    .into_iter()
 6556                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6557                let mut match_ranges = Vec::new();
 6558                let Ok(regex) = project::search::SearchQuery::text(
 6559                    query_text.clone(),
 6560                    false,
 6561                    false,
 6562                    false,
 6563                    Default::default(),
 6564                    Default::default(),
 6565                    false,
 6566                    None,
 6567                ) else {
 6568                    return Vec::default();
 6569                };
 6570                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6571                    match_ranges.extend(
 6572                        regex
 6573                            .search(&buffer_snapshot, Some(search_range.clone()))
 6574                            .await
 6575                            .into_iter()
 6576                            .filter_map(|match_range| {
 6577                                let match_start = buffer_snapshot
 6578                                    .anchor_after(search_range.start + match_range.start);
 6579                                let match_end = buffer_snapshot
 6580                                    .anchor_before(search_range.start + match_range.end);
 6581                                let match_anchor_range = Anchor::range_in_buffer(
 6582                                    excerpt_id,
 6583                                    buffer_snapshot.remote_id(),
 6584                                    match_start..match_end,
 6585                                );
 6586                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6587                            }),
 6588                    );
 6589                }
 6590                match_ranges
 6591            });
 6592            let match_ranges = match_task.await;
 6593            editor
 6594                .update_in(cx, |editor, _, cx| {
 6595                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6596                    if !match_ranges.is_empty() {
 6597                        editor.highlight_background::<SelectedTextHighlight>(
 6598                            &match_ranges,
 6599                            |theme| theme.editor_document_highlight_bracket_background,
 6600                            cx,
 6601                        )
 6602                    }
 6603                })
 6604                .log_err();
 6605        })
 6606    }
 6607
 6608    fn refresh_selected_text_highlights(
 6609        &mut self,
 6610        on_buffer_edit: bool,
 6611        window: &mut Window,
 6612        cx: &mut Context<Editor>,
 6613    ) {
 6614        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6615        else {
 6616            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6617            self.quick_selection_highlight_task.take();
 6618            self.debounced_selection_highlight_task.take();
 6619            return;
 6620        };
 6621        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6622        if on_buffer_edit
 6623            || self
 6624                .quick_selection_highlight_task
 6625                .as_ref()
 6626                .map_or(true, |(prev_anchor_range, _)| {
 6627                    prev_anchor_range != &query_range
 6628                })
 6629        {
 6630            let multi_buffer_visible_start = self
 6631                .scroll_manager
 6632                .anchor()
 6633                .anchor
 6634                .to_point(&multi_buffer_snapshot);
 6635            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6636                multi_buffer_visible_start
 6637                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6638                Bias::Left,
 6639            );
 6640            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6641            self.quick_selection_highlight_task = Some((
 6642                query_range.clone(),
 6643                self.update_selection_occurrence_highlights(
 6644                    query_text.clone(),
 6645                    query_range.clone(),
 6646                    multi_buffer_visible_range,
 6647                    false,
 6648                    window,
 6649                    cx,
 6650                ),
 6651            ));
 6652        }
 6653        if on_buffer_edit
 6654            || self
 6655                .debounced_selection_highlight_task
 6656                .as_ref()
 6657                .map_or(true, |(prev_anchor_range, _)| {
 6658                    prev_anchor_range != &query_range
 6659                })
 6660        {
 6661            let multi_buffer_start = multi_buffer_snapshot
 6662                .anchor_before(0)
 6663                .to_point(&multi_buffer_snapshot);
 6664            let multi_buffer_end = multi_buffer_snapshot
 6665                .anchor_after(multi_buffer_snapshot.len())
 6666                .to_point(&multi_buffer_snapshot);
 6667            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6668            self.debounced_selection_highlight_task = Some((
 6669                query_range.clone(),
 6670                self.update_selection_occurrence_highlights(
 6671                    query_text,
 6672                    query_range,
 6673                    multi_buffer_full_range,
 6674                    true,
 6675                    window,
 6676                    cx,
 6677                ),
 6678            ));
 6679        }
 6680    }
 6681
 6682    pub fn refresh_inline_completion(
 6683        &mut self,
 6684        debounce: bool,
 6685        user_requested: bool,
 6686        window: &mut Window,
 6687        cx: &mut Context<Self>,
 6688    ) -> Option<()> {
 6689        let provider = self.edit_prediction_provider()?;
 6690        let cursor = self.selections.newest_anchor().head();
 6691        let (buffer, cursor_buffer_position) =
 6692            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6693
 6694        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6695            self.discard_inline_completion(false, cx);
 6696            return None;
 6697        }
 6698
 6699        if !user_requested
 6700            && (!self.should_show_edit_predictions()
 6701                || !self.is_focused(window)
 6702                || buffer.read(cx).is_empty())
 6703        {
 6704            self.discard_inline_completion(false, cx);
 6705            return None;
 6706        }
 6707
 6708        self.update_visible_inline_completion(window, cx);
 6709        provider.refresh(
 6710            self.project.clone(),
 6711            buffer,
 6712            cursor_buffer_position,
 6713            debounce,
 6714            cx,
 6715        );
 6716        Some(())
 6717    }
 6718
 6719    fn show_edit_predictions_in_menu(&self) -> bool {
 6720        match self.edit_prediction_settings {
 6721            EditPredictionSettings::Disabled => false,
 6722            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6723        }
 6724    }
 6725
 6726    pub fn edit_predictions_enabled(&self) -> bool {
 6727        match self.edit_prediction_settings {
 6728            EditPredictionSettings::Disabled => false,
 6729            EditPredictionSettings::Enabled { .. } => true,
 6730        }
 6731    }
 6732
 6733    fn edit_prediction_requires_modifier(&self) -> bool {
 6734        match self.edit_prediction_settings {
 6735            EditPredictionSettings::Disabled => false,
 6736            EditPredictionSettings::Enabled {
 6737                preview_requires_modifier,
 6738                ..
 6739            } => preview_requires_modifier,
 6740        }
 6741    }
 6742
 6743    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6744        if self.edit_prediction_provider.is_none() {
 6745            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6746        } else {
 6747            let selection = self.selections.newest_anchor();
 6748            let cursor = selection.head();
 6749
 6750            if let Some((buffer, cursor_buffer_position)) =
 6751                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6752            {
 6753                self.edit_prediction_settings =
 6754                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6755            }
 6756        }
 6757    }
 6758
 6759    fn edit_prediction_settings_at_position(
 6760        &self,
 6761        buffer: &Entity<Buffer>,
 6762        buffer_position: language::Anchor,
 6763        cx: &App,
 6764    ) -> EditPredictionSettings {
 6765        if !self.mode.is_full()
 6766            || !self.show_inline_completions_override.unwrap_or(true)
 6767            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6768        {
 6769            return EditPredictionSettings::Disabled;
 6770        }
 6771
 6772        let buffer = buffer.read(cx);
 6773
 6774        let file = buffer.file();
 6775
 6776        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6777            return EditPredictionSettings::Disabled;
 6778        };
 6779
 6780        let by_provider = matches!(
 6781            self.menu_inline_completions_policy,
 6782            MenuInlineCompletionsPolicy::ByProvider
 6783        );
 6784
 6785        let show_in_menu = by_provider
 6786            && self
 6787                .edit_prediction_provider
 6788                .as_ref()
 6789                .map_or(false, |provider| {
 6790                    provider.provider.show_completions_in_menu()
 6791                });
 6792
 6793        let preview_requires_modifier =
 6794            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6795
 6796        EditPredictionSettings::Enabled {
 6797            show_in_menu,
 6798            preview_requires_modifier,
 6799        }
 6800    }
 6801
 6802    fn should_show_edit_predictions(&self) -> bool {
 6803        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6804    }
 6805
 6806    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6807        matches!(
 6808            self.edit_prediction_preview,
 6809            EditPredictionPreview::Active { .. }
 6810        )
 6811    }
 6812
 6813    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6814        let cursor = self.selections.newest_anchor().head();
 6815        if let Some((buffer, cursor_position)) =
 6816            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6817        {
 6818            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6819        } else {
 6820            false
 6821        }
 6822    }
 6823
 6824    pub fn supports_minimap(&self, cx: &App) -> bool {
 6825        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6826    }
 6827
 6828    fn edit_predictions_enabled_in_buffer(
 6829        &self,
 6830        buffer: &Entity<Buffer>,
 6831        buffer_position: language::Anchor,
 6832        cx: &App,
 6833    ) -> bool {
 6834        maybe!({
 6835            if self.read_only(cx) {
 6836                return Some(false);
 6837            }
 6838            let provider = self.edit_prediction_provider()?;
 6839            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6840                return Some(false);
 6841            }
 6842            let buffer = buffer.read(cx);
 6843            let Some(file) = buffer.file() else {
 6844                return Some(true);
 6845            };
 6846            let settings = all_language_settings(Some(file), cx);
 6847            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6848        })
 6849        .unwrap_or(false)
 6850    }
 6851
 6852    fn cycle_inline_completion(
 6853        &mut self,
 6854        direction: Direction,
 6855        window: &mut Window,
 6856        cx: &mut Context<Self>,
 6857    ) -> Option<()> {
 6858        let provider = self.edit_prediction_provider()?;
 6859        let cursor = self.selections.newest_anchor().head();
 6860        let (buffer, cursor_buffer_position) =
 6861            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6862        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6863            return None;
 6864        }
 6865
 6866        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6867        self.update_visible_inline_completion(window, cx);
 6868
 6869        Some(())
 6870    }
 6871
 6872    pub fn show_inline_completion(
 6873        &mut self,
 6874        _: &ShowEditPrediction,
 6875        window: &mut Window,
 6876        cx: &mut Context<Self>,
 6877    ) {
 6878        if !self.has_active_inline_completion() {
 6879            self.refresh_inline_completion(false, true, window, cx);
 6880            return;
 6881        }
 6882
 6883        self.update_visible_inline_completion(window, cx);
 6884    }
 6885
 6886    pub fn display_cursor_names(
 6887        &mut self,
 6888        _: &DisplayCursorNames,
 6889        window: &mut Window,
 6890        cx: &mut Context<Self>,
 6891    ) {
 6892        self.show_cursor_names(window, cx);
 6893    }
 6894
 6895    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6896        self.show_cursor_names = true;
 6897        cx.notify();
 6898        cx.spawn_in(window, async move |this, cx| {
 6899            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6900            this.update(cx, |this, cx| {
 6901                this.show_cursor_names = false;
 6902                cx.notify()
 6903            })
 6904            .ok()
 6905        })
 6906        .detach();
 6907    }
 6908
 6909    pub fn next_edit_prediction(
 6910        &mut self,
 6911        _: &NextEditPrediction,
 6912        window: &mut Window,
 6913        cx: &mut Context<Self>,
 6914    ) {
 6915        if self.has_active_inline_completion() {
 6916            self.cycle_inline_completion(Direction::Next, window, cx);
 6917        } else {
 6918            let is_copilot_disabled = self
 6919                .refresh_inline_completion(false, true, window, cx)
 6920                .is_none();
 6921            if is_copilot_disabled {
 6922                cx.propagate();
 6923            }
 6924        }
 6925    }
 6926
 6927    pub fn previous_edit_prediction(
 6928        &mut self,
 6929        _: &PreviousEditPrediction,
 6930        window: &mut Window,
 6931        cx: &mut Context<Self>,
 6932    ) {
 6933        if self.has_active_inline_completion() {
 6934            self.cycle_inline_completion(Direction::Prev, window, cx);
 6935        } else {
 6936            let is_copilot_disabled = self
 6937                .refresh_inline_completion(false, true, window, cx)
 6938                .is_none();
 6939            if is_copilot_disabled {
 6940                cx.propagate();
 6941            }
 6942        }
 6943    }
 6944
 6945    pub fn accept_edit_prediction(
 6946        &mut self,
 6947        _: &AcceptEditPrediction,
 6948        window: &mut Window,
 6949        cx: &mut Context<Self>,
 6950    ) {
 6951        if self.show_edit_predictions_in_menu() {
 6952            self.hide_context_menu(window, cx);
 6953        }
 6954
 6955        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6956            return;
 6957        };
 6958
 6959        self.report_inline_completion_event(
 6960            active_inline_completion.completion_id.clone(),
 6961            true,
 6962            cx,
 6963        );
 6964
 6965        match &active_inline_completion.completion {
 6966            InlineCompletion::Move { target, .. } => {
 6967                let target = *target;
 6968
 6969                if let Some(position_map) = &self.last_position_map {
 6970                    if position_map
 6971                        .visible_row_range
 6972                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6973                        || !self.edit_prediction_requires_modifier()
 6974                    {
 6975                        self.unfold_ranges(&[target..target], true, false, cx);
 6976                        // Note that this is also done in vim's handler of the Tab action.
 6977                        self.change_selections(
 6978                            Some(Autoscroll::newest()),
 6979                            window,
 6980                            cx,
 6981                            |selections| {
 6982                                selections.select_anchor_ranges([target..target]);
 6983                            },
 6984                        );
 6985                        self.clear_row_highlights::<EditPredictionPreview>();
 6986
 6987                        self.edit_prediction_preview
 6988                            .set_previous_scroll_position(None);
 6989                    } else {
 6990                        self.edit_prediction_preview
 6991                            .set_previous_scroll_position(Some(
 6992                                position_map.snapshot.scroll_anchor,
 6993                            ));
 6994
 6995                        self.highlight_rows::<EditPredictionPreview>(
 6996                            target..target,
 6997                            cx.theme().colors().editor_highlighted_line_background,
 6998                            RowHighlightOptions {
 6999                                autoscroll: true,
 7000                                ..Default::default()
 7001                            },
 7002                            cx,
 7003                        );
 7004                        self.request_autoscroll(Autoscroll::fit(), cx);
 7005                    }
 7006                }
 7007            }
 7008            InlineCompletion::Edit { edits, .. } => {
 7009                if let Some(provider) = self.edit_prediction_provider() {
 7010                    provider.accept(cx);
 7011                }
 7012
 7013                // Store the transaction ID and selections before applying the edit
 7014                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7015
 7016                let snapshot = self.buffer.read(cx).snapshot(cx);
 7017                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7018
 7019                self.buffer.update(cx, |buffer, cx| {
 7020                    buffer.edit(edits.iter().cloned(), None, cx)
 7021                });
 7022
 7023                self.change_selections(None, window, cx, |s| {
 7024                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7025                });
 7026
 7027                let selections = self.selections.disjoint_anchors();
 7028                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7029                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7030                    if has_new_transaction {
 7031                        self.selection_history
 7032                            .insert_transaction(transaction_id_now, selections);
 7033                    }
 7034                }
 7035
 7036                self.update_visible_inline_completion(window, cx);
 7037                if self.active_inline_completion.is_none() {
 7038                    self.refresh_inline_completion(true, true, window, cx);
 7039                }
 7040
 7041                cx.notify();
 7042            }
 7043        }
 7044
 7045        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7046    }
 7047
 7048    pub fn accept_partial_inline_completion(
 7049        &mut self,
 7050        _: &AcceptPartialEditPrediction,
 7051        window: &mut Window,
 7052        cx: &mut Context<Self>,
 7053    ) {
 7054        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7055            return;
 7056        };
 7057        if self.selections.count() != 1 {
 7058            return;
 7059        }
 7060
 7061        self.report_inline_completion_event(
 7062            active_inline_completion.completion_id.clone(),
 7063            true,
 7064            cx,
 7065        );
 7066
 7067        match &active_inline_completion.completion {
 7068            InlineCompletion::Move { target, .. } => {
 7069                let target = *target;
 7070                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7071                    selections.select_anchor_ranges([target..target]);
 7072                });
 7073            }
 7074            InlineCompletion::Edit { edits, .. } => {
 7075                // Find an insertion that starts at the cursor position.
 7076                let snapshot = self.buffer.read(cx).snapshot(cx);
 7077                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7078                let insertion = edits.iter().find_map(|(range, text)| {
 7079                    let range = range.to_offset(&snapshot);
 7080                    if range.is_empty() && range.start == cursor_offset {
 7081                        Some(text)
 7082                    } else {
 7083                        None
 7084                    }
 7085                });
 7086
 7087                if let Some(text) = insertion {
 7088                    let mut partial_completion = text
 7089                        .chars()
 7090                        .by_ref()
 7091                        .take_while(|c| c.is_alphabetic())
 7092                        .collect::<String>();
 7093                    if partial_completion.is_empty() {
 7094                        partial_completion = text
 7095                            .chars()
 7096                            .by_ref()
 7097                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7098                            .collect::<String>();
 7099                    }
 7100
 7101                    cx.emit(EditorEvent::InputHandled {
 7102                        utf16_range_to_replace: None,
 7103                        text: partial_completion.clone().into(),
 7104                    });
 7105
 7106                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7107
 7108                    self.refresh_inline_completion(true, true, window, cx);
 7109                    cx.notify();
 7110                } else {
 7111                    self.accept_edit_prediction(&Default::default(), window, cx);
 7112                }
 7113            }
 7114        }
 7115    }
 7116
 7117    fn discard_inline_completion(
 7118        &mut self,
 7119        should_report_inline_completion_event: bool,
 7120        cx: &mut Context<Self>,
 7121    ) -> bool {
 7122        if should_report_inline_completion_event {
 7123            let completion_id = self
 7124                .active_inline_completion
 7125                .as_ref()
 7126                .and_then(|active_completion| active_completion.completion_id.clone());
 7127
 7128            self.report_inline_completion_event(completion_id, false, cx);
 7129        }
 7130
 7131        if let Some(provider) = self.edit_prediction_provider() {
 7132            provider.discard(cx);
 7133        }
 7134
 7135        self.take_active_inline_completion(cx)
 7136    }
 7137
 7138    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7139        let Some(provider) = self.edit_prediction_provider() else {
 7140            return;
 7141        };
 7142
 7143        let Some((_, buffer, _)) = self
 7144            .buffer
 7145            .read(cx)
 7146            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7147        else {
 7148            return;
 7149        };
 7150
 7151        let extension = buffer
 7152            .read(cx)
 7153            .file()
 7154            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7155
 7156        let event_type = match accepted {
 7157            true => "Edit Prediction Accepted",
 7158            false => "Edit Prediction Discarded",
 7159        };
 7160        telemetry::event!(
 7161            event_type,
 7162            provider = provider.name(),
 7163            prediction_id = id,
 7164            suggestion_accepted = accepted,
 7165            file_extension = extension,
 7166        );
 7167    }
 7168
 7169    pub fn has_active_inline_completion(&self) -> bool {
 7170        self.active_inline_completion.is_some()
 7171    }
 7172
 7173    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7174        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7175            return false;
 7176        };
 7177
 7178        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7179        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7180        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7181        true
 7182    }
 7183
 7184    /// Returns true when we're displaying the edit prediction popover below the cursor
 7185    /// like we are not previewing and the LSP autocomplete menu is visible
 7186    /// or we are in `when_holding_modifier` mode.
 7187    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7188        if self.edit_prediction_preview_is_active()
 7189            || !self.show_edit_predictions_in_menu()
 7190            || !self.edit_predictions_enabled()
 7191        {
 7192            return false;
 7193        }
 7194
 7195        if self.has_visible_completions_menu() {
 7196            return true;
 7197        }
 7198
 7199        has_completion && self.edit_prediction_requires_modifier()
 7200    }
 7201
 7202    fn handle_modifiers_changed(
 7203        &mut self,
 7204        modifiers: Modifiers,
 7205        position_map: &PositionMap,
 7206        window: &mut Window,
 7207        cx: &mut Context<Self>,
 7208    ) {
 7209        if self.show_edit_predictions_in_menu() {
 7210            self.update_edit_prediction_preview(&modifiers, window, cx);
 7211        }
 7212
 7213        self.update_selection_mode(&modifiers, position_map, window, cx);
 7214
 7215        let mouse_position = window.mouse_position();
 7216        if !position_map.text_hitbox.is_hovered(window) {
 7217            return;
 7218        }
 7219
 7220        self.update_hovered_link(
 7221            position_map.point_for_position(mouse_position),
 7222            &position_map.snapshot,
 7223            modifiers,
 7224            window,
 7225            cx,
 7226        )
 7227    }
 7228
 7229    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7230        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7231        if invert {
 7232            match multi_cursor_setting {
 7233                MultiCursorModifier::Alt => modifiers.alt,
 7234                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7235            }
 7236        } else {
 7237            match multi_cursor_setting {
 7238                MultiCursorModifier::Alt => modifiers.secondary(),
 7239                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7240            }
 7241        }
 7242    }
 7243
 7244    fn columnar_selection_mode(
 7245        modifiers: &Modifiers,
 7246        cx: &mut Context<Self>,
 7247    ) -> Option<ColumnarMode> {
 7248        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7249            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7250                Some(ColumnarMode::FromMouse)
 7251            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7252                Some(ColumnarMode::FromSelection)
 7253            } else {
 7254                None
 7255            }
 7256        } else {
 7257            None
 7258        }
 7259    }
 7260
 7261    fn update_selection_mode(
 7262        &mut self,
 7263        modifiers: &Modifiers,
 7264        position_map: &PositionMap,
 7265        window: &mut Window,
 7266        cx: &mut Context<Self>,
 7267    ) {
 7268        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7269            return;
 7270        };
 7271        if self.selections.pending.is_none() {
 7272            return;
 7273        }
 7274
 7275        let mouse_position = window.mouse_position();
 7276        let point_for_position = position_map.point_for_position(mouse_position);
 7277        let position = point_for_position.previous_valid;
 7278
 7279        self.select(
 7280            SelectPhase::BeginColumnar {
 7281                position,
 7282                reset: false,
 7283                mode,
 7284                goal_column: point_for_position.exact_unclipped.column(),
 7285            },
 7286            window,
 7287            cx,
 7288        );
 7289    }
 7290
 7291    fn update_edit_prediction_preview(
 7292        &mut self,
 7293        modifiers: &Modifiers,
 7294        window: &mut Window,
 7295        cx: &mut Context<Self>,
 7296    ) {
 7297        let mut modifiers_held = false;
 7298        if let Some(accept_keystroke) = self
 7299            .accept_edit_prediction_keybind(false, window, cx)
 7300            .keystroke()
 7301        {
 7302            modifiers_held = modifiers_held
 7303                || (&accept_keystroke.modifiers == modifiers
 7304                    && accept_keystroke.modifiers.modified());
 7305        };
 7306        if let Some(accept_partial_keystroke) = self
 7307            .accept_edit_prediction_keybind(true, window, cx)
 7308            .keystroke()
 7309        {
 7310            modifiers_held = modifiers_held
 7311                || (&accept_partial_keystroke.modifiers == modifiers
 7312                    && accept_partial_keystroke.modifiers.modified());
 7313        }
 7314
 7315        if modifiers_held {
 7316            if matches!(
 7317                self.edit_prediction_preview,
 7318                EditPredictionPreview::Inactive { .. }
 7319            ) {
 7320                self.edit_prediction_preview = EditPredictionPreview::Active {
 7321                    previous_scroll_position: None,
 7322                    since: Instant::now(),
 7323                };
 7324
 7325                self.update_visible_inline_completion(window, cx);
 7326                cx.notify();
 7327            }
 7328        } else if let EditPredictionPreview::Active {
 7329            previous_scroll_position,
 7330            since,
 7331        } = self.edit_prediction_preview
 7332        {
 7333            if let (Some(previous_scroll_position), Some(position_map)) =
 7334                (previous_scroll_position, self.last_position_map.as_ref())
 7335            {
 7336                self.set_scroll_position(
 7337                    previous_scroll_position
 7338                        .scroll_position(&position_map.snapshot.display_snapshot),
 7339                    window,
 7340                    cx,
 7341                );
 7342            }
 7343
 7344            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7345                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7346            };
 7347            self.clear_row_highlights::<EditPredictionPreview>();
 7348            self.update_visible_inline_completion(window, cx);
 7349            cx.notify();
 7350        }
 7351    }
 7352
 7353    fn update_visible_inline_completion(
 7354        &mut self,
 7355        _window: &mut Window,
 7356        cx: &mut Context<Self>,
 7357    ) -> Option<()> {
 7358        let selection = self.selections.newest_anchor();
 7359        let cursor = selection.head();
 7360        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7361        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7362        let excerpt_id = cursor.excerpt_id;
 7363
 7364        let show_in_menu = self.show_edit_predictions_in_menu();
 7365        let completions_menu_has_precedence = !show_in_menu
 7366            && (self.context_menu.borrow().is_some()
 7367                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7368
 7369        if completions_menu_has_precedence
 7370            || !offset_selection.is_empty()
 7371            || self
 7372                .active_inline_completion
 7373                .as_ref()
 7374                .map_or(false, |completion| {
 7375                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7376                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7377                    !invalidation_range.contains(&offset_selection.head())
 7378                })
 7379        {
 7380            self.discard_inline_completion(false, cx);
 7381            return None;
 7382        }
 7383
 7384        self.take_active_inline_completion(cx);
 7385        let Some(provider) = self.edit_prediction_provider() else {
 7386            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7387            return None;
 7388        };
 7389
 7390        let (buffer, cursor_buffer_position) =
 7391            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7392
 7393        self.edit_prediction_settings =
 7394            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7395
 7396        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7397
 7398        if self.edit_prediction_indent_conflict {
 7399            let cursor_point = cursor.to_point(&multibuffer);
 7400
 7401            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7402
 7403            if let Some((_, indent)) = indents.iter().next() {
 7404                if indent.len == cursor_point.column {
 7405                    self.edit_prediction_indent_conflict = false;
 7406                }
 7407            }
 7408        }
 7409
 7410        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7411        let edits = inline_completion
 7412            .edits
 7413            .into_iter()
 7414            .flat_map(|(range, new_text)| {
 7415                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7416                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7417                Some((start..end, new_text))
 7418            })
 7419            .collect::<Vec<_>>();
 7420        if edits.is_empty() {
 7421            return None;
 7422        }
 7423
 7424        let first_edit_start = edits.first().unwrap().0.start;
 7425        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7426        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7427
 7428        let last_edit_end = edits.last().unwrap().0.end;
 7429        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7430        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7431
 7432        let cursor_row = cursor.to_point(&multibuffer).row;
 7433
 7434        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7435
 7436        let mut inlay_ids = Vec::new();
 7437        let invalidation_row_range;
 7438        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7439            Some(cursor_row..edit_end_row)
 7440        } else if cursor_row > edit_end_row {
 7441            Some(edit_start_row..cursor_row)
 7442        } else {
 7443            None
 7444        };
 7445        let is_move =
 7446            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7447        let completion = if is_move {
 7448            invalidation_row_range =
 7449                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7450            let target = first_edit_start;
 7451            InlineCompletion::Move { target, snapshot }
 7452        } else {
 7453            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7454                && !self.inline_completions_hidden_for_vim_mode;
 7455
 7456            if show_completions_in_buffer {
 7457                if edits
 7458                    .iter()
 7459                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7460                {
 7461                    let mut inlays = Vec::new();
 7462                    for (range, new_text) in &edits {
 7463                        let inlay = Inlay::inline_completion(
 7464                            post_inc(&mut self.next_inlay_id),
 7465                            range.start,
 7466                            new_text.as_str(),
 7467                        );
 7468                        inlay_ids.push(inlay.id);
 7469                        inlays.push(inlay);
 7470                    }
 7471
 7472                    self.splice_inlays(&[], inlays, cx);
 7473                } else {
 7474                    let background_color = cx.theme().status().deleted_background;
 7475                    self.highlight_text::<InlineCompletionHighlight>(
 7476                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7477                        HighlightStyle {
 7478                            background_color: Some(background_color),
 7479                            ..Default::default()
 7480                        },
 7481                        cx,
 7482                    );
 7483                }
 7484            }
 7485
 7486            invalidation_row_range = edit_start_row..edit_end_row;
 7487
 7488            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7489                if provider.show_tab_accept_marker() {
 7490                    EditDisplayMode::TabAccept
 7491                } else {
 7492                    EditDisplayMode::Inline
 7493                }
 7494            } else {
 7495                EditDisplayMode::DiffPopover
 7496            };
 7497
 7498            InlineCompletion::Edit {
 7499                edits,
 7500                edit_preview: inline_completion.edit_preview,
 7501                display_mode,
 7502                snapshot,
 7503            }
 7504        };
 7505
 7506        let invalidation_range = multibuffer
 7507            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7508            ..multibuffer.anchor_after(Point::new(
 7509                invalidation_row_range.end,
 7510                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7511            ));
 7512
 7513        self.stale_inline_completion_in_menu = None;
 7514        self.active_inline_completion = Some(InlineCompletionState {
 7515            inlay_ids,
 7516            completion,
 7517            completion_id: inline_completion.id,
 7518            invalidation_range,
 7519        });
 7520
 7521        cx.notify();
 7522
 7523        Some(())
 7524    }
 7525
 7526    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7527        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7528    }
 7529
 7530    fn clear_tasks(&mut self) {
 7531        self.tasks.clear()
 7532    }
 7533
 7534    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7535        if self.tasks.insert(key, value).is_some() {
 7536            // This case should hopefully be rare, but just in case...
 7537            log::error!(
 7538                "multiple different run targets found on a single line, only the last target will be rendered"
 7539            )
 7540        }
 7541    }
 7542
 7543    /// Get all display points of breakpoints that will be rendered within editor
 7544    ///
 7545    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7546    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7547    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7548    fn active_breakpoints(
 7549        &self,
 7550        range: Range<DisplayRow>,
 7551        window: &mut Window,
 7552        cx: &mut Context<Self>,
 7553    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7554        let mut breakpoint_display_points = HashMap::default();
 7555
 7556        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7557            return breakpoint_display_points;
 7558        };
 7559
 7560        let snapshot = self.snapshot(window, cx);
 7561
 7562        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7563        let Some(project) = self.project.as_ref() else {
 7564            return breakpoint_display_points;
 7565        };
 7566
 7567        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7568            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7569
 7570        for (buffer_snapshot, range, excerpt_id) in
 7571            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7572        {
 7573            let Some(buffer) = project
 7574                .read(cx)
 7575                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7576            else {
 7577                continue;
 7578            };
 7579            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7580                &buffer,
 7581                Some(
 7582                    buffer_snapshot.anchor_before(range.start)
 7583                        ..buffer_snapshot.anchor_after(range.end),
 7584                ),
 7585                buffer_snapshot,
 7586                cx,
 7587            );
 7588            for (breakpoint, state) in breakpoints {
 7589                let multi_buffer_anchor =
 7590                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7591                let position = multi_buffer_anchor
 7592                    .to_point(&multi_buffer_snapshot)
 7593                    .to_display_point(&snapshot);
 7594
 7595                breakpoint_display_points.insert(
 7596                    position.row(),
 7597                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7598                );
 7599            }
 7600        }
 7601
 7602        breakpoint_display_points
 7603    }
 7604
 7605    fn breakpoint_context_menu(
 7606        &self,
 7607        anchor: Anchor,
 7608        window: &mut Window,
 7609        cx: &mut Context<Self>,
 7610    ) -> Entity<ui::ContextMenu> {
 7611        let weak_editor = cx.weak_entity();
 7612        let focus_handle = self.focus_handle(cx);
 7613
 7614        let row = self
 7615            .buffer
 7616            .read(cx)
 7617            .snapshot(cx)
 7618            .summary_for_anchor::<Point>(&anchor)
 7619            .row;
 7620
 7621        let breakpoint = self
 7622            .breakpoint_at_row(row, window, cx)
 7623            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7624
 7625        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7626            "Edit Log Breakpoint"
 7627        } else {
 7628            "Set Log Breakpoint"
 7629        };
 7630
 7631        let condition_breakpoint_msg = if breakpoint
 7632            .as_ref()
 7633            .is_some_and(|bp| bp.1.condition.is_some())
 7634        {
 7635            "Edit Condition Breakpoint"
 7636        } else {
 7637            "Set Condition Breakpoint"
 7638        };
 7639
 7640        let hit_condition_breakpoint_msg = if breakpoint
 7641            .as_ref()
 7642            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7643        {
 7644            "Edit Hit Condition Breakpoint"
 7645        } else {
 7646            "Set Hit Condition Breakpoint"
 7647        };
 7648
 7649        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7650            "Unset Breakpoint"
 7651        } else {
 7652            "Set Breakpoint"
 7653        };
 7654
 7655        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7656
 7657        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7658            BreakpointState::Enabled => Some("Disable"),
 7659            BreakpointState::Disabled => Some("Enable"),
 7660        });
 7661
 7662        let (anchor, breakpoint) =
 7663            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7664
 7665        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7666            menu.on_blur_subscription(Subscription::new(|| {}))
 7667                .context(focus_handle)
 7668                .when(run_to_cursor, |this| {
 7669                    let weak_editor = weak_editor.clone();
 7670                    this.entry("Run to cursor", None, move |window, cx| {
 7671                        weak_editor
 7672                            .update(cx, |editor, cx| {
 7673                                editor.change_selections(None, window, cx, |s| {
 7674                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7675                                });
 7676                            })
 7677                            .ok();
 7678
 7679                        window.dispatch_action(Box::new(RunToCursor), cx);
 7680                    })
 7681                    .separator()
 7682                })
 7683                .when_some(toggle_state_msg, |this, msg| {
 7684                    this.entry(msg, None, {
 7685                        let weak_editor = weak_editor.clone();
 7686                        let breakpoint = breakpoint.clone();
 7687                        move |_window, cx| {
 7688                            weak_editor
 7689                                .update(cx, |this, cx| {
 7690                                    this.edit_breakpoint_at_anchor(
 7691                                        anchor,
 7692                                        breakpoint.as_ref().clone(),
 7693                                        BreakpointEditAction::InvertState,
 7694                                        cx,
 7695                                    );
 7696                                })
 7697                                .log_err();
 7698                        }
 7699                    })
 7700                })
 7701                .entry(set_breakpoint_msg, None, {
 7702                    let weak_editor = weak_editor.clone();
 7703                    let breakpoint = breakpoint.clone();
 7704                    move |_window, cx| {
 7705                        weak_editor
 7706                            .update(cx, |this, cx| {
 7707                                this.edit_breakpoint_at_anchor(
 7708                                    anchor,
 7709                                    breakpoint.as_ref().clone(),
 7710                                    BreakpointEditAction::Toggle,
 7711                                    cx,
 7712                                );
 7713                            })
 7714                            .log_err();
 7715                    }
 7716                })
 7717                .entry(log_breakpoint_msg, None, {
 7718                    let breakpoint = breakpoint.clone();
 7719                    let weak_editor = weak_editor.clone();
 7720                    move |window, cx| {
 7721                        weak_editor
 7722                            .update(cx, |this, cx| {
 7723                                this.add_edit_breakpoint_block(
 7724                                    anchor,
 7725                                    breakpoint.as_ref(),
 7726                                    BreakpointPromptEditAction::Log,
 7727                                    window,
 7728                                    cx,
 7729                                );
 7730                            })
 7731                            .log_err();
 7732                    }
 7733                })
 7734                .entry(condition_breakpoint_msg, None, {
 7735                    let breakpoint = breakpoint.clone();
 7736                    let weak_editor = weak_editor.clone();
 7737                    move |window, cx| {
 7738                        weak_editor
 7739                            .update(cx, |this, cx| {
 7740                                this.add_edit_breakpoint_block(
 7741                                    anchor,
 7742                                    breakpoint.as_ref(),
 7743                                    BreakpointPromptEditAction::Condition,
 7744                                    window,
 7745                                    cx,
 7746                                );
 7747                            })
 7748                            .log_err();
 7749                    }
 7750                })
 7751                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7752                    weak_editor
 7753                        .update(cx, |this, cx| {
 7754                            this.add_edit_breakpoint_block(
 7755                                anchor,
 7756                                breakpoint.as_ref(),
 7757                                BreakpointPromptEditAction::HitCondition,
 7758                                window,
 7759                                cx,
 7760                            );
 7761                        })
 7762                        .log_err();
 7763                })
 7764        })
 7765    }
 7766
 7767    fn render_breakpoint(
 7768        &self,
 7769        position: Anchor,
 7770        row: DisplayRow,
 7771        breakpoint: &Breakpoint,
 7772        state: Option<BreakpointSessionState>,
 7773        cx: &mut Context<Self>,
 7774    ) -> IconButton {
 7775        let is_rejected = state.is_some_and(|s| !s.verified);
 7776        // Is it a breakpoint that shows up when hovering over gutter?
 7777        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7778            (false, false),
 7779            |PhantomBreakpointIndicator {
 7780                 is_active,
 7781                 display_row,
 7782                 collides_with_existing_breakpoint,
 7783             }| {
 7784                (
 7785                    is_active && display_row == row,
 7786                    collides_with_existing_breakpoint,
 7787                )
 7788            },
 7789        );
 7790
 7791        let (color, icon) = {
 7792            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7793                (false, false) => ui::IconName::DebugBreakpoint,
 7794                (true, false) => ui::IconName::DebugLogBreakpoint,
 7795                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7796                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7797            };
 7798
 7799            let color = if is_phantom {
 7800                Color::Hint
 7801            } else if is_rejected {
 7802                Color::Disabled
 7803            } else {
 7804                Color::Debugger
 7805            };
 7806
 7807            (color, icon)
 7808        };
 7809
 7810        let breakpoint = Arc::from(breakpoint.clone());
 7811
 7812        let alt_as_text = gpui::Keystroke {
 7813            modifiers: Modifiers::secondary_key(),
 7814            ..Default::default()
 7815        };
 7816        let primary_action_text = if breakpoint.is_disabled() {
 7817            "Enable breakpoint"
 7818        } else if is_phantom && !collides_with_existing {
 7819            "Set breakpoint"
 7820        } else {
 7821            "Unset breakpoint"
 7822        };
 7823        let focus_handle = self.focus_handle.clone();
 7824
 7825        let meta = if is_rejected {
 7826            SharedString::from("No executable code is associated with this line.")
 7827        } else if collides_with_existing && !breakpoint.is_disabled() {
 7828            SharedString::from(format!(
 7829                "{alt_as_text}-click to disable,\nright-click for more options."
 7830            ))
 7831        } else {
 7832            SharedString::from("Right-click for more options.")
 7833        };
 7834        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7835            .icon_size(IconSize::XSmall)
 7836            .size(ui::ButtonSize::None)
 7837            .when(is_rejected, |this| {
 7838                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7839            })
 7840            .icon_color(color)
 7841            .style(ButtonStyle::Transparent)
 7842            .on_click(cx.listener({
 7843                let breakpoint = breakpoint.clone();
 7844
 7845                move |editor, event: &ClickEvent, window, cx| {
 7846                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7847                        BreakpointEditAction::InvertState
 7848                    } else {
 7849                        BreakpointEditAction::Toggle
 7850                    };
 7851
 7852                    window.focus(&editor.focus_handle(cx));
 7853                    editor.edit_breakpoint_at_anchor(
 7854                        position,
 7855                        breakpoint.as_ref().clone(),
 7856                        edit_action,
 7857                        cx,
 7858                    );
 7859                }
 7860            }))
 7861            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7862                editor.set_breakpoint_context_menu(
 7863                    row,
 7864                    Some(position),
 7865                    event.down.position,
 7866                    window,
 7867                    cx,
 7868                );
 7869            }))
 7870            .tooltip(move |window, cx| {
 7871                Tooltip::with_meta_in(
 7872                    primary_action_text,
 7873                    Some(&ToggleBreakpoint),
 7874                    meta.clone(),
 7875                    &focus_handle,
 7876                    window,
 7877                    cx,
 7878                )
 7879            })
 7880    }
 7881
 7882    fn build_tasks_context(
 7883        project: &Entity<Project>,
 7884        buffer: &Entity<Buffer>,
 7885        buffer_row: u32,
 7886        tasks: &Arc<RunnableTasks>,
 7887        cx: &mut Context<Self>,
 7888    ) -> Task<Option<task::TaskContext>> {
 7889        let position = Point::new(buffer_row, tasks.column);
 7890        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7891        let location = Location {
 7892            buffer: buffer.clone(),
 7893            range: range_start..range_start,
 7894        };
 7895        // Fill in the environmental variables from the tree-sitter captures
 7896        let mut captured_task_variables = TaskVariables::default();
 7897        for (capture_name, value) in tasks.extra_variables.clone() {
 7898            captured_task_variables.insert(
 7899                task::VariableName::Custom(capture_name.into()),
 7900                value.clone(),
 7901            );
 7902        }
 7903        project.update(cx, |project, cx| {
 7904            project.task_store().update(cx, |task_store, cx| {
 7905                task_store.task_context_for_location(captured_task_variables, location, cx)
 7906            })
 7907        })
 7908    }
 7909
 7910    pub fn spawn_nearest_task(
 7911        &mut self,
 7912        action: &SpawnNearestTask,
 7913        window: &mut Window,
 7914        cx: &mut Context<Self>,
 7915    ) {
 7916        let Some((workspace, _)) = self.workspace.clone() else {
 7917            return;
 7918        };
 7919        let Some(project) = self.project.clone() else {
 7920            return;
 7921        };
 7922
 7923        // Try to find a closest, enclosing node using tree-sitter that has a
 7924        // task
 7925        let Some((buffer, buffer_row, tasks)) = self
 7926            .find_enclosing_node_task(cx)
 7927            // Or find the task that's closest in row-distance.
 7928            .or_else(|| self.find_closest_task(cx))
 7929        else {
 7930            return;
 7931        };
 7932
 7933        let reveal_strategy = action.reveal;
 7934        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7935        cx.spawn_in(window, async move |_, cx| {
 7936            let context = task_context.await?;
 7937            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7938
 7939            let resolved = &mut resolved_task.resolved;
 7940            resolved.reveal = reveal_strategy;
 7941
 7942            workspace
 7943                .update_in(cx, |workspace, window, cx| {
 7944                    workspace.schedule_resolved_task(
 7945                        task_source_kind,
 7946                        resolved_task,
 7947                        false,
 7948                        window,
 7949                        cx,
 7950                    );
 7951                })
 7952                .ok()
 7953        })
 7954        .detach();
 7955    }
 7956
 7957    fn find_closest_task(
 7958        &mut self,
 7959        cx: &mut Context<Self>,
 7960    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7961        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7962
 7963        let ((buffer_id, row), tasks) = self
 7964            .tasks
 7965            .iter()
 7966            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7967
 7968        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7969        let tasks = Arc::new(tasks.to_owned());
 7970        Some((buffer, *row, tasks))
 7971    }
 7972
 7973    fn find_enclosing_node_task(
 7974        &mut self,
 7975        cx: &mut Context<Self>,
 7976    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7977        let snapshot = self.buffer.read(cx).snapshot(cx);
 7978        let offset = self.selections.newest::<usize>(cx).head();
 7979        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7980        let buffer_id = excerpt.buffer().remote_id();
 7981
 7982        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7983        let mut cursor = layer.node().walk();
 7984
 7985        while cursor.goto_first_child_for_byte(offset).is_some() {
 7986            if cursor.node().end_byte() == offset {
 7987                cursor.goto_next_sibling();
 7988            }
 7989        }
 7990
 7991        // Ascend to the smallest ancestor that contains the range and has a task.
 7992        loop {
 7993            let node = cursor.node();
 7994            let node_range = node.byte_range();
 7995            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7996
 7997            // Check if this node contains our offset
 7998            if node_range.start <= offset && node_range.end >= offset {
 7999                // If it contains offset, check for task
 8000                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8001                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8002                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8003                }
 8004            }
 8005
 8006            if !cursor.goto_parent() {
 8007                break;
 8008            }
 8009        }
 8010        None
 8011    }
 8012
 8013    fn render_run_indicator(
 8014        &self,
 8015        _style: &EditorStyle,
 8016        is_active: bool,
 8017        row: DisplayRow,
 8018        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8019        cx: &mut Context<Self>,
 8020    ) -> IconButton {
 8021        let color = Color::Muted;
 8022        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8023
 8024        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8025            .shape(ui::IconButtonShape::Square)
 8026            .icon_size(IconSize::XSmall)
 8027            .icon_color(color)
 8028            .toggle_state(is_active)
 8029            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8030                let quick_launch = e.down.button == MouseButton::Left;
 8031                window.focus(&editor.focus_handle(cx));
 8032                editor.toggle_code_actions(
 8033                    &ToggleCodeActions {
 8034                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8035                        quick_launch,
 8036                    },
 8037                    window,
 8038                    cx,
 8039                );
 8040            }))
 8041            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8042                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8043            }))
 8044    }
 8045
 8046    pub fn context_menu_visible(&self) -> bool {
 8047        !self.edit_prediction_preview_is_active()
 8048            && self
 8049                .context_menu
 8050                .borrow()
 8051                .as_ref()
 8052                .map_or(false, |menu| menu.visible())
 8053    }
 8054
 8055    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8056        self.context_menu
 8057            .borrow()
 8058            .as_ref()
 8059            .map(|menu| menu.origin())
 8060    }
 8061
 8062    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8063        self.context_menu_options = Some(options);
 8064    }
 8065
 8066    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8067    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8068
 8069    fn render_edit_prediction_popover(
 8070        &mut self,
 8071        text_bounds: &Bounds<Pixels>,
 8072        content_origin: gpui::Point<Pixels>,
 8073        right_margin: Pixels,
 8074        editor_snapshot: &EditorSnapshot,
 8075        visible_row_range: Range<DisplayRow>,
 8076        scroll_top: f32,
 8077        scroll_bottom: f32,
 8078        line_layouts: &[LineWithInvisibles],
 8079        line_height: Pixels,
 8080        scroll_pixel_position: gpui::Point<Pixels>,
 8081        newest_selection_head: Option<DisplayPoint>,
 8082        editor_width: Pixels,
 8083        style: &EditorStyle,
 8084        window: &mut Window,
 8085        cx: &mut App,
 8086    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8087        if self.mode().is_minimap() {
 8088            return None;
 8089        }
 8090        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8091
 8092        if self.edit_prediction_visible_in_cursor_popover(true) {
 8093            return None;
 8094        }
 8095
 8096        match &active_inline_completion.completion {
 8097            InlineCompletion::Move { target, .. } => {
 8098                let target_display_point = target.to_display_point(editor_snapshot);
 8099
 8100                if self.edit_prediction_requires_modifier() {
 8101                    if !self.edit_prediction_preview_is_active() {
 8102                        return None;
 8103                    }
 8104
 8105                    self.render_edit_prediction_modifier_jump_popover(
 8106                        text_bounds,
 8107                        content_origin,
 8108                        visible_row_range,
 8109                        line_layouts,
 8110                        line_height,
 8111                        scroll_pixel_position,
 8112                        newest_selection_head,
 8113                        target_display_point,
 8114                        window,
 8115                        cx,
 8116                    )
 8117                } else {
 8118                    self.render_edit_prediction_eager_jump_popover(
 8119                        text_bounds,
 8120                        content_origin,
 8121                        editor_snapshot,
 8122                        visible_row_range,
 8123                        scroll_top,
 8124                        scroll_bottom,
 8125                        line_height,
 8126                        scroll_pixel_position,
 8127                        target_display_point,
 8128                        editor_width,
 8129                        window,
 8130                        cx,
 8131                    )
 8132                }
 8133            }
 8134            InlineCompletion::Edit {
 8135                display_mode: EditDisplayMode::Inline,
 8136                ..
 8137            } => None,
 8138            InlineCompletion::Edit {
 8139                display_mode: EditDisplayMode::TabAccept,
 8140                edits,
 8141                ..
 8142            } => {
 8143                let range = &edits.first()?.0;
 8144                let target_display_point = range.end.to_display_point(editor_snapshot);
 8145
 8146                self.render_edit_prediction_end_of_line_popover(
 8147                    "Accept",
 8148                    editor_snapshot,
 8149                    visible_row_range,
 8150                    target_display_point,
 8151                    line_height,
 8152                    scroll_pixel_position,
 8153                    content_origin,
 8154                    editor_width,
 8155                    window,
 8156                    cx,
 8157                )
 8158            }
 8159            InlineCompletion::Edit {
 8160                edits,
 8161                edit_preview,
 8162                display_mode: EditDisplayMode::DiffPopover,
 8163                snapshot,
 8164            } => self.render_edit_prediction_diff_popover(
 8165                text_bounds,
 8166                content_origin,
 8167                right_margin,
 8168                editor_snapshot,
 8169                visible_row_range,
 8170                line_layouts,
 8171                line_height,
 8172                scroll_pixel_position,
 8173                newest_selection_head,
 8174                editor_width,
 8175                style,
 8176                edits,
 8177                edit_preview,
 8178                snapshot,
 8179                window,
 8180                cx,
 8181            ),
 8182        }
 8183    }
 8184
 8185    fn render_edit_prediction_modifier_jump_popover(
 8186        &mut self,
 8187        text_bounds: &Bounds<Pixels>,
 8188        content_origin: gpui::Point<Pixels>,
 8189        visible_row_range: Range<DisplayRow>,
 8190        line_layouts: &[LineWithInvisibles],
 8191        line_height: Pixels,
 8192        scroll_pixel_position: gpui::Point<Pixels>,
 8193        newest_selection_head: Option<DisplayPoint>,
 8194        target_display_point: DisplayPoint,
 8195        window: &mut Window,
 8196        cx: &mut App,
 8197    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8198        let scrolled_content_origin =
 8199            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8200
 8201        const SCROLL_PADDING_Y: Pixels = px(12.);
 8202
 8203        if target_display_point.row() < visible_row_range.start {
 8204            return self.render_edit_prediction_scroll_popover(
 8205                |_| SCROLL_PADDING_Y,
 8206                IconName::ArrowUp,
 8207                visible_row_range,
 8208                line_layouts,
 8209                newest_selection_head,
 8210                scrolled_content_origin,
 8211                window,
 8212                cx,
 8213            );
 8214        } else if target_display_point.row() >= visible_row_range.end {
 8215            return self.render_edit_prediction_scroll_popover(
 8216                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8217                IconName::ArrowDown,
 8218                visible_row_range,
 8219                line_layouts,
 8220                newest_selection_head,
 8221                scrolled_content_origin,
 8222                window,
 8223                cx,
 8224            );
 8225        }
 8226
 8227        const POLE_WIDTH: Pixels = px(2.);
 8228
 8229        let line_layout =
 8230            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8231        let target_column = target_display_point.column() as usize;
 8232
 8233        let target_x = line_layout.x_for_index(target_column);
 8234        let target_y =
 8235            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8236
 8237        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8238
 8239        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8240        border_color.l += 0.001;
 8241
 8242        let mut element = v_flex()
 8243            .items_end()
 8244            .when(flag_on_right, |el| el.items_start())
 8245            .child(if flag_on_right {
 8246                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8247                    .rounded_bl(px(0.))
 8248                    .rounded_tl(px(0.))
 8249                    .border_l_2()
 8250                    .border_color(border_color)
 8251            } else {
 8252                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8253                    .rounded_br(px(0.))
 8254                    .rounded_tr(px(0.))
 8255                    .border_r_2()
 8256                    .border_color(border_color)
 8257            })
 8258            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8259            .into_any();
 8260
 8261        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8262
 8263        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8264            - point(
 8265                if flag_on_right {
 8266                    POLE_WIDTH
 8267                } else {
 8268                    size.width - POLE_WIDTH
 8269                },
 8270                size.height - line_height,
 8271            );
 8272
 8273        origin.x = origin.x.max(content_origin.x);
 8274
 8275        element.prepaint_at(origin, window, cx);
 8276
 8277        Some((element, origin))
 8278    }
 8279
 8280    fn render_edit_prediction_scroll_popover(
 8281        &mut self,
 8282        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8283        scroll_icon: IconName,
 8284        visible_row_range: Range<DisplayRow>,
 8285        line_layouts: &[LineWithInvisibles],
 8286        newest_selection_head: Option<DisplayPoint>,
 8287        scrolled_content_origin: gpui::Point<Pixels>,
 8288        window: &mut Window,
 8289        cx: &mut App,
 8290    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8291        let mut element = self
 8292            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8293            .into_any();
 8294
 8295        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8296
 8297        let cursor = newest_selection_head?;
 8298        let cursor_row_layout =
 8299            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8300        let cursor_column = cursor.column() as usize;
 8301
 8302        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8303
 8304        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8305
 8306        element.prepaint_at(origin, window, cx);
 8307        Some((element, origin))
 8308    }
 8309
 8310    fn render_edit_prediction_eager_jump_popover(
 8311        &mut self,
 8312        text_bounds: &Bounds<Pixels>,
 8313        content_origin: gpui::Point<Pixels>,
 8314        editor_snapshot: &EditorSnapshot,
 8315        visible_row_range: Range<DisplayRow>,
 8316        scroll_top: f32,
 8317        scroll_bottom: f32,
 8318        line_height: Pixels,
 8319        scroll_pixel_position: gpui::Point<Pixels>,
 8320        target_display_point: DisplayPoint,
 8321        editor_width: Pixels,
 8322        window: &mut Window,
 8323        cx: &mut App,
 8324    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8325        if target_display_point.row().as_f32() < scroll_top {
 8326            let mut element = self
 8327                .render_edit_prediction_line_popover(
 8328                    "Jump to Edit",
 8329                    Some(IconName::ArrowUp),
 8330                    window,
 8331                    cx,
 8332                )?
 8333                .into_any();
 8334
 8335            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8336            let offset = point(
 8337                (text_bounds.size.width - size.width) / 2.,
 8338                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8339            );
 8340
 8341            let origin = text_bounds.origin + offset;
 8342            element.prepaint_at(origin, window, cx);
 8343            Some((element, origin))
 8344        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8345            let mut element = self
 8346                .render_edit_prediction_line_popover(
 8347                    "Jump to Edit",
 8348                    Some(IconName::ArrowDown),
 8349                    window,
 8350                    cx,
 8351                )?
 8352                .into_any();
 8353
 8354            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8355            let offset = point(
 8356                (text_bounds.size.width - size.width) / 2.,
 8357                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8358            );
 8359
 8360            let origin = text_bounds.origin + offset;
 8361            element.prepaint_at(origin, window, cx);
 8362            Some((element, origin))
 8363        } else {
 8364            self.render_edit_prediction_end_of_line_popover(
 8365                "Jump to Edit",
 8366                editor_snapshot,
 8367                visible_row_range,
 8368                target_display_point,
 8369                line_height,
 8370                scroll_pixel_position,
 8371                content_origin,
 8372                editor_width,
 8373                window,
 8374                cx,
 8375            )
 8376        }
 8377    }
 8378
 8379    fn render_edit_prediction_end_of_line_popover(
 8380        self: &mut Editor,
 8381        label: &'static str,
 8382        editor_snapshot: &EditorSnapshot,
 8383        visible_row_range: Range<DisplayRow>,
 8384        target_display_point: DisplayPoint,
 8385        line_height: Pixels,
 8386        scroll_pixel_position: gpui::Point<Pixels>,
 8387        content_origin: gpui::Point<Pixels>,
 8388        editor_width: Pixels,
 8389        window: &mut Window,
 8390        cx: &mut App,
 8391    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8392        let target_line_end = DisplayPoint::new(
 8393            target_display_point.row(),
 8394            editor_snapshot.line_len(target_display_point.row()),
 8395        );
 8396
 8397        let mut element = self
 8398            .render_edit_prediction_line_popover(label, None, window, cx)?
 8399            .into_any();
 8400
 8401        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8402
 8403        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8404
 8405        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8406        let mut origin = start_point
 8407            + line_origin
 8408            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8409        origin.x = origin.x.max(content_origin.x);
 8410
 8411        let max_x = content_origin.x + editor_width - size.width;
 8412
 8413        if origin.x > max_x {
 8414            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8415
 8416            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8417                origin.y += offset;
 8418                IconName::ArrowUp
 8419            } else {
 8420                origin.y -= offset;
 8421                IconName::ArrowDown
 8422            };
 8423
 8424            element = self
 8425                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8426                .into_any();
 8427
 8428            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8429
 8430            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8431        }
 8432
 8433        element.prepaint_at(origin, window, cx);
 8434        Some((element, origin))
 8435    }
 8436
 8437    fn render_edit_prediction_diff_popover(
 8438        self: &Editor,
 8439        text_bounds: &Bounds<Pixels>,
 8440        content_origin: gpui::Point<Pixels>,
 8441        right_margin: Pixels,
 8442        editor_snapshot: &EditorSnapshot,
 8443        visible_row_range: Range<DisplayRow>,
 8444        line_layouts: &[LineWithInvisibles],
 8445        line_height: Pixels,
 8446        scroll_pixel_position: gpui::Point<Pixels>,
 8447        newest_selection_head: Option<DisplayPoint>,
 8448        editor_width: Pixels,
 8449        style: &EditorStyle,
 8450        edits: &Vec<(Range<Anchor>, String)>,
 8451        edit_preview: &Option<language::EditPreview>,
 8452        snapshot: &language::BufferSnapshot,
 8453        window: &mut Window,
 8454        cx: &mut App,
 8455    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8456        let edit_start = edits
 8457            .first()
 8458            .unwrap()
 8459            .0
 8460            .start
 8461            .to_display_point(editor_snapshot);
 8462        let edit_end = edits
 8463            .last()
 8464            .unwrap()
 8465            .0
 8466            .end
 8467            .to_display_point(editor_snapshot);
 8468
 8469        let is_visible = visible_row_range.contains(&edit_start.row())
 8470            || visible_row_range.contains(&edit_end.row());
 8471        if !is_visible {
 8472            return None;
 8473        }
 8474
 8475        let highlighted_edits =
 8476            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8477
 8478        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8479        let line_count = highlighted_edits.text.lines().count();
 8480
 8481        const BORDER_WIDTH: Pixels = px(1.);
 8482
 8483        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8484        let has_keybind = keybind.is_some();
 8485
 8486        let mut element = h_flex()
 8487            .items_start()
 8488            .child(
 8489                h_flex()
 8490                    .bg(cx.theme().colors().editor_background)
 8491                    .border(BORDER_WIDTH)
 8492                    .shadow_sm()
 8493                    .border_color(cx.theme().colors().border)
 8494                    .rounded_l_lg()
 8495                    .when(line_count > 1, |el| el.rounded_br_lg())
 8496                    .pr_1()
 8497                    .child(styled_text),
 8498            )
 8499            .child(
 8500                h_flex()
 8501                    .h(line_height + BORDER_WIDTH * 2.)
 8502                    .px_1p5()
 8503                    .gap_1()
 8504                    // Workaround: For some reason, there's a gap if we don't do this
 8505                    .ml(-BORDER_WIDTH)
 8506                    .shadow(vec![gpui::BoxShadow {
 8507                        color: gpui::black().opacity(0.05),
 8508                        offset: point(px(1.), px(1.)),
 8509                        blur_radius: px(2.),
 8510                        spread_radius: px(0.),
 8511                    }])
 8512                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8513                    .border(BORDER_WIDTH)
 8514                    .border_color(cx.theme().colors().border)
 8515                    .rounded_r_lg()
 8516                    .id("edit_prediction_diff_popover_keybind")
 8517                    .when(!has_keybind, |el| {
 8518                        let status_colors = cx.theme().status();
 8519
 8520                        el.bg(status_colors.error_background)
 8521                            .border_color(status_colors.error.opacity(0.6))
 8522                            .child(Icon::new(IconName::Info).color(Color::Error))
 8523                            .cursor_default()
 8524                            .hoverable_tooltip(move |_window, cx| {
 8525                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8526                            })
 8527                    })
 8528                    .children(keybind),
 8529            )
 8530            .into_any();
 8531
 8532        let longest_row =
 8533            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8534        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8535            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8536        } else {
 8537            layout_line(
 8538                longest_row,
 8539                editor_snapshot,
 8540                style,
 8541                editor_width,
 8542                |_| false,
 8543                window,
 8544                cx,
 8545            )
 8546            .width
 8547        };
 8548
 8549        let viewport_bounds =
 8550            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8551                right: -right_margin,
 8552                ..Default::default()
 8553            });
 8554
 8555        let x_after_longest =
 8556            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8557                - scroll_pixel_position.x;
 8558
 8559        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8560
 8561        // Fully visible if it can be displayed within the window (allow overlapping other
 8562        // panes). However, this is only allowed if the popover starts within text_bounds.
 8563        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8564            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8565
 8566        let mut origin = if can_position_to_the_right {
 8567            point(
 8568                x_after_longest,
 8569                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8570                    - scroll_pixel_position.y,
 8571            )
 8572        } else {
 8573            let cursor_row = newest_selection_head.map(|head| head.row());
 8574            let above_edit = edit_start
 8575                .row()
 8576                .0
 8577                .checked_sub(line_count as u32)
 8578                .map(DisplayRow);
 8579            let below_edit = Some(edit_end.row() + 1);
 8580            let above_cursor =
 8581                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8582            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8583
 8584            // Place the edit popover adjacent to the edit if there is a location
 8585            // available that is onscreen and does not obscure the cursor. Otherwise,
 8586            // place it adjacent to the cursor.
 8587            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8588                .into_iter()
 8589                .flatten()
 8590                .find(|&start_row| {
 8591                    let end_row = start_row + line_count as u32;
 8592                    visible_row_range.contains(&start_row)
 8593                        && visible_row_range.contains(&end_row)
 8594                        && cursor_row.map_or(true, |cursor_row| {
 8595                            !((start_row..end_row).contains(&cursor_row))
 8596                        })
 8597                })?;
 8598
 8599            content_origin
 8600                + point(
 8601                    -scroll_pixel_position.x,
 8602                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8603                )
 8604        };
 8605
 8606        origin.x -= BORDER_WIDTH;
 8607
 8608        window.defer_draw(element, origin, 1);
 8609
 8610        // Do not return an element, since it will already be drawn due to defer_draw.
 8611        None
 8612    }
 8613
 8614    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8615        px(30.)
 8616    }
 8617
 8618    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8619        if self.read_only(cx) {
 8620            cx.theme().players().read_only()
 8621        } else {
 8622            self.style.as_ref().unwrap().local_player
 8623        }
 8624    }
 8625
 8626    fn render_edit_prediction_accept_keybind(
 8627        &self,
 8628        window: &mut Window,
 8629        cx: &App,
 8630    ) -> Option<AnyElement> {
 8631        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8632        let accept_keystroke = accept_binding.keystroke()?;
 8633
 8634        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8635
 8636        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8637            Color::Accent
 8638        } else {
 8639            Color::Muted
 8640        };
 8641
 8642        h_flex()
 8643            .px_0p5()
 8644            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8645            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8646            .text_size(TextSize::XSmall.rems(cx))
 8647            .child(h_flex().children(ui::render_modifiers(
 8648                &accept_keystroke.modifiers,
 8649                PlatformStyle::platform(),
 8650                Some(modifiers_color),
 8651                Some(IconSize::XSmall.rems().into()),
 8652                true,
 8653            )))
 8654            .when(is_platform_style_mac, |parent| {
 8655                parent.child(accept_keystroke.key.clone())
 8656            })
 8657            .when(!is_platform_style_mac, |parent| {
 8658                parent.child(
 8659                    Key::new(
 8660                        util::capitalize(&accept_keystroke.key),
 8661                        Some(Color::Default),
 8662                    )
 8663                    .size(Some(IconSize::XSmall.rems().into())),
 8664                )
 8665            })
 8666            .into_any()
 8667            .into()
 8668    }
 8669
 8670    fn render_edit_prediction_line_popover(
 8671        &self,
 8672        label: impl Into<SharedString>,
 8673        icon: Option<IconName>,
 8674        window: &mut Window,
 8675        cx: &App,
 8676    ) -> Option<Stateful<Div>> {
 8677        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8678
 8679        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8680        let has_keybind = keybind.is_some();
 8681
 8682        let result = h_flex()
 8683            .id("ep-line-popover")
 8684            .py_0p5()
 8685            .pl_1()
 8686            .pr(padding_right)
 8687            .gap_1()
 8688            .rounded_md()
 8689            .border_1()
 8690            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8691            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8692            .shadow_sm()
 8693            .when(!has_keybind, |el| {
 8694                let status_colors = cx.theme().status();
 8695
 8696                el.bg(status_colors.error_background)
 8697                    .border_color(status_colors.error.opacity(0.6))
 8698                    .pl_2()
 8699                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8700                    .cursor_default()
 8701                    .hoverable_tooltip(move |_window, cx| {
 8702                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8703                    })
 8704            })
 8705            .children(keybind)
 8706            .child(
 8707                Label::new(label)
 8708                    .size(LabelSize::Small)
 8709                    .when(!has_keybind, |el| {
 8710                        el.color(cx.theme().status().error.into()).strikethrough()
 8711                    }),
 8712            )
 8713            .when(!has_keybind, |el| {
 8714                el.child(
 8715                    h_flex().ml_1().child(
 8716                        Icon::new(IconName::Info)
 8717                            .size(IconSize::Small)
 8718                            .color(cx.theme().status().error.into()),
 8719                    ),
 8720                )
 8721            })
 8722            .when_some(icon, |element, icon| {
 8723                element.child(
 8724                    div()
 8725                        .mt(px(1.5))
 8726                        .child(Icon::new(icon).size(IconSize::Small)),
 8727                )
 8728            });
 8729
 8730        Some(result)
 8731    }
 8732
 8733    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8734        let accent_color = cx.theme().colors().text_accent;
 8735        let editor_bg_color = cx.theme().colors().editor_background;
 8736        editor_bg_color.blend(accent_color.opacity(0.1))
 8737    }
 8738
 8739    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8740        let accent_color = cx.theme().colors().text_accent;
 8741        let editor_bg_color = cx.theme().colors().editor_background;
 8742        editor_bg_color.blend(accent_color.opacity(0.6))
 8743    }
 8744
 8745    fn render_edit_prediction_cursor_popover(
 8746        &self,
 8747        min_width: Pixels,
 8748        max_width: Pixels,
 8749        cursor_point: Point,
 8750        style: &EditorStyle,
 8751        accept_keystroke: Option<&gpui::Keystroke>,
 8752        _window: &Window,
 8753        cx: &mut Context<Editor>,
 8754    ) -> Option<AnyElement> {
 8755        let provider = self.edit_prediction_provider.as_ref()?;
 8756
 8757        if provider.provider.needs_terms_acceptance(cx) {
 8758            return Some(
 8759                h_flex()
 8760                    .min_w(min_width)
 8761                    .flex_1()
 8762                    .px_2()
 8763                    .py_1()
 8764                    .gap_3()
 8765                    .elevation_2(cx)
 8766                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8767                    .id("accept-terms")
 8768                    .cursor_pointer()
 8769                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8770                    .on_click(cx.listener(|this, _event, window, cx| {
 8771                        cx.stop_propagation();
 8772                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8773                        window.dispatch_action(
 8774                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8775                            cx,
 8776                        );
 8777                    }))
 8778                    .child(
 8779                        h_flex()
 8780                            .flex_1()
 8781                            .gap_2()
 8782                            .child(Icon::new(IconName::ZedPredict))
 8783                            .child(Label::new("Accept Terms of Service"))
 8784                            .child(div().w_full())
 8785                            .child(
 8786                                Icon::new(IconName::ArrowUpRight)
 8787                                    .color(Color::Muted)
 8788                                    .size(IconSize::Small),
 8789                            )
 8790                            .into_any_element(),
 8791                    )
 8792                    .into_any(),
 8793            );
 8794        }
 8795
 8796        let is_refreshing = provider.provider.is_refreshing(cx);
 8797
 8798        fn pending_completion_container() -> Div {
 8799            h_flex()
 8800                .h_full()
 8801                .flex_1()
 8802                .gap_2()
 8803                .child(Icon::new(IconName::ZedPredict))
 8804        }
 8805
 8806        let completion = match &self.active_inline_completion {
 8807            Some(prediction) => {
 8808                if !self.has_visible_completions_menu() {
 8809                    const RADIUS: Pixels = px(6.);
 8810                    const BORDER_WIDTH: Pixels = px(1.);
 8811
 8812                    return Some(
 8813                        h_flex()
 8814                            .elevation_2(cx)
 8815                            .border(BORDER_WIDTH)
 8816                            .border_color(cx.theme().colors().border)
 8817                            .when(accept_keystroke.is_none(), |el| {
 8818                                el.border_color(cx.theme().status().error)
 8819                            })
 8820                            .rounded(RADIUS)
 8821                            .rounded_tl(px(0.))
 8822                            .overflow_hidden()
 8823                            .child(div().px_1p5().child(match &prediction.completion {
 8824                                InlineCompletion::Move { target, snapshot } => {
 8825                                    use text::ToPoint as _;
 8826                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8827                                    {
 8828                                        Icon::new(IconName::ZedPredictDown)
 8829                                    } else {
 8830                                        Icon::new(IconName::ZedPredictUp)
 8831                                    }
 8832                                }
 8833                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8834                            }))
 8835                            .child(
 8836                                h_flex()
 8837                                    .gap_1()
 8838                                    .py_1()
 8839                                    .px_2()
 8840                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8841                                    .border_l_1()
 8842                                    .border_color(cx.theme().colors().border)
 8843                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8844                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8845                                        el.child(
 8846                                            Label::new("Hold")
 8847                                                .size(LabelSize::Small)
 8848                                                .when(accept_keystroke.is_none(), |el| {
 8849                                                    el.strikethrough()
 8850                                                })
 8851                                                .line_height_style(LineHeightStyle::UiLabel),
 8852                                        )
 8853                                    })
 8854                                    .id("edit_prediction_cursor_popover_keybind")
 8855                                    .when(accept_keystroke.is_none(), |el| {
 8856                                        let status_colors = cx.theme().status();
 8857
 8858                                        el.bg(status_colors.error_background)
 8859                                            .border_color(status_colors.error.opacity(0.6))
 8860                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8861                                            .cursor_default()
 8862                                            .hoverable_tooltip(move |_window, cx| {
 8863                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8864                                                    .into()
 8865                                            })
 8866                                    })
 8867                                    .when_some(
 8868                                        accept_keystroke.as_ref(),
 8869                                        |el, accept_keystroke| {
 8870                                            el.child(h_flex().children(ui::render_modifiers(
 8871                                                &accept_keystroke.modifiers,
 8872                                                PlatformStyle::platform(),
 8873                                                Some(Color::Default),
 8874                                                Some(IconSize::XSmall.rems().into()),
 8875                                                false,
 8876                                            )))
 8877                                        },
 8878                                    ),
 8879                            )
 8880                            .into_any(),
 8881                    );
 8882                }
 8883
 8884                self.render_edit_prediction_cursor_popover_preview(
 8885                    prediction,
 8886                    cursor_point,
 8887                    style,
 8888                    cx,
 8889                )?
 8890            }
 8891
 8892            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8893                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8894                    stale_completion,
 8895                    cursor_point,
 8896                    style,
 8897                    cx,
 8898                )?,
 8899
 8900                None => {
 8901                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8902                }
 8903            },
 8904
 8905            None => pending_completion_container().child(Label::new("No Prediction")),
 8906        };
 8907
 8908        let completion = if is_refreshing {
 8909            completion
 8910                .with_animation(
 8911                    "loading-completion",
 8912                    Animation::new(Duration::from_secs(2))
 8913                        .repeat()
 8914                        .with_easing(pulsating_between(0.4, 0.8)),
 8915                    |label, delta| label.opacity(delta),
 8916                )
 8917                .into_any_element()
 8918        } else {
 8919            completion.into_any_element()
 8920        };
 8921
 8922        let has_completion = self.active_inline_completion.is_some();
 8923
 8924        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8925        Some(
 8926            h_flex()
 8927                .min_w(min_width)
 8928                .max_w(max_width)
 8929                .flex_1()
 8930                .elevation_2(cx)
 8931                .border_color(cx.theme().colors().border)
 8932                .child(
 8933                    div()
 8934                        .flex_1()
 8935                        .py_1()
 8936                        .px_2()
 8937                        .overflow_hidden()
 8938                        .child(completion),
 8939                )
 8940                .when_some(accept_keystroke, |el, accept_keystroke| {
 8941                    if !accept_keystroke.modifiers.modified() {
 8942                        return el;
 8943                    }
 8944
 8945                    el.child(
 8946                        h_flex()
 8947                            .h_full()
 8948                            .border_l_1()
 8949                            .rounded_r_lg()
 8950                            .border_color(cx.theme().colors().border)
 8951                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8952                            .gap_1()
 8953                            .py_1()
 8954                            .px_2()
 8955                            .child(
 8956                                h_flex()
 8957                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8958                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8959                                    .child(h_flex().children(ui::render_modifiers(
 8960                                        &accept_keystroke.modifiers,
 8961                                        PlatformStyle::platform(),
 8962                                        Some(if !has_completion {
 8963                                            Color::Muted
 8964                                        } else {
 8965                                            Color::Default
 8966                                        }),
 8967                                        None,
 8968                                        false,
 8969                                    ))),
 8970                            )
 8971                            .child(Label::new("Preview").into_any_element())
 8972                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8973                    )
 8974                })
 8975                .into_any(),
 8976        )
 8977    }
 8978
 8979    fn render_edit_prediction_cursor_popover_preview(
 8980        &self,
 8981        completion: &InlineCompletionState,
 8982        cursor_point: Point,
 8983        style: &EditorStyle,
 8984        cx: &mut Context<Editor>,
 8985    ) -> Option<Div> {
 8986        use text::ToPoint as _;
 8987
 8988        fn render_relative_row_jump(
 8989            prefix: impl Into<String>,
 8990            current_row: u32,
 8991            target_row: u32,
 8992        ) -> Div {
 8993            let (row_diff, arrow) = if target_row < current_row {
 8994                (current_row - target_row, IconName::ArrowUp)
 8995            } else {
 8996                (target_row - current_row, IconName::ArrowDown)
 8997            };
 8998
 8999            h_flex()
 9000                .child(
 9001                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9002                        .color(Color::Muted)
 9003                        .size(LabelSize::Small),
 9004                )
 9005                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9006        }
 9007
 9008        match &completion.completion {
 9009            InlineCompletion::Move {
 9010                target, snapshot, ..
 9011            } => Some(
 9012                h_flex()
 9013                    .px_2()
 9014                    .gap_2()
 9015                    .flex_1()
 9016                    .child(
 9017                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9018                            Icon::new(IconName::ZedPredictDown)
 9019                        } else {
 9020                            Icon::new(IconName::ZedPredictUp)
 9021                        },
 9022                    )
 9023                    .child(Label::new("Jump to Edit")),
 9024            ),
 9025
 9026            InlineCompletion::Edit {
 9027                edits,
 9028                edit_preview,
 9029                snapshot,
 9030                display_mode: _,
 9031            } => {
 9032                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9033
 9034                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9035                    &snapshot,
 9036                    &edits,
 9037                    edit_preview.as_ref()?,
 9038                    true,
 9039                    cx,
 9040                )
 9041                .first_line_preview();
 9042
 9043                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9044                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9045
 9046                let preview = h_flex()
 9047                    .gap_1()
 9048                    .min_w_16()
 9049                    .child(styled_text)
 9050                    .when(has_more_lines, |parent| parent.child(""));
 9051
 9052                let left = if first_edit_row != cursor_point.row {
 9053                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9054                        .into_any_element()
 9055                } else {
 9056                    Icon::new(IconName::ZedPredict).into_any_element()
 9057                };
 9058
 9059                Some(
 9060                    h_flex()
 9061                        .h_full()
 9062                        .flex_1()
 9063                        .gap_2()
 9064                        .pr_1()
 9065                        .overflow_x_hidden()
 9066                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9067                        .child(left)
 9068                        .child(preview),
 9069                )
 9070            }
 9071        }
 9072    }
 9073
 9074    pub fn render_context_menu(
 9075        &self,
 9076        style: &EditorStyle,
 9077        max_height_in_lines: u32,
 9078        window: &mut Window,
 9079        cx: &mut Context<Editor>,
 9080    ) -> Option<AnyElement> {
 9081        let menu = self.context_menu.borrow();
 9082        let menu = menu.as_ref()?;
 9083        if !menu.visible() {
 9084            return None;
 9085        };
 9086        Some(menu.render(style, max_height_in_lines, window, cx))
 9087    }
 9088
 9089    fn render_context_menu_aside(
 9090        &mut self,
 9091        max_size: Size<Pixels>,
 9092        window: &mut Window,
 9093        cx: &mut Context<Editor>,
 9094    ) -> Option<AnyElement> {
 9095        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9096            if menu.visible() {
 9097                menu.render_aside(max_size, window, cx)
 9098            } else {
 9099                None
 9100            }
 9101        })
 9102    }
 9103
 9104    fn hide_context_menu(
 9105        &mut self,
 9106        window: &mut Window,
 9107        cx: &mut Context<Self>,
 9108    ) -> Option<CodeContextMenu> {
 9109        cx.notify();
 9110        self.completion_tasks.clear();
 9111        let context_menu = self.context_menu.borrow_mut().take();
 9112        self.stale_inline_completion_in_menu.take();
 9113        self.update_visible_inline_completion(window, cx);
 9114        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9115            if let Some(completion_provider) = &self.completion_provider {
 9116                completion_provider.selection_changed(None, window, cx);
 9117            }
 9118        }
 9119        context_menu
 9120    }
 9121
 9122    fn show_snippet_choices(
 9123        &mut self,
 9124        choices: &Vec<String>,
 9125        selection: Range<Anchor>,
 9126        cx: &mut Context<Self>,
 9127    ) {
 9128        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9129            (Some(a), Some(b)) if a == b => a,
 9130            _ => {
 9131                log::error!("expected anchor range to have matching buffer IDs");
 9132                return;
 9133            }
 9134        };
 9135        let multi_buffer = self.buffer().read(cx);
 9136        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9137            return;
 9138        };
 9139
 9140        let id = post_inc(&mut self.next_completion_id);
 9141        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9142        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9143            CompletionsMenu::new_snippet_choices(
 9144                id,
 9145                true,
 9146                choices,
 9147                selection,
 9148                buffer,
 9149                snippet_sort_order,
 9150            ),
 9151        ));
 9152    }
 9153
 9154    pub fn insert_snippet(
 9155        &mut self,
 9156        insertion_ranges: &[Range<usize>],
 9157        snippet: Snippet,
 9158        window: &mut Window,
 9159        cx: &mut Context<Self>,
 9160    ) -> Result<()> {
 9161        struct Tabstop<T> {
 9162            is_end_tabstop: bool,
 9163            ranges: Vec<Range<T>>,
 9164            choices: Option<Vec<String>>,
 9165        }
 9166
 9167        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9168            let snippet_text: Arc<str> = snippet.text.clone().into();
 9169            let edits = insertion_ranges
 9170                .iter()
 9171                .cloned()
 9172                .map(|range| (range, snippet_text.clone()));
 9173            let autoindent_mode = AutoindentMode::Block {
 9174                original_indent_columns: Vec::new(),
 9175            };
 9176            buffer.edit(edits, Some(autoindent_mode), cx);
 9177
 9178            let snapshot = &*buffer.read(cx);
 9179            let snippet = &snippet;
 9180            snippet
 9181                .tabstops
 9182                .iter()
 9183                .map(|tabstop| {
 9184                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9185                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9186                    });
 9187                    let mut tabstop_ranges = tabstop
 9188                        .ranges
 9189                        .iter()
 9190                        .flat_map(|tabstop_range| {
 9191                            let mut delta = 0_isize;
 9192                            insertion_ranges.iter().map(move |insertion_range| {
 9193                                let insertion_start = insertion_range.start as isize + delta;
 9194                                delta +=
 9195                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9196
 9197                                let start = ((insertion_start + tabstop_range.start) as usize)
 9198                                    .min(snapshot.len());
 9199                                let end = ((insertion_start + tabstop_range.end) as usize)
 9200                                    .min(snapshot.len());
 9201                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9202                            })
 9203                        })
 9204                        .collect::<Vec<_>>();
 9205                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9206
 9207                    Tabstop {
 9208                        is_end_tabstop,
 9209                        ranges: tabstop_ranges,
 9210                        choices: tabstop.choices.clone(),
 9211                    }
 9212                })
 9213                .collect::<Vec<_>>()
 9214        });
 9215        if let Some(tabstop) = tabstops.first() {
 9216            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9217                // Reverse order so that the first range is the newest created selection.
 9218                // Completions will use it and autoscroll will prioritize it.
 9219                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9220            });
 9221
 9222            if let Some(choices) = &tabstop.choices {
 9223                if let Some(selection) = tabstop.ranges.first() {
 9224                    self.show_snippet_choices(choices, selection.clone(), cx)
 9225                }
 9226            }
 9227
 9228            // If we're already at the last tabstop and it's at the end of the snippet,
 9229            // we're done, we don't need to keep the state around.
 9230            if !tabstop.is_end_tabstop {
 9231                let choices = tabstops
 9232                    .iter()
 9233                    .map(|tabstop| tabstop.choices.clone())
 9234                    .collect();
 9235
 9236                let ranges = tabstops
 9237                    .into_iter()
 9238                    .map(|tabstop| tabstop.ranges)
 9239                    .collect::<Vec<_>>();
 9240
 9241                self.snippet_stack.push(SnippetState {
 9242                    active_index: 0,
 9243                    ranges,
 9244                    choices,
 9245                });
 9246            }
 9247
 9248            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9249            if self.autoclose_regions.is_empty() {
 9250                let snapshot = self.buffer.read(cx).snapshot(cx);
 9251                for selection in &mut self.selections.all::<Point>(cx) {
 9252                    let selection_head = selection.head();
 9253                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9254                        continue;
 9255                    };
 9256
 9257                    let mut bracket_pair = None;
 9258                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9259                    let prev_chars = snapshot
 9260                        .reversed_chars_at(selection_head)
 9261                        .collect::<String>();
 9262                    for (pair, enabled) in scope.brackets() {
 9263                        if enabled
 9264                            && pair.close
 9265                            && prev_chars.starts_with(pair.start.as_str())
 9266                            && next_chars.starts_with(pair.end.as_str())
 9267                        {
 9268                            bracket_pair = Some(pair.clone());
 9269                            break;
 9270                        }
 9271                    }
 9272                    if let Some(pair) = bracket_pair {
 9273                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9274                        let autoclose_enabled =
 9275                            self.use_autoclose && snapshot_settings.use_autoclose;
 9276                        if autoclose_enabled {
 9277                            let start = snapshot.anchor_after(selection_head);
 9278                            let end = snapshot.anchor_after(selection_head);
 9279                            self.autoclose_regions.push(AutocloseRegion {
 9280                                selection_id: selection.id,
 9281                                range: start..end,
 9282                                pair,
 9283                            });
 9284                        }
 9285                    }
 9286                }
 9287            }
 9288        }
 9289        Ok(())
 9290    }
 9291
 9292    pub fn move_to_next_snippet_tabstop(
 9293        &mut self,
 9294        window: &mut Window,
 9295        cx: &mut Context<Self>,
 9296    ) -> bool {
 9297        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9298    }
 9299
 9300    pub fn move_to_prev_snippet_tabstop(
 9301        &mut self,
 9302        window: &mut Window,
 9303        cx: &mut Context<Self>,
 9304    ) -> bool {
 9305        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9306    }
 9307
 9308    pub fn move_to_snippet_tabstop(
 9309        &mut self,
 9310        bias: Bias,
 9311        window: &mut Window,
 9312        cx: &mut Context<Self>,
 9313    ) -> bool {
 9314        if let Some(mut snippet) = self.snippet_stack.pop() {
 9315            match bias {
 9316                Bias::Left => {
 9317                    if snippet.active_index > 0 {
 9318                        snippet.active_index -= 1;
 9319                    } else {
 9320                        self.snippet_stack.push(snippet);
 9321                        return false;
 9322                    }
 9323                }
 9324                Bias::Right => {
 9325                    if snippet.active_index + 1 < snippet.ranges.len() {
 9326                        snippet.active_index += 1;
 9327                    } else {
 9328                        self.snippet_stack.push(snippet);
 9329                        return false;
 9330                    }
 9331                }
 9332            }
 9333            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9334                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9335                    // Reverse order so that the first range is the newest created selection.
 9336                    // Completions will use it and autoscroll will prioritize it.
 9337                    s.select_ranges(current_ranges.iter().rev().cloned())
 9338                });
 9339
 9340                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9341                    if let Some(selection) = current_ranges.first() {
 9342                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9343                    }
 9344                }
 9345
 9346                // If snippet state is not at the last tabstop, push it back on the stack
 9347                if snippet.active_index + 1 < snippet.ranges.len() {
 9348                    self.snippet_stack.push(snippet);
 9349                }
 9350                return true;
 9351            }
 9352        }
 9353
 9354        false
 9355    }
 9356
 9357    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9358        self.transact(window, cx, |this, window, cx| {
 9359            this.select_all(&SelectAll, window, cx);
 9360            this.insert("", window, cx);
 9361        });
 9362    }
 9363
 9364    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9365        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9366        self.transact(window, cx, |this, window, cx| {
 9367            this.select_autoclose_pair(window, cx);
 9368            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9369            if !this.linked_edit_ranges.is_empty() {
 9370                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9371                let snapshot = this.buffer.read(cx).snapshot(cx);
 9372
 9373                for selection in selections.iter() {
 9374                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9375                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9376                    if selection_start.buffer_id != selection_end.buffer_id {
 9377                        continue;
 9378                    }
 9379                    if let Some(ranges) =
 9380                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9381                    {
 9382                        for (buffer, entries) in ranges {
 9383                            linked_ranges.entry(buffer).or_default().extend(entries);
 9384                        }
 9385                    }
 9386                }
 9387            }
 9388
 9389            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9390            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9391            for selection in &mut selections {
 9392                if selection.is_empty() {
 9393                    let old_head = selection.head();
 9394                    let mut new_head =
 9395                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9396                            .to_point(&display_map);
 9397                    if let Some((buffer, line_buffer_range)) = display_map
 9398                        .buffer_snapshot
 9399                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9400                    {
 9401                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9402                        let indent_len = match indent_size.kind {
 9403                            IndentKind::Space => {
 9404                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9405                            }
 9406                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9407                        };
 9408                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9409                            let indent_len = indent_len.get();
 9410                            new_head = cmp::min(
 9411                                new_head,
 9412                                MultiBufferPoint::new(
 9413                                    old_head.row,
 9414                                    ((old_head.column - 1) / indent_len) * indent_len,
 9415                                ),
 9416                            );
 9417                        }
 9418                    }
 9419
 9420                    selection.set_head(new_head, SelectionGoal::None);
 9421                }
 9422            }
 9423
 9424            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9425                s.select(selections)
 9426            });
 9427            this.insert("", window, cx);
 9428            let empty_str: Arc<str> = Arc::from("");
 9429            for (buffer, edits) in linked_ranges {
 9430                let snapshot = buffer.read(cx).snapshot();
 9431                use text::ToPoint as TP;
 9432
 9433                let edits = edits
 9434                    .into_iter()
 9435                    .map(|range| {
 9436                        let end_point = TP::to_point(&range.end, &snapshot);
 9437                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9438
 9439                        if end_point == start_point {
 9440                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9441                                .saturating_sub(1);
 9442                            start_point =
 9443                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9444                        };
 9445
 9446                        (start_point..end_point, empty_str.clone())
 9447                    })
 9448                    .sorted_by_key(|(range, _)| range.start)
 9449                    .collect::<Vec<_>>();
 9450                buffer.update(cx, |this, cx| {
 9451                    this.edit(edits, None, cx);
 9452                })
 9453            }
 9454            this.refresh_inline_completion(true, false, window, cx);
 9455            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9456        });
 9457    }
 9458
 9459    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9460        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9461        self.transact(window, cx, |this, window, cx| {
 9462            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9463                s.move_with(|map, selection| {
 9464                    if selection.is_empty() {
 9465                        let cursor = movement::right(map, selection.head());
 9466                        selection.end = cursor;
 9467                        selection.reversed = true;
 9468                        selection.goal = SelectionGoal::None;
 9469                    }
 9470                })
 9471            });
 9472            this.insert("", window, cx);
 9473            this.refresh_inline_completion(true, false, window, cx);
 9474        });
 9475    }
 9476
 9477    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9478        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9479        if self.move_to_prev_snippet_tabstop(window, cx) {
 9480            return;
 9481        }
 9482        self.outdent(&Outdent, window, cx);
 9483    }
 9484
 9485    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9486        if self.move_to_next_snippet_tabstop(window, cx) {
 9487            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9488            return;
 9489        }
 9490        if self.read_only(cx) {
 9491            return;
 9492        }
 9493        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9494        let mut selections = self.selections.all_adjusted(cx);
 9495        let buffer = self.buffer.read(cx);
 9496        let snapshot = buffer.snapshot(cx);
 9497        let rows_iter = selections.iter().map(|s| s.head().row);
 9498        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9499
 9500        let has_some_cursor_in_whitespace = selections
 9501            .iter()
 9502            .filter(|selection| selection.is_empty())
 9503            .any(|selection| {
 9504                let cursor = selection.head();
 9505                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9506                cursor.column < current_indent.len
 9507            });
 9508
 9509        let mut edits = Vec::new();
 9510        let mut prev_edited_row = 0;
 9511        let mut row_delta = 0;
 9512        for selection in &mut selections {
 9513            if selection.start.row != prev_edited_row {
 9514                row_delta = 0;
 9515            }
 9516            prev_edited_row = selection.end.row;
 9517
 9518            // If the selection is non-empty, then increase the indentation of the selected lines.
 9519            if !selection.is_empty() {
 9520                row_delta =
 9521                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9522                continue;
 9523            }
 9524
 9525            let cursor = selection.head();
 9526            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9527            if let Some(suggested_indent) =
 9528                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9529            {
 9530                // Don't do anything if already at suggested indent
 9531                // and there is any other cursor which is not
 9532                if has_some_cursor_in_whitespace
 9533                    && cursor.column == current_indent.len
 9534                    && current_indent.len == suggested_indent.len
 9535                {
 9536                    continue;
 9537                }
 9538
 9539                // Adjust line and move cursor to suggested indent
 9540                // if cursor is not at suggested indent
 9541                if cursor.column < suggested_indent.len
 9542                    && cursor.column <= current_indent.len
 9543                    && current_indent.len <= suggested_indent.len
 9544                {
 9545                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9546                    selection.end = selection.start;
 9547                    if row_delta == 0 {
 9548                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9549                            cursor.row,
 9550                            current_indent,
 9551                            suggested_indent,
 9552                        ));
 9553                        row_delta = suggested_indent.len - current_indent.len;
 9554                    }
 9555                    continue;
 9556                }
 9557
 9558                // If current indent is more than suggested indent
 9559                // only move cursor to current indent and skip indent
 9560                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9561                    selection.start = Point::new(cursor.row, current_indent.len);
 9562                    selection.end = selection.start;
 9563                    continue;
 9564                }
 9565            }
 9566
 9567            // Otherwise, insert a hard or soft tab.
 9568            let settings = buffer.language_settings_at(cursor, cx);
 9569            let tab_size = if settings.hard_tabs {
 9570                IndentSize::tab()
 9571            } else {
 9572                let tab_size = settings.tab_size.get();
 9573                let indent_remainder = snapshot
 9574                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9575                    .flat_map(str::chars)
 9576                    .fold(row_delta % tab_size, |counter: u32, c| {
 9577                        if c == '\t' {
 9578                            0
 9579                        } else {
 9580                            (counter + 1) % tab_size
 9581                        }
 9582                    });
 9583
 9584                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9585                IndentSize::spaces(chars_to_next_tab_stop)
 9586            };
 9587            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9588            selection.end = selection.start;
 9589            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9590            row_delta += tab_size.len;
 9591        }
 9592
 9593        self.transact(window, cx, |this, window, cx| {
 9594            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9595            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9596                s.select(selections)
 9597            });
 9598            this.refresh_inline_completion(true, false, window, cx);
 9599        });
 9600    }
 9601
 9602    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9603        if self.read_only(cx) {
 9604            return;
 9605        }
 9606        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9607        let mut selections = self.selections.all::<Point>(cx);
 9608        let mut prev_edited_row = 0;
 9609        let mut row_delta = 0;
 9610        let mut edits = Vec::new();
 9611        let buffer = self.buffer.read(cx);
 9612        let snapshot = buffer.snapshot(cx);
 9613        for selection in &mut selections {
 9614            if selection.start.row != prev_edited_row {
 9615                row_delta = 0;
 9616            }
 9617            prev_edited_row = selection.end.row;
 9618
 9619            row_delta =
 9620                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9621        }
 9622
 9623        self.transact(window, cx, |this, window, cx| {
 9624            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9625            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9626                s.select(selections)
 9627            });
 9628        });
 9629    }
 9630
 9631    fn indent_selection(
 9632        buffer: &MultiBuffer,
 9633        snapshot: &MultiBufferSnapshot,
 9634        selection: &mut Selection<Point>,
 9635        edits: &mut Vec<(Range<Point>, String)>,
 9636        delta_for_start_row: u32,
 9637        cx: &App,
 9638    ) -> u32 {
 9639        let settings = buffer.language_settings_at(selection.start, cx);
 9640        let tab_size = settings.tab_size.get();
 9641        let indent_kind = if settings.hard_tabs {
 9642            IndentKind::Tab
 9643        } else {
 9644            IndentKind::Space
 9645        };
 9646        let mut start_row = selection.start.row;
 9647        let mut end_row = selection.end.row + 1;
 9648
 9649        // If a selection ends at the beginning of a line, don't indent
 9650        // that last line.
 9651        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9652            end_row -= 1;
 9653        }
 9654
 9655        // Avoid re-indenting a row that has already been indented by a
 9656        // previous selection, but still update this selection's column
 9657        // to reflect that indentation.
 9658        if delta_for_start_row > 0 {
 9659            start_row += 1;
 9660            selection.start.column += delta_for_start_row;
 9661            if selection.end.row == selection.start.row {
 9662                selection.end.column += delta_for_start_row;
 9663            }
 9664        }
 9665
 9666        let mut delta_for_end_row = 0;
 9667        let has_multiple_rows = start_row + 1 != end_row;
 9668        for row in start_row..end_row {
 9669            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9670            let indent_delta = match (current_indent.kind, indent_kind) {
 9671                (IndentKind::Space, IndentKind::Space) => {
 9672                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9673                    IndentSize::spaces(columns_to_next_tab_stop)
 9674                }
 9675                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9676                (_, IndentKind::Tab) => IndentSize::tab(),
 9677            };
 9678
 9679            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9680                0
 9681            } else {
 9682                selection.start.column
 9683            };
 9684            let row_start = Point::new(row, start);
 9685            edits.push((
 9686                row_start..row_start,
 9687                indent_delta.chars().collect::<String>(),
 9688            ));
 9689
 9690            // Update this selection's endpoints to reflect the indentation.
 9691            if row == selection.start.row {
 9692                selection.start.column += indent_delta.len;
 9693            }
 9694            if row == selection.end.row {
 9695                selection.end.column += indent_delta.len;
 9696                delta_for_end_row = indent_delta.len;
 9697            }
 9698        }
 9699
 9700        if selection.start.row == selection.end.row {
 9701            delta_for_start_row + delta_for_end_row
 9702        } else {
 9703            delta_for_end_row
 9704        }
 9705    }
 9706
 9707    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9708        if self.read_only(cx) {
 9709            return;
 9710        }
 9711        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9712        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9713        let selections = self.selections.all::<Point>(cx);
 9714        let mut deletion_ranges = Vec::new();
 9715        let mut last_outdent = None;
 9716        {
 9717            let buffer = self.buffer.read(cx);
 9718            let snapshot = buffer.snapshot(cx);
 9719            for selection in &selections {
 9720                let settings = buffer.language_settings_at(selection.start, cx);
 9721                let tab_size = settings.tab_size.get();
 9722                let mut rows = selection.spanned_rows(false, &display_map);
 9723
 9724                // Avoid re-outdenting a row that has already been outdented by a
 9725                // previous selection.
 9726                if let Some(last_row) = last_outdent {
 9727                    if last_row == rows.start {
 9728                        rows.start = rows.start.next_row();
 9729                    }
 9730                }
 9731                let has_multiple_rows = rows.len() > 1;
 9732                for row in rows.iter_rows() {
 9733                    let indent_size = snapshot.indent_size_for_line(row);
 9734                    if indent_size.len > 0 {
 9735                        let deletion_len = match indent_size.kind {
 9736                            IndentKind::Space => {
 9737                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9738                                if columns_to_prev_tab_stop == 0 {
 9739                                    tab_size
 9740                                } else {
 9741                                    columns_to_prev_tab_stop
 9742                                }
 9743                            }
 9744                            IndentKind::Tab => 1,
 9745                        };
 9746                        let start = if has_multiple_rows
 9747                            || deletion_len > selection.start.column
 9748                            || indent_size.len < selection.start.column
 9749                        {
 9750                            0
 9751                        } else {
 9752                            selection.start.column - deletion_len
 9753                        };
 9754                        deletion_ranges.push(
 9755                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9756                        );
 9757                        last_outdent = Some(row);
 9758                    }
 9759                }
 9760            }
 9761        }
 9762
 9763        self.transact(window, cx, |this, window, cx| {
 9764            this.buffer.update(cx, |buffer, cx| {
 9765                let empty_str: Arc<str> = Arc::default();
 9766                buffer.edit(
 9767                    deletion_ranges
 9768                        .into_iter()
 9769                        .map(|range| (range, empty_str.clone())),
 9770                    None,
 9771                    cx,
 9772                );
 9773            });
 9774            let selections = this.selections.all::<usize>(cx);
 9775            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9776                s.select(selections)
 9777            });
 9778        });
 9779    }
 9780
 9781    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9782        if self.read_only(cx) {
 9783            return;
 9784        }
 9785        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9786        let selections = self
 9787            .selections
 9788            .all::<usize>(cx)
 9789            .into_iter()
 9790            .map(|s| s.range());
 9791
 9792        self.transact(window, cx, |this, window, cx| {
 9793            this.buffer.update(cx, |buffer, cx| {
 9794                buffer.autoindent_ranges(selections, cx);
 9795            });
 9796            let selections = this.selections.all::<usize>(cx);
 9797            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9798                s.select(selections)
 9799            });
 9800        });
 9801    }
 9802
 9803    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9804        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9805        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9806        let selections = self.selections.all::<Point>(cx);
 9807
 9808        let mut new_cursors = Vec::new();
 9809        let mut edit_ranges = Vec::new();
 9810        let mut selections = selections.iter().peekable();
 9811        while let Some(selection) = selections.next() {
 9812            let mut rows = selection.spanned_rows(false, &display_map);
 9813            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9814
 9815            // Accumulate contiguous regions of rows that we want to delete.
 9816            while let Some(next_selection) = selections.peek() {
 9817                let next_rows = next_selection.spanned_rows(false, &display_map);
 9818                if next_rows.start <= rows.end {
 9819                    rows.end = next_rows.end;
 9820                    selections.next().unwrap();
 9821                } else {
 9822                    break;
 9823                }
 9824            }
 9825
 9826            let buffer = &display_map.buffer_snapshot;
 9827            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9828            let edit_end;
 9829            let cursor_buffer_row;
 9830            if buffer.max_point().row >= rows.end.0 {
 9831                // If there's a line after the range, delete the \n from the end of the row range
 9832                // and position the cursor on the next line.
 9833                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9834                cursor_buffer_row = rows.end;
 9835            } else {
 9836                // If there isn't a line after the range, delete the \n from the line before the
 9837                // start of the row range and position the cursor there.
 9838                edit_start = edit_start.saturating_sub(1);
 9839                edit_end = buffer.len();
 9840                cursor_buffer_row = rows.start.previous_row();
 9841            }
 9842
 9843            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9844            *cursor.column_mut() =
 9845                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9846
 9847            new_cursors.push((
 9848                selection.id,
 9849                buffer.anchor_after(cursor.to_point(&display_map)),
 9850            ));
 9851            edit_ranges.push(edit_start..edit_end);
 9852        }
 9853
 9854        self.transact(window, cx, |this, window, cx| {
 9855            let buffer = this.buffer.update(cx, |buffer, cx| {
 9856                let empty_str: Arc<str> = Arc::default();
 9857                buffer.edit(
 9858                    edit_ranges
 9859                        .into_iter()
 9860                        .map(|range| (range, empty_str.clone())),
 9861                    None,
 9862                    cx,
 9863                );
 9864                buffer.snapshot(cx)
 9865            });
 9866            let new_selections = new_cursors
 9867                .into_iter()
 9868                .map(|(id, cursor)| {
 9869                    let cursor = cursor.to_point(&buffer);
 9870                    Selection {
 9871                        id,
 9872                        start: cursor,
 9873                        end: cursor,
 9874                        reversed: false,
 9875                        goal: SelectionGoal::None,
 9876                    }
 9877                })
 9878                .collect();
 9879
 9880            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9881                s.select(new_selections);
 9882            });
 9883        });
 9884    }
 9885
 9886    pub fn join_lines_impl(
 9887        &mut self,
 9888        insert_whitespace: bool,
 9889        window: &mut Window,
 9890        cx: &mut Context<Self>,
 9891    ) {
 9892        if self.read_only(cx) {
 9893            return;
 9894        }
 9895        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9896        for selection in self.selections.all::<Point>(cx) {
 9897            let start = MultiBufferRow(selection.start.row);
 9898            // Treat single line selections as if they include the next line. Otherwise this action
 9899            // would do nothing for single line selections individual cursors.
 9900            let end = if selection.start.row == selection.end.row {
 9901                MultiBufferRow(selection.start.row + 1)
 9902            } else {
 9903                MultiBufferRow(selection.end.row)
 9904            };
 9905
 9906            if let Some(last_row_range) = row_ranges.last_mut() {
 9907                if start <= last_row_range.end {
 9908                    last_row_range.end = end;
 9909                    continue;
 9910                }
 9911            }
 9912            row_ranges.push(start..end);
 9913        }
 9914
 9915        let snapshot = self.buffer.read(cx).snapshot(cx);
 9916        let mut cursor_positions = Vec::new();
 9917        for row_range in &row_ranges {
 9918            let anchor = snapshot.anchor_before(Point::new(
 9919                row_range.end.previous_row().0,
 9920                snapshot.line_len(row_range.end.previous_row()),
 9921            ));
 9922            cursor_positions.push(anchor..anchor);
 9923        }
 9924
 9925        self.transact(window, cx, |this, window, cx| {
 9926            for row_range in row_ranges.into_iter().rev() {
 9927                for row in row_range.iter_rows().rev() {
 9928                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9929                    let next_line_row = row.next_row();
 9930                    let indent = snapshot.indent_size_for_line(next_line_row);
 9931                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9932
 9933                    let replace =
 9934                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9935                            " "
 9936                        } else {
 9937                            ""
 9938                        };
 9939
 9940                    this.buffer.update(cx, |buffer, cx| {
 9941                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9942                    });
 9943                }
 9944            }
 9945
 9946            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9947                s.select_anchor_ranges(cursor_positions)
 9948            });
 9949        });
 9950    }
 9951
 9952    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9953        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9954        self.join_lines_impl(true, window, cx);
 9955    }
 9956
 9957    pub fn sort_lines_case_sensitive(
 9958        &mut self,
 9959        _: &SortLinesCaseSensitive,
 9960        window: &mut Window,
 9961        cx: &mut Context<Self>,
 9962    ) {
 9963        self.manipulate_lines(window, cx, |lines| lines.sort())
 9964    }
 9965
 9966    pub fn sort_lines_case_insensitive(
 9967        &mut self,
 9968        _: &SortLinesCaseInsensitive,
 9969        window: &mut Window,
 9970        cx: &mut Context<Self>,
 9971    ) {
 9972        self.manipulate_lines(window, cx, |lines| {
 9973            lines.sort_by_key(|line| line.to_lowercase())
 9974        })
 9975    }
 9976
 9977    pub fn unique_lines_case_insensitive(
 9978        &mut self,
 9979        _: &UniqueLinesCaseInsensitive,
 9980        window: &mut Window,
 9981        cx: &mut Context<Self>,
 9982    ) {
 9983        self.manipulate_lines(window, cx, |lines| {
 9984            let mut seen = HashSet::default();
 9985            lines.retain(|line| seen.insert(line.to_lowercase()));
 9986        })
 9987    }
 9988
 9989    pub fn unique_lines_case_sensitive(
 9990        &mut self,
 9991        _: &UniqueLinesCaseSensitive,
 9992        window: &mut Window,
 9993        cx: &mut Context<Self>,
 9994    ) {
 9995        self.manipulate_lines(window, cx, |lines| {
 9996            let mut seen = HashSet::default();
 9997            lines.retain(|line| seen.insert(*line));
 9998        })
 9999    }
10000
10001    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10002        let Some(project) = self.project.clone() else {
10003            return;
10004        };
10005        self.reload(project, window, cx)
10006            .detach_and_notify_err(window, cx);
10007    }
10008
10009    pub fn restore_file(
10010        &mut self,
10011        _: &::git::RestoreFile,
10012        window: &mut Window,
10013        cx: &mut Context<Self>,
10014    ) {
10015        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10016        let mut buffer_ids = HashSet::default();
10017        let snapshot = self.buffer().read(cx).snapshot(cx);
10018        for selection in self.selections.all::<usize>(cx) {
10019            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10020        }
10021
10022        let buffer = self.buffer().read(cx);
10023        let ranges = buffer_ids
10024            .into_iter()
10025            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10026            .collect::<Vec<_>>();
10027
10028        self.restore_hunks_in_ranges(ranges, window, cx);
10029    }
10030
10031    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10032        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10033        let selections = self
10034            .selections
10035            .all(cx)
10036            .into_iter()
10037            .map(|s| s.range())
10038            .collect();
10039        self.restore_hunks_in_ranges(selections, window, cx);
10040    }
10041
10042    pub fn restore_hunks_in_ranges(
10043        &mut self,
10044        ranges: Vec<Range<Point>>,
10045        window: &mut Window,
10046        cx: &mut Context<Editor>,
10047    ) {
10048        let mut revert_changes = HashMap::default();
10049        let chunk_by = self
10050            .snapshot(window, cx)
10051            .hunks_for_ranges(ranges)
10052            .into_iter()
10053            .chunk_by(|hunk| hunk.buffer_id);
10054        for (buffer_id, hunks) in &chunk_by {
10055            let hunks = hunks.collect::<Vec<_>>();
10056            for hunk in &hunks {
10057                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10058            }
10059            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10060        }
10061        drop(chunk_by);
10062        if !revert_changes.is_empty() {
10063            self.transact(window, cx, |editor, window, cx| {
10064                editor.restore(revert_changes, window, cx);
10065            });
10066        }
10067    }
10068
10069    pub fn open_active_item_in_terminal(
10070        &mut self,
10071        _: &OpenInTerminal,
10072        window: &mut Window,
10073        cx: &mut Context<Self>,
10074    ) {
10075        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10076            let project_path = buffer.read(cx).project_path(cx)?;
10077            let project = self.project.as_ref()?.read(cx);
10078            let entry = project.entry_for_path(&project_path, cx)?;
10079            let parent = match &entry.canonical_path {
10080                Some(canonical_path) => canonical_path.to_path_buf(),
10081                None => project.absolute_path(&project_path, cx)?,
10082            }
10083            .parent()?
10084            .to_path_buf();
10085            Some(parent)
10086        }) {
10087            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10088        }
10089    }
10090
10091    fn set_breakpoint_context_menu(
10092        &mut self,
10093        display_row: DisplayRow,
10094        position: Option<Anchor>,
10095        clicked_point: gpui::Point<Pixels>,
10096        window: &mut Window,
10097        cx: &mut Context<Self>,
10098    ) {
10099        if !cx.has_flag::<DebuggerFeatureFlag>() {
10100            return;
10101        }
10102        let source = self
10103            .buffer
10104            .read(cx)
10105            .snapshot(cx)
10106            .anchor_before(Point::new(display_row.0, 0u32));
10107
10108        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10109
10110        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10111            self,
10112            source,
10113            clicked_point,
10114            context_menu,
10115            window,
10116            cx,
10117        );
10118    }
10119
10120    fn add_edit_breakpoint_block(
10121        &mut self,
10122        anchor: Anchor,
10123        breakpoint: &Breakpoint,
10124        edit_action: BreakpointPromptEditAction,
10125        window: &mut Window,
10126        cx: &mut Context<Self>,
10127    ) {
10128        let weak_editor = cx.weak_entity();
10129        let bp_prompt = cx.new(|cx| {
10130            BreakpointPromptEditor::new(
10131                weak_editor,
10132                anchor,
10133                breakpoint.clone(),
10134                edit_action,
10135                window,
10136                cx,
10137            )
10138        });
10139
10140        let height = bp_prompt.update(cx, |this, cx| {
10141            this.prompt
10142                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10143        });
10144        let cloned_prompt = bp_prompt.clone();
10145        let blocks = vec![BlockProperties {
10146            style: BlockStyle::Sticky,
10147            placement: BlockPlacement::Above(anchor),
10148            height: Some(height),
10149            render: Arc::new(move |cx| {
10150                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10151                cloned_prompt.clone().into_any_element()
10152            }),
10153            priority: 0,
10154            render_in_minimap: true,
10155        }];
10156
10157        let focus_handle = bp_prompt.focus_handle(cx);
10158        window.focus(&focus_handle);
10159
10160        let block_ids = self.insert_blocks(blocks, None, cx);
10161        bp_prompt.update(cx, |prompt, _| {
10162            prompt.add_block_ids(block_ids);
10163        });
10164    }
10165
10166    pub(crate) fn breakpoint_at_row(
10167        &self,
10168        row: u32,
10169        window: &mut Window,
10170        cx: &mut Context<Self>,
10171    ) -> Option<(Anchor, Breakpoint)> {
10172        let snapshot = self.snapshot(window, cx);
10173        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10174
10175        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10176    }
10177
10178    pub(crate) fn breakpoint_at_anchor(
10179        &self,
10180        breakpoint_position: Anchor,
10181        snapshot: &EditorSnapshot,
10182        cx: &mut Context<Self>,
10183    ) -> Option<(Anchor, Breakpoint)> {
10184        let project = self.project.clone()?;
10185
10186        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10187            snapshot
10188                .buffer_snapshot
10189                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10190        })?;
10191
10192        let enclosing_excerpt = breakpoint_position.excerpt_id;
10193        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10194        let buffer_snapshot = buffer.read(cx).snapshot();
10195
10196        let row = buffer_snapshot
10197            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10198            .row;
10199
10200        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10201        let anchor_end = snapshot
10202            .buffer_snapshot
10203            .anchor_after(Point::new(row, line_len));
10204
10205        let bp = self
10206            .breakpoint_store
10207            .as_ref()?
10208            .read_with(cx, |breakpoint_store, cx| {
10209                breakpoint_store
10210                    .breakpoints(
10211                        &buffer,
10212                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10213                        &buffer_snapshot,
10214                        cx,
10215                    )
10216                    .next()
10217                    .and_then(|(bp, _)| {
10218                        let breakpoint_row = buffer_snapshot
10219                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10220                            .row;
10221
10222                        if breakpoint_row == row {
10223                            snapshot
10224                                .buffer_snapshot
10225                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10226                                .map(|position| (position, bp.bp.clone()))
10227                        } else {
10228                            None
10229                        }
10230                    })
10231            });
10232        bp
10233    }
10234
10235    pub fn edit_log_breakpoint(
10236        &mut self,
10237        _: &EditLogBreakpoint,
10238        window: &mut Window,
10239        cx: &mut Context<Self>,
10240    ) {
10241        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10242            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10243                message: None,
10244                state: BreakpointState::Enabled,
10245                condition: None,
10246                hit_condition: None,
10247            });
10248
10249            self.add_edit_breakpoint_block(
10250                anchor,
10251                &breakpoint,
10252                BreakpointPromptEditAction::Log,
10253                window,
10254                cx,
10255            );
10256        }
10257    }
10258
10259    fn breakpoints_at_cursors(
10260        &self,
10261        window: &mut Window,
10262        cx: &mut Context<Self>,
10263    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10264        let snapshot = self.snapshot(window, cx);
10265        let cursors = self
10266            .selections
10267            .disjoint_anchors()
10268            .into_iter()
10269            .map(|selection| {
10270                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10271
10272                let breakpoint_position = self
10273                    .breakpoint_at_row(cursor_position.row, window, cx)
10274                    .map(|bp| bp.0)
10275                    .unwrap_or_else(|| {
10276                        snapshot
10277                            .display_snapshot
10278                            .buffer_snapshot
10279                            .anchor_after(Point::new(cursor_position.row, 0))
10280                    });
10281
10282                let breakpoint = self
10283                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10284                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10285
10286                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10287            })
10288            // 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.
10289            .collect::<HashMap<Anchor, _>>();
10290
10291        cursors.into_iter().collect()
10292    }
10293
10294    pub fn enable_breakpoint(
10295        &mut self,
10296        _: &crate::actions::EnableBreakpoint,
10297        window: &mut Window,
10298        cx: &mut Context<Self>,
10299    ) {
10300        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10301            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10302                continue;
10303            };
10304            self.edit_breakpoint_at_anchor(
10305                anchor,
10306                breakpoint,
10307                BreakpointEditAction::InvertState,
10308                cx,
10309            );
10310        }
10311    }
10312
10313    pub fn disable_breakpoint(
10314        &mut self,
10315        _: &crate::actions::DisableBreakpoint,
10316        window: &mut Window,
10317        cx: &mut Context<Self>,
10318    ) {
10319        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10320            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10321                continue;
10322            };
10323            self.edit_breakpoint_at_anchor(
10324                anchor,
10325                breakpoint,
10326                BreakpointEditAction::InvertState,
10327                cx,
10328            );
10329        }
10330    }
10331
10332    pub fn toggle_breakpoint(
10333        &mut self,
10334        _: &crate::actions::ToggleBreakpoint,
10335        window: &mut Window,
10336        cx: &mut Context<Self>,
10337    ) {
10338        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10339            if let Some(breakpoint) = breakpoint {
10340                self.edit_breakpoint_at_anchor(
10341                    anchor,
10342                    breakpoint,
10343                    BreakpointEditAction::Toggle,
10344                    cx,
10345                );
10346            } else {
10347                self.edit_breakpoint_at_anchor(
10348                    anchor,
10349                    Breakpoint::new_standard(),
10350                    BreakpointEditAction::Toggle,
10351                    cx,
10352                );
10353            }
10354        }
10355    }
10356
10357    pub fn edit_breakpoint_at_anchor(
10358        &mut self,
10359        breakpoint_position: Anchor,
10360        breakpoint: Breakpoint,
10361        edit_action: BreakpointEditAction,
10362        cx: &mut Context<Self>,
10363    ) {
10364        let Some(breakpoint_store) = &self.breakpoint_store else {
10365            return;
10366        };
10367
10368        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10369            if breakpoint_position == Anchor::min() {
10370                self.buffer()
10371                    .read(cx)
10372                    .excerpt_buffer_ids()
10373                    .into_iter()
10374                    .next()
10375            } else {
10376                None
10377            }
10378        }) else {
10379            return;
10380        };
10381
10382        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10383            return;
10384        };
10385
10386        breakpoint_store.update(cx, |breakpoint_store, cx| {
10387            breakpoint_store.toggle_breakpoint(
10388                buffer,
10389                BreakpointWithPosition {
10390                    position: breakpoint_position.text_anchor,
10391                    bp: breakpoint,
10392                },
10393                edit_action,
10394                cx,
10395            );
10396        });
10397
10398        cx.notify();
10399    }
10400
10401    #[cfg(any(test, feature = "test-support"))]
10402    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10403        self.breakpoint_store.clone()
10404    }
10405
10406    pub fn prepare_restore_change(
10407        &self,
10408        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10409        hunk: &MultiBufferDiffHunk,
10410        cx: &mut App,
10411    ) -> Option<()> {
10412        if hunk.is_created_file() {
10413            return None;
10414        }
10415        let buffer = self.buffer.read(cx);
10416        let diff = buffer.diff_for(hunk.buffer_id)?;
10417        let buffer = buffer.buffer(hunk.buffer_id)?;
10418        let buffer = buffer.read(cx);
10419        let original_text = diff
10420            .read(cx)
10421            .base_text()
10422            .as_rope()
10423            .slice(hunk.diff_base_byte_range.clone());
10424        let buffer_snapshot = buffer.snapshot();
10425        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10426        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10427            probe
10428                .0
10429                .start
10430                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10431                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10432        }) {
10433            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10434            Some(())
10435        } else {
10436            None
10437        }
10438    }
10439
10440    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10441        self.manipulate_lines(window, cx, |lines| lines.reverse())
10442    }
10443
10444    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10445        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10446    }
10447
10448    fn manipulate_lines<Fn>(
10449        &mut self,
10450        window: &mut Window,
10451        cx: &mut Context<Self>,
10452        mut callback: Fn,
10453    ) where
10454        Fn: FnMut(&mut Vec<&str>),
10455    {
10456        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10457
10458        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10459        let buffer = self.buffer.read(cx).snapshot(cx);
10460
10461        let mut edits = Vec::new();
10462
10463        let selections = self.selections.all::<Point>(cx);
10464        let mut selections = selections.iter().peekable();
10465        let mut contiguous_row_selections = Vec::new();
10466        let mut new_selections = Vec::new();
10467        let mut added_lines = 0;
10468        let mut removed_lines = 0;
10469
10470        while let Some(selection) = selections.next() {
10471            let (start_row, end_row) = consume_contiguous_rows(
10472                &mut contiguous_row_selections,
10473                selection,
10474                &display_map,
10475                &mut selections,
10476            );
10477
10478            let start_point = Point::new(start_row.0, 0);
10479            let end_point = Point::new(
10480                end_row.previous_row().0,
10481                buffer.line_len(end_row.previous_row()),
10482            );
10483            let text = buffer
10484                .text_for_range(start_point..end_point)
10485                .collect::<String>();
10486
10487            let mut lines = text.split('\n').collect_vec();
10488
10489            let lines_before = lines.len();
10490            callback(&mut lines);
10491            let lines_after = lines.len();
10492
10493            edits.push((start_point..end_point, lines.join("\n")));
10494
10495            // Selections must change based on added and removed line count
10496            let start_row =
10497                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10498            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10499            new_selections.push(Selection {
10500                id: selection.id,
10501                start: start_row,
10502                end: end_row,
10503                goal: SelectionGoal::None,
10504                reversed: selection.reversed,
10505            });
10506
10507            if lines_after > lines_before {
10508                added_lines += lines_after - lines_before;
10509            } else if lines_before > lines_after {
10510                removed_lines += lines_before - lines_after;
10511            }
10512        }
10513
10514        self.transact(window, cx, |this, window, cx| {
10515            let buffer = this.buffer.update(cx, |buffer, cx| {
10516                buffer.edit(edits, None, cx);
10517                buffer.snapshot(cx)
10518            });
10519
10520            // Recalculate offsets on newly edited buffer
10521            let new_selections = new_selections
10522                .iter()
10523                .map(|s| {
10524                    let start_point = Point::new(s.start.0, 0);
10525                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10526                    Selection {
10527                        id: s.id,
10528                        start: buffer.point_to_offset(start_point),
10529                        end: buffer.point_to_offset(end_point),
10530                        goal: s.goal,
10531                        reversed: s.reversed,
10532                    }
10533                })
10534                .collect();
10535
10536            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10537                s.select(new_selections);
10538            });
10539
10540            this.request_autoscroll(Autoscroll::fit(), cx);
10541        });
10542    }
10543
10544    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10545        self.manipulate_text(window, cx, |text| {
10546            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10547            if has_upper_case_characters {
10548                text.to_lowercase()
10549            } else {
10550                text.to_uppercase()
10551            }
10552        })
10553    }
10554
10555    pub fn convert_to_upper_case(
10556        &mut self,
10557        _: &ConvertToUpperCase,
10558        window: &mut Window,
10559        cx: &mut Context<Self>,
10560    ) {
10561        self.manipulate_text(window, cx, |text| text.to_uppercase())
10562    }
10563
10564    pub fn convert_to_lower_case(
10565        &mut self,
10566        _: &ConvertToLowerCase,
10567        window: &mut Window,
10568        cx: &mut Context<Self>,
10569    ) {
10570        self.manipulate_text(window, cx, |text| text.to_lowercase())
10571    }
10572
10573    pub fn convert_to_title_case(
10574        &mut self,
10575        _: &ConvertToTitleCase,
10576        window: &mut Window,
10577        cx: &mut Context<Self>,
10578    ) {
10579        self.manipulate_text(window, cx, |text| {
10580            text.split('\n')
10581                .map(|line| line.to_case(Case::Title))
10582                .join("\n")
10583        })
10584    }
10585
10586    pub fn convert_to_snake_case(
10587        &mut self,
10588        _: &ConvertToSnakeCase,
10589        window: &mut Window,
10590        cx: &mut Context<Self>,
10591    ) {
10592        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10593    }
10594
10595    pub fn convert_to_kebab_case(
10596        &mut self,
10597        _: &ConvertToKebabCase,
10598        window: &mut Window,
10599        cx: &mut Context<Self>,
10600    ) {
10601        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10602    }
10603
10604    pub fn convert_to_upper_camel_case(
10605        &mut self,
10606        _: &ConvertToUpperCamelCase,
10607        window: &mut Window,
10608        cx: &mut Context<Self>,
10609    ) {
10610        self.manipulate_text(window, cx, |text| {
10611            text.split('\n')
10612                .map(|line| line.to_case(Case::UpperCamel))
10613                .join("\n")
10614        })
10615    }
10616
10617    pub fn convert_to_lower_camel_case(
10618        &mut self,
10619        _: &ConvertToLowerCamelCase,
10620        window: &mut Window,
10621        cx: &mut Context<Self>,
10622    ) {
10623        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10624    }
10625
10626    pub fn convert_to_opposite_case(
10627        &mut self,
10628        _: &ConvertToOppositeCase,
10629        window: &mut Window,
10630        cx: &mut Context<Self>,
10631    ) {
10632        self.manipulate_text(window, cx, |text| {
10633            text.chars()
10634                .fold(String::with_capacity(text.len()), |mut t, c| {
10635                    if c.is_uppercase() {
10636                        t.extend(c.to_lowercase());
10637                    } else {
10638                        t.extend(c.to_uppercase());
10639                    }
10640                    t
10641                })
10642        })
10643    }
10644
10645    pub fn convert_to_rot13(
10646        &mut self,
10647        _: &ConvertToRot13,
10648        window: &mut Window,
10649        cx: &mut Context<Self>,
10650    ) {
10651        self.manipulate_text(window, cx, |text| {
10652            text.chars()
10653                .map(|c| match c {
10654                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10655                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10656                    _ => c,
10657                })
10658                .collect()
10659        })
10660    }
10661
10662    pub fn convert_to_rot47(
10663        &mut self,
10664        _: &ConvertToRot47,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        self.manipulate_text(window, cx, |text| {
10669            text.chars()
10670                .map(|c| {
10671                    let code_point = c as u32;
10672                    if code_point >= 33 && code_point <= 126 {
10673                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10674                    }
10675                    c
10676                })
10677                .collect()
10678        })
10679    }
10680
10681    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10682    where
10683        Fn: FnMut(&str) -> String,
10684    {
10685        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10686        let buffer = self.buffer.read(cx).snapshot(cx);
10687
10688        let mut new_selections = Vec::new();
10689        let mut edits = Vec::new();
10690        let mut selection_adjustment = 0i32;
10691
10692        for selection in self.selections.all::<usize>(cx) {
10693            let selection_is_empty = selection.is_empty();
10694
10695            let (start, end) = if selection_is_empty {
10696                let word_range = movement::surrounding_word(
10697                    &display_map,
10698                    selection.start.to_display_point(&display_map),
10699                );
10700                let start = word_range.start.to_offset(&display_map, Bias::Left);
10701                let end = word_range.end.to_offset(&display_map, Bias::Left);
10702                (start, end)
10703            } else {
10704                (selection.start, selection.end)
10705            };
10706
10707            let text = buffer.text_for_range(start..end).collect::<String>();
10708            let old_length = text.len() as i32;
10709            let text = callback(&text);
10710
10711            new_selections.push(Selection {
10712                start: (start as i32 - selection_adjustment) as usize,
10713                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10714                goal: SelectionGoal::None,
10715                ..selection
10716            });
10717
10718            selection_adjustment += old_length - text.len() as i32;
10719
10720            edits.push((start..end, text));
10721        }
10722
10723        self.transact(window, cx, |this, window, cx| {
10724            this.buffer.update(cx, |buffer, cx| {
10725                buffer.edit(edits, None, cx);
10726            });
10727
10728            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10729                s.select(new_selections);
10730            });
10731
10732            this.request_autoscroll(Autoscroll::fit(), cx);
10733        });
10734    }
10735
10736    pub fn move_selection_on_drop(
10737        &mut self,
10738        selection: &Selection<Anchor>,
10739        target: DisplayPoint,
10740        is_cut: bool,
10741        window: &mut Window,
10742        cx: &mut Context<Self>,
10743    ) {
10744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10745        let buffer = &display_map.buffer_snapshot;
10746        let mut edits = Vec::new();
10747        let insert_point = display_map
10748            .clip_point(target, Bias::Left)
10749            .to_point(&display_map);
10750        let text = buffer
10751            .text_for_range(selection.start..selection.end)
10752            .collect::<String>();
10753        if is_cut {
10754            edits.push(((selection.start..selection.end), String::new()));
10755        }
10756        let insert_anchor = buffer.anchor_before(insert_point);
10757        edits.push(((insert_anchor..insert_anchor), text));
10758        let last_edit_start = insert_anchor.bias_left(buffer);
10759        let last_edit_end = insert_anchor.bias_right(buffer);
10760        self.transact(window, cx, |this, window, cx| {
10761            this.buffer.update(cx, |buffer, cx| {
10762                buffer.edit(edits, None, cx);
10763            });
10764            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10765                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10766            });
10767        });
10768    }
10769
10770    pub fn clear_selection_drag_state(&mut self) {
10771        self.selection_drag_state = SelectionDragState::None;
10772    }
10773
10774    pub fn duplicate(
10775        &mut self,
10776        upwards: bool,
10777        whole_lines: bool,
10778        window: &mut Window,
10779        cx: &mut Context<Self>,
10780    ) {
10781        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10782
10783        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10784        let buffer = &display_map.buffer_snapshot;
10785        let selections = self.selections.all::<Point>(cx);
10786
10787        let mut edits = Vec::new();
10788        let mut selections_iter = selections.iter().peekable();
10789        while let Some(selection) = selections_iter.next() {
10790            let mut rows = selection.spanned_rows(false, &display_map);
10791            // duplicate line-wise
10792            if whole_lines || selection.start == selection.end {
10793                // Avoid duplicating the same lines twice.
10794                while let Some(next_selection) = selections_iter.peek() {
10795                    let next_rows = next_selection.spanned_rows(false, &display_map);
10796                    if next_rows.start < rows.end {
10797                        rows.end = next_rows.end;
10798                        selections_iter.next().unwrap();
10799                    } else {
10800                        break;
10801                    }
10802                }
10803
10804                // Copy the text from the selected row region and splice it either at the start
10805                // or end of the region.
10806                let start = Point::new(rows.start.0, 0);
10807                let end = Point::new(
10808                    rows.end.previous_row().0,
10809                    buffer.line_len(rows.end.previous_row()),
10810                );
10811                let text = buffer
10812                    .text_for_range(start..end)
10813                    .chain(Some("\n"))
10814                    .collect::<String>();
10815                let insert_location = if upwards {
10816                    Point::new(rows.end.0, 0)
10817                } else {
10818                    start
10819                };
10820                edits.push((insert_location..insert_location, text));
10821            } else {
10822                // duplicate character-wise
10823                let start = selection.start;
10824                let end = selection.end;
10825                let text = buffer.text_for_range(start..end).collect::<String>();
10826                edits.push((selection.end..selection.end, text));
10827            }
10828        }
10829
10830        self.transact(window, cx, |this, _, cx| {
10831            this.buffer.update(cx, |buffer, cx| {
10832                buffer.edit(edits, None, cx);
10833            });
10834
10835            this.request_autoscroll(Autoscroll::fit(), cx);
10836        });
10837    }
10838
10839    pub fn duplicate_line_up(
10840        &mut self,
10841        _: &DuplicateLineUp,
10842        window: &mut Window,
10843        cx: &mut Context<Self>,
10844    ) {
10845        self.duplicate(true, true, window, cx);
10846    }
10847
10848    pub fn duplicate_line_down(
10849        &mut self,
10850        _: &DuplicateLineDown,
10851        window: &mut Window,
10852        cx: &mut Context<Self>,
10853    ) {
10854        self.duplicate(false, true, window, cx);
10855    }
10856
10857    pub fn duplicate_selection(
10858        &mut self,
10859        _: &DuplicateSelection,
10860        window: &mut Window,
10861        cx: &mut Context<Self>,
10862    ) {
10863        self.duplicate(false, false, window, cx);
10864    }
10865
10866    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10867        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10868
10869        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10870        let buffer = self.buffer.read(cx).snapshot(cx);
10871
10872        let mut edits = Vec::new();
10873        let mut unfold_ranges = Vec::new();
10874        let mut refold_creases = Vec::new();
10875
10876        let selections = self.selections.all::<Point>(cx);
10877        let mut selections = selections.iter().peekable();
10878        let mut contiguous_row_selections = Vec::new();
10879        let mut new_selections = Vec::new();
10880
10881        while let Some(selection) = selections.next() {
10882            // Find all the selections that span a contiguous row range
10883            let (start_row, end_row) = consume_contiguous_rows(
10884                &mut contiguous_row_selections,
10885                selection,
10886                &display_map,
10887                &mut selections,
10888            );
10889
10890            // Move the text spanned by the row range to be before the line preceding the row range
10891            if start_row.0 > 0 {
10892                let range_to_move = Point::new(
10893                    start_row.previous_row().0,
10894                    buffer.line_len(start_row.previous_row()),
10895                )
10896                    ..Point::new(
10897                        end_row.previous_row().0,
10898                        buffer.line_len(end_row.previous_row()),
10899                    );
10900                let insertion_point = display_map
10901                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10902                    .0;
10903
10904                // Don't move lines across excerpts
10905                if buffer
10906                    .excerpt_containing(insertion_point..range_to_move.end)
10907                    .is_some()
10908                {
10909                    let text = buffer
10910                        .text_for_range(range_to_move.clone())
10911                        .flat_map(|s| s.chars())
10912                        .skip(1)
10913                        .chain(['\n'])
10914                        .collect::<String>();
10915
10916                    edits.push((
10917                        buffer.anchor_after(range_to_move.start)
10918                            ..buffer.anchor_before(range_to_move.end),
10919                        String::new(),
10920                    ));
10921                    let insertion_anchor = buffer.anchor_after(insertion_point);
10922                    edits.push((insertion_anchor..insertion_anchor, text));
10923
10924                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10925
10926                    // Move selections up
10927                    new_selections.extend(contiguous_row_selections.drain(..).map(
10928                        |mut selection| {
10929                            selection.start.row -= row_delta;
10930                            selection.end.row -= row_delta;
10931                            selection
10932                        },
10933                    ));
10934
10935                    // Move folds up
10936                    unfold_ranges.push(range_to_move.clone());
10937                    for fold in display_map.folds_in_range(
10938                        buffer.anchor_before(range_to_move.start)
10939                            ..buffer.anchor_after(range_to_move.end),
10940                    ) {
10941                        let mut start = fold.range.start.to_point(&buffer);
10942                        let mut end = fold.range.end.to_point(&buffer);
10943                        start.row -= row_delta;
10944                        end.row -= row_delta;
10945                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10946                    }
10947                }
10948            }
10949
10950            // If we didn't move line(s), preserve the existing selections
10951            new_selections.append(&mut contiguous_row_selections);
10952        }
10953
10954        self.transact(window, cx, |this, window, cx| {
10955            this.unfold_ranges(&unfold_ranges, true, true, cx);
10956            this.buffer.update(cx, |buffer, cx| {
10957                for (range, text) in edits {
10958                    buffer.edit([(range, text)], None, cx);
10959                }
10960            });
10961            this.fold_creases(refold_creases, true, window, cx);
10962            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10963                s.select(new_selections);
10964            })
10965        });
10966    }
10967
10968    pub fn move_line_down(
10969        &mut self,
10970        _: &MoveLineDown,
10971        window: &mut Window,
10972        cx: &mut Context<Self>,
10973    ) {
10974        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10975
10976        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10977        let buffer = self.buffer.read(cx).snapshot(cx);
10978
10979        let mut edits = Vec::new();
10980        let mut unfold_ranges = Vec::new();
10981        let mut refold_creases = Vec::new();
10982
10983        let selections = self.selections.all::<Point>(cx);
10984        let mut selections = selections.iter().peekable();
10985        let mut contiguous_row_selections = Vec::new();
10986        let mut new_selections = Vec::new();
10987
10988        while let Some(selection) = selections.next() {
10989            // Find all the selections that span a contiguous row range
10990            let (start_row, end_row) = consume_contiguous_rows(
10991                &mut contiguous_row_selections,
10992                selection,
10993                &display_map,
10994                &mut selections,
10995            );
10996
10997            // Move the text spanned by the row range to be after the last line of the row range
10998            if end_row.0 <= buffer.max_point().row {
10999                let range_to_move =
11000                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11001                let insertion_point = display_map
11002                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11003                    .0;
11004
11005                // Don't move lines across excerpt boundaries
11006                if buffer
11007                    .excerpt_containing(range_to_move.start..insertion_point)
11008                    .is_some()
11009                {
11010                    let mut text = String::from("\n");
11011                    text.extend(buffer.text_for_range(range_to_move.clone()));
11012                    text.pop(); // Drop trailing newline
11013                    edits.push((
11014                        buffer.anchor_after(range_to_move.start)
11015                            ..buffer.anchor_before(range_to_move.end),
11016                        String::new(),
11017                    ));
11018                    let insertion_anchor = buffer.anchor_after(insertion_point);
11019                    edits.push((insertion_anchor..insertion_anchor, text));
11020
11021                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11022
11023                    // Move selections down
11024                    new_selections.extend(contiguous_row_selections.drain(..).map(
11025                        |mut selection| {
11026                            selection.start.row += row_delta;
11027                            selection.end.row += row_delta;
11028                            selection
11029                        },
11030                    ));
11031
11032                    // Move folds down
11033                    unfold_ranges.push(range_to_move.clone());
11034                    for fold in display_map.folds_in_range(
11035                        buffer.anchor_before(range_to_move.start)
11036                            ..buffer.anchor_after(range_to_move.end),
11037                    ) {
11038                        let mut start = fold.range.start.to_point(&buffer);
11039                        let mut end = fold.range.end.to_point(&buffer);
11040                        start.row += row_delta;
11041                        end.row += row_delta;
11042                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11043                    }
11044                }
11045            }
11046
11047            // If we didn't move line(s), preserve the existing selections
11048            new_selections.append(&mut contiguous_row_selections);
11049        }
11050
11051        self.transact(window, cx, |this, window, cx| {
11052            this.unfold_ranges(&unfold_ranges, true, true, cx);
11053            this.buffer.update(cx, |buffer, cx| {
11054                for (range, text) in edits {
11055                    buffer.edit([(range, text)], None, cx);
11056                }
11057            });
11058            this.fold_creases(refold_creases, true, window, cx);
11059            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11060                s.select(new_selections)
11061            });
11062        });
11063    }
11064
11065    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11066        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11067        let text_layout_details = &self.text_layout_details(window);
11068        self.transact(window, cx, |this, window, cx| {
11069            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11070                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11071                s.move_with(|display_map, selection| {
11072                    if !selection.is_empty() {
11073                        return;
11074                    }
11075
11076                    let mut head = selection.head();
11077                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11078                    if head.column() == display_map.line_len(head.row()) {
11079                        transpose_offset = display_map
11080                            .buffer_snapshot
11081                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11082                    }
11083
11084                    if transpose_offset == 0 {
11085                        return;
11086                    }
11087
11088                    *head.column_mut() += 1;
11089                    head = display_map.clip_point(head, Bias::Right);
11090                    let goal = SelectionGoal::HorizontalPosition(
11091                        display_map
11092                            .x_for_display_point(head, text_layout_details)
11093                            .into(),
11094                    );
11095                    selection.collapse_to(head, goal);
11096
11097                    let transpose_start = display_map
11098                        .buffer_snapshot
11099                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11100                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11101                        let transpose_end = display_map
11102                            .buffer_snapshot
11103                            .clip_offset(transpose_offset + 1, Bias::Right);
11104                        if let Some(ch) =
11105                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11106                        {
11107                            edits.push((transpose_start..transpose_offset, String::new()));
11108                            edits.push((transpose_end..transpose_end, ch.to_string()));
11109                        }
11110                    }
11111                });
11112                edits
11113            });
11114            this.buffer
11115                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11116            let selections = this.selections.all::<usize>(cx);
11117            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11118                s.select(selections);
11119            });
11120        });
11121    }
11122
11123    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11124        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11125        self.rewrap_impl(RewrapOptions::default(), cx)
11126    }
11127
11128    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11129        let buffer = self.buffer.read(cx).snapshot(cx);
11130        let selections = self.selections.all::<Point>(cx);
11131
11132        // Shrink and split selections to respect paragraph boundaries.
11133        let ranges = selections.into_iter().flat_map(|selection| {
11134            let language_settings = buffer.language_settings_at(selection.head(), cx);
11135            let language_scope = buffer.language_scope_at(selection.head());
11136
11137            let Some(start_row) = (selection.start.row..=selection.end.row)
11138                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11139            else {
11140                return vec![];
11141            };
11142            let Some(end_row) = (selection.start.row..=selection.end.row)
11143                .rev()
11144                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11145            else {
11146                return vec![];
11147            };
11148
11149            let mut row = start_row;
11150            let mut ranges = Vec::new();
11151            while let Some(blank_row) =
11152                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11153            {
11154                let next_paragraph_start = (blank_row + 1..=end_row)
11155                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11156                    .unwrap();
11157                ranges.push((
11158                    language_settings.clone(),
11159                    language_scope.clone(),
11160                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11161                ));
11162                row = next_paragraph_start;
11163            }
11164            ranges.push((
11165                language_settings.clone(),
11166                language_scope.clone(),
11167                Point::new(row, 0)..Point::new(end_row, 0),
11168            ));
11169
11170            ranges
11171        });
11172
11173        let mut edits = Vec::new();
11174        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11175
11176        for (language_settings, language_scope, range) in ranges {
11177            let mut start_row = range.start.row;
11178            let mut end_row = range.end.row;
11179
11180            // Skip selections that overlap with a range that has already been rewrapped.
11181            let selection_range = start_row..end_row;
11182            if rewrapped_row_ranges
11183                .iter()
11184                .any(|range| range.overlaps(&selection_range))
11185            {
11186                continue;
11187            }
11188
11189            let tab_size = language_settings.tab_size;
11190
11191            // Since not all lines in the selection may be at the same indent
11192            // level, choose the indent size that is the most common between all
11193            // of the lines.
11194            //
11195            // If there is a tie, we use the deepest indent.
11196            let (indent_size, indent_end) = {
11197                let mut indent_size_occurrences = HashMap::default();
11198                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11199
11200                for row in start_row..=end_row {
11201                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11202                    rows_by_indent_size.entry(indent).or_default().push(row);
11203                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11204                }
11205
11206                let indent_size = indent_size_occurrences
11207                    .into_iter()
11208                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11209                    .map(|(indent, _)| indent)
11210                    .unwrap_or_default();
11211                let row = rows_by_indent_size[&indent_size][0];
11212                let indent_end = Point::new(row, indent_size.len);
11213
11214                (indent_size, indent_end)
11215            };
11216
11217            let mut line_prefix = indent_size.chars().collect::<String>();
11218
11219            let mut inside_comment = false;
11220            if let Some(comment_prefix) = language_scope.and_then(|language| {
11221                language
11222                    .line_comment_prefixes()
11223                    .iter()
11224                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11225                    .cloned()
11226            }) {
11227                line_prefix.push_str(&comment_prefix);
11228                inside_comment = true;
11229            }
11230
11231            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11232                RewrapBehavior::InComments => inside_comment,
11233                RewrapBehavior::InSelections => !range.is_empty(),
11234                RewrapBehavior::Anywhere => true,
11235            };
11236
11237            let should_rewrap = options.override_language_settings
11238                || allow_rewrap_based_on_language
11239                || self.hard_wrap.is_some();
11240            if !should_rewrap {
11241                continue;
11242            }
11243
11244            if range.is_empty() {
11245                'expand_upwards: while start_row > 0 {
11246                    let prev_row = start_row - 1;
11247                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11248                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11249                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11250                    {
11251                        start_row = prev_row;
11252                    } else {
11253                        break 'expand_upwards;
11254                    }
11255                }
11256
11257                'expand_downwards: while end_row < buffer.max_point().row {
11258                    let next_row = end_row + 1;
11259                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11260                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11261                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11262                    {
11263                        end_row = next_row;
11264                    } else {
11265                        break 'expand_downwards;
11266                    }
11267                }
11268            }
11269
11270            let start = Point::new(start_row, 0);
11271            let start_offset = start.to_offset(&buffer);
11272            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11273            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11274            let Some(lines_without_prefixes) = selection_text
11275                .lines()
11276                .map(|line| {
11277                    line.strip_prefix(&line_prefix)
11278                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11279                        .with_context(|| {
11280                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11281                        })
11282                })
11283                .collect::<Result<Vec<_>, _>>()
11284                .log_err()
11285            else {
11286                continue;
11287            };
11288
11289            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11290                buffer
11291                    .language_settings_at(Point::new(start_row, 0), cx)
11292                    .preferred_line_length as usize
11293            });
11294            let wrapped_text = wrap_with_prefix(
11295                line_prefix,
11296                lines_without_prefixes.join("\n"),
11297                wrap_column,
11298                tab_size,
11299                options.preserve_existing_whitespace,
11300            );
11301
11302            // TODO: should always use char-based diff while still supporting cursor behavior that
11303            // matches vim.
11304            let mut diff_options = DiffOptions::default();
11305            if options.override_language_settings {
11306                diff_options.max_word_diff_len = 0;
11307                diff_options.max_word_diff_line_count = 0;
11308            } else {
11309                diff_options.max_word_diff_len = usize::MAX;
11310                diff_options.max_word_diff_line_count = usize::MAX;
11311            }
11312
11313            for (old_range, new_text) in
11314                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11315            {
11316                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11317                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11318                edits.push((edit_start..edit_end, new_text));
11319            }
11320
11321            rewrapped_row_ranges.push(start_row..=end_row);
11322        }
11323
11324        self.buffer
11325            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11326    }
11327
11328    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11329        let mut text = String::new();
11330        let buffer = self.buffer.read(cx).snapshot(cx);
11331        let mut selections = self.selections.all::<Point>(cx);
11332        let mut clipboard_selections = Vec::with_capacity(selections.len());
11333        {
11334            let max_point = buffer.max_point();
11335            let mut is_first = true;
11336            for selection in &mut selections {
11337                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11338                if is_entire_line {
11339                    selection.start = Point::new(selection.start.row, 0);
11340                    if !selection.is_empty() && selection.end.column == 0 {
11341                        selection.end = cmp::min(max_point, selection.end);
11342                    } else {
11343                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11344                    }
11345                    selection.goal = SelectionGoal::None;
11346                }
11347                if is_first {
11348                    is_first = false;
11349                } else {
11350                    text += "\n";
11351                }
11352                let mut len = 0;
11353                for chunk in buffer.text_for_range(selection.start..selection.end) {
11354                    text.push_str(chunk);
11355                    len += chunk.len();
11356                }
11357                clipboard_selections.push(ClipboardSelection {
11358                    len,
11359                    is_entire_line,
11360                    first_line_indent: buffer
11361                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11362                        .len,
11363                });
11364            }
11365        }
11366
11367        self.transact(window, cx, |this, window, cx| {
11368            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11369                s.select(selections);
11370            });
11371            this.insert("", window, cx);
11372        });
11373        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11374    }
11375
11376    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11377        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11378        let item = self.cut_common(window, cx);
11379        cx.write_to_clipboard(item);
11380    }
11381
11382    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11383        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11384        self.change_selections(None, window, cx, |s| {
11385            s.move_with(|snapshot, sel| {
11386                if sel.is_empty() {
11387                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11388                }
11389            });
11390        });
11391        let item = self.cut_common(window, cx);
11392        cx.set_global(KillRing(item))
11393    }
11394
11395    pub fn kill_ring_yank(
11396        &mut self,
11397        _: &KillRingYank,
11398        window: &mut Window,
11399        cx: &mut Context<Self>,
11400    ) {
11401        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11402        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11403            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11404                (kill_ring.text().to_string(), kill_ring.metadata_json())
11405            } else {
11406                return;
11407            }
11408        } else {
11409            return;
11410        };
11411        self.do_paste(&text, metadata, false, window, cx);
11412    }
11413
11414    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11415        self.do_copy(true, cx);
11416    }
11417
11418    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11419        self.do_copy(false, cx);
11420    }
11421
11422    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11423        let selections = self.selections.all::<Point>(cx);
11424        let buffer = self.buffer.read(cx).read(cx);
11425        let mut text = String::new();
11426
11427        let mut clipboard_selections = Vec::with_capacity(selections.len());
11428        {
11429            let max_point = buffer.max_point();
11430            let mut is_first = true;
11431            for selection in &selections {
11432                let mut start = selection.start;
11433                let mut end = selection.end;
11434                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11435                if is_entire_line {
11436                    start = Point::new(start.row, 0);
11437                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11438                }
11439
11440                let mut trimmed_selections = Vec::new();
11441                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11442                    let row = MultiBufferRow(start.row);
11443                    let first_indent = buffer.indent_size_for_line(row);
11444                    if first_indent.len == 0 || start.column > first_indent.len {
11445                        trimmed_selections.push(start..end);
11446                    } else {
11447                        trimmed_selections.push(
11448                            Point::new(row.0, first_indent.len)
11449                                ..Point::new(row.0, buffer.line_len(row)),
11450                        );
11451                        for row in start.row + 1..=end.row {
11452                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11453                            if row == end.row {
11454                                line_len = end.column;
11455                            }
11456                            if line_len == 0 {
11457                                trimmed_selections
11458                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11459                                continue;
11460                            }
11461                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11462                            if row_indent_size.len >= first_indent.len {
11463                                trimmed_selections.push(
11464                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11465                                );
11466                            } else {
11467                                trimmed_selections.clear();
11468                                trimmed_selections.push(start..end);
11469                                break;
11470                            }
11471                        }
11472                    }
11473                } else {
11474                    trimmed_selections.push(start..end);
11475                }
11476
11477                for trimmed_range in trimmed_selections {
11478                    if is_first {
11479                        is_first = false;
11480                    } else {
11481                        text += "\n";
11482                    }
11483                    let mut len = 0;
11484                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11485                        text.push_str(chunk);
11486                        len += chunk.len();
11487                    }
11488                    clipboard_selections.push(ClipboardSelection {
11489                        len,
11490                        is_entire_line,
11491                        first_line_indent: buffer
11492                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11493                            .len,
11494                    });
11495                }
11496            }
11497        }
11498
11499        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11500            text,
11501            clipboard_selections,
11502        ));
11503    }
11504
11505    pub fn do_paste(
11506        &mut self,
11507        text: &String,
11508        clipboard_selections: Option<Vec<ClipboardSelection>>,
11509        handle_entire_lines: bool,
11510        window: &mut Window,
11511        cx: &mut Context<Self>,
11512    ) {
11513        if self.read_only(cx) {
11514            return;
11515        }
11516
11517        let clipboard_text = Cow::Borrowed(text);
11518
11519        self.transact(window, cx, |this, window, cx| {
11520            if let Some(mut clipboard_selections) = clipboard_selections {
11521                let old_selections = this.selections.all::<usize>(cx);
11522                let all_selections_were_entire_line =
11523                    clipboard_selections.iter().all(|s| s.is_entire_line);
11524                let first_selection_indent_column =
11525                    clipboard_selections.first().map(|s| s.first_line_indent);
11526                if clipboard_selections.len() != old_selections.len() {
11527                    clipboard_selections.drain(..);
11528                }
11529                let cursor_offset = this.selections.last::<usize>(cx).head();
11530                let mut auto_indent_on_paste = true;
11531
11532                this.buffer.update(cx, |buffer, cx| {
11533                    let snapshot = buffer.read(cx);
11534                    auto_indent_on_paste = snapshot
11535                        .language_settings_at(cursor_offset, cx)
11536                        .auto_indent_on_paste;
11537
11538                    let mut start_offset = 0;
11539                    let mut edits = Vec::new();
11540                    let mut original_indent_columns = Vec::new();
11541                    for (ix, selection) in old_selections.iter().enumerate() {
11542                        let to_insert;
11543                        let entire_line;
11544                        let original_indent_column;
11545                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11546                            let end_offset = start_offset + clipboard_selection.len;
11547                            to_insert = &clipboard_text[start_offset..end_offset];
11548                            entire_line = clipboard_selection.is_entire_line;
11549                            start_offset = end_offset + 1;
11550                            original_indent_column = Some(clipboard_selection.first_line_indent);
11551                        } else {
11552                            to_insert = clipboard_text.as_str();
11553                            entire_line = all_selections_were_entire_line;
11554                            original_indent_column = first_selection_indent_column
11555                        }
11556
11557                        // If the corresponding selection was empty when this slice of the
11558                        // clipboard text was written, then the entire line containing the
11559                        // selection was copied. If this selection is also currently empty,
11560                        // then paste the line before the current line of the buffer.
11561                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11562                            let column = selection.start.to_point(&snapshot).column as usize;
11563                            let line_start = selection.start - column;
11564                            line_start..line_start
11565                        } else {
11566                            selection.range()
11567                        };
11568
11569                        edits.push((range, to_insert));
11570                        original_indent_columns.push(original_indent_column);
11571                    }
11572                    drop(snapshot);
11573
11574                    buffer.edit(
11575                        edits,
11576                        if auto_indent_on_paste {
11577                            Some(AutoindentMode::Block {
11578                                original_indent_columns,
11579                            })
11580                        } else {
11581                            None
11582                        },
11583                        cx,
11584                    );
11585                });
11586
11587                let selections = this.selections.all::<usize>(cx);
11588                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11589                    s.select(selections)
11590                });
11591            } else {
11592                this.insert(&clipboard_text, window, cx);
11593            }
11594        });
11595    }
11596
11597    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11598        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11599        if let Some(item) = cx.read_from_clipboard() {
11600            let entries = item.entries();
11601
11602            match entries.first() {
11603                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11604                // of all the pasted entries.
11605                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11606                    .do_paste(
11607                        clipboard_string.text(),
11608                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11609                        true,
11610                        window,
11611                        cx,
11612                    ),
11613                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11614            }
11615        }
11616    }
11617
11618    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11619        if self.read_only(cx) {
11620            return;
11621        }
11622
11623        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11624
11625        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11626            if let Some((selections, _)) =
11627                self.selection_history.transaction(transaction_id).cloned()
11628            {
11629                self.change_selections(None, window, cx, |s| {
11630                    s.select_anchors(selections.to_vec());
11631                });
11632            } else {
11633                log::error!(
11634                    "No entry in selection_history found for undo. \
11635                     This may correspond to a bug where undo does not update the selection. \
11636                     If this is occurring, please add details to \
11637                     https://github.com/zed-industries/zed/issues/22692"
11638                );
11639            }
11640            self.request_autoscroll(Autoscroll::fit(), cx);
11641            self.unmark_text(window, cx);
11642            self.refresh_inline_completion(true, false, window, cx);
11643            cx.emit(EditorEvent::Edited { transaction_id });
11644            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11645        }
11646    }
11647
11648    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11649        if self.read_only(cx) {
11650            return;
11651        }
11652
11653        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11654
11655        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11656            if let Some((_, Some(selections))) =
11657                self.selection_history.transaction(transaction_id).cloned()
11658            {
11659                self.change_selections(None, window, cx, |s| {
11660                    s.select_anchors(selections.to_vec());
11661                });
11662            } else {
11663                log::error!(
11664                    "No entry in selection_history found for redo. \
11665                     This may correspond to a bug where undo does not update the selection. \
11666                     If this is occurring, please add details to \
11667                     https://github.com/zed-industries/zed/issues/22692"
11668                );
11669            }
11670            self.request_autoscroll(Autoscroll::fit(), cx);
11671            self.unmark_text(window, cx);
11672            self.refresh_inline_completion(true, false, window, cx);
11673            cx.emit(EditorEvent::Edited { transaction_id });
11674        }
11675    }
11676
11677    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11678        self.buffer
11679            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11680    }
11681
11682    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11683        self.buffer
11684            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11685    }
11686
11687    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11688        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11689        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11690            s.move_with(|map, selection| {
11691                let cursor = if selection.is_empty() {
11692                    movement::left(map, selection.start)
11693                } else {
11694                    selection.start
11695                };
11696                selection.collapse_to(cursor, SelectionGoal::None);
11697            });
11698        })
11699    }
11700
11701    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11702        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11703        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11704            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11705        })
11706    }
11707
11708    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11709        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11710        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11711            s.move_with(|map, selection| {
11712                let cursor = if selection.is_empty() {
11713                    movement::right(map, selection.end)
11714                } else {
11715                    selection.end
11716                };
11717                selection.collapse_to(cursor, SelectionGoal::None)
11718            });
11719        })
11720    }
11721
11722    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11723        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11724        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11725            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11726        })
11727    }
11728
11729    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11730        if self.take_rename(true, window, cx).is_some() {
11731            return;
11732        }
11733
11734        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11735            cx.propagate();
11736            return;
11737        }
11738
11739        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11740
11741        let text_layout_details = &self.text_layout_details(window);
11742        let selection_count = self.selections.count();
11743        let first_selection = self.selections.first_anchor();
11744
11745        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11746            s.move_with(|map, selection| {
11747                if !selection.is_empty() {
11748                    selection.goal = SelectionGoal::None;
11749                }
11750                let (cursor, goal) = movement::up(
11751                    map,
11752                    selection.start,
11753                    selection.goal,
11754                    false,
11755                    text_layout_details,
11756                );
11757                selection.collapse_to(cursor, goal);
11758            });
11759        });
11760
11761        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11762        {
11763            cx.propagate();
11764        }
11765    }
11766
11767    pub fn move_up_by_lines(
11768        &mut self,
11769        action: &MoveUpByLines,
11770        window: &mut Window,
11771        cx: &mut Context<Self>,
11772    ) {
11773        if self.take_rename(true, window, cx).is_some() {
11774            return;
11775        }
11776
11777        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11778            cx.propagate();
11779            return;
11780        }
11781
11782        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11783
11784        let text_layout_details = &self.text_layout_details(window);
11785
11786        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11787            s.move_with(|map, selection| {
11788                if !selection.is_empty() {
11789                    selection.goal = SelectionGoal::None;
11790                }
11791                let (cursor, goal) = movement::up_by_rows(
11792                    map,
11793                    selection.start,
11794                    action.lines,
11795                    selection.goal,
11796                    false,
11797                    text_layout_details,
11798                );
11799                selection.collapse_to(cursor, goal);
11800            });
11801        })
11802    }
11803
11804    pub fn move_down_by_lines(
11805        &mut self,
11806        action: &MoveDownByLines,
11807        window: &mut Window,
11808        cx: &mut Context<Self>,
11809    ) {
11810        if self.take_rename(true, window, cx).is_some() {
11811            return;
11812        }
11813
11814        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11815            cx.propagate();
11816            return;
11817        }
11818
11819        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11820
11821        let text_layout_details = &self.text_layout_details(window);
11822
11823        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11824            s.move_with(|map, selection| {
11825                if !selection.is_empty() {
11826                    selection.goal = SelectionGoal::None;
11827                }
11828                let (cursor, goal) = movement::down_by_rows(
11829                    map,
11830                    selection.start,
11831                    action.lines,
11832                    selection.goal,
11833                    false,
11834                    text_layout_details,
11835                );
11836                selection.collapse_to(cursor, goal);
11837            });
11838        })
11839    }
11840
11841    pub fn select_down_by_lines(
11842        &mut self,
11843        action: &SelectDownByLines,
11844        window: &mut Window,
11845        cx: &mut Context<Self>,
11846    ) {
11847        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11848        let text_layout_details = &self.text_layout_details(window);
11849        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11850            s.move_heads_with(|map, head, goal| {
11851                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11852            })
11853        })
11854    }
11855
11856    pub fn select_up_by_lines(
11857        &mut self,
11858        action: &SelectUpByLines,
11859        window: &mut Window,
11860        cx: &mut Context<Self>,
11861    ) {
11862        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
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::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11867            })
11868        })
11869    }
11870
11871    pub fn select_page_up(
11872        &mut self,
11873        _: &SelectPageUp,
11874        window: &mut Window,
11875        cx: &mut Context<Self>,
11876    ) {
11877        let Some(row_count) = self.visible_row_count() else {
11878            return;
11879        };
11880
11881        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11882
11883        let text_layout_details = &self.text_layout_details(window);
11884
11885        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11886            s.move_heads_with(|map, head, goal| {
11887                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11888            })
11889        })
11890    }
11891
11892    pub fn move_page_up(
11893        &mut self,
11894        action: &MovePageUp,
11895        window: &mut Window,
11896        cx: &mut Context<Self>,
11897    ) {
11898        if self.take_rename(true, window, cx).is_some() {
11899            return;
11900        }
11901
11902        if self
11903            .context_menu
11904            .borrow_mut()
11905            .as_mut()
11906            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11907            .unwrap_or(false)
11908        {
11909            return;
11910        }
11911
11912        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11913            cx.propagate();
11914            return;
11915        }
11916
11917        let Some(row_count) = self.visible_row_count() else {
11918            return;
11919        };
11920
11921        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11922
11923        let autoscroll = if action.center_cursor {
11924            Autoscroll::center()
11925        } else {
11926            Autoscroll::fit()
11927        };
11928
11929        let text_layout_details = &self.text_layout_details(window);
11930
11931        self.change_selections(Some(autoscroll), window, cx, |s| {
11932            s.move_with(|map, selection| {
11933                if !selection.is_empty() {
11934                    selection.goal = SelectionGoal::None;
11935                }
11936                let (cursor, goal) = movement::up_by_rows(
11937                    map,
11938                    selection.end,
11939                    row_count,
11940                    selection.goal,
11941                    false,
11942                    text_layout_details,
11943                );
11944                selection.collapse_to(cursor, goal);
11945            });
11946        });
11947    }
11948
11949    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11950        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11951        let text_layout_details = &self.text_layout_details(window);
11952        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11953            s.move_heads_with(|map, head, goal| {
11954                movement::up(map, head, goal, false, text_layout_details)
11955            })
11956        })
11957    }
11958
11959    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11960        self.take_rename(true, window, cx);
11961
11962        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11963            cx.propagate();
11964            return;
11965        }
11966
11967        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11968
11969        let text_layout_details = &self.text_layout_details(window);
11970        let selection_count = self.selections.count();
11971        let first_selection = self.selections.first_anchor();
11972
11973        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11974            s.move_with(|map, selection| {
11975                if !selection.is_empty() {
11976                    selection.goal = SelectionGoal::None;
11977                }
11978                let (cursor, goal) = movement::down(
11979                    map,
11980                    selection.end,
11981                    selection.goal,
11982                    false,
11983                    text_layout_details,
11984                );
11985                selection.collapse_to(cursor, goal);
11986            });
11987        });
11988
11989        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11990        {
11991            cx.propagate();
11992        }
11993    }
11994
11995    pub fn select_page_down(
11996        &mut self,
11997        _: &SelectPageDown,
11998        window: &mut Window,
11999        cx: &mut Context<Self>,
12000    ) {
12001        let Some(row_count) = self.visible_row_count() else {
12002            return;
12003        };
12004
12005        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12006
12007        let text_layout_details = &self.text_layout_details(window);
12008
12009        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12010            s.move_heads_with(|map, head, goal| {
12011                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12012            })
12013        })
12014    }
12015
12016    pub fn move_page_down(
12017        &mut self,
12018        action: &MovePageDown,
12019        window: &mut Window,
12020        cx: &mut Context<Self>,
12021    ) {
12022        if self.take_rename(true, window, cx).is_some() {
12023            return;
12024        }
12025
12026        if self
12027            .context_menu
12028            .borrow_mut()
12029            .as_mut()
12030            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12031            .unwrap_or(false)
12032        {
12033            return;
12034        }
12035
12036        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12037            cx.propagate();
12038            return;
12039        }
12040
12041        let Some(row_count) = self.visible_row_count() else {
12042            return;
12043        };
12044
12045        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12046
12047        let autoscroll = if action.center_cursor {
12048            Autoscroll::center()
12049        } else {
12050            Autoscroll::fit()
12051        };
12052
12053        let text_layout_details = &self.text_layout_details(window);
12054        self.change_selections(Some(autoscroll), window, cx, |s| {
12055            s.move_with(|map, selection| {
12056                if !selection.is_empty() {
12057                    selection.goal = SelectionGoal::None;
12058                }
12059                let (cursor, goal) = movement::down_by_rows(
12060                    map,
12061                    selection.end,
12062                    row_count,
12063                    selection.goal,
12064                    false,
12065                    text_layout_details,
12066                );
12067                selection.collapse_to(cursor, goal);
12068            });
12069        });
12070    }
12071
12072    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12073        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12074        let text_layout_details = &self.text_layout_details(window);
12075        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12076            s.move_heads_with(|map, head, goal| {
12077                movement::down(map, head, goal, false, text_layout_details)
12078            })
12079        });
12080    }
12081
12082    pub fn context_menu_first(
12083        &mut self,
12084        _: &ContextMenuFirst,
12085        window: &mut Window,
12086        cx: &mut Context<Self>,
12087    ) {
12088        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12089            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12090        }
12091    }
12092
12093    pub fn context_menu_prev(
12094        &mut self,
12095        _: &ContextMenuPrevious,
12096        window: &mut Window,
12097        cx: &mut Context<Self>,
12098    ) {
12099        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12100            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12101        }
12102    }
12103
12104    pub fn context_menu_next(
12105        &mut self,
12106        _: &ContextMenuNext,
12107        window: &mut Window,
12108        cx: &mut Context<Self>,
12109    ) {
12110        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12111            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12112        }
12113    }
12114
12115    pub fn context_menu_last(
12116        &mut self,
12117        _: &ContextMenuLast,
12118        window: &mut Window,
12119        cx: &mut Context<Self>,
12120    ) {
12121        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12122            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12123        }
12124    }
12125
12126    pub fn move_to_previous_word_start(
12127        &mut self,
12128        _: &MoveToPreviousWordStart,
12129        window: &mut Window,
12130        cx: &mut Context<Self>,
12131    ) {
12132        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12133        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12134            s.move_cursors_with(|map, head, _| {
12135                (
12136                    movement::previous_word_start(map, head),
12137                    SelectionGoal::None,
12138                )
12139            });
12140        })
12141    }
12142
12143    pub fn move_to_previous_subword_start(
12144        &mut self,
12145        _: &MoveToPreviousSubwordStart,
12146        window: &mut Window,
12147        cx: &mut Context<Self>,
12148    ) {
12149        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12150        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12151            s.move_cursors_with(|map, head, _| {
12152                (
12153                    movement::previous_subword_start(map, head),
12154                    SelectionGoal::None,
12155                )
12156            });
12157        })
12158    }
12159
12160    pub fn select_to_previous_word_start(
12161        &mut self,
12162        _: &SelectToPreviousWordStart,
12163        window: &mut Window,
12164        cx: &mut Context<Self>,
12165    ) {
12166        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12167        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12168            s.move_heads_with(|map, head, _| {
12169                (
12170                    movement::previous_word_start(map, head),
12171                    SelectionGoal::None,
12172                )
12173            });
12174        })
12175    }
12176
12177    pub fn select_to_previous_subword_start(
12178        &mut self,
12179        _: &SelectToPreviousSubwordStart,
12180        window: &mut Window,
12181        cx: &mut Context<Self>,
12182    ) {
12183        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12184        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12185            s.move_heads_with(|map, head, _| {
12186                (
12187                    movement::previous_subword_start(map, head),
12188                    SelectionGoal::None,
12189                )
12190            });
12191        })
12192    }
12193
12194    pub fn delete_to_previous_word_start(
12195        &mut self,
12196        action: &DeleteToPreviousWordStart,
12197        window: &mut Window,
12198        cx: &mut Context<Self>,
12199    ) {
12200        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12201        self.transact(window, cx, |this, window, cx| {
12202            this.select_autoclose_pair(window, cx);
12203            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12204                s.move_with(|map, selection| {
12205                    if selection.is_empty() {
12206                        let cursor = if action.ignore_newlines {
12207                            movement::previous_word_start(map, selection.head())
12208                        } else {
12209                            movement::previous_word_start_or_newline(map, selection.head())
12210                        };
12211                        selection.set_head(cursor, SelectionGoal::None);
12212                    }
12213                });
12214            });
12215            this.insert("", window, cx);
12216        });
12217    }
12218
12219    pub fn delete_to_previous_subword_start(
12220        &mut self,
12221        _: &DeleteToPreviousSubwordStart,
12222        window: &mut Window,
12223        cx: &mut Context<Self>,
12224    ) {
12225        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12226        self.transact(window, cx, |this, window, cx| {
12227            this.select_autoclose_pair(window, cx);
12228            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12229                s.move_with(|map, selection| {
12230                    if selection.is_empty() {
12231                        let cursor = movement::previous_subword_start(map, selection.head());
12232                        selection.set_head(cursor, SelectionGoal::None);
12233                    }
12234                });
12235            });
12236            this.insert("", window, cx);
12237        });
12238    }
12239
12240    pub fn move_to_next_word_end(
12241        &mut self,
12242        _: &MoveToNextWordEnd,
12243        window: &mut Window,
12244        cx: &mut Context<Self>,
12245    ) {
12246        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12247        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12248            s.move_cursors_with(|map, head, _| {
12249                (movement::next_word_end(map, head), SelectionGoal::None)
12250            });
12251        })
12252    }
12253
12254    pub fn move_to_next_subword_end(
12255        &mut self,
12256        _: &MoveToNextSubwordEnd,
12257        window: &mut Window,
12258        cx: &mut Context<Self>,
12259    ) {
12260        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12261        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12262            s.move_cursors_with(|map, head, _| {
12263                (movement::next_subword_end(map, head), SelectionGoal::None)
12264            });
12265        })
12266    }
12267
12268    pub fn select_to_next_word_end(
12269        &mut self,
12270        _: &SelectToNextWordEnd,
12271        window: &mut Window,
12272        cx: &mut Context<Self>,
12273    ) {
12274        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12275        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12276            s.move_heads_with(|map, head, _| {
12277                (movement::next_word_end(map, head), SelectionGoal::None)
12278            });
12279        })
12280    }
12281
12282    pub fn select_to_next_subword_end(
12283        &mut self,
12284        _: &SelectToNextSubwordEnd,
12285        window: &mut Window,
12286        cx: &mut Context<Self>,
12287    ) {
12288        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12289        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12290            s.move_heads_with(|map, head, _| {
12291                (movement::next_subword_end(map, head), SelectionGoal::None)
12292            });
12293        })
12294    }
12295
12296    pub fn delete_to_next_word_end(
12297        &mut self,
12298        action: &DeleteToNextWordEnd,
12299        window: &mut Window,
12300        cx: &mut Context<Self>,
12301    ) {
12302        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12303        self.transact(window, cx, |this, window, cx| {
12304            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12305                s.move_with(|map, selection| {
12306                    if selection.is_empty() {
12307                        let cursor = if action.ignore_newlines {
12308                            movement::next_word_end(map, selection.head())
12309                        } else {
12310                            movement::next_word_end_or_newline(map, selection.head())
12311                        };
12312                        selection.set_head(cursor, SelectionGoal::None);
12313                    }
12314                });
12315            });
12316            this.insert("", window, cx);
12317        });
12318    }
12319
12320    pub fn delete_to_next_subword_end(
12321        &mut self,
12322        _: &DeleteToNextSubwordEnd,
12323        window: &mut Window,
12324        cx: &mut Context<Self>,
12325    ) {
12326        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12327        self.transact(window, cx, |this, window, cx| {
12328            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12329                s.move_with(|map, selection| {
12330                    if selection.is_empty() {
12331                        let cursor = movement::next_subword_end(map, selection.head());
12332                        selection.set_head(cursor, SelectionGoal::None);
12333                    }
12334                });
12335            });
12336            this.insert("", window, cx);
12337        });
12338    }
12339
12340    pub fn move_to_beginning_of_line(
12341        &mut self,
12342        action: &MoveToBeginningOfLine,
12343        window: &mut Window,
12344        cx: &mut Context<Self>,
12345    ) {
12346        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12347        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12348            s.move_cursors_with(|map, head, _| {
12349                (
12350                    movement::indented_line_beginning(
12351                        map,
12352                        head,
12353                        action.stop_at_soft_wraps,
12354                        action.stop_at_indent,
12355                    ),
12356                    SelectionGoal::None,
12357                )
12358            });
12359        })
12360    }
12361
12362    pub fn select_to_beginning_of_line(
12363        &mut self,
12364        action: &SelectToBeginningOfLine,
12365        window: &mut Window,
12366        cx: &mut Context<Self>,
12367    ) {
12368        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12369        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12370            s.move_heads_with(|map, head, _| {
12371                (
12372                    movement::indented_line_beginning(
12373                        map,
12374                        head,
12375                        action.stop_at_soft_wraps,
12376                        action.stop_at_indent,
12377                    ),
12378                    SelectionGoal::None,
12379                )
12380            });
12381        });
12382    }
12383
12384    pub fn delete_to_beginning_of_line(
12385        &mut self,
12386        action: &DeleteToBeginningOfLine,
12387        window: &mut Window,
12388        cx: &mut Context<Self>,
12389    ) {
12390        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12391        self.transact(window, cx, |this, window, cx| {
12392            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12393                s.move_with(|_, selection| {
12394                    selection.reversed = true;
12395                });
12396            });
12397
12398            this.select_to_beginning_of_line(
12399                &SelectToBeginningOfLine {
12400                    stop_at_soft_wraps: false,
12401                    stop_at_indent: action.stop_at_indent,
12402                },
12403                window,
12404                cx,
12405            );
12406            this.backspace(&Backspace, window, cx);
12407        });
12408    }
12409
12410    pub fn move_to_end_of_line(
12411        &mut self,
12412        action: &MoveToEndOfLine,
12413        window: &mut Window,
12414        cx: &mut Context<Self>,
12415    ) {
12416        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12417        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12418            s.move_cursors_with(|map, head, _| {
12419                (
12420                    movement::line_end(map, head, action.stop_at_soft_wraps),
12421                    SelectionGoal::None,
12422                )
12423            });
12424        })
12425    }
12426
12427    pub fn select_to_end_of_line(
12428        &mut self,
12429        action: &SelectToEndOfLine,
12430        window: &mut Window,
12431        cx: &mut Context<Self>,
12432    ) {
12433        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12434        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12435            s.move_heads_with(|map, head, _| {
12436                (
12437                    movement::line_end(map, head, action.stop_at_soft_wraps),
12438                    SelectionGoal::None,
12439                )
12440            });
12441        })
12442    }
12443
12444    pub fn delete_to_end_of_line(
12445        &mut self,
12446        _: &DeleteToEndOfLine,
12447        window: &mut Window,
12448        cx: &mut Context<Self>,
12449    ) {
12450        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12451        self.transact(window, cx, |this, window, cx| {
12452            this.select_to_end_of_line(
12453                &SelectToEndOfLine {
12454                    stop_at_soft_wraps: false,
12455                },
12456                window,
12457                cx,
12458            );
12459            this.delete(&Delete, window, cx);
12460        });
12461    }
12462
12463    pub fn cut_to_end_of_line(
12464        &mut self,
12465        _: &CutToEndOfLine,
12466        window: &mut Window,
12467        cx: &mut Context<Self>,
12468    ) {
12469        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12470        self.transact(window, cx, |this, window, cx| {
12471            this.select_to_end_of_line(
12472                &SelectToEndOfLine {
12473                    stop_at_soft_wraps: false,
12474                },
12475                window,
12476                cx,
12477            );
12478            this.cut(&Cut, window, cx);
12479        });
12480    }
12481
12482    pub fn move_to_start_of_paragraph(
12483        &mut self,
12484        _: &MoveToStartOfParagraph,
12485        window: &mut Window,
12486        cx: &mut Context<Self>,
12487    ) {
12488        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12489            cx.propagate();
12490            return;
12491        }
12492        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12493        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12494            s.move_with(|map, selection| {
12495                selection.collapse_to(
12496                    movement::start_of_paragraph(map, selection.head(), 1),
12497                    SelectionGoal::None,
12498                )
12499            });
12500        })
12501    }
12502
12503    pub fn move_to_end_of_paragraph(
12504        &mut self,
12505        _: &MoveToEndOfParagraph,
12506        window: &mut Window,
12507        cx: &mut Context<Self>,
12508    ) {
12509        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12510            cx.propagate();
12511            return;
12512        }
12513        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12514        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12515            s.move_with(|map, selection| {
12516                selection.collapse_to(
12517                    movement::end_of_paragraph(map, selection.head(), 1),
12518                    SelectionGoal::None,
12519                )
12520            });
12521        })
12522    }
12523
12524    pub fn select_to_start_of_paragraph(
12525        &mut self,
12526        _: &SelectToStartOfParagraph,
12527        window: &mut Window,
12528        cx: &mut Context<Self>,
12529    ) {
12530        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12531            cx.propagate();
12532            return;
12533        }
12534        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12535        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12536            s.move_heads_with(|map, head, _| {
12537                (
12538                    movement::start_of_paragraph(map, head, 1),
12539                    SelectionGoal::None,
12540                )
12541            });
12542        })
12543    }
12544
12545    pub fn select_to_end_of_paragraph(
12546        &mut self,
12547        _: &SelectToEndOfParagraph,
12548        window: &mut Window,
12549        cx: &mut Context<Self>,
12550    ) {
12551        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12552            cx.propagate();
12553            return;
12554        }
12555        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12556        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12557            s.move_heads_with(|map, head, _| {
12558                (
12559                    movement::end_of_paragraph(map, head, 1),
12560                    SelectionGoal::None,
12561                )
12562            });
12563        })
12564    }
12565
12566    pub fn move_to_start_of_excerpt(
12567        &mut self,
12568        _: &MoveToStartOfExcerpt,
12569        window: &mut Window,
12570        cx: &mut Context<Self>,
12571    ) {
12572        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12573            cx.propagate();
12574            return;
12575        }
12576        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12577        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12578            s.move_with(|map, selection| {
12579                selection.collapse_to(
12580                    movement::start_of_excerpt(
12581                        map,
12582                        selection.head(),
12583                        workspace::searchable::Direction::Prev,
12584                    ),
12585                    SelectionGoal::None,
12586                )
12587            });
12588        })
12589    }
12590
12591    pub fn move_to_start_of_next_excerpt(
12592        &mut self,
12593        _: &MoveToStartOfNextExcerpt,
12594        window: &mut Window,
12595        cx: &mut Context<Self>,
12596    ) {
12597        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12598            cx.propagate();
12599            return;
12600        }
12601
12602        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12603            s.move_with(|map, selection| {
12604                selection.collapse_to(
12605                    movement::start_of_excerpt(
12606                        map,
12607                        selection.head(),
12608                        workspace::searchable::Direction::Next,
12609                    ),
12610                    SelectionGoal::None,
12611                )
12612            });
12613        })
12614    }
12615
12616    pub fn move_to_end_of_excerpt(
12617        &mut self,
12618        _: &MoveToEndOfExcerpt,
12619        window: &mut Window,
12620        cx: &mut Context<Self>,
12621    ) {
12622        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12623            cx.propagate();
12624            return;
12625        }
12626        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12627        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12628            s.move_with(|map, selection| {
12629                selection.collapse_to(
12630                    movement::end_of_excerpt(
12631                        map,
12632                        selection.head(),
12633                        workspace::searchable::Direction::Next,
12634                    ),
12635                    SelectionGoal::None,
12636                )
12637            });
12638        })
12639    }
12640
12641    pub fn move_to_end_of_previous_excerpt(
12642        &mut self,
12643        _: &MoveToEndOfPreviousExcerpt,
12644        window: &mut Window,
12645        cx: &mut Context<Self>,
12646    ) {
12647        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12648            cx.propagate();
12649            return;
12650        }
12651        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12652        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12653            s.move_with(|map, selection| {
12654                selection.collapse_to(
12655                    movement::end_of_excerpt(
12656                        map,
12657                        selection.head(),
12658                        workspace::searchable::Direction::Prev,
12659                    ),
12660                    SelectionGoal::None,
12661                )
12662            });
12663        })
12664    }
12665
12666    pub fn select_to_start_of_excerpt(
12667        &mut self,
12668        _: &SelectToStartOfExcerpt,
12669        window: &mut Window,
12670        cx: &mut Context<Self>,
12671    ) {
12672        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12673            cx.propagate();
12674            return;
12675        }
12676        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12677        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12678            s.move_heads_with(|map, head, _| {
12679                (
12680                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12681                    SelectionGoal::None,
12682                )
12683            });
12684        })
12685    }
12686
12687    pub fn select_to_start_of_next_excerpt(
12688        &mut self,
12689        _: &SelectToStartOfNextExcerpt,
12690        window: &mut Window,
12691        cx: &mut Context<Self>,
12692    ) {
12693        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12694            cx.propagate();
12695            return;
12696        }
12697        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12698        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12699            s.move_heads_with(|map, head, _| {
12700                (
12701                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12702                    SelectionGoal::None,
12703                )
12704            });
12705        })
12706    }
12707
12708    pub fn select_to_end_of_excerpt(
12709        &mut self,
12710        _: &SelectToEndOfExcerpt,
12711        window: &mut Window,
12712        cx: &mut Context<Self>,
12713    ) {
12714        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12715            cx.propagate();
12716            return;
12717        }
12718        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12719        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12720            s.move_heads_with(|map, head, _| {
12721                (
12722                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12723                    SelectionGoal::None,
12724                )
12725            });
12726        })
12727    }
12728
12729    pub fn select_to_end_of_previous_excerpt(
12730        &mut self,
12731        _: &SelectToEndOfPreviousExcerpt,
12732        window: &mut Window,
12733        cx: &mut Context<Self>,
12734    ) {
12735        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12736            cx.propagate();
12737            return;
12738        }
12739        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12740        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12741            s.move_heads_with(|map, head, _| {
12742                (
12743                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12744                    SelectionGoal::None,
12745                )
12746            });
12747        })
12748    }
12749
12750    pub fn move_to_beginning(
12751        &mut self,
12752        _: &MoveToBeginning,
12753        window: &mut Window,
12754        cx: &mut Context<Self>,
12755    ) {
12756        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12757            cx.propagate();
12758            return;
12759        }
12760        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12761        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12762            s.select_ranges(vec![0..0]);
12763        });
12764    }
12765
12766    pub fn select_to_beginning(
12767        &mut self,
12768        _: &SelectToBeginning,
12769        window: &mut Window,
12770        cx: &mut Context<Self>,
12771    ) {
12772        let mut selection = self.selections.last::<Point>(cx);
12773        selection.set_head(Point::zero(), SelectionGoal::None);
12774        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12775        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12776            s.select(vec![selection]);
12777        });
12778    }
12779
12780    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12781        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12782            cx.propagate();
12783            return;
12784        }
12785        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12786        let cursor = self.buffer.read(cx).read(cx).len();
12787        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12788            s.select_ranges(vec![cursor..cursor])
12789        });
12790    }
12791
12792    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12793        self.nav_history = nav_history;
12794    }
12795
12796    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12797        self.nav_history.as_ref()
12798    }
12799
12800    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12801        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12802    }
12803
12804    fn push_to_nav_history(
12805        &mut self,
12806        cursor_anchor: Anchor,
12807        new_position: Option<Point>,
12808        is_deactivate: bool,
12809        cx: &mut Context<Self>,
12810    ) {
12811        if let Some(nav_history) = self.nav_history.as_mut() {
12812            let buffer = self.buffer.read(cx).read(cx);
12813            let cursor_position = cursor_anchor.to_point(&buffer);
12814            let scroll_state = self.scroll_manager.anchor();
12815            let scroll_top_row = scroll_state.top_row(&buffer);
12816            drop(buffer);
12817
12818            if let Some(new_position) = new_position {
12819                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12820                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12821                    return;
12822                }
12823            }
12824
12825            nav_history.push(
12826                Some(NavigationData {
12827                    cursor_anchor,
12828                    cursor_position,
12829                    scroll_anchor: scroll_state,
12830                    scroll_top_row,
12831                }),
12832                cx,
12833            );
12834            cx.emit(EditorEvent::PushedToNavHistory {
12835                anchor: cursor_anchor,
12836                is_deactivate,
12837            })
12838        }
12839    }
12840
12841    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12842        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12843        let buffer = self.buffer.read(cx).snapshot(cx);
12844        let mut selection = self.selections.first::<usize>(cx);
12845        selection.set_head(buffer.len(), SelectionGoal::None);
12846        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12847            s.select(vec![selection]);
12848        });
12849    }
12850
12851    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12852        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12853        let end = self.buffer.read(cx).read(cx).len();
12854        self.change_selections(None, window, cx, |s| {
12855            s.select_ranges(vec![0..end]);
12856        });
12857    }
12858
12859    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12860        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12861        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12862        let mut selections = self.selections.all::<Point>(cx);
12863        let max_point = display_map.buffer_snapshot.max_point();
12864        for selection in &mut selections {
12865            let rows = selection.spanned_rows(true, &display_map);
12866            selection.start = Point::new(rows.start.0, 0);
12867            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12868            selection.reversed = false;
12869        }
12870        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12871            s.select(selections);
12872        });
12873    }
12874
12875    pub fn split_selection_into_lines(
12876        &mut self,
12877        _: &SplitSelectionIntoLines,
12878        window: &mut Window,
12879        cx: &mut Context<Self>,
12880    ) {
12881        let selections = self
12882            .selections
12883            .all::<Point>(cx)
12884            .into_iter()
12885            .map(|selection| selection.start..selection.end)
12886            .collect::<Vec<_>>();
12887        self.unfold_ranges(&selections, true, true, cx);
12888
12889        let mut new_selection_ranges = Vec::new();
12890        {
12891            let buffer = self.buffer.read(cx).read(cx);
12892            for selection in selections {
12893                for row in selection.start.row..selection.end.row {
12894                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12895                    new_selection_ranges.push(cursor..cursor);
12896                }
12897
12898                let is_multiline_selection = selection.start.row != selection.end.row;
12899                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12900                // so this action feels more ergonomic when paired with other selection operations
12901                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12902                if !should_skip_last {
12903                    new_selection_ranges.push(selection.end..selection.end);
12904                }
12905            }
12906        }
12907        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12908            s.select_ranges(new_selection_ranges);
12909        });
12910    }
12911
12912    pub fn add_selection_above(
12913        &mut self,
12914        _: &AddSelectionAbove,
12915        window: &mut Window,
12916        cx: &mut Context<Self>,
12917    ) {
12918        self.add_selection(true, window, cx);
12919    }
12920
12921    pub fn add_selection_below(
12922        &mut self,
12923        _: &AddSelectionBelow,
12924        window: &mut Window,
12925        cx: &mut Context<Self>,
12926    ) {
12927        self.add_selection(false, window, cx);
12928    }
12929
12930    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12931        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12932
12933        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12934        let all_selections = self.selections.all::<Point>(cx);
12935        let text_layout_details = self.text_layout_details(window);
12936
12937        let (mut columnar_selections, new_selections_to_columnarize) = {
12938            if let Some(state) = self.add_selections_state.as_ref() {
12939                let columnar_selection_ids: HashSet<_> = state
12940                    .groups
12941                    .iter()
12942                    .flat_map(|group| group.stack.iter())
12943                    .copied()
12944                    .collect();
12945
12946                all_selections
12947                    .into_iter()
12948                    .partition(|s| columnar_selection_ids.contains(&s.id))
12949            } else {
12950                (Vec::new(), all_selections)
12951            }
12952        };
12953
12954        let mut state = self
12955            .add_selections_state
12956            .take()
12957            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12958
12959        for selection in new_selections_to_columnarize {
12960            let range = selection.display_range(&display_map).sorted();
12961            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12962            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12963            let positions = start_x.min(end_x)..start_x.max(end_x);
12964            let mut stack = Vec::new();
12965            for row in range.start.row().0..=range.end.row().0 {
12966                if let Some(selection) = self.selections.build_columnar_selection(
12967                    &display_map,
12968                    DisplayRow(row),
12969                    &positions,
12970                    selection.reversed,
12971                    &text_layout_details,
12972                ) {
12973                    stack.push(selection.id);
12974                    columnar_selections.push(selection);
12975                }
12976            }
12977            if !stack.is_empty() {
12978                if above {
12979                    stack.reverse();
12980                }
12981                state.groups.push(AddSelectionsGroup { above, stack });
12982            }
12983        }
12984
12985        let mut final_selections = Vec::new();
12986        let end_row = if above {
12987            DisplayRow(0)
12988        } else {
12989            display_map.max_point().row()
12990        };
12991
12992        let mut last_added_item_per_group = HashMap::default();
12993        for group in state.groups.iter_mut() {
12994            if let Some(last_id) = group.stack.last() {
12995                last_added_item_per_group.insert(*last_id, group);
12996            }
12997        }
12998
12999        for selection in columnar_selections {
13000            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13001                if above == group.above {
13002                    let range = selection.display_range(&display_map).sorted();
13003                    debug_assert_eq!(range.start.row(), range.end.row());
13004                    let mut row = range.start.row();
13005                    let positions =
13006                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13007                            px(start)..px(end)
13008                        } else {
13009                            let start_x =
13010                                display_map.x_for_display_point(range.start, &text_layout_details);
13011                            let end_x =
13012                                display_map.x_for_display_point(range.end, &text_layout_details);
13013                            start_x.min(end_x)..start_x.max(end_x)
13014                        };
13015
13016                    let mut maybe_new_selection = None;
13017                    while row != end_row {
13018                        if above {
13019                            row.0 -= 1;
13020                        } else {
13021                            row.0 += 1;
13022                        }
13023                        if let Some(new_selection) = self.selections.build_columnar_selection(
13024                            &display_map,
13025                            row,
13026                            &positions,
13027                            selection.reversed,
13028                            &text_layout_details,
13029                        ) {
13030                            maybe_new_selection = Some(new_selection);
13031                            break;
13032                        }
13033                    }
13034
13035                    if let Some(new_selection) = maybe_new_selection {
13036                        group.stack.push(new_selection.id);
13037                        if above {
13038                            final_selections.push(new_selection);
13039                            final_selections.push(selection);
13040                        } else {
13041                            final_selections.push(selection);
13042                            final_selections.push(new_selection);
13043                        }
13044                    } else {
13045                        final_selections.push(selection);
13046                    }
13047                } else {
13048                    group.stack.pop();
13049                }
13050            } else {
13051                final_selections.push(selection);
13052            }
13053        }
13054
13055        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13056            s.select(final_selections);
13057        });
13058
13059        let final_selection_ids: HashSet<_> = self
13060            .selections
13061            .all::<Point>(cx)
13062            .iter()
13063            .map(|s| s.id)
13064            .collect();
13065        state.groups.retain_mut(|group| {
13066            // selections might get merged above so we remove invalid items from stacks
13067            group.stack.retain(|id| final_selection_ids.contains(id));
13068
13069            // single selection in stack can be treated as initial state
13070            group.stack.len() > 1
13071        });
13072
13073        if !state.groups.is_empty() {
13074            self.add_selections_state = Some(state);
13075        }
13076    }
13077
13078    fn select_match_ranges(
13079        &mut self,
13080        range: Range<usize>,
13081        reversed: bool,
13082        replace_newest: bool,
13083        auto_scroll: Option<Autoscroll>,
13084        window: &mut Window,
13085        cx: &mut Context<Editor>,
13086    ) {
13087        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13088        self.change_selections(auto_scroll, window, cx, |s| {
13089            if replace_newest {
13090                s.delete(s.newest_anchor().id);
13091            }
13092            if reversed {
13093                s.insert_range(range.end..range.start);
13094            } else {
13095                s.insert_range(range);
13096            }
13097        });
13098    }
13099
13100    pub fn select_next_match_internal(
13101        &mut self,
13102        display_map: &DisplaySnapshot,
13103        replace_newest: bool,
13104        autoscroll: Option<Autoscroll>,
13105        window: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) -> Result<()> {
13108        let buffer = &display_map.buffer_snapshot;
13109        let mut selections = self.selections.all::<usize>(cx);
13110        if let Some(mut select_next_state) = self.select_next_state.take() {
13111            let query = &select_next_state.query;
13112            if !select_next_state.done {
13113                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13114                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13115                let mut next_selected_range = None;
13116
13117                let bytes_after_last_selection =
13118                    buffer.bytes_in_range(last_selection.end..buffer.len());
13119                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13120                let query_matches = query
13121                    .stream_find_iter(bytes_after_last_selection)
13122                    .map(|result| (last_selection.end, result))
13123                    .chain(
13124                        query
13125                            .stream_find_iter(bytes_before_first_selection)
13126                            .map(|result| (0, result)),
13127                    );
13128
13129                for (start_offset, query_match) in query_matches {
13130                    let query_match = query_match.unwrap(); // can only fail due to I/O
13131                    let offset_range =
13132                        start_offset + query_match.start()..start_offset + query_match.end();
13133                    let display_range = offset_range.start.to_display_point(display_map)
13134                        ..offset_range.end.to_display_point(display_map);
13135
13136                    if !select_next_state.wordwise
13137                        || (!movement::is_inside_word(display_map, display_range.start)
13138                            && !movement::is_inside_word(display_map, display_range.end))
13139                    {
13140                        // TODO: This is n^2, because we might check all the selections
13141                        if !selections
13142                            .iter()
13143                            .any(|selection| selection.range().overlaps(&offset_range))
13144                        {
13145                            next_selected_range = Some(offset_range);
13146                            break;
13147                        }
13148                    }
13149                }
13150
13151                if let Some(next_selected_range) = next_selected_range {
13152                    self.select_match_ranges(
13153                        next_selected_range,
13154                        last_selection.reversed,
13155                        replace_newest,
13156                        autoscroll,
13157                        window,
13158                        cx,
13159                    );
13160                } else {
13161                    select_next_state.done = true;
13162                }
13163            }
13164
13165            self.select_next_state = Some(select_next_state);
13166        } else {
13167            let mut only_carets = true;
13168            let mut same_text_selected = true;
13169            let mut selected_text = None;
13170
13171            let mut selections_iter = selections.iter().peekable();
13172            while let Some(selection) = selections_iter.next() {
13173                if selection.start != selection.end {
13174                    only_carets = false;
13175                }
13176
13177                if same_text_selected {
13178                    if selected_text.is_none() {
13179                        selected_text =
13180                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13181                    }
13182
13183                    if let Some(next_selection) = selections_iter.peek() {
13184                        if next_selection.range().len() == selection.range().len() {
13185                            let next_selected_text = buffer
13186                                .text_for_range(next_selection.range())
13187                                .collect::<String>();
13188                            if Some(next_selected_text) != selected_text {
13189                                same_text_selected = false;
13190                                selected_text = None;
13191                            }
13192                        } else {
13193                            same_text_selected = false;
13194                            selected_text = None;
13195                        }
13196                    }
13197                }
13198            }
13199
13200            if only_carets {
13201                for selection in &mut selections {
13202                    let word_range = movement::surrounding_word(
13203                        display_map,
13204                        selection.start.to_display_point(display_map),
13205                    );
13206                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13207                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13208                    selection.goal = SelectionGoal::None;
13209                    selection.reversed = false;
13210                    self.select_match_ranges(
13211                        selection.start..selection.end,
13212                        selection.reversed,
13213                        replace_newest,
13214                        autoscroll,
13215                        window,
13216                        cx,
13217                    );
13218                }
13219
13220                if selections.len() == 1 {
13221                    let selection = selections
13222                        .last()
13223                        .expect("ensured that there's only one selection");
13224                    let query = buffer
13225                        .text_for_range(selection.start..selection.end)
13226                        .collect::<String>();
13227                    let is_empty = query.is_empty();
13228                    let select_state = SelectNextState {
13229                        query: AhoCorasick::new(&[query])?,
13230                        wordwise: true,
13231                        done: is_empty,
13232                    };
13233                    self.select_next_state = Some(select_state);
13234                } else {
13235                    self.select_next_state = None;
13236                }
13237            } else if let Some(selected_text) = selected_text {
13238                self.select_next_state = Some(SelectNextState {
13239                    query: AhoCorasick::new(&[selected_text])?,
13240                    wordwise: false,
13241                    done: false,
13242                });
13243                self.select_next_match_internal(
13244                    display_map,
13245                    replace_newest,
13246                    autoscroll,
13247                    window,
13248                    cx,
13249                )?;
13250            }
13251        }
13252        Ok(())
13253    }
13254
13255    pub fn select_all_matches(
13256        &mut self,
13257        _action: &SelectAllMatches,
13258        window: &mut Window,
13259        cx: &mut Context<Self>,
13260    ) -> Result<()> {
13261        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13262
13263        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13264
13265        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13266        let Some(select_next_state) = self.select_next_state.as_mut() else {
13267            return Ok(());
13268        };
13269        if select_next_state.done {
13270            return Ok(());
13271        }
13272
13273        let mut new_selections = Vec::new();
13274
13275        let reversed = self.selections.oldest::<usize>(cx).reversed;
13276        let buffer = &display_map.buffer_snapshot;
13277        let query_matches = select_next_state
13278            .query
13279            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13280
13281        for query_match in query_matches.into_iter() {
13282            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13283            let offset_range = if reversed {
13284                query_match.end()..query_match.start()
13285            } else {
13286                query_match.start()..query_match.end()
13287            };
13288            let display_range = offset_range.start.to_display_point(&display_map)
13289                ..offset_range.end.to_display_point(&display_map);
13290
13291            if !select_next_state.wordwise
13292                || (!movement::is_inside_word(&display_map, display_range.start)
13293                    && !movement::is_inside_word(&display_map, display_range.end))
13294            {
13295                new_selections.push(offset_range.start..offset_range.end);
13296            }
13297        }
13298
13299        select_next_state.done = true;
13300        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13301        self.change_selections(None, window, cx, |selections| {
13302            selections.select_ranges(new_selections)
13303        });
13304
13305        Ok(())
13306    }
13307
13308    pub fn select_next(
13309        &mut self,
13310        action: &SelectNext,
13311        window: &mut Window,
13312        cx: &mut Context<Self>,
13313    ) -> Result<()> {
13314        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13315        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13316        self.select_next_match_internal(
13317            &display_map,
13318            action.replace_newest,
13319            Some(Autoscroll::newest()),
13320            window,
13321            cx,
13322        )?;
13323        Ok(())
13324    }
13325
13326    pub fn select_previous(
13327        &mut self,
13328        action: &SelectPrevious,
13329        window: &mut Window,
13330        cx: &mut Context<Self>,
13331    ) -> Result<()> {
13332        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13333        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13334        let buffer = &display_map.buffer_snapshot;
13335        let mut selections = self.selections.all::<usize>(cx);
13336        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13337            let query = &select_prev_state.query;
13338            if !select_prev_state.done {
13339                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13340                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13341                let mut next_selected_range = None;
13342                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13343                let bytes_before_last_selection =
13344                    buffer.reversed_bytes_in_range(0..last_selection.start);
13345                let bytes_after_first_selection =
13346                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13347                let query_matches = query
13348                    .stream_find_iter(bytes_before_last_selection)
13349                    .map(|result| (last_selection.start, result))
13350                    .chain(
13351                        query
13352                            .stream_find_iter(bytes_after_first_selection)
13353                            .map(|result| (buffer.len(), result)),
13354                    );
13355                for (end_offset, query_match) in query_matches {
13356                    let query_match = query_match.unwrap(); // can only fail due to I/O
13357                    let offset_range =
13358                        end_offset - query_match.end()..end_offset - query_match.start();
13359                    let display_range = offset_range.start.to_display_point(&display_map)
13360                        ..offset_range.end.to_display_point(&display_map);
13361
13362                    if !select_prev_state.wordwise
13363                        || (!movement::is_inside_word(&display_map, display_range.start)
13364                            && !movement::is_inside_word(&display_map, display_range.end))
13365                    {
13366                        next_selected_range = Some(offset_range);
13367                        break;
13368                    }
13369                }
13370
13371                if let Some(next_selected_range) = next_selected_range {
13372                    self.select_match_ranges(
13373                        next_selected_range,
13374                        last_selection.reversed,
13375                        action.replace_newest,
13376                        Some(Autoscroll::newest()),
13377                        window,
13378                        cx,
13379                    );
13380                } else {
13381                    select_prev_state.done = true;
13382                }
13383            }
13384
13385            self.select_prev_state = Some(select_prev_state);
13386        } else {
13387            let mut only_carets = true;
13388            let mut same_text_selected = true;
13389            let mut selected_text = None;
13390
13391            let mut selections_iter = selections.iter().peekable();
13392            while let Some(selection) = selections_iter.next() {
13393                if selection.start != selection.end {
13394                    only_carets = false;
13395                }
13396
13397                if same_text_selected {
13398                    if selected_text.is_none() {
13399                        selected_text =
13400                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13401                    }
13402
13403                    if let Some(next_selection) = selections_iter.peek() {
13404                        if next_selection.range().len() == selection.range().len() {
13405                            let next_selected_text = buffer
13406                                .text_for_range(next_selection.range())
13407                                .collect::<String>();
13408                            if Some(next_selected_text) != selected_text {
13409                                same_text_selected = false;
13410                                selected_text = None;
13411                            }
13412                        } else {
13413                            same_text_selected = false;
13414                            selected_text = None;
13415                        }
13416                    }
13417                }
13418            }
13419
13420            if only_carets {
13421                for selection in &mut selections {
13422                    let word_range = movement::surrounding_word(
13423                        &display_map,
13424                        selection.start.to_display_point(&display_map),
13425                    );
13426                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13427                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13428                    selection.goal = SelectionGoal::None;
13429                    selection.reversed = false;
13430                    self.select_match_ranges(
13431                        selection.start..selection.end,
13432                        selection.reversed,
13433                        action.replace_newest,
13434                        Some(Autoscroll::newest()),
13435                        window,
13436                        cx,
13437                    );
13438                }
13439                if selections.len() == 1 {
13440                    let selection = selections
13441                        .last()
13442                        .expect("ensured that there's only one selection");
13443                    let query = buffer
13444                        .text_for_range(selection.start..selection.end)
13445                        .collect::<String>();
13446                    let is_empty = query.is_empty();
13447                    let select_state = SelectNextState {
13448                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13449                        wordwise: true,
13450                        done: is_empty,
13451                    };
13452                    self.select_prev_state = Some(select_state);
13453                } else {
13454                    self.select_prev_state = None;
13455                }
13456            } else if let Some(selected_text) = selected_text {
13457                self.select_prev_state = Some(SelectNextState {
13458                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13459                    wordwise: false,
13460                    done: false,
13461                });
13462                self.select_previous(action, window, cx)?;
13463            }
13464        }
13465        Ok(())
13466    }
13467
13468    pub fn find_next_match(
13469        &mut self,
13470        _: &FindNextMatch,
13471        window: &mut Window,
13472        cx: &mut Context<Self>,
13473    ) -> Result<()> {
13474        let selections = self.selections.disjoint_anchors();
13475        match selections.first() {
13476            Some(first) if selections.len() >= 2 => {
13477                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13478                    s.select_ranges([first.range()]);
13479                });
13480            }
13481            _ => self.select_next(
13482                &SelectNext {
13483                    replace_newest: true,
13484                },
13485                window,
13486                cx,
13487            )?,
13488        }
13489        Ok(())
13490    }
13491
13492    pub fn find_previous_match(
13493        &mut self,
13494        _: &FindPreviousMatch,
13495        window: &mut Window,
13496        cx: &mut Context<Self>,
13497    ) -> Result<()> {
13498        let selections = self.selections.disjoint_anchors();
13499        match selections.last() {
13500            Some(last) if selections.len() >= 2 => {
13501                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13502                    s.select_ranges([last.range()]);
13503                });
13504            }
13505            _ => self.select_previous(
13506                &SelectPrevious {
13507                    replace_newest: true,
13508                },
13509                window,
13510                cx,
13511            )?,
13512        }
13513        Ok(())
13514    }
13515
13516    pub fn toggle_comments(
13517        &mut self,
13518        action: &ToggleComments,
13519        window: &mut Window,
13520        cx: &mut Context<Self>,
13521    ) {
13522        if self.read_only(cx) {
13523            return;
13524        }
13525        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13526        let text_layout_details = &self.text_layout_details(window);
13527        self.transact(window, cx, |this, window, cx| {
13528            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13529            let mut edits = Vec::new();
13530            let mut selection_edit_ranges = Vec::new();
13531            let mut last_toggled_row = None;
13532            let snapshot = this.buffer.read(cx).read(cx);
13533            let empty_str: Arc<str> = Arc::default();
13534            let mut suffixes_inserted = Vec::new();
13535            let ignore_indent = action.ignore_indent;
13536
13537            fn comment_prefix_range(
13538                snapshot: &MultiBufferSnapshot,
13539                row: MultiBufferRow,
13540                comment_prefix: &str,
13541                comment_prefix_whitespace: &str,
13542                ignore_indent: bool,
13543            ) -> Range<Point> {
13544                let indent_size = if ignore_indent {
13545                    0
13546                } else {
13547                    snapshot.indent_size_for_line(row).len
13548                };
13549
13550                let start = Point::new(row.0, indent_size);
13551
13552                let mut line_bytes = snapshot
13553                    .bytes_in_range(start..snapshot.max_point())
13554                    .flatten()
13555                    .copied();
13556
13557                // If this line currently begins with the line comment prefix, then record
13558                // the range containing the prefix.
13559                if line_bytes
13560                    .by_ref()
13561                    .take(comment_prefix.len())
13562                    .eq(comment_prefix.bytes())
13563                {
13564                    // Include any whitespace that matches the comment prefix.
13565                    let matching_whitespace_len = line_bytes
13566                        .zip(comment_prefix_whitespace.bytes())
13567                        .take_while(|(a, b)| a == b)
13568                        .count() as u32;
13569                    let end = Point::new(
13570                        start.row,
13571                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13572                    );
13573                    start..end
13574                } else {
13575                    start..start
13576                }
13577            }
13578
13579            fn comment_suffix_range(
13580                snapshot: &MultiBufferSnapshot,
13581                row: MultiBufferRow,
13582                comment_suffix: &str,
13583                comment_suffix_has_leading_space: bool,
13584            ) -> Range<Point> {
13585                let end = Point::new(row.0, snapshot.line_len(row));
13586                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13587
13588                let mut line_end_bytes = snapshot
13589                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13590                    .flatten()
13591                    .copied();
13592
13593                let leading_space_len = if suffix_start_column > 0
13594                    && line_end_bytes.next() == Some(b' ')
13595                    && comment_suffix_has_leading_space
13596                {
13597                    1
13598                } else {
13599                    0
13600                };
13601
13602                // If this line currently begins with the line comment prefix, then record
13603                // the range containing the prefix.
13604                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13605                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13606                    start..end
13607                } else {
13608                    end..end
13609                }
13610            }
13611
13612            // TODO: Handle selections that cross excerpts
13613            for selection in &mut selections {
13614                let start_column = snapshot
13615                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13616                    .len;
13617                let language = if let Some(language) =
13618                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13619                {
13620                    language
13621                } else {
13622                    continue;
13623                };
13624
13625                selection_edit_ranges.clear();
13626
13627                // If multiple selections contain a given row, avoid processing that
13628                // row more than once.
13629                let mut start_row = MultiBufferRow(selection.start.row);
13630                if last_toggled_row == Some(start_row) {
13631                    start_row = start_row.next_row();
13632                }
13633                let end_row =
13634                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13635                        MultiBufferRow(selection.end.row - 1)
13636                    } else {
13637                        MultiBufferRow(selection.end.row)
13638                    };
13639                last_toggled_row = Some(end_row);
13640
13641                if start_row > end_row {
13642                    continue;
13643                }
13644
13645                // If the language has line comments, toggle those.
13646                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13647
13648                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13649                if ignore_indent {
13650                    full_comment_prefixes = full_comment_prefixes
13651                        .into_iter()
13652                        .map(|s| Arc::from(s.trim_end()))
13653                        .collect();
13654                }
13655
13656                if !full_comment_prefixes.is_empty() {
13657                    let first_prefix = full_comment_prefixes
13658                        .first()
13659                        .expect("prefixes is non-empty");
13660                    let prefix_trimmed_lengths = full_comment_prefixes
13661                        .iter()
13662                        .map(|p| p.trim_end_matches(' ').len())
13663                        .collect::<SmallVec<[usize; 4]>>();
13664
13665                    let mut all_selection_lines_are_comments = true;
13666
13667                    for row in start_row.0..=end_row.0 {
13668                        let row = MultiBufferRow(row);
13669                        if start_row < end_row && snapshot.is_line_blank(row) {
13670                            continue;
13671                        }
13672
13673                        let prefix_range = full_comment_prefixes
13674                            .iter()
13675                            .zip(prefix_trimmed_lengths.iter().copied())
13676                            .map(|(prefix, trimmed_prefix_len)| {
13677                                comment_prefix_range(
13678                                    snapshot.deref(),
13679                                    row,
13680                                    &prefix[..trimmed_prefix_len],
13681                                    &prefix[trimmed_prefix_len..],
13682                                    ignore_indent,
13683                                )
13684                            })
13685                            .max_by_key(|range| range.end.column - range.start.column)
13686                            .expect("prefixes is non-empty");
13687
13688                        if prefix_range.is_empty() {
13689                            all_selection_lines_are_comments = false;
13690                        }
13691
13692                        selection_edit_ranges.push(prefix_range);
13693                    }
13694
13695                    if all_selection_lines_are_comments {
13696                        edits.extend(
13697                            selection_edit_ranges
13698                                .iter()
13699                                .cloned()
13700                                .map(|range| (range, empty_str.clone())),
13701                        );
13702                    } else {
13703                        let min_column = selection_edit_ranges
13704                            .iter()
13705                            .map(|range| range.start.column)
13706                            .min()
13707                            .unwrap_or(0);
13708                        edits.extend(selection_edit_ranges.iter().map(|range| {
13709                            let position = Point::new(range.start.row, min_column);
13710                            (position..position, first_prefix.clone())
13711                        }));
13712                    }
13713                } else if let Some((full_comment_prefix, comment_suffix)) =
13714                    language.block_comment_delimiters()
13715                {
13716                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13717                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13718                    let prefix_range = comment_prefix_range(
13719                        snapshot.deref(),
13720                        start_row,
13721                        comment_prefix,
13722                        comment_prefix_whitespace,
13723                        ignore_indent,
13724                    );
13725                    let suffix_range = comment_suffix_range(
13726                        snapshot.deref(),
13727                        end_row,
13728                        comment_suffix.trim_start_matches(' '),
13729                        comment_suffix.starts_with(' '),
13730                    );
13731
13732                    if prefix_range.is_empty() || suffix_range.is_empty() {
13733                        edits.push((
13734                            prefix_range.start..prefix_range.start,
13735                            full_comment_prefix.clone(),
13736                        ));
13737                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13738                        suffixes_inserted.push((end_row, comment_suffix.len()));
13739                    } else {
13740                        edits.push((prefix_range, empty_str.clone()));
13741                        edits.push((suffix_range, empty_str.clone()));
13742                    }
13743                } else {
13744                    continue;
13745                }
13746            }
13747
13748            drop(snapshot);
13749            this.buffer.update(cx, |buffer, cx| {
13750                buffer.edit(edits, None, cx);
13751            });
13752
13753            // Adjust selections so that they end before any comment suffixes that
13754            // were inserted.
13755            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13756            let mut selections = this.selections.all::<Point>(cx);
13757            let snapshot = this.buffer.read(cx).read(cx);
13758            for selection in &mut selections {
13759                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13760                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13761                        Ordering::Less => {
13762                            suffixes_inserted.next();
13763                            continue;
13764                        }
13765                        Ordering::Greater => break,
13766                        Ordering::Equal => {
13767                            if selection.end.column == snapshot.line_len(row) {
13768                                if selection.is_empty() {
13769                                    selection.start.column -= suffix_len as u32;
13770                                }
13771                                selection.end.column -= suffix_len as u32;
13772                            }
13773                            break;
13774                        }
13775                    }
13776                }
13777            }
13778
13779            drop(snapshot);
13780            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13781                s.select(selections)
13782            });
13783
13784            let selections = this.selections.all::<Point>(cx);
13785            let selections_on_single_row = selections.windows(2).all(|selections| {
13786                selections[0].start.row == selections[1].start.row
13787                    && selections[0].end.row == selections[1].end.row
13788                    && selections[0].start.row == selections[0].end.row
13789            });
13790            let selections_selecting = selections
13791                .iter()
13792                .any(|selection| selection.start != selection.end);
13793            let advance_downwards = action.advance_downwards
13794                && selections_on_single_row
13795                && !selections_selecting
13796                && !matches!(this.mode, EditorMode::SingleLine { .. });
13797
13798            if advance_downwards {
13799                let snapshot = this.buffer.read(cx).snapshot(cx);
13800
13801                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13802                    s.move_cursors_with(|display_snapshot, display_point, _| {
13803                        let mut point = display_point.to_point(display_snapshot);
13804                        point.row += 1;
13805                        point = snapshot.clip_point(point, Bias::Left);
13806                        let display_point = point.to_display_point(display_snapshot);
13807                        let goal = SelectionGoal::HorizontalPosition(
13808                            display_snapshot
13809                                .x_for_display_point(display_point, text_layout_details)
13810                                .into(),
13811                        );
13812                        (display_point, goal)
13813                    })
13814                });
13815            }
13816        });
13817    }
13818
13819    pub fn select_enclosing_symbol(
13820        &mut self,
13821        _: &SelectEnclosingSymbol,
13822        window: &mut Window,
13823        cx: &mut Context<Self>,
13824    ) {
13825        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13826
13827        let buffer = self.buffer.read(cx).snapshot(cx);
13828        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13829
13830        fn update_selection(
13831            selection: &Selection<usize>,
13832            buffer_snap: &MultiBufferSnapshot,
13833        ) -> Option<Selection<usize>> {
13834            let cursor = selection.head();
13835            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13836            for symbol in symbols.iter().rev() {
13837                let start = symbol.range.start.to_offset(buffer_snap);
13838                let end = symbol.range.end.to_offset(buffer_snap);
13839                let new_range = start..end;
13840                if start < selection.start || end > selection.end {
13841                    return Some(Selection {
13842                        id: selection.id,
13843                        start: new_range.start,
13844                        end: new_range.end,
13845                        goal: SelectionGoal::None,
13846                        reversed: selection.reversed,
13847                    });
13848                }
13849            }
13850            None
13851        }
13852
13853        let mut selected_larger_symbol = false;
13854        let new_selections = old_selections
13855            .iter()
13856            .map(|selection| match update_selection(selection, &buffer) {
13857                Some(new_selection) => {
13858                    if new_selection.range() != selection.range() {
13859                        selected_larger_symbol = true;
13860                    }
13861                    new_selection
13862                }
13863                None => selection.clone(),
13864            })
13865            .collect::<Vec<_>>();
13866
13867        if selected_larger_symbol {
13868            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13869                s.select(new_selections);
13870            });
13871        }
13872    }
13873
13874    pub fn select_larger_syntax_node(
13875        &mut self,
13876        _: &SelectLargerSyntaxNode,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) {
13880        let Some(visible_row_count) = self.visible_row_count() else {
13881            return;
13882        };
13883        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13884        if old_selections.is_empty() {
13885            return;
13886        }
13887
13888        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13889
13890        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13891        let buffer = self.buffer.read(cx).snapshot(cx);
13892
13893        let mut selected_larger_node = false;
13894        let mut new_selections = old_selections
13895            .iter()
13896            .map(|selection| {
13897                let old_range = selection.start..selection.end;
13898
13899                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13900                    // manually select word at selection
13901                    if ["string_content", "inline"].contains(&node.kind()) {
13902                        let word_range = {
13903                            let display_point = buffer
13904                                .offset_to_point(old_range.start)
13905                                .to_display_point(&display_map);
13906                            let Range { start, end } =
13907                                movement::surrounding_word(&display_map, display_point);
13908                            start.to_point(&display_map).to_offset(&buffer)
13909                                ..end.to_point(&display_map).to_offset(&buffer)
13910                        };
13911                        // ignore if word is already selected
13912                        if !word_range.is_empty() && old_range != word_range {
13913                            let last_word_range = {
13914                                let display_point = buffer
13915                                    .offset_to_point(old_range.end)
13916                                    .to_display_point(&display_map);
13917                                let Range { start, end } =
13918                                    movement::surrounding_word(&display_map, display_point);
13919                                start.to_point(&display_map).to_offset(&buffer)
13920                                    ..end.to_point(&display_map).to_offset(&buffer)
13921                            };
13922                            // only select word if start and end point belongs to same word
13923                            if word_range == last_word_range {
13924                                selected_larger_node = true;
13925                                return Selection {
13926                                    id: selection.id,
13927                                    start: word_range.start,
13928                                    end: word_range.end,
13929                                    goal: SelectionGoal::None,
13930                                    reversed: selection.reversed,
13931                                };
13932                            }
13933                        }
13934                    }
13935                }
13936
13937                let mut new_range = old_range.clone();
13938                while let Some((_node, containing_range)) =
13939                    buffer.syntax_ancestor(new_range.clone())
13940                {
13941                    new_range = match containing_range {
13942                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13943                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13944                    };
13945                    if !display_map.intersects_fold(new_range.start)
13946                        && !display_map.intersects_fold(new_range.end)
13947                    {
13948                        break;
13949                    }
13950                }
13951
13952                selected_larger_node |= new_range != old_range;
13953                Selection {
13954                    id: selection.id,
13955                    start: new_range.start,
13956                    end: new_range.end,
13957                    goal: SelectionGoal::None,
13958                    reversed: selection.reversed,
13959                }
13960            })
13961            .collect::<Vec<_>>();
13962
13963        if !selected_larger_node {
13964            return; // don't put this call in the history
13965        }
13966
13967        // scroll based on transformation done to the last selection created by the user
13968        let (last_old, last_new) = old_selections
13969            .last()
13970            .zip(new_selections.last().cloned())
13971            .expect("old_selections isn't empty");
13972
13973        // revert selection
13974        let is_selection_reversed = {
13975            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13976            new_selections.last_mut().expect("checked above").reversed =
13977                should_newest_selection_be_reversed;
13978            should_newest_selection_be_reversed
13979        };
13980
13981        if selected_larger_node {
13982            self.select_syntax_node_history.disable_clearing = true;
13983            self.change_selections(None, window, cx, |s| {
13984                s.select(new_selections.clone());
13985            });
13986            self.select_syntax_node_history.disable_clearing = false;
13987        }
13988
13989        let start_row = last_new.start.to_display_point(&display_map).row().0;
13990        let end_row = last_new.end.to_display_point(&display_map).row().0;
13991        let selection_height = end_row - start_row + 1;
13992        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13993
13994        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13995        let scroll_behavior = if fits_on_the_screen {
13996            self.request_autoscroll(Autoscroll::fit(), cx);
13997            SelectSyntaxNodeScrollBehavior::FitSelection
13998        } else if is_selection_reversed {
13999            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14000            SelectSyntaxNodeScrollBehavior::CursorTop
14001        } else {
14002            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14003            SelectSyntaxNodeScrollBehavior::CursorBottom
14004        };
14005
14006        self.select_syntax_node_history.push((
14007            old_selections,
14008            scroll_behavior,
14009            is_selection_reversed,
14010        ));
14011    }
14012
14013    pub fn select_smaller_syntax_node(
14014        &mut self,
14015        _: &SelectSmallerSyntaxNode,
14016        window: &mut Window,
14017        cx: &mut Context<Self>,
14018    ) {
14019        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14020
14021        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14022            self.select_syntax_node_history.pop()
14023        {
14024            if let Some(selection) = selections.last_mut() {
14025                selection.reversed = is_selection_reversed;
14026            }
14027
14028            self.select_syntax_node_history.disable_clearing = true;
14029            self.change_selections(None, window, cx, |s| {
14030                s.select(selections.to_vec());
14031            });
14032            self.select_syntax_node_history.disable_clearing = false;
14033
14034            match scroll_behavior {
14035                SelectSyntaxNodeScrollBehavior::CursorTop => {
14036                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14037                }
14038                SelectSyntaxNodeScrollBehavior::FitSelection => {
14039                    self.request_autoscroll(Autoscroll::fit(), cx);
14040                }
14041                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14042                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14043                }
14044            }
14045        }
14046    }
14047
14048    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14049        if !EditorSettings::get_global(cx).gutter.runnables {
14050            self.clear_tasks();
14051            return Task::ready(());
14052        }
14053        let project = self.project.as_ref().map(Entity::downgrade);
14054        let task_sources = self.lsp_task_sources(cx);
14055        let multi_buffer = self.buffer.downgrade();
14056        cx.spawn_in(window, async move |editor, cx| {
14057            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14058            let Some(project) = project.and_then(|p| p.upgrade()) else {
14059                return;
14060            };
14061            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14062                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14063            }) else {
14064                return;
14065            };
14066
14067            let hide_runnables = project
14068                .update(cx, |project, cx| {
14069                    // Do not display any test indicators in non-dev server remote projects.
14070                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14071                })
14072                .unwrap_or(true);
14073            if hide_runnables {
14074                return;
14075            }
14076            let new_rows =
14077                cx.background_spawn({
14078                    let snapshot = display_snapshot.clone();
14079                    async move {
14080                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14081                    }
14082                })
14083                    .await;
14084            let Ok(lsp_tasks) =
14085                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14086            else {
14087                return;
14088            };
14089            let lsp_tasks = lsp_tasks.await;
14090
14091            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14092                lsp_tasks
14093                    .into_iter()
14094                    .flat_map(|(kind, tasks)| {
14095                        tasks.into_iter().filter_map(move |(location, task)| {
14096                            Some((kind.clone(), location?, task))
14097                        })
14098                    })
14099                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14100                        let buffer = location.target.buffer;
14101                        let buffer_snapshot = buffer.read(cx).snapshot();
14102                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14103                            |(excerpt_id, snapshot, _)| {
14104                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14105                                    display_snapshot
14106                                        .buffer_snapshot
14107                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14108                                } else {
14109                                    None
14110                                }
14111                            },
14112                        );
14113                        if let Some(offset) = offset {
14114                            let task_buffer_range =
14115                                location.target.range.to_point(&buffer_snapshot);
14116                            let context_buffer_range =
14117                                task_buffer_range.to_offset(&buffer_snapshot);
14118                            let context_range = BufferOffset(context_buffer_range.start)
14119                                ..BufferOffset(context_buffer_range.end);
14120
14121                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14122                                .or_insert_with(|| RunnableTasks {
14123                                    templates: Vec::new(),
14124                                    offset,
14125                                    column: task_buffer_range.start.column,
14126                                    extra_variables: HashMap::default(),
14127                                    context_range,
14128                                })
14129                                .templates
14130                                .push((kind, task.original_task().clone()));
14131                        }
14132
14133                        acc
14134                    })
14135            }) else {
14136                return;
14137            };
14138
14139            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14140                buffer.language_settings(cx).tasks.prefer_lsp
14141            }) else {
14142                return;
14143            };
14144
14145            let rows = Self::runnable_rows(
14146                project,
14147                display_snapshot,
14148                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14149                new_rows,
14150                cx.clone(),
14151            )
14152            .await;
14153            editor
14154                .update(cx, |editor, _| {
14155                    editor.clear_tasks();
14156                    for (key, mut value) in rows {
14157                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14158                            value.templates.extend(lsp_tasks.templates);
14159                        }
14160
14161                        editor.insert_tasks(key, value);
14162                    }
14163                    for (key, value) in lsp_tasks_by_rows {
14164                        editor.insert_tasks(key, value);
14165                    }
14166                })
14167                .ok();
14168        })
14169    }
14170    fn fetch_runnable_ranges(
14171        snapshot: &DisplaySnapshot,
14172        range: Range<Anchor>,
14173    ) -> Vec<language::RunnableRange> {
14174        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14175    }
14176
14177    fn runnable_rows(
14178        project: Entity<Project>,
14179        snapshot: DisplaySnapshot,
14180        prefer_lsp: bool,
14181        runnable_ranges: Vec<RunnableRange>,
14182        cx: AsyncWindowContext,
14183    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14184        cx.spawn(async move |cx| {
14185            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14186            for mut runnable in runnable_ranges {
14187                let Some(tasks) = cx
14188                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14189                    .ok()
14190                else {
14191                    continue;
14192                };
14193                let mut tasks = tasks.await;
14194
14195                if prefer_lsp {
14196                    tasks.retain(|(task_kind, _)| {
14197                        !matches!(task_kind, TaskSourceKind::Language { .. })
14198                    });
14199                }
14200                if tasks.is_empty() {
14201                    continue;
14202                }
14203
14204                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14205                let Some(row) = snapshot
14206                    .buffer_snapshot
14207                    .buffer_line_for_row(MultiBufferRow(point.row))
14208                    .map(|(_, range)| range.start.row)
14209                else {
14210                    continue;
14211                };
14212
14213                let context_range =
14214                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14215                runnable_rows.push((
14216                    (runnable.buffer_id, row),
14217                    RunnableTasks {
14218                        templates: tasks,
14219                        offset: snapshot
14220                            .buffer_snapshot
14221                            .anchor_before(runnable.run_range.start),
14222                        context_range,
14223                        column: point.column,
14224                        extra_variables: runnable.extra_captures,
14225                    },
14226                ));
14227            }
14228            runnable_rows
14229        })
14230    }
14231
14232    fn templates_with_tags(
14233        project: &Entity<Project>,
14234        runnable: &mut Runnable,
14235        cx: &mut App,
14236    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14237        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14238            let (worktree_id, file) = project
14239                .buffer_for_id(runnable.buffer, cx)
14240                .and_then(|buffer| buffer.read(cx).file())
14241                .map(|file| (file.worktree_id(cx), file.clone()))
14242                .unzip();
14243
14244            (
14245                project.task_store().read(cx).task_inventory().cloned(),
14246                worktree_id,
14247                file,
14248            )
14249        });
14250
14251        let tags = mem::take(&mut runnable.tags);
14252        let language = runnable.language.clone();
14253        cx.spawn(async move |cx| {
14254            let mut templates_with_tags = Vec::new();
14255            if let Some(inventory) = inventory {
14256                for RunnableTag(tag) in tags {
14257                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14258                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14259                    }) else {
14260                        return templates_with_tags;
14261                    };
14262                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14263                        move |(_, template)| {
14264                            template.tags.iter().any(|source_tag| source_tag == &tag)
14265                        },
14266                    ));
14267                }
14268            }
14269            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14270
14271            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14272                // Strongest source wins; if we have worktree tag binding, prefer that to
14273                // global and language bindings;
14274                // if we have a global binding, prefer that to language binding.
14275                let first_mismatch = templates_with_tags
14276                    .iter()
14277                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14278                if let Some(index) = first_mismatch {
14279                    templates_with_tags.truncate(index);
14280                }
14281            }
14282
14283            templates_with_tags
14284        })
14285    }
14286
14287    pub fn move_to_enclosing_bracket(
14288        &mut self,
14289        _: &MoveToEnclosingBracket,
14290        window: &mut Window,
14291        cx: &mut Context<Self>,
14292    ) {
14293        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14294        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14295            s.move_offsets_with(|snapshot, selection| {
14296                let Some(enclosing_bracket_ranges) =
14297                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14298                else {
14299                    return;
14300                };
14301
14302                let mut best_length = usize::MAX;
14303                let mut best_inside = false;
14304                let mut best_in_bracket_range = false;
14305                let mut best_destination = None;
14306                for (open, close) in enclosing_bracket_ranges {
14307                    let close = close.to_inclusive();
14308                    let length = close.end() - open.start;
14309                    let inside = selection.start >= open.end && selection.end <= *close.start();
14310                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14311                        || close.contains(&selection.head());
14312
14313                    // If best is next to a bracket and current isn't, skip
14314                    if !in_bracket_range && best_in_bracket_range {
14315                        continue;
14316                    }
14317
14318                    // Prefer smaller lengths unless best is inside and current isn't
14319                    if length > best_length && (best_inside || !inside) {
14320                        continue;
14321                    }
14322
14323                    best_length = length;
14324                    best_inside = inside;
14325                    best_in_bracket_range = in_bracket_range;
14326                    best_destination = Some(
14327                        if close.contains(&selection.start) && close.contains(&selection.end) {
14328                            if inside { open.end } else { open.start }
14329                        } else if inside {
14330                            *close.start()
14331                        } else {
14332                            *close.end()
14333                        },
14334                    );
14335                }
14336
14337                if let Some(destination) = best_destination {
14338                    selection.collapse_to(destination, SelectionGoal::None);
14339                }
14340            })
14341        });
14342    }
14343
14344    pub fn undo_selection(
14345        &mut self,
14346        _: &UndoSelection,
14347        window: &mut Window,
14348        cx: &mut Context<Self>,
14349    ) {
14350        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14351        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14352            self.selection_history.mode = SelectionHistoryMode::Undoing;
14353            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14354                this.end_selection(window, cx);
14355                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14356                    s.select_anchors(entry.selections.to_vec())
14357                });
14358            });
14359            self.selection_history.mode = SelectionHistoryMode::Normal;
14360
14361            self.select_next_state = entry.select_next_state;
14362            self.select_prev_state = entry.select_prev_state;
14363            self.add_selections_state = entry.add_selections_state;
14364        }
14365    }
14366
14367    pub fn redo_selection(
14368        &mut self,
14369        _: &RedoSelection,
14370        window: &mut Window,
14371        cx: &mut Context<Self>,
14372    ) {
14373        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14374        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14375            self.selection_history.mode = SelectionHistoryMode::Redoing;
14376            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14377                this.end_selection(window, cx);
14378                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14379                    s.select_anchors(entry.selections.to_vec())
14380                });
14381            });
14382            self.selection_history.mode = SelectionHistoryMode::Normal;
14383
14384            self.select_next_state = entry.select_next_state;
14385            self.select_prev_state = entry.select_prev_state;
14386            self.add_selections_state = entry.add_selections_state;
14387        }
14388    }
14389
14390    pub fn expand_excerpts(
14391        &mut self,
14392        action: &ExpandExcerpts,
14393        _: &mut Window,
14394        cx: &mut Context<Self>,
14395    ) {
14396        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14397    }
14398
14399    pub fn expand_excerpts_down(
14400        &mut self,
14401        action: &ExpandExcerptsDown,
14402        _: &mut Window,
14403        cx: &mut Context<Self>,
14404    ) {
14405        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14406    }
14407
14408    pub fn expand_excerpts_up(
14409        &mut self,
14410        action: &ExpandExcerptsUp,
14411        _: &mut Window,
14412        cx: &mut Context<Self>,
14413    ) {
14414        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14415    }
14416
14417    pub fn expand_excerpts_for_direction(
14418        &mut self,
14419        lines: u32,
14420        direction: ExpandExcerptDirection,
14421
14422        cx: &mut Context<Self>,
14423    ) {
14424        let selections = self.selections.disjoint_anchors();
14425
14426        let lines = if lines == 0 {
14427            EditorSettings::get_global(cx).expand_excerpt_lines
14428        } else {
14429            lines
14430        };
14431
14432        self.buffer.update(cx, |buffer, cx| {
14433            let snapshot = buffer.snapshot(cx);
14434            let mut excerpt_ids = selections
14435                .iter()
14436                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14437                .collect::<Vec<_>>();
14438            excerpt_ids.sort();
14439            excerpt_ids.dedup();
14440            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14441        })
14442    }
14443
14444    pub fn expand_excerpt(
14445        &mut self,
14446        excerpt: ExcerptId,
14447        direction: ExpandExcerptDirection,
14448        window: &mut Window,
14449        cx: &mut Context<Self>,
14450    ) {
14451        let current_scroll_position = self.scroll_position(cx);
14452        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14453        let mut should_scroll_up = false;
14454
14455        if direction == ExpandExcerptDirection::Down {
14456            let multi_buffer = self.buffer.read(cx);
14457            let snapshot = multi_buffer.snapshot(cx);
14458            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14459                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14460                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14461                        let buffer_snapshot = buffer.read(cx).snapshot();
14462                        let excerpt_end_row =
14463                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14464                        let last_row = buffer_snapshot.max_point().row;
14465                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14466                        should_scroll_up = lines_below >= lines_to_expand;
14467                    }
14468                }
14469            }
14470        }
14471
14472        self.buffer.update(cx, |buffer, cx| {
14473            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14474        });
14475
14476        if should_scroll_up {
14477            let new_scroll_position =
14478                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14479            self.set_scroll_position(new_scroll_position, window, cx);
14480        }
14481    }
14482
14483    pub fn go_to_singleton_buffer_point(
14484        &mut self,
14485        point: Point,
14486        window: &mut Window,
14487        cx: &mut Context<Self>,
14488    ) {
14489        self.go_to_singleton_buffer_range(point..point, window, cx);
14490    }
14491
14492    pub fn go_to_singleton_buffer_range(
14493        &mut self,
14494        range: Range<Point>,
14495        window: &mut Window,
14496        cx: &mut Context<Self>,
14497    ) {
14498        let multibuffer = self.buffer().read(cx);
14499        let Some(buffer) = multibuffer.as_singleton() else {
14500            return;
14501        };
14502        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14503            return;
14504        };
14505        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14506            return;
14507        };
14508        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14509            s.select_anchor_ranges([start..end])
14510        });
14511    }
14512
14513    pub fn go_to_diagnostic(
14514        &mut self,
14515        _: &GoToDiagnostic,
14516        window: &mut Window,
14517        cx: &mut Context<Self>,
14518    ) {
14519        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14520        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14521    }
14522
14523    pub fn go_to_prev_diagnostic(
14524        &mut self,
14525        _: &GoToPreviousDiagnostic,
14526        window: &mut Window,
14527        cx: &mut Context<Self>,
14528    ) {
14529        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14530        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14531    }
14532
14533    pub fn go_to_diagnostic_impl(
14534        &mut self,
14535        direction: Direction,
14536        window: &mut Window,
14537        cx: &mut Context<Self>,
14538    ) {
14539        let buffer = self.buffer.read(cx).snapshot(cx);
14540        let selection = self.selections.newest::<usize>(cx);
14541
14542        let mut active_group_id = None;
14543        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14544            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14545                active_group_id = Some(active_group.group_id);
14546            }
14547        }
14548
14549        fn filtered(
14550            snapshot: EditorSnapshot,
14551            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14552        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14553            diagnostics
14554                .filter(|entry| entry.range.start != entry.range.end)
14555                .filter(|entry| !entry.diagnostic.is_unnecessary)
14556                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14557        }
14558
14559        let snapshot = self.snapshot(window, cx);
14560        let before = filtered(
14561            snapshot.clone(),
14562            buffer
14563                .diagnostics_in_range(0..selection.start)
14564                .filter(|entry| entry.range.start <= selection.start),
14565        );
14566        let after = filtered(
14567            snapshot,
14568            buffer
14569                .diagnostics_in_range(selection.start..buffer.len())
14570                .filter(|entry| entry.range.start >= selection.start),
14571        );
14572
14573        let mut found: Option<DiagnosticEntry<usize>> = None;
14574        if direction == Direction::Prev {
14575            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14576            {
14577                for diagnostic in prev_diagnostics.into_iter().rev() {
14578                    if diagnostic.range.start != selection.start
14579                        || active_group_id
14580                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14581                    {
14582                        found = Some(diagnostic);
14583                        break 'outer;
14584                    }
14585                }
14586            }
14587        } else {
14588            for diagnostic in after.chain(before) {
14589                if diagnostic.range.start != selection.start
14590                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14591                {
14592                    found = Some(diagnostic);
14593                    break;
14594                }
14595            }
14596        }
14597        let Some(next_diagnostic) = found else {
14598            return;
14599        };
14600
14601        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14602            return;
14603        };
14604        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14605            s.select_ranges(vec![
14606                next_diagnostic.range.start..next_diagnostic.range.start,
14607            ])
14608        });
14609        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14610        self.refresh_inline_completion(false, true, window, cx);
14611    }
14612
14613    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14614        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14615        let snapshot = self.snapshot(window, cx);
14616        let selection = self.selections.newest::<Point>(cx);
14617        self.go_to_hunk_before_or_after_position(
14618            &snapshot,
14619            selection.head(),
14620            Direction::Next,
14621            window,
14622            cx,
14623        );
14624    }
14625
14626    pub fn go_to_hunk_before_or_after_position(
14627        &mut self,
14628        snapshot: &EditorSnapshot,
14629        position: Point,
14630        direction: Direction,
14631        window: &mut Window,
14632        cx: &mut Context<Editor>,
14633    ) {
14634        let row = if direction == Direction::Next {
14635            self.hunk_after_position(snapshot, position)
14636                .map(|hunk| hunk.row_range.start)
14637        } else {
14638            self.hunk_before_position(snapshot, position)
14639        };
14640
14641        if let Some(row) = row {
14642            let destination = Point::new(row.0, 0);
14643            let autoscroll = Autoscroll::center();
14644
14645            self.unfold_ranges(&[destination..destination], false, false, cx);
14646            self.change_selections(Some(autoscroll), window, cx, |s| {
14647                s.select_ranges([destination..destination]);
14648            });
14649        }
14650    }
14651
14652    fn hunk_after_position(
14653        &mut self,
14654        snapshot: &EditorSnapshot,
14655        position: Point,
14656    ) -> Option<MultiBufferDiffHunk> {
14657        snapshot
14658            .buffer_snapshot
14659            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14660            .find(|hunk| hunk.row_range.start.0 > position.row)
14661            .or_else(|| {
14662                snapshot
14663                    .buffer_snapshot
14664                    .diff_hunks_in_range(Point::zero()..position)
14665                    .find(|hunk| hunk.row_range.end.0 < position.row)
14666            })
14667    }
14668
14669    fn go_to_prev_hunk(
14670        &mut self,
14671        _: &GoToPreviousHunk,
14672        window: &mut Window,
14673        cx: &mut Context<Self>,
14674    ) {
14675        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14676        let snapshot = self.snapshot(window, cx);
14677        let selection = self.selections.newest::<Point>(cx);
14678        self.go_to_hunk_before_or_after_position(
14679            &snapshot,
14680            selection.head(),
14681            Direction::Prev,
14682            window,
14683            cx,
14684        );
14685    }
14686
14687    fn hunk_before_position(
14688        &mut self,
14689        snapshot: &EditorSnapshot,
14690        position: Point,
14691    ) -> Option<MultiBufferRow> {
14692        snapshot
14693            .buffer_snapshot
14694            .diff_hunk_before(position)
14695            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14696    }
14697
14698    fn go_to_next_change(
14699        &mut self,
14700        _: &GoToNextChange,
14701        window: &mut Window,
14702        cx: &mut Context<Self>,
14703    ) {
14704        if let Some(selections) = self
14705            .change_list
14706            .next_change(1, Direction::Next)
14707            .map(|s| s.to_vec())
14708        {
14709            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14710                let map = s.display_map();
14711                s.select_display_ranges(selections.iter().map(|a| {
14712                    let point = a.to_display_point(&map);
14713                    point..point
14714                }))
14715            })
14716        }
14717    }
14718
14719    fn go_to_previous_change(
14720        &mut self,
14721        _: &GoToPreviousChange,
14722        window: &mut Window,
14723        cx: &mut Context<Self>,
14724    ) {
14725        if let Some(selections) = self
14726            .change_list
14727            .next_change(1, Direction::Prev)
14728            .map(|s| s.to_vec())
14729        {
14730            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14731                let map = s.display_map();
14732                s.select_display_ranges(selections.iter().map(|a| {
14733                    let point = a.to_display_point(&map);
14734                    point..point
14735                }))
14736            })
14737        }
14738    }
14739
14740    fn go_to_line<T: 'static>(
14741        &mut self,
14742        position: Anchor,
14743        highlight_color: Option<Hsla>,
14744        window: &mut Window,
14745        cx: &mut Context<Self>,
14746    ) {
14747        let snapshot = self.snapshot(window, cx).display_snapshot;
14748        let position = position.to_point(&snapshot.buffer_snapshot);
14749        let start = snapshot
14750            .buffer_snapshot
14751            .clip_point(Point::new(position.row, 0), Bias::Left);
14752        let end = start + Point::new(1, 0);
14753        let start = snapshot.buffer_snapshot.anchor_before(start);
14754        let end = snapshot.buffer_snapshot.anchor_before(end);
14755
14756        self.highlight_rows::<T>(
14757            start..end,
14758            highlight_color
14759                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14760            Default::default(),
14761            cx,
14762        );
14763
14764        if self.buffer.read(cx).is_singleton() {
14765            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14766        }
14767    }
14768
14769    pub fn go_to_definition(
14770        &mut self,
14771        _: &GoToDefinition,
14772        window: &mut Window,
14773        cx: &mut Context<Self>,
14774    ) -> Task<Result<Navigated>> {
14775        let definition =
14776            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14777        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14778        cx.spawn_in(window, async move |editor, cx| {
14779            if definition.await? == Navigated::Yes {
14780                return Ok(Navigated::Yes);
14781            }
14782            match fallback_strategy {
14783                GoToDefinitionFallback::None => Ok(Navigated::No),
14784                GoToDefinitionFallback::FindAllReferences => {
14785                    match editor.update_in(cx, |editor, window, cx| {
14786                        editor.find_all_references(&FindAllReferences, window, cx)
14787                    })? {
14788                        Some(references) => references.await,
14789                        None => Ok(Navigated::No),
14790                    }
14791                }
14792            }
14793        })
14794    }
14795
14796    pub fn go_to_declaration(
14797        &mut self,
14798        _: &GoToDeclaration,
14799        window: &mut Window,
14800        cx: &mut Context<Self>,
14801    ) -> Task<Result<Navigated>> {
14802        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14803    }
14804
14805    pub fn go_to_declaration_split(
14806        &mut self,
14807        _: &GoToDeclaration,
14808        window: &mut Window,
14809        cx: &mut Context<Self>,
14810    ) -> Task<Result<Navigated>> {
14811        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14812    }
14813
14814    pub fn go_to_implementation(
14815        &mut self,
14816        _: &GoToImplementation,
14817        window: &mut Window,
14818        cx: &mut Context<Self>,
14819    ) -> Task<Result<Navigated>> {
14820        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14821    }
14822
14823    pub fn go_to_implementation_split(
14824        &mut self,
14825        _: &GoToImplementationSplit,
14826        window: &mut Window,
14827        cx: &mut Context<Self>,
14828    ) -> Task<Result<Navigated>> {
14829        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14830    }
14831
14832    pub fn go_to_type_definition(
14833        &mut self,
14834        _: &GoToTypeDefinition,
14835        window: &mut Window,
14836        cx: &mut Context<Self>,
14837    ) -> Task<Result<Navigated>> {
14838        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14839    }
14840
14841    pub fn go_to_definition_split(
14842        &mut self,
14843        _: &GoToDefinitionSplit,
14844        window: &mut Window,
14845        cx: &mut Context<Self>,
14846    ) -> Task<Result<Navigated>> {
14847        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14848    }
14849
14850    pub fn go_to_type_definition_split(
14851        &mut self,
14852        _: &GoToTypeDefinitionSplit,
14853        window: &mut Window,
14854        cx: &mut Context<Self>,
14855    ) -> Task<Result<Navigated>> {
14856        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14857    }
14858
14859    fn go_to_definition_of_kind(
14860        &mut self,
14861        kind: GotoDefinitionKind,
14862        split: bool,
14863        window: &mut Window,
14864        cx: &mut Context<Self>,
14865    ) -> Task<Result<Navigated>> {
14866        let Some(provider) = self.semantics_provider.clone() else {
14867            return Task::ready(Ok(Navigated::No));
14868        };
14869        let head = self.selections.newest::<usize>(cx).head();
14870        let buffer = self.buffer.read(cx);
14871        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14872            text_anchor
14873        } else {
14874            return Task::ready(Ok(Navigated::No));
14875        };
14876
14877        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14878            return Task::ready(Ok(Navigated::No));
14879        };
14880
14881        cx.spawn_in(window, async move |editor, cx| {
14882            let definitions = definitions.await?;
14883            let navigated = editor
14884                .update_in(cx, |editor, window, cx| {
14885                    editor.navigate_to_hover_links(
14886                        Some(kind),
14887                        definitions
14888                            .into_iter()
14889                            .filter(|location| {
14890                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14891                            })
14892                            .map(HoverLink::Text)
14893                            .collect::<Vec<_>>(),
14894                        split,
14895                        window,
14896                        cx,
14897                    )
14898                })?
14899                .await?;
14900            anyhow::Ok(navigated)
14901        })
14902    }
14903
14904    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14905        let selection = self.selections.newest_anchor();
14906        let head = selection.head();
14907        let tail = selection.tail();
14908
14909        let Some((buffer, start_position)) =
14910            self.buffer.read(cx).text_anchor_for_position(head, cx)
14911        else {
14912            return;
14913        };
14914
14915        let end_position = if head != tail {
14916            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14917                return;
14918            };
14919            Some(pos)
14920        } else {
14921            None
14922        };
14923
14924        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14925            let url = if let Some(end_pos) = end_position {
14926                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14927            } else {
14928                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14929            };
14930
14931            if let Some(url) = url {
14932                editor.update(cx, |_, cx| {
14933                    cx.open_url(&url);
14934                })
14935            } else {
14936                Ok(())
14937            }
14938        });
14939
14940        url_finder.detach();
14941    }
14942
14943    pub fn open_selected_filename(
14944        &mut self,
14945        _: &OpenSelectedFilename,
14946        window: &mut Window,
14947        cx: &mut Context<Self>,
14948    ) {
14949        let Some(workspace) = self.workspace() else {
14950            return;
14951        };
14952
14953        let position = self.selections.newest_anchor().head();
14954
14955        let Some((buffer, buffer_position)) =
14956            self.buffer.read(cx).text_anchor_for_position(position, cx)
14957        else {
14958            return;
14959        };
14960
14961        let project = self.project.clone();
14962
14963        cx.spawn_in(window, async move |_, cx| {
14964            let result = find_file(&buffer, project, buffer_position, cx).await;
14965
14966            if let Some((_, path)) = result {
14967                workspace
14968                    .update_in(cx, |workspace, window, cx| {
14969                        workspace.open_resolved_path(path, window, cx)
14970                    })?
14971                    .await?;
14972            }
14973            anyhow::Ok(())
14974        })
14975        .detach();
14976    }
14977
14978    pub(crate) fn navigate_to_hover_links(
14979        &mut self,
14980        kind: Option<GotoDefinitionKind>,
14981        mut definitions: Vec<HoverLink>,
14982        split: bool,
14983        window: &mut Window,
14984        cx: &mut Context<Editor>,
14985    ) -> Task<Result<Navigated>> {
14986        // If there is one definition, just open it directly
14987        if definitions.len() == 1 {
14988            let definition = definitions.pop().unwrap();
14989
14990            enum TargetTaskResult {
14991                Location(Option<Location>),
14992                AlreadyNavigated,
14993            }
14994
14995            let target_task = match definition {
14996                HoverLink::Text(link) => {
14997                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14998                }
14999                HoverLink::InlayHint(lsp_location, server_id) => {
15000                    let computation =
15001                        self.compute_target_location(lsp_location, server_id, window, cx);
15002                    cx.background_spawn(async move {
15003                        let location = computation.await?;
15004                        Ok(TargetTaskResult::Location(location))
15005                    })
15006                }
15007                HoverLink::Url(url) => {
15008                    cx.open_url(&url);
15009                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15010                }
15011                HoverLink::File(path) => {
15012                    if let Some(workspace) = self.workspace() {
15013                        cx.spawn_in(window, async move |_, cx| {
15014                            workspace
15015                                .update_in(cx, |workspace, window, cx| {
15016                                    workspace.open_resolved_path(path, window, cx)
15017                                })?
15018                                .await
15019                                .map(|_| TargetTaskResult::AlreadyNavigated)
15020                        })
15021                    } else {
15022                        Task::ready(Ok(TargetTaskResult::Location(None)))
15023                    }
15024                }
15025            };
15026            cx.spawn_in(window, async move |editor, cx| {
15027                let target = match target_task.await.context("target resolution task")? {
15028                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15029                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15030                    TargetTaskResult::Location(Some(target)) => target,
15031                };
15032
15033                editor.update_in(cx, |editor, window, cx| {
15034                    let Some(workspace) = editor.workspace() else {
15035                        return Navigated::No;
15036                    };
15037                    let pane = workspace.read(cx).active_pane().clone();
15038
15039                    let range = target.range.to_point(target.buffer.read(cx));
15040                    let range = editor.range_for_match(&range);
15041                    let range = collapse_multiline_range(range);
15042
15043                    if !split
15044                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15045                    {
15046                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15047                    } else {
15048                        window.defer(cx, move |window, cx| {
15049                            let target_editor: Entity<Self> =
15050                                workspace.update(cx, |workspace, cx| {
15051                                    let pane = if split {
15052                                        workspace.adjacent_pane(window, cx)
15053                                    } else {
15054                                        workspace.active_pane().clone()
15055                                    };
15056
15057                                    workspace.open_project_item(
15058                                        pane,
15059                                        target.buffer.clone(),
15060                                        true,
15061                                        true,
15062                                        window,
15063                                        cx,
15064                                    )
15065                                });
15066                            target_editor.update(cx, |target_editor, cx| {
15067                                // When selecting a definition in a different buffer, disable the nav history
15068                                // to avoid creating a history entry at the previous cursor location.
15069                                pane.update(cx, |pane, _| pane.disable_history());
15070                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15071                                pane.update(cx, |pane, _| pane.enable_history());
15072                            });
15073                        });
15074                    }
15075                    Navigated::Yes
15076                })
15077            })
15078        } else if !definitions.is_empty() {
15079            cx.spawn_in(window, async move |editor, cx| {
15080                let (title, location_tasks, workspace) = editor
15081                    .update_in(cx, |editor, window, cx| {
15082                        let tab_kind = match kind {
15083                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15084                            _ => "Definitions",
15085                        };
15086                        let title = definitions
15087                            .iter()
15088                            .find_map(|definition| match definition {
15089                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15090                                    let buffer = origin.buffer.read(cx);
15091                                    format!(
15092                                        "{} for {}",
15093                                        tab_kind,
15094                                        buffer
15095                                            .text_for_range(origin.range.clone())
15096                                            .collect::<String>()
15097                                    )
15098                                }),
15099                                HoverLink::InlayHint(_, _) => None,
15100                                HoverLink::Url(_) => None,
15101                                HoverLink::File(_) => None,
15102                            })
15103                            .unwrap_or(tab_kind.to_string());
15104                        let location_tasks = definitions
15105                            .into_iter()
15106                            .map(|definition| match definition {
15107                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15108                                HoverLink::InlayHint(lsp_location, server_id) => editor
15109                                    .compute_target_location(lsp_location, server_id, window, cx),
15110                                HoverLink::Url(_) => Task::ready(Ok(None)),
15111                                HoverLink::File(_) => Task::ready(Ok(None)),
15112                            })
15113                            .collect::<Vec<_>>();
15114                        (title, location_tasks, editor.workspace().clone())
15115                    })
15116                    .context("location tasks preparation")?;
15117
15118                let locations = future::join_all(location_tasks)
15119                    .await
15120                    .into_iter()
15121                    .filter_map(|location| location.transpose())
15122                    .collect::<Result<_>>()
15123                    .context("location tasks")?;
15124
15125                let Some(workspace) = workspace else {
15126                    return Ok(Navigated::No);
15127                };
15128                let opened = workspace
15129                    .update_in(cx, |workspace, window, cx| {
15130                        Self::open_locations_in_multibuffer(
15131                            workspace,
15132                            locations,
15133                            title,
15134                            split,
15135                            MultibufferSelectionMode::First,
15136                            window,
15137                            cx,
15138                        )
15139                    })
15140                    .ok();
15141
15142                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15143            })
15144        } else {
15145            Task::ready(Ok(Navigated::No))
15146        }
15147    }
15148
15149    fn compute_target_location(
15150        &self,
15151        lsp_location: lsp::Location,
15152        server_id: LanguageServerId,
15153        window: &mut Window,
15154        cx: &mut Context<Self>,
15155    ) -> Task<anyhow::Result<Option<Location>>> {
15156        let Some(project) = self.project.clone() else {
15157            return Task::ready(Ok(None));
15158        };
15159
15160        cx.spawn_in(window, async move |editor, cx| {
15161            let location_task = editor.update(cx, |_, cx| {
15162                project.update(cx, |project, cx| {
15163                    let language_server_name = project
15164                        .language_server_statuses(cx)
15165                        .find(|(id, _)| server_id == *id)
15166                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15167                    language_server_name.map(|language_server_name| {
15168                        project.open_local_buffer_via_lsp(
15169                            lsp_location.uri.clone(),
15170                            server_id,
15171                            language_server_name,
15172                            cx,
15173                        )
15174                    })
15175                })
15176            })?;
15177            let location = match location_task {
15178                Some(task) => Some({
15179                    let target_buffer_handle = task.await.context("open local buffer")?;
15180                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15181                        let target_start = target_buffer
15182                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15183                        let target_end = target_buffer
15184                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15185                        target_buffer.anchor_after(target_start)
15186                            ..target_buffer.anchor_before(target_end)
15187                    })?;
15188                    Location {
15189                        buffer: target_buffer_handle,
15190                        range,
15191                    }
15192                }),
15193                None => None,
15194            };
15195            Ok(location)
15196        })
15197    }
15198
15199    pub fn find_all_references(
15200        &mut self,
15201        _: &FindAllReferences,
15202        window: &mut Window,
15203        cx: &mut Context<Self>,
15204    ) -> Option<Task<Result<Navigated>>> {
15205        let selection = self.selections.newest::<usize>(cx);
15206        let multi_buffer = self.buffer.read(cx);
15207        let head = selection.head();
15208
15209        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15210        let head_anchor = multi_buffer_snapshot.anchor_at(
15211            head,
15212            if head < selection.tail() {
15213                Bias::Right
15214            } else {
15215                Bias::Left
15216            },
15217        );
15218
15219        match self
15220            .find_all_references_task_sources
15221            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15222        {
15223            Ok(_) => {
15224                log::info!(
15225                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15226                );
15227                return None;
15228            }
15229            Err(i) => {
15230                self.find_all_references_task_sources.insert(i, head_anchor);
15231            }
15232        }
15233
15234        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15235        let workspace = self.workspace()?;
15236        let project = workspace.read(cx).project().clone();
15237        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15238        Some(cx.spawn_in(window, async move |editor, cx| {
15239            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15240                if let Ok(i) = editor
15241                    .find_all_references_task_sources
15242                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15243                {
15244                    editor.find_all_references_task_sources.remove(i);
15245                }
15246            });
15247
15248            let locations = references.await?;
15249            if locations.is_empty() {
15250                return anyhow::Ok(Navigated::No);
15251            }
15252
15253            workspace.update_in(cx, |workspace, window, cx| {
15254                let title = locations
15255                    .first()
15256                    .as_ref()
15257                    .map(|location| {
15258                        let buffer = location.buffer.read(cx);
15259                        format!(
15260                            "References to `{}`",
15261                            buffer
15262                                .text_for_range(location.range.clone())
15263                                .collect::<String>()
15264                        )
15265                    })
15266                    .unwrap();
15267                Self::open_locations_in_multibuffer(
15268                    workspace,
15269                    locations,
15270                    title,
15271                    false,
15272                    MultibufferSelectionMode::First,
15273                    window,
15274                    cx,
15275                );
15276                Navigated::Yes
15277            })
15278        }))
15279    }
15280
15281    /// Opens a multibuffer with the given project locations in it
15282    pub fn open_locations_in_multibuffer(
15283        workspace: &mut Workspace,
15284        mut locations: Vec<Location>,
15285        title: String,
15286        split: bool,
15287        multibuffer_selection_mode: MultibufferSelectionMode,
15288        window: &mut Window,
15289        cx: &mut Context<Workspace>,
15290    ) {
15291        // If there are multiple definitions, open them in a multibuffer
15292        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15293        let mut locations = locations.into_iter().peekable();
15294        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15295        let capability = workspace.project().read(cx).capability();
15296
15297        let excerpt_buffer = cx.new(|cx| {
15298            let mut multibuffer = MultiBuffer::new(capability);
15299            while let Some(location) = locations.next() {
15300                let buffer = location.buffer.read(cx);
15301                let mut ranges_for_buffer = Vec::new();
15302                let range = location.range.to_point(buffer);
15303                ranges_for_buffer.push(range.clone());
15304
15305                while let Some(next_location) = locations.peek() {
15306                    if next_location.buffer == location.buffer {
15307                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15308                        locations.next();
15309                    } else {
15310                        break;
15311                    }
15312                }
15313
15314                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15315                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15316                    PathKey::for_buffer(&location.buffer, cx),
15317                    location.buffer.clone(),
15318                    ranges_for_buffer,
15319                    DEFAULT_MULTIBUFFER_CONTEXT,
15320                    cx,
15321                );
15322                ranges.extend(new_ranges)
15323            }
15324
15325            multibuffer.with_title(title)
15326        });
15327
15328        let editor = cx.new(|cx| {
15329            Editor::for_multibuffer(
15330                excerpt_buffer,
15331                Some(workspace.project().clone()),
15332                window,
15333                cx,
15334            )
15335        });
15336        editor.update(cx, |editor, cx| {
15337            match multibuffer_selection_mode {
15338                MultibufferSelectionMode::First => {
15339                    if let Some(first_range) = ranges.first() {
15340                        editor.change_selections(None, window, cx, |selections| {
15341                            selections.clear_disjoint();
15342                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15343                        });
15344                    }
15345                    editor.highlight_background::<Self>(
15346                        &ranges,
15347                        |theme| theme.editor_highlighted_line_background,
15348                        cx,
15349                    );
15350                }
15351                MultibufferSelectionMode::All => {
15352                    editor.change_selections(None, window, cx, |selections| {
15353                        selections.clear_disjoint();
15354                        selections.select_anchor_ranges(ranges);
15355                    });
15356                }
15357            }
15358            editor.register_buffers_with_language_servers(cx);
15359        });
15360
15361        let item = Box::new(editor);
15362        let item_id = item.item_id();
15363
15364        if split {
15365            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15366        } else {
15367            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15368                let (preview_item_id, preview_item_idx) =
15369                    workspace.active_pane().read_with(cx, |pane, _| {
15370                        (pane.preview_item_id(), pane.preview_item_idx())
15371                    });
15372
15373                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15374
15375                if let Some(preview_item_id) = preview_item_id {
15376                    workspace.active_pane().update(cx, |pane, cx| {
15377                        pane.remove_item(preview_item_id, false, false, window, cx);
15378                    });
15379                }
15380            } else {
15381                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15382            }
15383        }
15384        workspace.active_pane().update(cx, |pane, cx| {
15385            pane.set_preview_item_id(Some(item_id), cx);
15386        });
15387    }
15388
15389    pub fn rename(
15390        &mut self,
15391        _: &Rename,
15392        window: &mut Window,
15393        cx: &mut Context<Self>,
15394    ) -> Option<Task<Result<()>>> {
15395        use language::ToOffset as _;
15396
15397        let provider = self.semantics_provider.clone()?;
15398        let selection = self.selections.newest_anchor().clone();
15399        let (cursor_buffer, cursor_buffer_position) = self
15400            .buffer
15401            .read(cx)
15402            .text_anchor_for_position(selection.head(), cx)?;
15403        let (tail_buffer, cursor_buffer_position_end) = self
15404            .buffer
15405            .read(cx)
15406            .text_anchor_for_position(selection.tail(), cx)?;
15407        if tail_buffer != cursor_buffer {
15408            return None;
15409        }
15410
15411        let snapshot = cursor_buffer.read(cx).snapshot();
15412        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15413        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15414        let prepare_rename = provider
15415            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15416            .unwrap_or_else(|| Task::ready(Ok(None)));
15417        drop(snapshot);
15418
15419        Some(cx.spawn_in(window, async move |this, cx| {
15420            let rename_range = if let Some(range) = prepare_rename.await? {
15421                Some(range)
15422            } else {
15423                this.update(cx, |this, cx| {
15424                    let buffer = this.buffer.read(cx).snapshot(cx);
15425                    let mut buffer_highlights = this
15426                        .document_highlights_for_position(selection.head(), &buffer)
15427                        .filter(|highlight| {
15428                            highlight.start.excerpt_id == selection.head().excerpt_id
15429                                && highlight.end.excerpt_id == selection.head().excerpt_id
15430                        });
15431                    buffer_highlights
15432                        .next()
15433                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15434                })?
15435            };
15436            if let Some(rename_range) = rename_range {
15437                this.update_in(cx, |this, window, cx| {
15438                    let snapshot = cursor_buffer.read(cx).snapshot();
15439                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15440                    let cursor_offset_in_rename_range =
15441                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15442                    let cursor_offset_in_rename_range_end =
15443                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15444
15445                    this.take_rename(false, window, cx);
15446                    let buffer = this.buffer.read(cx).read(cx);
15447                    let cursor_offset = selection.head().to_offset(&buffer);
15448                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15449                    let rename_end = rename_start + rename_buffer_range.len();
15450                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15451                    let mut old_highlight_id = None;
15452                    let old_name: Arc<str> = buffer
15453                        .chunks(rename_start..rename_end, true)
15454                        .map(|chunk| {
15455                            if old_highlight_id.is_none() {
15456                                old_highlight_id = chunk.syntax_highlight_id;
15457                            }
15458                            chunk.text
15459                        })
15460                        .collect::<String>()
15461                        .into();
15462
15463                    drop(buffer);
15464
15465                    // Position the selection in the rename editor so that it matches the current selection.
15466                    this.show_local_selections = false;
15467                    let rename_editor = cx.new(|cx| {
15468                        let mut editor = Editor::single_line(window, cx);
15469                        editor.buffer.update(cx, |buffer, cx| {
15470                            buffer.edit([(0..0, old_name.clone())], None, cx)
15471                        });
15472                        let rename_selection_range = match cursor_offset_in_rename_range
15473                            .cmp(&cursor_offset_in_rename_range_end)
15474                        {
15475                            Ordering::Equal => {
15476                                editor.select_all(&SelectAll, window, cx);
15477                                return editor;
15478                            }
15479                            Ordering::Less => {
15480                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15481                            }
15482                            Ordering::Greater => {
15483                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15484                            }
15485                        };
15486                        if rename_selection_range.end > old_name.len() {
15487                            editor.select_all(&SelectAll, window, cx);
15488                        } else {
15489                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15490                                s.select_ranges([rename_selection_range]);
15491                            });
15492                        }
15493                        editor
15494                    });
15495                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15496                        if e == &EditorEvent::Focused {
15497                            cx.emit(EditorEvent::FocusedIn)
15498                        }
15499                    })
15500                    .detach();
15501
15502                    let write_highlights =
15503                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15504                    let read_highlights =
15505                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15506                    let ranges = write_highlights
15507                        .iter()
15508                        .flat_map(|(_, ranges)| ranges.iter())
15509                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15510                        .cloned()
15511                        .collect();
15512
15513                    this.highlight_text::<Rename>(
15514                        ranges,
15515                        HighlightStyle {
15516                            fade_out: Some(0.6),
15517                            ..Default::default()
15518                        },
15519                        cx,
15520                    );
15521                    let rename_focus_handle = rename_editor.focus_handle(cx);
15522                    window.focus(&rename_focus_handle);
15523                    let block_id = this.insert_blocks(
15524                        [BlockProperties {
15525                            style: BlockStyle::Flex,
15526                            placement: BlockPlacement::Below(range.start),
15527                            height: Some(1),
15528                            render: Arc::new({
15529                                let rename_editor = rename_editor.clone();
15530                                move |cx: &mut BlockContext| {
15531                                    let mut text_style = cx.editor_style.text.clone();
15532                                    if let Some(highlight_style) = old_highlight_id
15533                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15534                                    {
15535                                        text_style = text_style.highlight(highlight_style);
15536                                    }
15537                                    div()
15538                                        .block_mouse_except_scroll()
15539                                        .pl(cx.anchor_x)
15540                                        .child(EditorElement::new(
15541                                            &rename_editor,
15542                                            EditorStyle {
15543                                                background: cx.theme().system().transparent,
15544                                                local_player: cx.editor_style.local_player,
15545                                                text: text_style,
15546                                                scrollbar_width: cx.editor_style.scrollbar_width,
15547                                                syntax: cx.editor_style.syntax.clone(),
15548                                                status: cx.editor_style.status.clone(),
15549                                                inlay_hints_style: HighlightStyle {
15550                                                    font_weight: Some(FontWeight::BOLD),
15551                                                    ..make_inlay_hints_style(cx.app)
15552                                                },
15553                                                inline_completion_styles: make_suggestion_styles(
15554                                                    cx.app,
15555                                                ),
15556                                                ..EditorStyle::default()
15557                                            },
15558                                        ))
15559                                        .into_any_element()
15560                                }
15561                            }),
15562                            priority: 0,
15563                            render_in_minimap: true,
15564                        }],
15565                        Some(Autoscroll::fit()),
15566                        cx,
15567                    )[0];
15568                    this.pending_rename = Some(RenameState {
15569                        range,
15570                        old_name,
15571                        editor: rename_editor,
15572                        block_id,
15573                    });
15574                })?;
15575            }
15576
15577            Ok(())
15578        }))
15579    }
15580
15581    pub fn confirm_rename(
15582        &mut self,
15583        _: &ConfirmRename,
15584        window: &mut Window,
15585        cx: &mut Context<Self>,
15586    ) -> Option<Task<Result<()>>> {
15587        let rename = self.take_rename(false, window, cx)?;
15588        let workspace = self.workspace()?.downgrade();
15589        let (buffer, start) = self
15590            .buffer
15591            .read(cx)
15592            .text_anchor_for_position(rename.range.start, cx)?;
15593        let (end_buffer, _) = self
15594            .buffer
15595            .read(cx)
15596            .text_anchor_for_position(rename.range.end, cx)?;
15597        if buffer != end_buffer {
15598            return None;
15599        }
15600
15601        let old_name = rename.old_name;
15602        let new_name = rename.editor.read(cx).text(cx);
15603
15604        let rename = self.semantics_provider.as_ref()?.perform_rename(
15605            &buffer,
15606            start,
15607            new_name.clone(),
15608            cx,
15609        )?;
15610
15611        Some(cx.spawn_in(window, async move |editor, cx| {
15612            let project_transaction = rename.await?;
15613            Self::open_project_transaction(
15614                &editor,
15615                workspace,
15616                project_transaction,
15617                format!("Rename: {}{}", old_name, new_name),
15618                cx,
15619            )
15620            .await?;
15621
15622            editor.update(cx, |editor, cx| {
15623                editor.refresh_document_highlights(cx);
15624            })?;
15625            Ok(())
15626        }))
15627    }
15628
15629    fn take_rename(
15630        &mut self,
15631        moving_cursor: bool,
15632        window: &mut Window,
15633        cx: &mut Context<Self>,
15634    ) -> Option<RenameState> {
15635        let rename = self.pending_rename.take()?;
15636        if rename.editor.focus_handle(cx).is_focused(window) {
15637            window.focus(&self.focus_handle);
15638        }
15639
15640        self.remove_blocks(
15641            [rename.block_id].into_iter().collect(),
15642            Some(Autoscroll::fit()),
15643            cx,
15644        );
15645        self.clear_highlights::<Rename>(cx);
15646        self.show_local_selections = true;
15647
15648        if moving_cursor {
15649            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15650                editor.selections.newest::<usize>(cx).head()
15651            });
15652
15653            // Update the selection to match the position of the selection inside
15654            // the rename editor.
15655            let snapshot = self.buffer.read(cx).read(cx);
15656            let rename_range = rename.range.to_offset(&snapshot);
15657            let cursor_in_editor = snapshot
15658                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15659                .min(rename_range.end);
15660            drop(snapshot);
15661
15662            self.change_selections(None, window, cx, |s| {
15663                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15664            });
15665        } else {
15666            self.refresh_document_highlights(cx);
15667        }
15668
15669        Some(rename)
15670    }
15671
15672    pub fn pending_rename(&self) -> Option<&RenameState> {
15673        self.pending_rename.as_ref()
15674    }
15675
15676    fn format(
15677        &mut self,
15678        _: &Format,
15679        window: &mut Window,
15680        cx: &mut Context<Self>,
15681    ) -> Option<Task<Result<()>>> {
15682        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15683
15684        let project = match &self.project {
15685            Some(project) => project.clone(),
15686            None => return None,
15687        };
15688
15689        Some(self.perform_format(
15690            project,
15691            FormatTrigger::Manual,
15692            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15693            window,
15694            cx,
15695        ))
15696    }
15697
15698    fn format_selections(
15699        &mut self,
15700        _: &FormatSelections,
15701        window: &mut Window,
15702        cx: &mut Context<Self>,
15703    ) -> Option<Task<Result<()>>> {
15704        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15705
15706        let project = match &self.project {
15707            Some(project) => project.clone(),
15708            None => return None,
15709        };
15710
15711        let ranges = self
15712            .selections
15713            .all_adjusted(cx)
15714            .into_iter()
15715            .map(|selection| selection.range())
15716            .collect_vec();
15717
15718        Some(self.perform_format(
15719            project,
15720            FormatTrigger::Manual,
15721            FormatTarget::Ranges(ranges),
15722            window,
15723            cx,
15724        ))
15725    }
15726
15727    fn perform_format(
15728        &mut self,
15729        project: Entity<Project>,
15730        trigger: FormatTrigger,
15731        target: FormatTarget,
15732        window: &mut Window,
15733        cx: &mut Context<Self>,
15734    ) -> Task<Result<()>> {
15735        let buffer = self.buffer.clone();
15736        let (buffers, target) = match target {
15737            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15738            FormatTarget::Ranges(selection_ranges) => {
15739                let multi_buffer = buffer.read(cx);
15740                let snapshot = multi_buffer.read(cx);
15741                let mut buffers = HashSet::default();
15742                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15743                    BTreeMap::new();
15744                for selection_range in selection_ranges {
15745                    for (buffer, buffer_range, _) in
15746                        snapshot.range_to_buffer_ranges(selection_range)
15747                    {
15748                        let buffer_id = buffer.remote_id();
15749                        let start = buffer.anchor_before(buffer_range.start);
15750                        let end = buffer.anchor_after(buffer_range.end);
15751                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15752                        buffer_id_to_ranges
15753                            .entry(buffer_id)
15754                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15755                            .or_insert_with(|| vec![start..end]);
15756                    }
15757                }
15758                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15759            }
15760        };
15761
15762        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15763        let selections_prev = transaction_id_prev
15764            .and_then(|transaction_id_prev| {
15765                // default to selections as they were after the last edit, if we have them,
15766                // instead of how they are now.
15767                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15768                // will take you back to where you made the last edit, instead of staying where you scrolled
15769                self.selection_history
15770                    .transaction(transaction_id_prev)
15771                    .map(|t| t.0.clone())
15772            })
15773            .unwrap_or_else(|| {
15774                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15775                self.selections.disjoint_anchors()
15776            });
15777
15778        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15779        let format = project.update(cx, |project, cx| {
15780            project.format(buffers, target, true, trigger, cx)
15781        });
15782
15783        cx.spawn_in(window, async move |editor, cx| {
15784            let transaction = futures::select_biased! {
15785                transaction = format.log_err().fuse() => transaction,
15786                () = timeout => {
15787                    log::warn!("timed out waiting for formatting");
15788                    None
15789                }
15790            };
15791
15792            buffer
15793                .update(cx, |buffer, cx| {
15794                    if let Some(transaction) = transaction {
15795                        if !buffer.is_singleton() {
15796                            buffer.push_transaction(&transaction.0, cx);
15797                        }
15798                    }
15799                    cx.notify();
15800                })
15801                .ok();
15802
15803            if let Some(transaction_id_now) =
15804                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15805            {
15806                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15807                if has_new_transaction {
15808                    _ = editor.update(cx, |editor, _| {
15809                        editor
15810                            .selection_history
15811                            .insert_transaction(transaction_id_now, selections_prev);
15812                    });
15813                }
15814            }
15815
15816            Ok(())
15817        })
15818    }
15819
15820    fn organize_imports(
15821        &mut self,
15822        _: &OrganizeImports,
15823        window: &mut Window,
15824        cx: &mut Context<Self>,
15825    ) -> Option<Task<Result<()>>> {
15826        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15827        let project = match &self.project {
15828            Some(project) => project.clone(),
15829            None => return None,
15830        };
15831        Some(self.perform_code_action_kind(
15832            project,
15833            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15834            window,
15835            cx,
15836        ))
15837    }
15838
15839    fn perform_code_action_kind(
15840        &mut self,
15841        project: Entity<Project>,
15842        kind: CodeActionKind,
15843        window: &mut Window,
15844        cx: &mut Context<Self>,
15845    ) -> Task<Result<()>> {
15846        let buffer = self.buffer.clone();
15847        let buffers = buffer.read(cx).all_buffers();
15848        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15849        let apply_action = project.update(cx, |project, cx| {
15850            project.apply_code_action_kind(buffers, kind, true, cx)
15851        });
15852        cx.spawn_in(window, async move |_, cx| {
15853            let transaction = futures::select_biased! {
15854                () = timeout => {
15855                    log::warn!("timed out waiting for executing code action");
15856                    None
15857                }
15858                transaction = apply_action.log_err().fuse() => transaction,
15859            };
15860            buffer
15861                .update(cx, |buffer, cx| {
15862                    // check if we need this
15863                    if let Some(transaction) = transaction {
15864                        if !buffer.is_singleton() {
15865                            buffer.push_transaction(&transaction.0, cx);
15866                        }
15867                    }
15868                    cx.notify();
15869                })
15870                .ok();
15871            Ok(())
15872        })
15873    }
15874
15875    fn restart_language_server(
15876        &mut self,
15877        _: &RestartLanguageServer,
15878        _: &mut Window,
15879        cx: &mut Context<Self>,
15880    ) {
15881        if let Some(project) = self.project.clone() {
15882            self.buffer.update(cx, |multi_buffer, cx| {
15883                project.update(cx, |project, cx| {
15884                    project.restart_language_servers_for_buffers(
15885                        multi_buffer.all_buffers().into_iter().collect(),
15886                        cx,
15887                    );
15888                });
15889            })
15890        }
15891    }
15892
15893    fn stop_language_server(
15894        &mut self,
15895        _: &StopLanguageServer,
15896        _: &mut Window,
15897        cx: &mut Context<Self>,
15898    ) {
15899        if let Some(project) = self.project.clone() {
15900            self.buffer.update(cx, |multi_buffer, cx| {
15901                project.update(cx, |project, cx| {
15902                    project.stop_language_servers_for_buffers(
15903                        multi_buffer.all_buffers().into_iter().collect(),
15904                        cx,
15905                    );
15906                    cx.emit(project::Event::RefreshInlayHints);
15907                });
15908            });
15909        }
15910    }
15911
15912    fn cancel_language_server_work(
15913        workspace: &mut Workspace,
15914        _: &actions::CancelLanguageServerWork,
15915        _: &mut Window,
15916        cx: &mut Context<Workspace>,
15917    ) {
15918        let project = workspace.project();
15919        let buffers = workspace
15920            .active_item(cx)
15921            .and_then(|item| item.act_as::<Editor>(cx))
15922            .map_or(HashSet::default(), |editor| {
15923                editor.read(cx).buffer.read(cx).all_buffers()
15924            });
15925        project.update(cx, |project, cx| {
15926            project.cancel_language_server_work_for_buffers(buffers, cx);
15927        });
15928    }
15929
15930    fn show_character_palette(
15931        &mut self,
15932        _: &ShowCharacterPalette,
15933        window: &mut Window,
15934        _: &mut Context<Self>,
15935    ) {
15936        window.show_character_palette();
15937    }
15938
15939    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15940        if self.mode.is_minimap() {
15941            return;
15942        }
15943
15944        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15945            let buffer = self.buffer.read(cx).snapshot(cx);
15946            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15947            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15948            let is_valid = buffer
15949                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15950                .any(|entry| {
15951                    entry.diagnostic.is_primary
15952                        && !entry.range.is_empty()
15953                        && entry.range.start == primary_range_start
15954                        && entry.diagnostic.message == active_diagnostics.active_message
15955                });
15956
15957            if !is_valid {
15958                self.dismiss_diagnostics(cx);
15959            }
15960        }
15961    }
15962
15963    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15964        match &self.active_diagnostics {
15965            ActiveDiagnostic::Group(group) => Some(group),
15966            _ => None,
15967        }
15968    }
15969
15970    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15971        self.dismiss_diagnostics(cx);
15972        self.active_diagnostics = ActiveDiagnostic::All;
15973    }
15974
15975    fn activate_diagnostics(
15976        &mut self,
15977        buffer_id: BufferId,
15978        diagnostic: DiagnosticEntry<usize>,
15979        window: &mut Window,
15980        cx: &mut Context<Self>,
15981    ) {
15982        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15983            return;
15984        }
15985        self.dismiss_diagnostics(cx);
15986        let snapshot = self.snapshot(window, cx);
15987        let buffer = self.buffer.read(cx).snapshot(cx);
15988        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15989            return;
15990        };
15991
15992        let diagnostic_group = buffer
15993            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15994            .collect::<Vec<_>>();
15995
15996        let blocks =
15997            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15998
15999        let blocks = self.display_map.update(cx, |display_map, cx| {
16000            display_map.insert_blocks(blocks, cx).into_iter().collect()
16001        });
16002        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16003            active_range: buffer.anchor_before(diagnostic.range.start)
16004                ..buffer.anchor_after(diagnostic.range.end),
16005            active_message: diagnostic.diagnostic.message.clone(),
16006            group_id: diagnostic.diagnostic.group_id,
16007            blocks,
16008        });
16009        cx.notify();
16010    }
16011
16012    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16013        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16014            return;
16015        };
16016
16017        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16018        if let ActiveDiagnostic::Group(group) = prev {
16019            self.display_map.update(cx, |display_map, cx| {
16020                display_map.remove_blocks(group.blocks, cx);
16021            });
16022            cx.notify();
16023        }
16024    }
16025
16026    /// Disable inline diagnostics rendering for this editor.
16027    pub fn disable_inline_diagnostics(&mut self) {
16028        self.inline_diagnostics_enabled = false;
16029        self.inline_diagnostics_update = Task::ready(());
16030        self.inline_diagnostics.clear();
16031    }
16032
16033    pub fn diagnostics_enabled(&self) -> bool {
16034        self.mode.is_full()
16035    }
16036
16037    pub fn inline_diagnostics_enabled(&self) -> bool {
16038        self.diagnostics_enabled() && self.inline_diagnostics_enabled
16039    }
16040
16041    pub fn show_inline_diagnostics(&self) -> bool {
16042        self.show_inline_diagnostics
16043    }
16044
16045    pub fn toggle_inline_diagnostics(
16046        &mut self,
16047        _: &ToggleInlineDiagnostics,
16048        window: &mut Window,
16049        cx: &mut Context<Editor>,
16050    ) {
16051        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16052        self.refresh_inline_diagnostics(false, window, cx);
16053    }
16054
16055    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16056        self.diagnostics_max_severity = severity;
16057        self.display_map.update(cx, |display_map, _| {
16058            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16059        });
16060    }
16061
16062    pub fn toggle_diagnostics(
16063        &mut self,
16064        _: &ToggleDiagnostics,
16065        window: &mut Window,
16066        cx: &mut Context<Editor>,
16067    ) {
16068        if !self.diagnostics_enabled() {
16069            return;
16070        }
16071
16072        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16073            EditorSettings::get_global(cx)
16074                .diagnostics_max_severity
16075                .filter(|severity| severity != &DiagnosticSeverity::Off)
16076                .unwrap_or(DiagnosticSeverity::Hint)
16077        } else {
16078            DiagnosticSeverity::Off
16079        };
16080        self.set_max_diagnostics_severity(new_severity, cx);
16081        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16082            self.active_diagnostics = ActiveDiagnostic::None;
16083            self.inline_diagnostics_update = Task::ready(());
16084            self.inline_diagnostics.clear();
16085        } else {
16086            self.refresh_inline_diagnostics(false, window, cx);
16087        }
16088
16089        cx.notify();
16090    }
16091
16092    pub fn toggle_minimap(
16093        &mut self,
16094        _: &ToggleMinimap,
16095        window: &mut Window,
16096        cx: &mut Context<Editor>,
16097    ) {
16098        if self.supports_minimap(cx) {
16099            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16100        }
16101    }
16102
16103    fn refresh_inline_diagnostics(
16104        &mut self,
16105        debounce: bool,
16106        window: &mut Window,
16107        cx: &mut Context<Self>,
16108    ) {
16109        let max_severity = ProjectSettings::get_global(cx)
16110            .diagnostics
16111            .inline
16112            .max_severity
16113            .unwrap_or(self.diagnostics_max_severity);
16114
16115        if !self.inline_diagnostics_enabled()
16116            || !self.show_inline_diagnostics
16117            || max_severity == DiagnosticSeverity::Off
16118        {
16119            self.inline_diagnostics_update = Task::ready(());
16120            self.inline_diagnostics.clear();
16121            return;
16122        }
16123
16124        let debounce_ms = ProjectSettings::get_global(cx)
16125            .diagnostics
16126            .inline
16127            .update_debounce_ms;
16128        let debounce = if debounce && debounce_ms > 0 {
16129            Some(Duration::from_millis(debounce_ms))
16130        } else {
16131            None
16132        };
16133        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16134            if let Some(debounce) = debounce {
16135                cx.background_executor().timer(debounce).await;
16136            }
16137            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16138                editor
16139                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16140                    .ok()
16141            }) else {
16142                return;
16143            };
16144
16145            let new_inline_diagnostics = cx
16146                .background_spawn(async move {
16147                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16148                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16149                        let message = diagnostic_entry
16150                            .diagnostic
16151                            .message
16152                            .split_once('\n')
16153                            .map(|(line, _)| line)
16154                            .map(SharedString::new)
16155                            .unwrap_or_else(|| {
16156                                SharedString::from(diagnostic_entry.diagnostic.message)
16157                            });
16158                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16159                        let (Ok(i) | Err(i)) = inline_diagnostics
16160                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16161                        inline_diagnostics.insert(
16162                            i,
16163                            (
16164                                start_anchor,
16165                                InlineDiagnostic {
16166                                    message,
16167                                    group_id: diagnostic_entry.diagnostic.group_id,
16168                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16169                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16170                                    severity: diagnostic_entry.diagnostic.severity,
16171                                },
16172                            ),
16173                        );
16174                    }
16175                    inline_diagnostics
16176                })
16177                .await;
16178
16179            editor
16180                .update(cx, |editor, cx| {
16181                    editor.inline_diagnostics = new_inline_diagnostics;
16182                    cx.notify();
16183                })
16184                .ok();
16185        });
16186    }
16187
16188    fn pull_diagnostics(
16189        &mut self,
16190        buffer_id: Option<BufferId>,
16191        window: &Window,
16192        cx: &mut Context<Self>,
16193    ) -> Option<()> {
16194        if !self.mode().is_full() {
16195            return None;
16196        }
16197        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16198            .diagnostics
16199            .lsp_pull_diagnostics;
16200        if !pull_diagnostics_settings.enabled {
16201            return None;
16202        }
16203        let project = self.project.as_ref()?.downgrade();
16204        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16205        let mut buffers = self.buffer.read(cx).all_buffers();
16206        if let Some(buffer_id) = buffer_id {
16207            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16208        }
16209
16210        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16211            cx.background_executor().timer(debounce).await;
16212
16213            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16214                buffers
16215                    .into_iter()
16216                    .flat_map(|buffer| {
16217                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16218                    })
16219                    .collect::<FuturesUnordered<_>>()
16220            }) else {
16221                return;
16222            };
16223
16224            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16225                match pull_task {
16226                    Ok(()) => {
16227                        if editor
16228                            .update_in(cx, |editor, window, cx| {
16229                                editor.update_diagnostics_state(window, cx);
16230                            })
16231                            .is_err()
16232                        {
16233                            return;
16234                        }
16235                    }
16236                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16237                }
16238            }
16239        });
16240
16241        Some(())
16242    }
16243
16244    pub fn set_selections_from_remote(
16245        &mut self,
16246        selections: Vec<Selection<Anchor>>,
16247        pending_selection: Option<Selection<Anchor>>,
16248        window: &mut Window,
16249        cx: &mut Context<Self>,
16250    ) {
16251        let old_cursor_position = self.selections.newest_anchor().head();
16252        self.selections.change_with(cx, |s| {
16253            s.select_anchors(selections);
16254            if let Some(pending_selection) = pending_selection {
16255                s.set_pending(pending_selection, SelectMode::Character);
16256            } else {
16257                s.clear_pending();
16258            }
16259        });
16260        self.selections_did_change(
16261            false,
16262            &old_cursor_position,
16263            SelectionEffects::default(),
16264            window,
16265            cx,
16266        );
16267    }
16268
16269    pub fn transact(
16270        &mut self,
16271        window: &mut Window,
16272        cx: &mut Context<Self>,
16273        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16274    ) -> Option<TransactionId> {
16275        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16276            this.start_transaction_at(Instant::now(), window, cx);
16277            update(this, window, cx);
16278            this.end_transaction_at(Instant::now(), cx)
16279        })
16280    }
16281
16282    pub fn start_transaction_at(
16283        &mut self,
16284        now: Instant,
16285        window: &mut Window,
16286        cx: &mut Context<Self>,
16287    ) {
16288        self.end_selection(window, cx);
16289        if let Some(tx_id) = self
16290            .buffer
16291            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16292        {
16293            self.selection_history
16294                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16295            cx.emit(EditorEvent::TransactionBegun {
16296                transaction_id: tx_id,
16297            })
16298        }
16299    }
16300
16301    pub fn end_transaction_at(
16302        &mut self,
16303        now: Instant,
16304        cx: &mut Context<Self>,
16305    ) -> Option<TransactionId> {
16306        if let Some(transaction_id) = self
16307            .buffer
16308            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16309        {
16310            if let Some((_, end_selections)) =
16311                self.selection_history.transaction_mut(transaction_id)
16312            {
16313                *end_selections = Some(self.selections.disjoint_anchors());
16314            } else {
16315                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16316            }
16317
16318            cx.emit(EditorEvent::Edited { transaction_id });
16319            Some(transaction_id)
16320        } else {
16321            None
16322        }
16323    }
16324
16325    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16326        if self.selection_mark_mode {
16327            self.change_selections(None, window, cx, |s| {
16328                s.move_with(|_, sel| {
16329                    sel.collapse_to(sel.head(), SelectionGoal::None);
16330                });
16331            })
16332        }
16333        self.selection_mark_mode = true;
16334        cx.notify();
16335    }
16336
16337    pub fn swap_selection_ends(
16338        &mut self,
16339        _: &actions::SwapSelectionEnds,
16340        window: &mut Window,
16341        cx: &mut Context<Self>,
16342    ) {
16343        self.change_selections(None, window, cx, |s| {
16344            s.move_with(|_, sel| {
16345                if sel.start != sel.end {
16346                    sel.reversed = !sel.reversed
16347                }
16348            });
16349        });
16350        self.request_autoscroll(Autoscroll::newest(), cx);
16351        cx.notify();
16352    }
16353
16354    pub fn toggle_fold(
16355        &mut self,
16356        _: &actions::ToggleFold,
16357        window: &mut Window,
16358        cx: &mut Context<Self>,
16359    ) {
16360        if self.is_singleton(cx) {
16361            let selection = self.selections.newest::<Point>(cx);
16362
16363            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16364            let range = if selection.is_empty() {
16365                let point = selection.head().to_display_point(&display_map);
16366                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16367                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16368                    .to_point(&display_map);
16369                start..end
16370            } else {
16371                selection.range()
16372            };
16373            if display_map.folds_in_range(range).next().is_some() {
16374                self.unfold_lines(&Default::default(), window, cx)
16375            } else {
16376                self.fold(&Default::default(), window, cx)
16377            }
16378        } else {
16379            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16380            let buffer_ids: HashSet<_> = self
16381                .selections
16382                .disjoint_anchor_ranges()
16383                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16384                .collect();
16385
16386            let should_unfold = buffer_ids
16387                .iter()
16388                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16389
16390            for buffer_id in buffer_ids {
16391                if should_unfold {
16392                    self.unfold_buffer(buffer_id, cx);
16393                } else {
16394                    self.fold_buffer(buffer_id, cx);
16395                }
16396            }
16397        }
16398    }
16399
16400    pub fn toggle_fold_recursive(
16401        &mut self,
16402        _: &actions::ToggleFoldRecursive,
16403        window: &mut Window,
16404        cx: &mut Context<Self>,
16405    ) {
16406        let selection = self.selections.newest::<Point>(cx);
16407
16408        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16409        let range = if selection.is_empty() {
16410            let point = selection.head().to_display_point(&display_map);
16411            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16412            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16413                .to_point(&display_map);
16414            start..end
16415        } else {
16416            selection.range()
16417        };
16418        if display_map.folds_in_range(range).next().is_some() {
16419            self.unfold_recursive(&Default::default(), window, cx)
16420        } else {
16421            self.fold_recursive(&Default::default(), window, cx)
16422        }
16423    }
16424
16425    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16426        if self.is_singleton(cx) {
16427            let mut to_fold = Vec::new();
16428            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16429            let selections = self.selections.all_adjusted(cx);
16430
16431            for selection in selections {
16432                let range = selection.range().sorted();
16433                let buffer_start_row = range.start.row;
16434
16435                if range.start.row != range.end.row {
16436                    let mut found = false;
16437                    let mut row = range.start.row;
16438                    while row <= range.end.row {
16439                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16440                        {
16441                            found = true;
16442                            row = crease.range().end.row + 1;
16443                            to_fold.push(crease);
16444                        } else {
16445                            row += 1
16446                        }
16447                    }
16448                    if found {
16449                        continue;
16450                    }
16451                }
16452
16453                for row in (0..=range.start.row).rev() {
16454                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16455                        if crease.range().end.row >= buffer_start_row {
16456                            to_fold.push(crease);
16457                            if row <= range.start.row {
16458                                break;
16459                            }
16460                        }
16461                    }
16462                }
16463            }
16464
16465            self.fold_creases(to_fold, true, window, cx);
16466        } else {
16467            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16468            let buffer_ids = self
16469                .selections
16470                .disjoint_anchor_ranges()
16471                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16472                .collect::<HashSet<_>>();
16473            for buffer_id in buffer_ids {
16474                self.fold_buffer(buffer_id, cx);
16475            }
16476        }
16477    }
16478
16479    fn fold_at_level(
16480        &mut self,
16481        fold_at: &FoldAtLevel,
16482        window: &mut Window,
16483        cx: &mut Context<Self>,
16484    ) {
16485        if !self.buffer.read(cx).is_singleton() {
16486            return;
16487        }
16488
16489        let fold_at_level = fold_at.0;
16490        let snapshot = self.buffer.read(cx).snapshot(cx);
16491        let mut to_fold = Vec::new();
16492        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16493
16494        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16495            while start_row < end_row {
16496                match self
16497                    .snapshot(window, cx)
16498                    .crease_for_buffer_row(MultiBufferRow(start_row))
16499                {
16500                    Some(crease) => {
16501                        let nested_start_row = crease.range().start.row + 1;
16502                        let nested_end_row = crease.range().end.row;
16503
16504                        if current_level < fold_at_level {
16505                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16506                        } else if current_level == fold_at_level {
16507                            to_fold.push(crease);
16508                        }
16509
16510                        start_row = nested_end_row + 1;
16511                    }
16512                    None => start_row += 1,
16513                }
16514            }
16515        }
16516
16517        self.fold_creases(to_fold, true, window, cx);
16518    }
16519
16520    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16521        if self.buffer.read(cx).is_singleton() {
16522            let mut fold_ranges = Vec::new();
16523            let snapshot = self.buffer.read(cx).snapshot(cx);
16524
16525            for row in 0..snapshot.max_row().0 {
16526                if let Some(foldable_range) = self
16527                    .snapshot(window, cx)
16528                    .crease_for_buffer_row(MultiBufferRow(row))
16529                {
16530                    fold_ranges.push(foldable_range);
16531                }
16532            }
16533
16534            self.fold_creases(fold_ranges, true, window, cx);
16535        } else {
16536            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16537                editor
16538                    .update_in(cx, |editor, _, cx| {
16539                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16540                            editor.fold_buffer(buffer_id, cx);
16541                        }
16542                    })
16543                    .ok();
16544            });
16545        }
16546    }
16547
16548    pub fn fold_function_bodies(
16549        &mut self,
16550        _: &actions::FoldFunctionBodies,
16551        window: &mut Window,
16552        cx: &mut Context<Self>,
16553    ) {
16554        let snapshot = self.buffer.read(cx).snapshot(cx);
16555
16556        let ranges = snapshot
16557            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16558            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16559            .collect::<Vec<_>>();
16560
16561        let creases = ranges
16562            .into_iter()
16563            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16564            .collect();
16565
16566        self.fold_creases(creases, true, window, cx);
16567    }
16568
16569    pub fn fold_recursive(
16570        &mut self,
16571        _: &actions::FoldRecursive,
16572        window: &mut Window,
16573        cx: &mut Context<Self>,
16574    ) {
16575        let mut to_fold = Vec::new();
16576        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16577        let selections = self.selections.all_adjusted(cx);
16578
16579        for selection in selections {
16580            let range = selection.range().sorted();
16581            let buffer_start_row = range.start.row;
16582
16583            if range.start.row != range.end.row {
16584                let mut found = false;
16585                for row in range.start.row..=range.end.row {
16586                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16587                        found = true;
16588                        to_fold.push(crease);
16589                    }
16590                }
16591                if found {
16592                    continue;
16593                }
16594            }
16595
16596            for row in (0..=range.start.row).rev() {
16597                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16598                    if crease.range().end.row >= buffer_start_row {
16599                        to_fold.push(crease);
16600                    } else {
16601                        break;
16602                    }
16603                }
16604            }
16605        }
16606
16607        self.fold_creases(to_fold, true, window, cx);
16608    }
16609
16610    pub fn fold_at(
16611        &mut self,
16612        buffer_row: MultiBufferRow,
16613        window: &mut Window,
16614        cx: &mut Context<Self>,
16615    ) {
16616        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16617
16618        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16619            let autoscroll = self
16620                .selections
16621                .all::<Point>(cx)
16622                .iter()
16623                .any(|selection| crease.range().overlaps(&selection.range()));
16624
16625            self.fold_creases(vec![crease], autoscroll, window, cx);
16626        }
16627    }
16628
16629    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16630        if self.is_singleton(cx) {
16631            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16632            let buffer = &display_map.buffer_snapshot;
16633            let selections = self.selections.all::<Point>(cx);
16634            let ranges = selections
16635                .iter()
16636                .map(|s| {
16637                    let range = s.display_range(&display_map).sorted();
16638                    let mut start = range.start.to_point(&display_map);
16639                    let mut end = range.end.to_point(&display_map);
16640                    start.column = 0;
16641                    end.column = buffer.line_len(MultiBufferRow(end.row));
16642                    start..end
16643                })
16644                .collect::<Vec<_>>();
16645
16646            self.unfold_ranges(&ranges, true, true, cx);
16647        } else {
16648            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16649            let buffer_ids = self
16650                .selections
16651                .disjoint_anchor_ranges()
16652                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16653                .collect::<HashSet<_>>();
16654            for buffer_id in buffer_ids {
16655                self.unfold_buffer(buffer_id, cx);
16656            }
16657        }
16658    }
16659
16660    pub fn unfold_recursive(
16661        &mut self,
16662        _: &UnfoldRecursive,
16663        _window: &mut Window,
16664        cx: &mut Context<Self>,
16665    ) {
16666        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16667        let selections = self.selections.all::<Point>(cx);
16668        let ranges = selections
16669            .iter()
16670            .map(|s| {
16671                let mut range = s.display_range(&display_map).sorted();
16672                *range.start.column_mut() = 0;
16673                *range.end.column_mut() = display_map.line_len(range.end.row());
16674                let start = range.start.to_point(&display_map);
16675                let end = range.end.to_point(&display_map);
16676                start..end
16677            })
16678            .collect::<Vec<_>>();
16679
16680        self.unfold_ranges(&ranges, true, true, cx);
16681    }
16682
16683    pub fn unfold_at(
16684        &mut self,
16685        buffer_row: MultiBufferRow,
16686        _window: &mut Window,
16687        cx: &mut Context<Self>,
16688    ) {
16689        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16690
16691        let intersection_range = Point::new(buffer_row.0, 0)
16692            ..Point::new(
16693                buffer_row.0,
16694                display_map.buffer_snapshot.line_len(buffer_row),
16695            );
16696
16697        let autoscroll = self
16698            .selections
16699            .all::<Point>(cx)
16700            .iter()
16701            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16702
16703        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16704    }
16705
16706    pub fn unfold_all(
16707        &mut self,
16708        _: &actions::UnfoldAll,
16709        _window: &mut Window,
16710        cx: &mut Context<Self>,
16711    ) {
16712        if self.buffer.read(cx).is_singleton() {
16713            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16714            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16715        } else {
16716            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16717                editor
16718                    .update(cx, |editor, cx| {
16719                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16720                            editor.unfold_buffer(buffer_id, cx);
16721                        }
16722                    })
16723                    .ok();
16724            });
16725        }
16726    }
16727
16728    pub fn fold_selected_ranges(
16729        &mut self,
16730        _: &FoldSelectedRanges,
16731        window: &mut Window,
16732        cx: &mut Context<Self>,
16733    ) {
16734        let selections = self.selections.all_adjusted(cx);
16735        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16736        let ranges = selections
16737            .into_iter()
16738            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16739            .collect::<Vec<_>>();
16740        self.fold_creases(ranges, true, window, cx);
16741    }
16742
16743    pub fn fold_ranges<T: ToOffset + Clone>(
16744        &mut self,
16745        ranges: Vec<Range<T>>,
16746        auto_scroll: bool,
16747        window: &mut Window,
16748        cx: &mut Context<Self>,
16749    ) {
16750        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16751        let ranges = ranges
16752            .into_iter()
16753            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16754            .collect::<Vec<_>>();
16755        self.fold_creases(ranges, auto_scroll, window, cx);
16756    }
16757
16758    pub fn fold_creases<T: ToOffset + Clone>(
16759        &mut self,
16760        creases: Vec<Crease<T>>,
16761        auto_scroll: bool,
16762        _window: &mut Window,
16763        cx: &mut Context<Self>,
16764    ) {
16765        if creases.is_empty() {
16766            return;
16767        }
16768
16769        let mut buffers_affected = HashSet::default();
16770        let multi_buffer = self.buffer().read(cx);
16771        for crease in &creases {
16772            if let Some((_, buffer, _)) =
16773                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16774            {
16775                buffers_affected.insert(buffer.read(cx).remote_id());
16776            };
16777        }
16778
16779        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16780
16781        if auto_scroll {
16782            self.request_autoscroll(Autoscroll::fit(), cx);
16783        }
16784
16785        cx.notify();
16786
16787        self.scrollbar_marker_state.dirty = true;
16788        self.folds_did_change(cx);
16789    }
16790
16791    /// Removes any folds whose ranges intersect any of the given ranges.
16792    pub fn unfold_ranges<T: ToOffset + Clone>(
16793        &mut self,
16794        ranges: &[Range<T>],
16795        inclusive: bool,
16796        auto_scroll: bool,
16797        cx: &mut Context<Self>,
16798    ) {
16799        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16800            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16801        });
16802        self.folds_did_change(cx);
16803    }
16804
16805    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16806        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16807            return;
16808        }
16809        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16810        self.display_map.update(cx, |display_map, cx| {
16811            display_map.fold_buffers([buffer_id], cx)
16812        });
16813        cx.emit(EditorEvent::BufferFoldToggled {
16814            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16815            folded: true,
16816        });
16817        cx.notify();
16818    }
16819
16820    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16821        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16822            return;
16823        }
16824        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16825        self.display_map.update(cx, |display_map, cx| {
16826            display_map.unfold_buffers([buffer_id], cx);
16827        });
16828        cx.emit(EditorEvent::BufferFoldToggled {
16829            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16830            folded: false,
16831        });
16832        cx.notify();
16833    }
16834
16835    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16836        self.display_map.read(cx).is_buffer_folded(buffer)
16837    }
16838
16839    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16840        self.display_map.read(cx).folded_buffers()
16841    }
16842
16843    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16844        self.display_map.update(cx, |display_map, cx| {
16845            display_map.disable_header_for_buffer(buffer_id, cx);
16846        });
16847        cx.notify();
16848    }
16849
16850    /// Removes any folds with the given ranges.
16851    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16852        &mut self,
16853        ranges: &[Range<T>],
16854        type_id: TypeId,
16855        auto_scroll: bool,
16856        cx: &mut Context<Self>,
16857    ) {
16858        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16859            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16860        });
16861        self.folds_did_change(cx);
16862    }
16863
16864    fn remove_folds_with<T: ToOffset + Clone>(
16865        &mut self,
16866        ranges: &[Range<T>],
16867        auto_scroll: bool,
16868        cx: &mut Context<Self>,
16869        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16870    ) {
16871        if ranges.is_empty() {
16872            return;
16873        }
16874
16875        let mut buffers_affected = HashSet::default();
16876        let multi_buffer = self.buffer().read(cx);
16877        for range in ranges {
16878            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16879                buffers_affected.insert(buffer.read(cx).remote_id());
16880            };
16881        }
16882
16883        self.display_map.update(cx, update);
16884
16885        if auto_scroll {
16886            self.request_autoscroll(Autoscroll::fit(), cx);
16887        }
16888
16889        cx.notify();
16890        self.scrollbar_marker_state.dirty = true;
16891        self.active_indent_guides_state.dirty = true;
16892    }
16893
16894    pub fn update_fold_widths(
16895        &mut self,
16896        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16897        cx: &mut Context<Self>,
16898    ) -> bool {
16899        self.display_map
16900            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16901    }
16902
16903    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16904        self.display_map.read(cx).fold_placeholder.clone()
16905    }
16906
16907    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16908        self.buffer.update(cx, |buffer, cx| {
16909            buffer.set_all_diff_hunks_expanded(cx);
16910        });
16911    }
16912
16913    pub fn expand_all_diff_hunks(
16914        &mut self,
16915        _: &ExpandAllDiffHunks,
16916        _window: &mut Window,
16917        cx: &mut Context<Self>,
16918    ) {
16919        self.buffer.update(cx, |buffer, cx| {
16920            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16921        });
16922    }
16923
16924    pub fn toggle_selected_diff_hunks(
16925        &mut self,
16926        _: &ToggleSelectedDiffHunks,
16927        _window: &mut Window,
16928        cx: &mut Context<Self>,
16929    ) {
16930        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16931        self.toggle_diff_hunks_in_ranges(ranges, cx);
16932    }
16933
16934    pub fn diff_hunks_in_ranges<'a>(
16935        &'a self,
16936        ranges: &'a [Range<Anchor>],
16937        buffer: &'a MultiBufferSnapshot,
16938    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16939        ranges.iter().flat_map(move |range| {
16940            let end_excerpt_id = range.end.excerpt_id;
16941            let range = range.to_point(buffer);
16942            let mut peek_end = range.end;
16943            if range.end.row < buffer.max_row().0 {
16944                peek_end = Point::new(range.end.row + 1, 0);
16945            }
16946            buffer
16947                .diff_hunks_in_range(range.start..peek_end)
16948                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16949        })
16950    }
16951
16952    pub fn has_stageable_diff_hunks_in_ranges(
16953        &self,
16954        ranges: &[Range<Anchor>],
16955        snapshot: &MultiBufferSnapshot,
16956    ) -> bool {
16957        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16958        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16959    }
16960
16961    pub fn toggle_staged_selected_diff_hunks(
16962        &mut self,
16963        _: &::git::ToggleStaged,
16964        _: &mut Window,
16965        cx: &mut Context<Self>,
16966    ) {
16967        let snapshot = self.buffer.read(cx).snapshot(cx);
16968        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16969        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16970        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16971    }
16972
16973    pub fn set_render_diff_hunk_controls(
16974        &mut self,
16975        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16976        cx: &mut Context<Self>,
16977    ) {
16978        self.render_diff_hunk_controls = render_diff_hunk_controls;
16979        cx.notify();
16980    }
16981
16982    pub fn stage_and_next(
16983        &mut self,
16984        _: &::git::StageAndNext,
16985        window: &mut Window,
16986        cx: &mut Context<Self>,
16987    ) {
16988        self.do_stage_or_unstage_and_next(true, window, cx);
16989    }
16990
16991    pub fn unstage_and_next(
16992        &mut self,
16993        _: &::git::UnstageAndNext,
16994        window: &mut Window,
16995        cx: &mut Context<Self>,
16996    ) {
16997        self.do_stage_or_unstage_and_next(false, window, cx);
16998    }
16999
17000    pub fn stage_or_unstage_diff_hunks(
17001        &mut self,
17002        stage: bool,
17003        ranges: Vec<Range<Anchor>>,
17004        cx: &mut Context<Self>,
17005    ) {
17006        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17007        cx.spawn(async move |this, cx| {
17008            task.await?;
17009            this.update(cx, |this, cx| {
17010                let snapshot = this.buffer.read(cx).snapshot(cx);
17011                let chunk_by = this
17012                    .diff_hunks_in_ranges(&ranges, &snapshot)
17013                    .chunk_by(|hunk| hunk.buffer_id);
17014                for (buffer_id, hunks) in &chunk_by {
17015                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17016                }
17017            })
17018        })
17019        .detach_and_log_err(cx);
17020    }
17021
17022    fn save_buffers_for_ranges_if_needed(
17023        &mut self,
17024        ranges: &[Range<Anchor>],
17025        cx: &mut Context<Editor>,
17026    ) -> Task<Result<()>> {
17027        let multibuffer = self.buffer.read(cx);
17028        let snapshot = multibuffer.read(cx);
17029        let buffer_ids: HashSet<_> = ranges
17030            .iter()
17031            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17032            .collect();
17033        drop(snapshot);
17034
17035        let mut buffers = HashSet::default();
17036        for buffer_id in buffer_ids {
17037            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17038                let buffer = buffer_entity.read(cx);
17039                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17040                {
17041                    buffers.insert(buffer_entity);
17042                }
17043            }
17044        }
17045
17046        if let Some(project) = &self.project {
17047            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17048        } else {
17049            Task::ready(Ok(()))
17050        }
17051    }
17052
17053    fn do_stage_or_unstage_and_next(
17054        &mut self,
17055        stage: bool,
17056        window: &mut Window,
17057        cx: &mut Context<Self>,
17058    ) {
17059        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17060
17061        if ranges.iter().any(|range| range.start != range.end) {
17062            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17063            return;
17064        }
17065
17066        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17067        let snapshot = self.snapshot(window, cx);
17068        let position = self.selections.newest::<Point>(cx).head();
17069        let mut row = snapshot
17070            .buffer_snapshot
17071            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17072            .find(|hunk| hunk.row_range.start.0 > position.row)
17073            .map(|hunk| hunk.row_range.start);
17074
17075        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17076        // Outside of the project diff editor, wrap around to the beginning.
17077        if !all_diff_hunks_expanded {
17078            row = row.or_else(|| {
17079                snapshot
17080                    .buffer_snapshot
17081                    .diff_hunks_in_range(Point::zero()..position)
17082                    .find(|hunk| hunk.row_range.end.0 < position.row)
17083                    .map(|hunk| hunk.row_range.start)
17084            });
17085        }
17086
17087        if let Some(row) = row {
17088            let destination = Point::new(row.0, 0);
17089            let autoscroll = Autoscroll::center();
17090
17091            self.unfold_ranges(&[destination..destination], false, false, cx);
17092            self.change_selections(Some(autoscroll), window, cx, |s| {
17093                s.select_ranges([destination..destination]);
17094            });
17095        }
17096    }
17097
17098    fn do_stage_or_unstage(
17099        &self,
17100        stage: bool,
17101        buffer_id: BufferId,
17102        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17103        cx: &mut App,
17104    ) -> Option<()> {
17105        let project = self.project.as_ref()?;
17106        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17107        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17108        let buffer_snapshot = buffer.read(cx).snapshot();
17109        let file_exists = buffer_snapshot
17110            .file()
17111            .is_some_and(|file| file.disk_state().exists());
17112        diff.update(cx, |diff, cx| {
17113            diff.stage_or_unstage_hunks(
17114                stage,
17115                &hunks
17116                    .map(|hunk| buffer_diff::DiffHunk {
17117                        buffer_range: hunk.buffer_range,
17118                        diff_base_byte_range: hunk.diff_base_byte_range,
17119                        secondary_status: hunk.secondary_status,
17120                        range: Point::zero()..Point::zero(), // unused
17121                    })
17122                    .collect::<Vec<_>>(),
17123                &buffer_snapshot,
17124                file_exists,
17125                cx,
17126            )
17127        });
17128        None
17129    }
17130
17131    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17132        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17133        self.buffer
17134            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17135    }
17136
17137    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17138        self.buffer.update(cx, |buffer, cx| {
17139            let ranges = vec![Anchor::min()..Anchor::max()];
17140            if !buffer.all_diff_hunks_expanded()
17141                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17142            {
17143                buffer.collapse_diff_hunks(ranges, cx);
17144                true
17145            } else {
17146                false
17147            }
17148        })
17149    }
17150
17151    fn toggle_diff_hunks_in_ranges(
17152        &mut self,
17153        ranges: Vec<Range<Anchor>>,
17154        cx: &mut Context<Editor>,
17155    ) {
17156        self.buffer.update(cx, |buffer, cx| {
17157            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17158            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17159        })
17160    }
17161
17162    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17163        self.buffer.update(cx, |buffer, cx| {
17164            let snapshot = buffer.snapshot(cx);
17165            let excerpt_id = range.end.excerpt_id;
17166            let point_range = range.to_point(&snapshot);
17167            let expand = !buffer.single_hunk_is_expanded(range, cx);
17168            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17169        })
17170    }
17171
17172    pub(crate) fn apply_all_diff_hunks(
17173        &mut self,
17174        _: &ApplyAllDiffHunks,
17175        window: &mut Window,
17176        cx: &mut Context<Self>,
17177    ) {
17178        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17179
17180        let buffers = self.buffer.read(cx).all_buffers();
17181        for branch_buffer in buffers {
17182            branch_buffer.update(cx, |branch_buffer, cx| {
17183                branch_buffer.merge_into_base(Vec::new(), cx);
17184            });
17185        }
17186
17187        if let Some(project) = self.project.clone() {
17188            self.save(
17189                SaveOptions {
17190                    format: true,
17191                    autosave: false,
17192                },
17193                project,
17194                window,
17195                cx,
17196            )
17197            .detach_and_log_err(cx);
17198        }
17199    }
17200
17201    pub(crate) fn apply_selected_diff_hunks(
17202        &mut self,
17203        _: &ApplyDiffHunk,
17204        window: &mut Window,
17205        cx: &mut Context<Self>,
17206    ) {
17207        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17208        let snapshot = self.snapshot(window, cx);
17209        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17210        let mut ranges_by_buffer = HashMap::default();
17211        self.transact(window, cx, |editor, _window, cx| {
17212            for hunk in hunks {
17213                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17214                    ranges_by_buffer
17215                        .entry(buffer.clone())
17216                        .or_insert_with(Vec::new)
17217                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17218                }
17219            }
17220
17221            for (buffer, ranges) in ranges_by_buffer {
17222                buffer.update(cx, |buffer, cx| {
17223                    buffer.merge_into_base(ranges, cx);
17224                });
17225            }
17226        });
17227
17228        if let Some(project) = self.project.clone() {
17229            self.save(
17230                SaveOptions {
17231                    format: true,
17232                    autosave: false,
17233                },
17234                project,
17235                window,
17236                cx,
17237            )
17238            .detach_and_log_err(cx);
17239        }
17240    }
17241
17242    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17243        if hovered != self.gutter_hovered {
17244            self.gutter_hovered = hovered;
17245            cx.notify();
17246        }
17247    }
17248
17249    pub fn insert_blocks(
17250        &mut self,
17251        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17252        autoscroll: Option<Autoscroll>,
17253        cx: &mut Context<Self>,
17254    ) -> Vec<CustomBlockId> {
17255        let blocks = self
17256            .display_map
17257            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17258        if let Some(autoscroll) = autoscroll {
17259            self.request_autoscroll(autoscroll, cx);
17260        }
17261        cx.notify();
17262        blocks
17263    }
17264
17265    pub fn resize_blocks(
17266        &mut self,
17267        heights: HashMap<CustomBlockId, u32>,
17268        autoscroll: Option<Autoscroll>,
17269        cx: &mut Context<Self>,
17270    ) {
17271        self.display_map
17272            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17273        if let Some(autoscroll) = autoscroll {
17274            self.request_autoscroll(autoscroll, cx);
17275        }
17276        cx.notify();
17277    }
17278
17279    pub fn replace_blocks(
17280        &mut self,
17281        renderers: HashMap<CustomBlockId, RenderBlock>,
17282        autoscroll: Option<Autoscroll>,
17283        cx: &mut Context<Self>,
17284    ) {
17285        self.display_map
17286            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17287        if let Some(autoscroll) = autoscroll {
17288            self.request_autoscroll(autoscroll, cx);
17289        }
17290        cx.notify();
17291    }
17292
17293    pub fn remove_blocks(
17294        &mut self,
17295        block_ids: HashSet<CustomBlockId>,
17296        autoscroll: Option<Autoscroll>,
17297        cx: &mut Context<Self>,
17298    ) {
17299        self.display_map.update(cx, |display_map, cx| {
17300            display_map.remove_blocks(block_ids, cx)
17301        });
17302        if let Some(autoscroll) = autoscroll {
17303            self.request_autoscroll(autoscroll, cx);
17304        }
17305        cx.notify();
17306    }
17307
17308    pub fn row_for_block(
17309        &self,
17310        block_id: CustomBlockId,
17311        cx: &mut Context<Self>,
17312    ) -> Option<DisplayRow> {
17313        self.display_map
17314            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17315    }
17316
17317    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17318        self.focused_block = Some(focused_block);
17319    }
17320
17321    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17322        self.focused_block.take()
17323    }
17324
17325    pub fn insert_creases(
17326        &mut self,
17327        creases: impl IntoIterator<Item = Crease<Anchor>>,
17328        cx: &mut Context<Self>,
17329    ) -> Vec<CreaseId> {
17330        self.display_map
17331            .update(cx, |map, cx| map.insert_creases(creases, cx))
17332    }
17333
17334    pub fn remove_creases(
17335        &mut self,
17336        ids: impl IntoIterator<Item = CreaseId>,
17337        cx: &mut Context<Self>,
17338    ) -> Vec<(CreaseId, Range<Anchor>)> {
17339        self.display_map
17340            .update(cx, |map, cx| map.remove_creases(ids, cx))
17341    }
17342
17343    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17344        self.display_map
17345            .update(cx, |map, cx| map.snapshot(cx))
17346            .longest_row()
17347    }
17348
17349    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17350        self.display_map
17351            .update(cx, |map, cx| map.snapshot(cx))
17352            .max_point()
17353    }
17354
17355    pub fn text(&self, cx: &App) -> String {
17356        self.buffer.read(cx).read(cx).text()
17357    }
17358
17359    pub fn is_empty(&self, cx: &App) -> bool {
17360        self.buffer.read(cx).read(cx).is_empty()
17361    }
17362
17363    pub fn text_option(&self, cx: &App) -> Option<String> {
17364        let text = self.text(cx);
17365        let text = text.trim();
17366
17367        if text.is_empty() {
17368            return None;
17369        }
17370
17371        Some(text.to_string())
17372    }
17373
17374    pub fn set_text(
17375        &mut self,
17376        text: impl Into<Arc<str>>,
17377        window: &mut Window,
17378        cx: &mut Context<Self>,
17379    ) {
17380        self.transact(window, cx, |this, _, cx| {
17381            this.buffer
17382                .read(cx)
17383                .as_singleton()
17384                .expect("you can only call set_text on editors for singleton buffers")
17385                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17386        });
17387    }
17388
17389    pub fn display_text(&self, cx: &mut App) -> String {
17390        self.display_map
17391            .update(cx, |map, cx| map.snapshot(cx))
17392            .text()
17393    }
17394
17395    fn create_minimap(
17396        &self,
17397        minimap_settings: MinimapSettings,
17398        window: &mut Window,
17399        cx: &mut Context<Self>,
17400    ) -> Option<Entity<Self>> {
17401        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17402            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17403    }
17404
17405    fn initialize_new_minimap(
17406        &self,
17407        minimap_settings: MinimapSettings,
17408        window: &mut Window,
17409        cx: &mut Context<Self>,
17410    ) -> Entity<Self> {
17411        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17412
17413        let mut minimap = Editor::new_internal(
17414            EditorMode::Minimap {
17415                parent: cx.weak_entity(),
17416            },
17417            self.buffer.clone(),
17418            self.project.clone(),
17419            Some(self.display_map.clone()),
17420            window,
17421            cx,
17422        );
17423        minimap.scroll_manager.clone_state(&self.scroll_manager);
17424        minimap.set_text_style_refinement(TextStyleRefinement {
17425            font_size: Some(MINIMAP_FONT_SIZE),
17426            font_weight: Some(MINIMAP_FONT_WEIGHT),
17427            ..Default::default()
17428        });
17429        minimap.update_minimap_configuration(minimap_settings, cx);
17430        cx.new(|_| minimap)
17431    }
17432
17433    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17434        let current_line_highlight = minimap_settings
17435            .current_line_highlight
17436            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17437        self.set_current_line_highlight(Some(current_line_highlight));
17438    }
17439
17440    pub fn minimap(&self) -> Option<&Entity<Self>> {
17441        self.minimap
17442            .as_ref()
17443            .filter(|_| self.minimap_visibility.visible())
17444    }
17445
17446    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17447        let mut wrap_guides = smallvec![];
17448
17449        if self.show_wrap_guides == Some(false) {
17450            return wrap_guides;
17451        }
17452
17453        let settings = self.buffer.read(cx).language_settings(cx);
17454        if settings.show_wrap_guides {
17455            match self.soft_wrap_mode(cx) {
17456                SoftWrap::Column(soft_wrap) => {
17457                    wrap_guides.push((soft_wrap as usize, true));
17458                }
17459                SoftWrap::Bounded(soft_wrap) => {
17460                    wrap_guides.push((soft_wrap as usize, true));
17461                }
17462                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17463            }
17464            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17465        }
17466
17467        wrap_guides
17468    }
17469
17470    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17471        let settings = self.buffer.read(cx).language_settings(cx);
17472        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17473        match mode {
17474            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17475                SoftWrap::None
17476            }
17477            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17478            language_settings::SoftWrap::PreferredLineLength => {
17479                SoftWrap::Column(settings.preferred_line_length)
17480            }
17481            language_settings::SoftWrap::Bounded => {
17482                SoftWrap::Bounded(settings.preferred_line_length)
17483            }
17484        }
17485    }
17486
17487    pub fn set_soft_wrap_mode(
17488        &mut self,
17489        mode: language_settings::SoftWrap,
17490
17491        cx: &mut Context<Self>,
17492    ) {
17493        self.soft_wrap_mode_override = Some(mode);
17494        cx.notify();
17495    }
17496
17497    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17498        self.hard_wrap = hard_wrap;
17499        cx.notify();
17500    }
17501
17502    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17503        self.text_style_refinement = Some(style);
17504    }
17505
17506    /// called by the Element so we know what style we were most recently rendered with.
17507    pub(crate) fn set_style(
17508        &mut self,
17509        style: EditorStyle,
17510        window: &mut Window,
17511        cx: &mut Context<Self>,
17512    ) {
17513        // We intentionally do not inform the display map about the minimap style
17514        // so that wrapping is not recalculated and stays consistent for the editor
17515        // and its linked minimap.
17516        if !self.mode.is_minimap() {
17517            let rem_size = window.rem_size();
17518            self.display_map.update(cx, |map, cx| {
17519                map.set_font(
17520                    style.text.font(),
17521                    style.text.font_size.to_pixels(rem_size),
17522                    cx,
17523                )
17524            });
17525        }
17526        self.style = Some(style);
17527    }
17528
17529    pub fn style(&self) -> Option<&EditorStyle> {
17530        self.style.as_ref()
17531    }
17532
17533    // Called by the element. This method is not designed to be called outside of the editor
17534    // element's layout code because it does not notify when rewrapping is computed synchronously.
17535    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17536        self.display_map
17537            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17538    }
17539
17540    pub fn set_soft_wrap(&mut self) {
17541        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17542    }
17543
17544    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17545        if self.soft_wrap_mode_override.is_some() {
17546            self.soft_wrap_mode_override.take();
17547        } else {
17548            let soft_wrap = match self.soft_wrap_mode(cx) {
17549                SoftWrap::GitDiff => return,
17550                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17551                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17552                    language_settings::SoftWrap::None
17553                }
17554            };
17555            self.soft_wrap_mode_override = Some(soft_wrap);
17556        }
17557        cx.notify();
17558    }
17559
17560    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17561        let Some(workspace) = self.workspace() else {
17562            return;
17563        };
17564        let fs = workspace.read(cx).app_state().fs.clone();
17565        let current_show = TabBarSettings::get_global(cx).show;
17566        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17567            setting.show = Some(!current_show);
17568        });
17569    }
17570
17571    pub fn toggle_indent_guides(
17572        &mut self,
17573        _: &ToggleIndentGuides,
17574        _: &mut Window,
17575        cx: &mut Context<Self>,
17576    ) {
17577        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17578            self.buffer
17579                .read(cx)
17580                .language_settings(cx)
17581                .indent_guides
17582                .enabled
17583        });
17584        self.show_indent_guides = Some(!currently_enabled);
17585        cx.notify();
17586    }
17587
17588    fn should_show_indent_guides(&self) -> Option<bool> {
17589        self.show_indent_guides
17590    }
17591
17592    pub fn toggle_line_numbers(
17593        &mut self,
17594        _: &ToggleLineNumbers,
17595        _: &mut Window,
17596        cx: &mut Context<Self>,
17597    ) {
17598        let mut editor_settings = EditorSettings::get_global(cx).clone();
17599        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17600        EditorSettings::override_global(editor_settings, cx);
17601    }
17602
17603    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17604        if let Some(show_line_numbers) = self.show_line_numbers {
17605            return show_line_numbers;
17606        }
17607        EditorSettings::get_global(cx).gutter.line_numbers
17608    }
17609
17610    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17611        self.use_relative_line_numbers
17612            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17613    }
17614
17615    pub fn toggle_relative_line_numbers(
17616        &mut self,
17617        _: &ToggleRelativeLineNumbers,
17618        _: &mut Window,
17619        cx: &mut Context<Self>,
17620    ) {
17621        let is_relative = self.should_use_relative_line_numbers(cx);
17622        self.set_relative_line_number(Some(!is_relative), cx)
17623    }
17624
17625    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17626        self.use_relative_line_numbers = is_relative;
17627        cx.notify();
17628    }
17629
17630    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17631        self.show_gutter = show_gutter;
17632        cx.notify();
17633    }
17634
17635    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17636        self.show_scrollbars = ScrollbarAxes {
17637            horizontal: show,
17638            vertical: show,
17639        };
17640        cx.notify();
17641    }
17642
17643    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17644        self.show_scrollbars.vertical = show;
17645        cx.notify();
17646    }
17647
17648    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17649        self.show_scrollbars.horizontal = show;
17650        cx.notify();
17651    }
17652
17653    pub fn set_minimap_visibility(
17654        &mut self,
17655        minimap_visibility: MinimapVisibility,
17656        window: &mut Window,
17657        cx: &mut Context<Self>,
17658    ) {
17659        if self.minimap_visibility != minimap_visibility {
17660            if minimap_visibility.visible() && self.minimap.is_none() {
17661                let minimap_settings = EditorSettings::get_global(cx).minimap;
17662                self.minimap =
17663                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17664            }
17665            self.minimap_visibility = minimap_visibility;
17666            cx.notify();
17667        }
17668    }
17669
17670    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17671        self.set_show_scrollbars(false, cx);
17672        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17673    }
17674
17675    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17676        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17677    }
17678
17679    /// Normally the text in full mode and auto height editors is padded on the
17680    /// left side by roughly half a character width for improved hit testing.
17681    ///
17682    /// Use this method to disable this for cases where this is not wanted (e.g.
17683    /// if you want to align the editor text with some other text above or below)
17684    /// or if you want to add this padding to single-line editors.
17685    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17686        self.offset_content = offset_content;
17687        cx.notify();
17688    }
17689
17690    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17691        self.show_line_numbers = Some(show_line_numbers);
17692        cx.notify();
17693    }
17694
17695    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17696        self.disable_expand_excerpt_buttons = true;
17697        cx.notify();
17698    }
17699
17700    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17701        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17702        cx.notify();
17703    }
17704
17705    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17706        self.show_code_actions = Some(show_code_actions);
17707        cx.notify();
17708    }
17709
17710    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17711        self.show_runnables = Some(show_runnables);
17712        cx.notify();
17713    }
17714
17715    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17716        self.show_breakpoints = Some(show_breakpoints);
17717        cx.notify();
17718    }
17719
17720    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17721        if self.display_map.read(cx).masked != masked {
17722            self.display_map.update(cx, |map, _| map.masked = masked);
17723        }
17724        cx.notify()
17725    }
17726
17727    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17728        self.show_wrap_guides = Some(show_wrap_guides);
17729        cx.notify();
17730    }
17731
17732    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17733        self.show_indent_guides = Some(show_indent_guides);
17734        cx.notify();
17735    }
17736
17737    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17738        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17739            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17740                if let Some(dir) = file.abs_path(cx).parent() {
17741                    return Some(dir.to_owned());
17742                }
17743            }
17744
17745            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17746                return Some(project_path.path.to_path_buf());
17747            }
17748        }
17749
17750        None
17751    }
17752
17753    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17754        self.active_excerpt(cx)?
17755            .1
17756            .read(cx)
17757            .file()
17758            .and_then(|f| f.as_local())
17759    }
17760
17761    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17762        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17763            let buffer = buffer.read(cx);
17764            if let Some(project_path) = buffer.project_path(cx) {
17765                let project = self.project.as_ref()?.read(cx);
17766                project.absolute_path(&project_path, cx)
17767            } else {
17768                buffer
17769                    .file()
17770                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17771            }
17772        })
17773    }
17774
17775    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17776        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17777            let project_path = buffer.read(cx).project_path(cx)?;
17778            let project = self.project.as_ref()?.read(cx);
17779            let entry = project.entry_for_path(&project_path, cx)?;
17780            let path = entry.path.to_path_buf();
17781            Some(path)
17782        })
17783    }
17784
17785    pub fn reveal_in_finder(
17786        &mut self,
17787        _: &RevealInFileManager,
17788        _window: &mut Window,
17789        cx: &mut Context<Self>,
17790    ) {
17791        if let Some(target) = self.target_file(cx) {
17792            cx.reveal_path(&target.abs_path(cx));
17793        }
17794    }
17795
17796    pub fn copy_path(
17797        &mut self,
17798        _: &zed_actions::workspace::CopyPath,
17799        _window: &mut Window,
17800        cx: &mut Context<Self>,
17801    ) {
17802        if let Some(path) = self.target_file_abs_path(cx) {
17803            if let Some(path) = path.to_str() {
17804                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17805            }
17806        }
17807    }
17808
17809    pub fn copy_relative_path(
17810        &mut self,
17811        _: &zed_actions::workspace::CopyRelativePath,
17812        _window: &mut Window,
17813        cx: &mut Context<Self>,
17814    ) {
17815        if let Some(path) = self.target_file_path(cx) {
17816            if let Some(path) = path.to_str() {
17817                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17818            }
17819        }
17820    }
17821
17822    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17823        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17824            buffer.read(cx).project_path(cx)
17825        } else {
17826            None
17827        }
17828    }
17829
17830    // Returns true if the editor handled a go-to-line request
17831    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17832        maybe!({
17833            let breakpoint_store = self.breakpoint_store.as_ref()?;
17834
17835            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17836            else {
17837                self.clear_row_highlights::<ActiveDebugLine>();
17838                return None;
17839            };
17840
17841            let position = active_stack_frame.position;
17842            let buffer_id = position.buffer_id?;
17843            let snapshot = self
17844                .project
17845                .as_ref()?
17846                .read(cx)
17847                .buffer_for_id(buffer_id, cx)?
17848                .read(cx)
17849                .snapshot();
17850
17851            let mut handled = false;
17852            for (id, ExcerptRange { context, .. }) in
17853                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17854            {
17855                if context.start.cmp(&position, &snapshot).is_ge()
17856                    || context.end.cmp(&position, &snapshot).is_lt()
17857                {
17858                    continue;
17859                }
17860                let snapshot = self.buffer.read(cx).snapshot(cx);
17861                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17862
17863                handled = true;
17864                self.clear_row_highlights::<ActiveDebugLine>();
17865
17866                self.go_to_line::<ActiveDebugLine>(
17867                    multibuffer_anchor,
17868                    Some(cx.theme().colors().editor_debugger_active_line_background),
17869                    window,
17870                    cx,
17871                );
17872
17873                cx.notify();
17874            }
17875
17876            handled.then_some(())
17877        })
17878        .is_some()
17879    }
17880
17881    pub fn copy_file_name_without_extension(
17882        &mut self,
17883        _: &CopyFileNameWithoutExtension,
17884        _: &mut Window,
17885        cx: &mut Context<Self>,
17886    ) {
17887        if let Some(file) = self.target_file(cx) {
17888            if let Some(file_stem) = file.path().file_stem() {
17889                if let Some(name) = file_stem.to_str() {
17890                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17891                }
17892            }
17893        }
17894    }
17895
17896    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17897        if let Some(file) = self.target_file(cx) {
17898            if let Some(file_name) = file.path().file_name() {
17899                if let Some(name) = file_name.to_str() {
17900                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17901                }
17902            }
17903        }
17904    }
17905
17906    pub fn toggle_git_blame(
17907        &mut self,
17908        _: &::git::Blame,
17909        window: &mut Window,
17910        cx: &mut Context<Self>,
17911    ) {
17912        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17913
17914        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17915            self.start_git_blame(true, window, cx);
17916        }
17917
17918        cx.notify();
17919    }
17920
17921    pub fn toggle_git_blame_inline(
17922        &mut self,
17923        _: &ToggleGitBlameInline,
17924        window: &mut Window,
17925        cx: &mut Context<Self>,
17926    ) {
17927        self.toggle_git_blame_inline_internal(true, window, cx);
17928        cx.notify();
17929    }
17930
17931    pub fn open_git_blame_commit(
17932        &mut self,
17933        _: &OpenGitBlameCommit,
17934        window: &mut Window,
17935        cx: &mut Context<Self>,
17936    ) {
17937        self.open_git_blame_commit_internal(window, cx);
17938    }
17939
17940    fn open_git_blame_commit_internal(
17941        &mut self,
17942        window: &mut Window,
17943        cx: &mut Context<Self>,
17944    ) -> Option<()> {
17945        let blame = self.blame.as_ref()?;
17946        let snapshot = self.snapshot(window, cx);
17947        let cursor = self.selections.newest::<Point>(cx).head();
17948        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17949        let blame_entry = blame
17950            .update(cx, |blame, cx| {
17951                blame
17952                    .blame_for_rows(
17953                        &[RowInfo {
17954                            buffer_id: Some(buffer.remote_id()),
17955                            buffer_row: Some(point.row),
17956                            ..Default::default()
17957                        }],
17958                        cx,
17959                    )
17960                    .next()
17961            })
17962            .flatten()?;
17963        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17964        let repo = blame.read(cx).repository(cx)?;
17965        let workspace = self.workspace()?.downgrade();
17966        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17967        None
17968    }
17969
17970    pub fn git_blame_inline_enabled(&self) -> bool {
17971        self.git_blame_inline_enabled
17972    }
17973
17974    pub fn toggle_selection_menu(
17975        &mut self,
17976        _: &ToggleSelectionMenu,
17977        _: &mut Window,
17978        cx: &mut Context<Self>,
17979    ) {
17980        self.show_selection_menu = self
17981            .show_selection_menu
17982            .map(|show_selections_menu| !show_selections_menu)
17983            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17984
17985        cx.notify();
17986    }
17987
17988    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17989        self.show_selection_menu
17990            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17991    }
17992
17993    fn start_git_blame(
17994        &mut self,
17995        user_triggered: bool,
17996        window: &mut Window,
17997        cx: &mut Context<Self>,
17998    ) {
17999        if let Some(project) = self.project.as_ref() {
18000            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18001                return;
18002            };
18003
18004            if buffer.read(cx).file().is_none() {
18005                return;
18006            }
18007
18008            let focused = self.focus_handle(cx).contains_focused(window, cx);
18009
18010            let project = project.clone();
18011            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18012            self.blame_subscription =
18013                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18014            self.blame = Some(blame);
18015        }
18016    }
18017
18018    fn toggle_git_blame_inline_internal(
18019        &mut self,
18020        user_triggered: bool,
18021        window: &mut Window,
18022        cx: &mut Context<Self>,
18023    ) {
18024        if self.git_blame_inline_enabled {
18025            self.git_blame_inline_enabled = false;
18026            self.show_git_blame_inline = false;
18027            self.show_git_blame_inline_delay_task.take();
18028        } else {
18029            self.git_blame_inline_enabled = true;
18030            self.start_git_blame_inline(user_triggered, window, cx);
18031        }
18032
18033        cx.notify();
18034    }
18035
18036    fn start_git_blame_inline(
18037        &mut self,
18038        user_triggered: bool,
18039        window: &mut Window,
18040        cx: &mut Context<Self>,
18041    ) {
18042        self.start_git_blame(user_triggered, window, cx);
18043
18044        if ProjectSettings::get_global(cx)
18045            .git
18046            .inline_blame_delay()
18047            .is_some()
18048        {
18049            self.start_inline_blame_timer(window, cx);
18050        } else {
18051            self.show_git_blame_inline = true
18052        }
18053    }
18054
18055    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18056        self.blame.as_ref()
18057    }
18058
18059    pub fn show_git_blame_gutter(&self) -> bool {
18060        self.show_git_blame_gutter
18061    }
18062
18063    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18064        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18065    }
18066
18067    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18068        self.show_git_blame_inline
18069            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18070            && !self.newest_selection_head_on_empty_line(cx)
18071            && self.has_blame_entries(cx)
18072    }
18073
18074    fn has_blame_entries(&self, cx: &App) -> bool {
18075        self.blame()
18076            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18077    }
18078
18079    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18080        let cursor_anchor = self.selections.newest_anchor().head();
18081
18082        let snapshot = self.buffer.read(cx).snapshot(cx);
18083        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18084
18085        snapshot.line_len(buffer_row) == 0
18086    }
18087
18088    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18089        let buffer_and_selection = maybe!({
18090            let selection = self.selections.newest::<Point>(cx);
18091            let selection_range = selection.range();
18092
18093            let multi_buffer = self.buffer().read(cx);
18094            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18095            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18096
18097            let (buffer, range, _) = if selection.reversed {
18098                buffer_ranges.first()
18099            } else {
18100                buffer_ranges.last()
18101            }?;
18102
18103            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18104                ..text::ToPoint::to_point(&range.end, &buffer).row;
18105            Some((
18106                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18107                selection,
18108            ))
18109        });
18110
18111        let Some((buffer, selection)) = buffer_and_selection else {
18112            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18113        };
18114
18115        let Some(project) = self.project.as_ref() else {
18116            return Task::ready(Err(anyhow!("editor does not have project")));
18117        };
18118
18119        project.update(cx, |project, cx| {
18120            project.get_permalink_to_line(&buffer, selection, cx)
18121        })
18122    }
18123
18124    pub fn copy_permalink_to_line(
18125        &mut self,
18126        _: &CopyPermalinkToLine,
18127        window: &mut Window,
18128        cx: &mut Context<Self>,
18129    ) {
18130        let permalink_task = self.get_permalink_to_line(cx);
18131        let workspace = self.workspace();
18132
18133        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18134            Ok(permalink) => {
18135                cx.update(|_, cx| {
18136                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18137                })
18138                .ok();
18139            }
18140            Err(err) => {
18141                let message = format!("Failed to copy permalink: {err}");
18142
18143                anyhow::Result::<()>::Err(err).log_err();
18144
18145                if let Some(workspace) = workspace {
18146                    workspace
18147                        .update_in(cx, |workspace, _, cx| {
18148                            struct CopyPermalinkToLine;
18149
18150                            workspace.show_toast(
18151                                Toast::new(
18152                                    NotificationId::unique::<CopyPermalinkToLine>(),
18153                                    message,
18154                                ),
18155                                cx,
18156                            )
18157                        })
18158                        .ok();
18159                }
18160            }
18161        })
18162        .detach();
18163    }
18164
18165    pub fn copy_file_location(
18166        &mut self,
18167        _: &CopyFileLocation,
18168        _: &mut Window,
18169        cx: &mut Context<Self>,
18170    ) {
18171        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18172        if let Some(file) = self.target_file(cx) {
18173            if let Some(path) = file.path().to_str() {
18174                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18175            }
18176        }
18177    }
18178
18179    pub fn open_permalink_to_line(
18180        &mut self,
18181        _: &OpenPermalinkToLine,
18182        window: &mut Window,
18183        cx: &mut Context<Self>,
18184    ) {
18185        let permalink_task = self.get_permalink_to_line(cx);
18186        let workspace = self.workspace();
18187
18188        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18189            Ok(permalink) => {
18190                cx.update(|_, cx| {
18191                    cx.open_url(permalink.as_ref());
18192                })
18193                .ok();
18194            }
18195            Err(err) => {
18196                let message = format!("Failed to open permalink: {err}");
18197
18198                anyhow::Result::<()>::Err(err).log_err();
18199
18200                if let Some(workspace) = workspace {
18201                    workspace
18202                        .update(cx, |workspace, cx| {
18203                            struct OpenPermalinkToLine;
18204
18205                            workspace.show_toast(
18206                                Toast::new(
18207                                    NotificationId::unique::<OpenPermalinkToLine>(),
18208                                    message,
18209                                ),
18210                                cx,
18211                            )
18212                        })
18213                        .ok();
18214                }
18215            }
18216        })
18217        .detach();
18218    }
18219
18220    pub fn insert_uuid_v4(
18221        &mut self,
18222        _: &InsertUuidV4,
18223        window: &mut Window,
18224        cx: &mut Context<Self>,
18225    ) {
18226        self.insert_uuid(UuidVersion::V4, window, cx);
18227    }
18228
18229    pub fn insert_uuid_v7(
18230        &mut self,
18231        _: &InsertUuidV7,
18232        window: &mut Window,
18233        cx: &mut Context<Self>,
18234    ) {
18235        self.insert_uuid(UuidVersion::V7, window, cx);
18236    }
18237
18238    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18239        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18240        self.transact(window, cx, |this, window, cx| {
18241            let edits = this
18242                .selections
18243                .all::<Point>(cx)
18244                .into_iter()
18245                .map(|selection| {
18246                    let uuid = match version {
18247                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18248                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18249                    };
18250
18251                    (selection.range(), uuid.to_string())
18252                });
18253            this.edit(edits, cx);
18254            this.refresh_inline_completion(true, false, window, cx);
18255        });
18256    }
18257
18258    pub fn open_selections_in_multibuffer(
18259        &mut self,
18260        _: &OpenSelectionsInMultibuffer,
18261        window: &mut Window,
18262        cx: &mut Context<Self>,
18263    ) {
18264        let multibuffer = self.buffer.read(cx);
18265
18266        let Some(buffer) = multibuffer.as_singleton() else {
18267            return;
18268        };
18269
18270        let Some(workspace) = self.workspace() else {
18271            return;
18272        };
18273
18274        let locations = self
18275            .selections
18276            .disjoint_anchors()
18277            .iter()
18278            .map(|range| Location {
18279                buffer: buffer.clone(),
18280                range: range.start.text_anchor..range.end.text_anchor,
18281            })
18282            .collect::<Vec<_>>();
18283
18284        let title = multibuffer.title(cx).to_string();
18285
18286        cx.spawn_in(window, async move |_, cx| {
18287            workspace.update_in(cx, |workspace, window, cx| {
18288                Self::open_locations_in_multibuffer(
18289                    workspace,
18290                    locations,
18291                    format!("Selections for '{title}'"),
18292                    false,
18293                    MultibufferSelectionMode::All,
18294                    window,
18295                    cx,
18296                );
18297            })
18298        })
18299        .detach();
18300    }
18301
18302    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18303    /// last highlight added will be used.
18304    ///
18305    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18306    pub fn highlight_rows<T: 'static>(
18307        &mut self,
18308        range: Range<Anchor>,
18309        color: Hsla,
18310        options: RowHighlightOptions,
18311        cx: &mut Context<Self>,
18312    ) {
18313        let snapshot = self.buffer().read(cx).snapshot(cx);
18314        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18315        let ix = row_highlights.binary_search_by(|highlight| {
18316            Ordering::Equal
18317                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18318                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18319        });
18320
18321        if let Err(mut ix) = ix {
18322            let index = post_inc(&mut self.highlight_order);
18323
18324            // If this range intersects with the preceding highlight, then merge it with
18325            // the preceding highlight. Otherwise insert a new highlight.
18326            let mut merged = false;
18327            if ix > 0 {
18328                let prev_highlight = &mut row_highlights[ix - 1];
18329                if prev_highlight
18330                    .range
18331                    .end
18332                    .cmp(&range.start, &snapshot)
18333                    .is_ge()
18334                {
18335                    ix -= 1;
18336                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18337                        prev_highlight.range.end = range.end;
18338                    }
18339                    merged = true;
18340                    prev_highlight.index = index;
18341                    prev_highlight.color = color;
18342                    prev_highlight.options = options;
18343                }
18344            }
18345
18346            if !merged {
18347                row_highlights.insert(
18348                    ix,
18349                    RowHighlight {
18350                        range: range.clone(),
18351                        index,
18352                        color,
18353                        options,
18354                        type_id: TypeId::of::<T>(),
18355                    },
18356                );
18357            }
18358
18359            // If any of the following highlights intersect with this one, merge them.
18360            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18361                let highlight = &row_highlights[ix];
18362                if next_highlight
18363                    .range
18364                    .start
18365                    .cmp(&highlight.range.end, &snapshot)
18366                    .is_le()
18367                {
18368                    if next_highlight
18369                        .range
18370                        .end
18371                        .cmp(&highlight.range.end, &snapshot)
18372                        .is_gt()
18373                    {
18374                        row_highlights[ix].range.end = next_highlight.range.end;
18375                    }
18376                    row_highlights.remove(ix + 1);
18377                } else {
18378                    break;
18379                }
18380            }
18381        }
18382    }
18383
18384    /// Remove any highlighted row ranges of the given type that intersect the
18385    /// given ranges.
18386    pub fn remove_highlighted_rows<T: 'static>(
18387        &mut self,
18388        ranges_to_remove: Vec<Range<Anchor>>,
18389        cx: &mut Context<Self>,
18390    ) {
18391        let snapshot = self.buffer().read(cx).snapshot(cx);
18392        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18393        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18394        row_highlights.retain(|highlight| {
18395            while let Some(range_to_remove) = ranges_to_remove.peek() {
18396                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18397                    Ordering::Less | Ordering::Equal => {
18398                        ranges_to_remove.next();
18399                    }
18400                    Ordering::Greater => {
18401                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18402                            Ordering::Less | Ordering::Equal => {
18403                                return false;
18404                            }
18405                            Ordering::Greater => break,
18406                        }
18407                    }
18408                }
18409            }
18410
18411            true
18412        })
18413    }
18414
18415    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18416    pub fn clear_row_highlights<T: 'static>(&mut self) {
18417        self.highlighted_rows.remove(&TypeId::of::<T>());
18418    }
18419
18420    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18421    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18422        self.highlighted_rows
18423            .get(&TypeId::of::<T>())
18424            .map_or(&[] as &[_], |vec| vec.as_slice())
18425            .iter()
18426            .map(|highlight| (highlight.range.clone(), highlight.color))
18427    }
18428
18429    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18430    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18431    /// Allows to ignore certain kinds of highlights.
18432    pub fn highlighted_display_rows(
18433        &self,
18434        window: &mut Window,
18435        cx: &mut App,
18436    ) -> BTreeMap<DisplayRow, LineHighlight> {
18437        let snapshot = self.snapshot(window, cx);
18438        let mut used_highlight_orders = HashMap::default();
18439        self.highlighted_rows
18440            .iter()
18441            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18442            .fold(
18443                BTreeMap::<DisplayRow, LineHighlight>::new(),
18444                |mut unique_rows, highlight| {
18445                    let start = highlight.range.start.to_display_point(&snapshot);
18446                    let end = highlight.range.end.to_display_point(&snapshot);
18447                    let start_row = start.row().0;
18448                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18449                        && end.column() == 0
18450                    {
18451                        end.row().0.saturating_sub(1)
18452                    } else {
18453                        end.row().0
18454                    };
18455                    for row in start_row..=end_row {
18456                        let used_index =
18457                            used_highlight_orders.entry(row).or_insert(highlight.index);
18458                        if highlight.index >= *used_index {
18459                            *used_index = highlight.index;
18460                            unique_rows.insert(
18461                                DisplayRow(row),
18462                                LineHighlight {
18463                                    include_gutter: highlight.options.include_gutter,
18464                                    border: None,
18465                                    background: highlight.color.into(),
18466                                    type_id: Some(highlight.type_id),
18467                                },
18468                            );
18469                        }
18470                    }
18471                    unique_rows
18472                },
18473            )
18474    }
18475
18476    pub fn highlighted_display_row_for_autoscroll(
18477        &self,
18478        snapshot: &DisplaySnapshot,
18479    ) -> Option<DisplayRow> {
18480        self.highlighted_rows
18481            .values()
18482            .flat_map(|highlighted_rows| highlighted_rows.iter())
18483            .filter_map(|highlight| {
18484                if highlight.options.autoscroll {
18485                    Some(highlight.range.start.to_display_point(snapshot).row())
18486                } else {
18487                    None
18488                }
18489            })
18490            .min()
18491    }
18492
18493    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18494        self.highlight_background::<SearchWithinRange>(
18495            ranges,
18496            |colors| colors.editor_document_highlight_read_background,
18497            cx,
18498        )
18499    }
18500
18501    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18502        self.breadcrumb_header = Some(new_header);
18503    }
18504
18505    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18506        self.clear_background_highlights::<SearchWithinRange>(cx);
18507    }
18508
18509    pub fn highlight_background<T: 'static>(
18510        &mut self,
18511        ranges: &[Range<Anchor>],
18512        color_fetcher: fn(&ThemeColors) -> Hsla,
18513        cx: &mut Context<Self>,
18514    ) {
18515        self.background_highlights
18516            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18517        self.scrollbar_marker_state.dirty = true;
18518        cx.notify();
18519    }
18520
18521    pub fn clear_background_highlights<T: 'static>(
18522        &mut self,
18523        cx: &mut Context<Self>,
18524    ) -> Option<BackgroundHighlight> {
18525        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18526        if !text_highlights.1.is_empty() {
18527            self.scrollbar_marker_state.dirty = true;
18528            cx.notify();
18529        }
18530        Some(text_highlights)
18531    }
18532
18533    pub fn highlight_gutter<T: 'static>(
18534        &mut self,
18535        ranges: impl Into<Vec<Range<Anchor>>>,
18536        color_fetcher: fn(&App) -> Hsla,
18537        cx: &mut Context<Self>,
18538    ) {
18539        self.gutter_highlights
18540            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18541        cx.notify();
18542    }
18543
18544    pub fn clear_gutter_highlights<T: 'static>(
18545        &mut self,
18546        cx: &mut Context<Self>,
18547    ) -> Option<GutterHighlight> {
18548        cx.notify();
18549        self.gutter_highlights.remove(&TypeId::of::<T>())
18550    }
18551
18552    pub fn insert_gutter_highlight<T: 'static>(
18553        &mut self,
18554        range: Range<Anchor>,
18555        color_fetcher: fn(&App) -> Hsla,
18556        cx: &mut Context<Self>,
18557    ) {
18558        let snapshot = self.buffer().read(cx).snapshot(cx);
18559        let mut highlights = self
18560            .gutter_highlights
18561            .remove(&TypeId::of::<T>())
18562            .map(|(_, highlights)| highlights)
18563            .unwrap_or_default();
18564        let ix = highlights.binary_search_by(|highlight| {
18565            Ordering::Equal
18566                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18567                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18568        });
18569        if let Err(ix) = ix {
18570            highlights.insert(ix, range);
18571        }
18572        self.gutter_highlights
18573            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18574    }
18575
18576    pub fn remove_gutter_highlights<T: 'static>(
18577        &mut self,
18578        ranges_to_remove: Vec<Range<Anchor>>,
18579        cx: &mut Context<Self>,
18580    ) {
18581        let snapshot = self.buffer().read(cx).snapshot(cx);
18582        let Some((color_fetcher, mut gutter_highlights)) =
18583            self.gutter_highlights.remove(&TypeId::of::<T>())
18584        else {
18585            return;
18586        };
18587        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18588        gutter_highlights.retain(|highlight| {
18589            while let Some(range_to_remove) = ranges_to_remove.peek() {
18590                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18591                    Ordering::Less | Ordering::Equal => {
18592                        ranges_to_remove.next();
18593                    }
18594                    Ordering::Greater => {
18595                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18596                            Ordering::Less | Ordering::Equal => {
18597                                return false;
18598                            }
18599                            Ordering::Greater => break,
18600                        }
18601                    }
18602                }
18603            }
18604
18605            true
18606        });
18607        self.gutter_highlights
18608            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18609    }
18610
18611    #[cfg(feature = "test-support")]
18612    pub fn all_text_background_highlights(
18613        &self,
18614        window: &mut Window,
18615        cx: &mut Context<Self>,
18616    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18617        let snapshot = self.snapshot(window, cx);
18618        let buffer = &snapshot.buffer_snapshot;
18619        let start = buffer.anchor_before(0);
18620        let end = buffer.anchor_after(buffer.len());
18621        let theme = cx.theme().colors();
18622        self.background_highlights_in_range(start..end, &snapshot, theme)
18623    }
18624
18625    #[cfg(feature = "test-support")]
18626    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18627        let snapshot = self.buffer().read(cx).snapshot(cx);
18628
18629        let highlights = self
18630            .background_highlights
18631            .get(&TypeId::of::<items::BufferSearchHighlights>());
18632
18633        if let Some((_color, ranges)) = highlights {
18634            ranges
18635                .iter()
18636                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18637                .collect_vec()
18638        } else {
18639            vec![]
18640        }
18641    }
18642
18643    fn document_highlights_for_position<'a>(
18644        &'a self,
18645        position: Anchor,
18646        buffer: &'a MultiBufferSnapshot,
18647    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18648        let read_highlights = self
18649            .background_highlights
18650            .get(&TypeId::of::<DocumentHighlightRead>())
18651            .map(|h| &h.1);
18652        let write_highlights = self
18653            .background_highlights
18654            .get(&TypeId::of::<DocumentHighlightWrite>())
18655            .map(|h| &h.1);
18656        let left_position = position.bias_left(buffer);
18657        let right_position = position.bias_right(buffer);
18658        read_highlights
18659            .into_iter()
18660            .chain(write_highlights)
18661            .flat_map(move |ranges| {
18662                let start_ix = match ranges.binary_search_by(|probe| {
18663                    let cmp = probe.end.cmp(&left_position, buffer);
18664                    if cmp.is_ge() {
18665                        Ordering::Greater
18666                    } else {
18667                        Ordering::Less
18668                    }
18669                }) {
18670                    Ok(i) | Err(i) => i,
18671                };
18672
18673                ranges[start_ix..]
18674                    .iter()
18675                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18676            })
18677    }
18678
18679    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18680        self.background_highlights
18681            .get(&TypeId::of::<T>())
18682            .map_or(false, |(_, highlights)| !highlights.is_empty())
18683    }
18684
18685    pub fn background_highlights_in_range(
18686        &self,
18687        search_range: Range<Anchor>,
18688        display_snapshot: &DisplaySnapshot,
18689        theme: &ThemeColors,
18690    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18691        let mut results = Vec::new();
18692        for (color_fetcher, ranges) in self.background_highlights.values() {
18693            let color = color_fetcher(theme);
18694            let start_ix = match ranges.binary_search_by(|probe| {
18695                let cmp = probe
18696                    .end
18697                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18698                if cmp.is_gt() {
18699                    Ordering::Greater
18700                } else {
18701                    Ordering::Less
18702                }
18703            }) {
18704                Ok(i) | Err(i) => i,
18705            };
18706            for range in &ranges[start_ix..] {
18707                if range
18708                    .start
18709                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18710                    .is_ge()
18711                {
18712                    break;
18713                }
18714
18715                let start = range.start.to_display_point(display_snapshot);
18716                let end = range.end.to_display_point(display_snapshot);
18717                results.push((start..end, color))
18718            }
18719        }
18720        results
18721    }
18722
18723    pub fn background_highlight_row_ranges<T: 'static>(
18724        &self,
18725        search_range: Range<Anchor>,
18726        display_snapshot: &DisplaySnapshot,
18727        count: usize,
18728    ) -> Vec<RangeInclusive<DisplayPoint>> {
18729        let mut results = Vec::new();
18730        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18731            return vec![];
18732        };
18733
18734        let start_ix = match ranges.binary_search_by(|probe| {
18735            let cmp = probe
18736                .end
18737                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18738            if cmp.is_gt() {
18739                Ordering::Greater
18740            } else {
18741                Ordering::Less
18742            }
18743        }) {
18744            Ok(i) | Err(i) => i,
18745        };
18746        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18747            if let (Some(start_display), Some(end_display)) = (start, end) {
18748                results.push(
18749                    start_display.to_display_point(display_snapshot)
18750                        ..=end_display.to_display_point(display_snapshot),
18751                );
18752            }
18753        };
18754        let mut start_row: Option<Point> = None;
18755        let mut end_row: Option<Point> = None;
18756        if ranges.len() > count {
18757            return Vec::new();
18758        }
18759        for range in &ranges[start_ix..] {
18760            if range
18761                .start
18762                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18763                .is_ge()
18764            {
18765                break;
18766            }
18767            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18768            if let Some(current_row) = &end_row {
18769                if end.row == current_row.row {
18770                    continue;
18771                }
18772            }
18773            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18774            if start_row.is_none() {
18775                assert_eq!(end_row, None);
18776                start_row = Some(start);
18777                end_row = Some(end);
18778                continue;
18779            }
18780            if let Some(current_end) = end_row.as_mut() {
18781                if start.row > current_end.row + 1 {
18782                    push_region(start_row, end_row);
18783                    start_row = Some(start);
18784                    end_row = Some(end);
18785                } else {
18786                    // Merge two hunks.
18787                    *current_end = end;
18788                }
18789            } else {
18790                unreachable!();
18791            }
18792        }
18793        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18794        push_region(start_row, end_row);
18795        results
18796    }
18797
18798    pub fn gutter_highlights_in_range(
18799        &self,
18800        search_range: Range<Anchor>,
18801        display_snapshot: &DisplaySnapshot,
18802        cx: &App,
18803    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18804        let mut results = Vec::new();
18805        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18806            let color = color_fetcher(cx);
18807            let start_ix = match ranges.binary_search_by(|probe| {
18808                let cmp = probe
18809                    .end
18810                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18811                if cmp.is_gt() {
18812                    Ordering::Greater
18813                } else {
18814                    Ordering::Less
18815                }
18816            }) {
18817                Ok(i) | Err(i) => i,
18818            };
18819            for range in &ranges[start_ix..] {
18820                if range
18821                    .start
18822                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18823                    .is_ge()
18824                {
18825                    break;
18826                }
18827
18828                let start = range.start.to_display_point(display_snapshot);
18829                let end = range.end.to_display_point(display_snapshot);
18830                results.push((start..end, color))
18831            }
18832        }
18833        results
18834    }
18835
18836    /// Get the text ranges corresponding to the redaction query
18837    pub fn redacted_ranges(
18838        &self,
18839        search_range: Range<Anchor>,
18840        display_snapshot: &DisplaySnapshot,
18841        cx: &App,
18842    ) -> Vec<Range<DisplayPoint>> {
18843        display_snapshot
18844            .buffer_snapshot
18845            .redacted_ranges(search_range, |file| {
18846                if let Some(file) = file {
18847                    file.is_private()
18848                        && EditorSettings::get(
18849                            Some(SettingsLocation {
18850                                worktree_id: file.worktree_id(cx),
18851                                path: file.path().as_ref(),
18852                            }),
18853                            cx,
18854                        )
18855                        .redact_private_values
18856                } else {
18857                    false
18858                }
18859            })
18860            .map(|range| {
18861                range.start.to_display_point(display_snapshot)
18862                    ..range.end.to_display_point(display_snapshot)
18863            })
18864            .collect()
18865    }
18866
18867    pub fn highlight_text<T: 'static>(
18868        &mut self,
18869        ranges: Vec<Range<Anchor>>,
18870        style: HighlightStyle,
18871        cx: &mut Context<Self>,
18872    ) {
18873        self.display_map.update(cx, |map, _| {
18874            map.highlight_text(TypeId::of::<T>(), ranges, style)
18875        });
18876        cx.notify();
18877    }
18878
18879    pub(crate) fn highlight_inlays<T: 'static>(
18880        &mut self,
18881        highlights: Vec<InlayHighlight>,
18882        style: HighlightStyle,
18883        cx: &mut Context<Self>,
18884    ) {
18885        self.display_map.update(cx, |map, _| {
18886            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18887        });
18888        cx.notify();
18889    }
18890
18891    pub fn text_highlights<'a, T: 'static>(
18892        &'a self,
18893        cx: &'a App,
18894    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18895        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18896    }
18897
18898    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18899        let cleared = self
18900            .display_map
18901            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18902        if cleared {
18903            cx.notify();
18904        }
18905    }
18906
18907    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18908        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18909            && self.focus_handle.is_focused(window)
18910    }
18911
18912    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18913        self.show_cursor_when_unfocused = is_enabled;
18914        cx.notify();
18915    }
18916
18917    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18918        cx.notify();
18919    }
18920
18921    fn on_debug_session_event(
18922        &mut self,
18923        _session: Entity<Session>,
18924        event: &SessionEvent,
18925        cx: &mut Context<Self>,
18926    ) {
18927        match event {
18928            SessionEvent::InvalidateInlineValue => {
18929                self.refresh_inline_values(cx);
18930            }
18931            _ => {}
18932        }
18933    }
18934
18935    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18936        let Some(project) = self.project.clone() else {
18937            return;
18938        };
18939
18940        if !self.inline_value_cache.enabled {
18941            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18942            self.splice_inlays(&inlays, Vec::new(), cx);
18943            return;
18944        }
18945
18946        let current_execution_position = self
18947            .highlighted_rows
18948            .get(&TypeId::of::<ActiveDebugLine>())
18949            .and_then(|lines| lines.last().map(|line| line.range.start));
18950
18951        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18952            let inline_values = editor
18953                .update(cx, |editor, cx| {
18954                    let Some(current_execution_position) = current_execution_position else {
18955                        return Some(Task::ready(Ok(Vec::new())));
18956                    };
18957
18958                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18959                        let snapshot = buffer.snapshot(cx);
18960
18961                        let excerpt = snapshot.excerpt_containing(
18962                            current_execution_position..current_execution_position,
18963                        )?;
18964
18965                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18966                    })?;
18967
18968                    let range =
18969                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18970
18971                    project.inline_values(buffer, range, cx)
18972                })
18973                .ok()
18974                .flatten()?
18975                .await
18976                .context("refreshing debugger inlays")
18977                .log_err()?;
18978
18979            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18980
18981            for (buffer_id, inline_value) in inline_values
18982                .into_iter()
18983                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18984            {
18985                buffer_inline_values
18986                    .entry(buffer_id)
18987                    .or_default()
18988                    .push(inline_value);
18989            }
18990
18991            editor
18992                .update(cx, |editor, cx| {
18993                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18994                    let mut new_inlays = Vec::default();
18995
18996                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18997                        let buffer_id = buffer_snapshot.remote_id();
18998                        buffer_inline_values
18999                            .get(&buffer_id)
19000                            .into_iter()
19001                            .flatten()
19002                            .for_each(|hint| {
19003                                let inlay = Inlay::debugger_hint(
19004                                    post_inc(&mut editor.next_inlay_id),
19005                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19006                                    hint.text(),
19007                                );
19008
19009                                new_inlays.push(inlay);
19010                            });
19011                    }
19012
19013                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19014                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19015
19016                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19017                })
19018                .ok()?;
19019            Some(())
19020        });
19021    }
19022
19023    fn on_buffer_event(
19024        &mut self,
19025        multibuffer: &Entity<MultiBuffer>,
19026        event: &multi_buffer::Event,
19027        window: &mut Window,
19028        cx: &mut Context<Self>,
19029    ) {
19030        match event {
19031            multi_buffer::Event::Edited {
19032                singleton_buffer_edited,
19033                edited_buffer,
19034            } => {
19035                self.scrollbar_marker_state.dirty = true;
19036                self.active_indent_guides_state.dirty = true;
19037                self.refresh_active_diagnostics(cx);
19038                self.refresh_code_actions(window, cx);
19039                self.refresh_selected_text_highlights(true, window, cx);
19040                refresh_matching_bracket_highlights(self, window, cx);
19041                if self.has_active_inline_completion() {
19042                    self.update_visible_inline_completion(window, cx);
19043                }
19044                if let Some(project) = self.project.as_ref() {
19045                    if let Some(edited_buffer) = edited_buffer {
19046                        project.update(cx, |project, cx| {
19047                            self.registered_buffers
19048                                .entry(edited_buffer.read(cx).remote_id())
19049                                .or_insert_with(|| {
19050                                    project
19051                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19052                                });
19053                        });
19054                        if edited_buffer.read(cx).file().is_some() {
19055                            self.pull_diagnostics(
19056                                Some(edited_buffer.read(cx).remote_id()),
19057                                window,
19058                                cx,
19059                            );
19060                        }
19061                    }
19062                }
19063                cx.emit(EditorEvent::BufferEdited);
19064                cx.emit(SearchEvent::MatchesInvalidated);
19065                if *singleton_buffer_edited {
19066                    if let Some(buffer) = edited_buffer {
19067                        if buffer.read(cx).file().is_none() {
19068                            cx.emit(EditorEvent::TitleChanged);
19069                        }
19070                    }
19071                    if let Some(project) = &self.project {
19072                        #[allow(clippy::mutable_key_type)]
19073                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19074                            multibuffer
19075                                .all_buffers()
19076                                .into_iter()
19077                                .filter_map(|buffer| {
19078                                    buffer.update(cx, |buffer, cx| {
19079                                        let language = buffer.language()?;
19080                                        let should_discard = project.update(cx, |project, cx| {
19081                                            project.is_local()
19082                                                && !project.has_language_servers_for(buffer, cx)
19083                                        });
19084                                        should_discard.not().then_some(language.clone())
19085                                    })
19086                                })
19087                                .collect::<HashSet<_>>()
19088                        });
19089                        if !languages_affected.is_empty() {
19090                            self.refresh_inlay_hints(
19091                                InlayHintRefreshReason::BufferEdited(languages_affected),
19092                                cx,
19093                            );
19094                        }
19095                    }
19096                }
19097
19098                let Some(project) = &self.project else { return };
19099                let (telemetry, is_via_ssh) = {
19100                    let project = project.read(cx);
19101                    let telemetry = project.client().telemetry().clone();
19102                    let is_via_ssh = project.is_via_ssh();
19103                    (telemetry, is_via_ssh)
19104                };
19105                refresh_linked_ranges(self, window, cx);
19106                telemetry.log_edit_event("editor", is_via_ssh);
19107            }
19108            multi_buffer::Event::ExcerptsAdded {
19109                buffer,
19110                predecessor,
19111                excerpts,
19112            } => {
19113                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19114                let buffer_id = buffer.read(cx).remote_id();
19115                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19116                    if let Some(project) = &self.project {
19117                        update_uncommitted_diff_for_buffer(
19118                            cx.entity(),
19119                            project,
19120                            [buffer.clone()],
19121                            self.buffer.clone(),
19122                            cx,
19123                        )
19124                        .detach();
19125                    }
19126                }
19127                cx.emit(EditorEvent::ExcerptsAdded {
19128                    buffer: buffer.clone(),
19129                    predecessor: *predecessor,
19130                    excerpts: excerpts.clone(),
19131                });
19132                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19133            }
19134            multi_buffer::Event::ExcerptsRemoved {
19135                ids,
19136                removed_buffer_ids,
19137            } => {
19138                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19139                let buffer = self.buffer.read(cx);
19140                self.registered_buffers
19141                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19142                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19143                cx.emit(EditorEvent::ExcerptsRemoved {
19144                    ids: ids.clone(),
19145                    removed_buffer_ids: removed_buffer_ids.clone(),
19146                })
19147            }
19148            multi_buffer::Event::ExcerptsEdited {
19149                excerpt_ids,
19150                buffer_ids,
19151            } => {
19152                self.display_map.update(cx, |map, cx| {
19153                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19154                });
19155                cx.emit(EditorEvent::ExcerptsEdited {
19156                    ids: excerpt_ids.clone(),
19157                })
19158            }
19159            multi_buffer::Event::ExcerptsExpanded { ids } => {
19160                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19161                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19162            }
19163            multi_buffer::Event::Reparsed(buffer_id) => {
19164                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19165                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19166
19167                cx.emit(EditorEvent::Reparsed(*buffer_id));
19168            }
19169            multi_buffer::Event::DiffHunksToggled => {
19170                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19171            }
19172            multi_buffer::Event::LanguageChanged(buffer_id) => {
19173                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19174                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19175                cx.emit(EditorEvent::Reparsed(*buffer_id));
19176                cx.notify();
19177            }
19178            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19179            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19180            multi_buffer::Event::FileHandleChanged
19181            | multi_buffer::Event::Reloaded
19182            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19183            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19184            multi_buffer::Event::DiagnosticsUpdated => {
19185                self.update_diagnostics_state(window, cx);
19186            }
19187            _ => {}
19188        };
19189    }
19190
19191    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19192        self.refresh_active_diagnostics(cx);
19193        self.refresh_inline_diagnostics(true, window, cx);
19194        self.scrollbar_marker_state.dirty = true;
19195        cx.notify();
19196    }
19197
19198    pub fn start_temporary_diff_override(&mut self) {
19199        self.load_diff_task.take();
19200        self.temporary_diff_override = true;
19201    }
19202
19203    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19204        self.temporary_diff_override = false;
19205        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19206        self.buffer.update(cx, |buffer, cx| {
19207            buffer.set_all_diff_hunks_collapsed(cx);
19208        });
19209
19210        if let Some(project) = self.project.clone() {
19211            self.load_diff_task = Some(
19212                update_uncommitted_diff_for_buffer(
19213                    cx.entity(),
19214                    &project,
19215                    self.buffer.read(cx).all_buffers(),
19216                    self.buffer.clone(),
19217                    cx,
19218                )
19219                .shared(),
19220            );
19221        }
19222    }
19223
19224    fn on_display_map_changed(
19225        &mut self,
19226        _: Entity<DisplayMap>,
19227        _: &mut Window,
19228        cx: &mut Context<Self>,
19229    ) {
19230        cx.notify();
19231    }
19232
19233    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19234        let new_severity = if self.diagnostics_enabled() {
19235            EditorSettings::get_global(cx)
19236                .diagnostics_max_severity
19237                .unwrap_or(DiagnosticSeverity::Hint)
19238        } else {
19239            DiagnosticSeverity::Off
19240        };
19241        self.set_max_diagnostics_severity(new_severity, cx);
19242        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19243        self.update_edit_prediction_settings(cx);
19244        self.refresh_inline_completion(true, false, window, cx);
19245        self.refresh_inlay_hints(
19246            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19247                self.selections.newest_anchor().head(),
19248                &self.buffer.read(cx).snapshot(cx),
19249                cx,
19250            )),
19251            cx,
19252        );
19253
19254        let old_cursor_shape = self.cursor_shape;
19255
19256        {
19257            let editor_settings = EditorSettings::get_global(cx);
19258            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19259            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19260            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19261            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19262            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19263        }
19264
19265        if old_cursor_shape != self.cursor_shape {
19266            cx.emit(EditorEvent::CursorShapeChanged);
19267        }
19268
19269        let project_settings = ProjectSettings::get_global(cx);
19270        self.serialize_dirty_buffers =
19271            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19272
19273        if self.mode.is_full() {
19274            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19275            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19276            if self.show_inline_diagnostics != show_inline_diagnostics {
19277                self.show_inline_diagnostics = show_inline_diagnostics;
19278                self.refresh_inline_diagnostics(false, window, cx);
19279            }
19280
19281            if self.git_blame_inline_enabled != inline_blame_enabled {
19282                self.toggle_git_blame_inline_internal(false, window, cx);
19283            }
19284
19285            let minimap_settings = EditorSettings::get_global(cx).minimap;
19286            if self.minimap_visibility != MinimapVisibility::Disabled {
19287                if self.minimap_visibility.settings_visibility()
19288                    != minimap_settings.minimap_enabled()
19289                {
19290                    self.set_minimap_visibility(
19291                        MinimapVisibility::for_mode(self.mode(), cx),
19292                        window,
19293                        cx,
19294                    );
19295                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19296                    minimap_entity.update(cx, |minimap_editor, cx| {
19297                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19298                    })
19299                }
19300            }
19301        }
19302
19303        cx.notify();
19304    }
19305
19306    pub fn set_searchable(&mut self, searchable: bool) {
19307        self.searchable = searchable;
19308    }
19309
19310    pub fn searchable(&self) -> bool {
19311        self.searchable
19312    }
19313
19314    fn open_proposed_changes_editor(
19315        &mut self,
19316        _: &OpenProposedChangesEditor,
19317        window: &mut Window,
19318        cx: &mut Context<Self>,
19319    ) {
19320        let Some(workspace) = self.workspace() else {
19321            cx.propagate();
19322            return;
19323        };
19324
19325        let selections = self.selections.all::<usize>(cx);
19326        let multi_buffer = self.buffer.read(cx);
19327        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19328        let mut new_selections_by_buffer = HashMap::default();
19329        for selection in selections {
19330            for (buffer, range, _) in
19331                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19332            {
19333                let mut range = range.to_point(buffer);
19334                range.start.column = 0;
19335                range.end.column = buffer.line_len(range.end.row);
19336                new_selections_by_buffer
19337                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19338                    .or_insert(Vec::new())
19339                    .push(range)
19340            }
19341        }
19342
19343        let proposed_changes_buffers = new_selections_by_buffer
19344            .into_iter()
19345            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19346            .collect::<Vec<_>>();
19347        let proposed_changes_editor = cx.new(|cx| {
19348            ProposedChangesEditor::new(
19349                "Proposed changes",
19350                proposed_changes_buffers,
19351                self.project.clone(),
19352                window,
19353                cx,
19354            )
19355        });
19356
19357        window.defer(cx, move |window, cx| {
19358            workspace.update(cx, |workspace, cx| {
19359                workspace.active_pane().update(cx, |pane, cx| {
19360                    pane.add_item(
19361                        Box::new(proposed_changes_editor),
19362                        true,
19363                        true,
19364                        None,
19365                        window,
19366                        cx,
19367                    );
19368                });
19369            });
19370        });
19371    }
19372
19373    pub fn open_excerpts_in_split(
19374        &mut self,
19375        _: &OpenExcerptsSplit,
19376        window: &mut Window,
19377        cx: &mut Context<Self>,
19378    ) {
19379        self.open_excerpts_common(None, true, window, cx)
19380    }
19381
19382    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19383        self.open_excerpts_common(None, false, window, cx)
19384    }
19385
19386    fn open_excerpts_common(
19387        &mut self,
19388        jump_data: Option<JumpData>,
19389        split: bool,
19390        window: &mut Window,
19391        cx: &mut Context<Self>,
19392    ) {
19393        let Some(workspace) = self.workspace() else {
19394            cx.propagate();
19395            return;
19396        };
19397
19398        if self.buffer.read(cx).is_singleton() {
19399            cx.propagate();
19400            return;
19401        }
19402
19403        let mut new_selections_by_buffer = HashMap::default();
19404        match &jump_data {
19405            Some(JumpData::MultiBufferPoint {
19406                excerpt_id,
19407                position,
19408                anchor,
19409                line_offset_from_top,
19410            }) => {
19411                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19412                if let Some(buffer) = multi_buffer_snapshot
19413                    .buffer_id_for_excerpt(*excerpt_id)
19414                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19415                {
19416                    let buffer_snapshot = buffer.read(cx).snapshot();
19417                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19418                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19419                    } else {
19420                        buffer_snapshot.clip_point(*position, Bias::Left)
19421                    };
19422                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19423                    new_selections_by_buffer.insert(
19424                        buffer,
19425                        (
19426                            vec![jump_to_offset..jump_to_offset],
19427                            Some(*line_offset_from_top),
19428                        ),
19429                    );
19430                }
19431            }
19432            Some(JumpData::MultiBufferRow {
19433                row,
19434                line_offset_from_top,
19435            }) => {
19436                let point = MultiBufferPoint::new(row.0, 0);
19437                if let Some((buffer, buffer_point, _)) =
19438                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19439                {
19440                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19441                    new_selections_by_buffer
19442                        .entry(buffer)
19443                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19444                        .0
19445                        .push(buffer_offset..buffer_offset)
19446                }
19447            }
19448            None => {
19449                let selections = self.selections.all::<usize>(cx);
19450                let multi_buffer = self.buffer.read(cx);
19451                for selection in selections {
19452                    for (snapshot, range, _, anchor) in multi_buffer
19453                        .snapshot(cx)
19454                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19455                    {
19456                        if let Some(anchor) = anchor {
19457                            // selection is in a deleted hunk
19458                            let Some(buffer_id) = anchor.buffer_id else {
19459                                continue;
19460                            };
19461                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19462                                continue;
19463                            };
19464                            let offset = text::ToOffset::to_offset(
19465                                &anchor.text_anchor,
19466                                &buffer_handle.read(cx).snapshot(),
19467                            );
19468                            let range = offset..offset;
19469                            new_selections_by_buffer
19470                                .entry(buffer_handle)
19471                                .or_insert((Vec::new(), None))
19472                                .0
19473                                .push(range)
19474                        } else {
19475                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19476                            else {
19477                                continue;
19478                            };
19479                            new_selections_by_buffer
19480                                .entry(buffer_handle)
19481                                .or_insert((Vec::new(), None))
19482                                .0
19483                                .push(range)
19484                        }
19485                    }
19486                }
19487            }
19488        }
19489
19490        new_selections_by_buffer
19491            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19492
19493        if new_selections_by_buffer.is_empty() {
19494            return;
19495        }
19496
19497        // We defer the pane interaction because we ourselves are a workspace item
19498        // and activating a new item causes the pane to call a method on us reentrantly,
19499        // which panics if we're on the stack.
19500        window.defer(cx, move |window, cx| {
19501            workspace.update(cx, |workspace, cx| {
19502                let pane = if split {
19503                    workspace.adjacent_pane(window, cx)
19504                } else {
19505                    workspace.active_pane().clone()
19506                };
19507
19508                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19509                    let editor = buffer
19510                        .read(cx)
19511                        .file()
19512                        .is_none()
19513                        .then(|| {
19514                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19515                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19516                            // Instead, we try to activate the existing editor in the pane first.
19517                            let (editor, pane_item_index) =
19518                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19519                                    let editor = item.downcast::<Editor>()?;
19520                                    let singleton_buffer =
19521                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19522                                    if singleton_buffer == buffer {
19523                                        Some((editor, i))
19524                                    } else {
19525                                        None
19526                                    }
19527                                })?;
19528                            pane.update(cx, |pane, cx| {
19529                                pane.activate_item(pane_item_index, true, true, window, cx)
19530                            });
19531                            Some(editor)
19532                        })
19533                        .flatten()
19534                        .unwrap_or_else(|| {
19535                            workspace.open_project_item::<Self>(
19536                                pane.clone(),
19537                                buffer,
19538                                true,
19539                                true,
19540                                window,
19541                                cx,
19542                            )
19543                        });
19544
19545                    editor.update(cx, |editor, cx| {
19546                        let autoscroll = match scroll_offset {
19547                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19548                            None => Autoscroll::newest(),
19549                        };
19550                        let nav_history = editor.nav_history.take();
19551                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19552                            s.select_ranges(ranges);
19553                        });
19554                        editor.nav_history = nav_history;
19555                    });
19556                }
19557            })
19558        });
19559    }
19560
19561    // For now, don't allow opening excerpts in buffers that aren't backed by
19562    // regular project files.
19563    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19564        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19565    }
19566
19567    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19568        let snapshot = self.buffer.read(cx).read(cx);
19569        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19570        Some(
19571            ranges
19572                .iter()
19573                .map(move |range| {
19574                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19575                })
19576                .collect(),
19577        )
19578    }
19579
19580    fn selection_replacement_ranges(
19581        &self,
19582        range: Range<OffsetUtf16>,
19583        cx: &mut App,
19584    ) -> Vec<Range<OffsetUtf16>> {
19585        let selections = self.selections.all::<OffsetUtf16>(cx);
19586        let newest_selection = selections
19587            .iter()
19588            .max_by_key(|selection| selection.id)
19589            .unwrap();
19590        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19591        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19592        let snapshot = self.buffer.read(cx).read(cx);
19593        selections
19594            .into_iter()
19595            .map(|mut selection| {
19596                selection.start.0 =
19597                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19598                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19599                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19600                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19601            })
19602            .collect()
19603    }
19604
19605    fn report_editor_event(
19606        &self,
19607        event_type: &'static str,
19608        file_extension: Option<String>,
19609        cx: &App,
19610    ) {
19611        if cfg!(any(test, feature = "test-support")) {
19612            return;
19613        }
19614
19615        let Some(project) = &self.project else { return };
19616
19617        // If None, we are in a file without an extension
19618        let file = self
19619            .buffer
19620            .read(cx)
19621            .as_singleton()
19622            .and_then(|b| b.read(cx).file());
19623        let file_extension = file_extension.or(file
19624            .as_ref()
19625            .and_then(|file| Path::new(file.file_name(cx)).extension())
19626            .and_then(|e| e.to_str())
19627            .map(|a| a.to_string()));
19628
19629        let vim_mode = vim_enabled(cx);
19630
19631        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19632        let copilot_enabled = edit_predictions_provider
19633            == language::language_settings::EditPredictionProvider::Copilot;
19634        let copilot_enabled_for_language = self
19635            .buffer
19636            .read(cx)
19637            .language_settings(cx)
19638            .show_edit_predictions;
19639
19640        let project = project.read(cx);
19641        telemetry::event!(
19642            event_type,
19643            file_extension,
19644            vim_mode,
19645            copilot_enabled,
19646            copilot_enabled_for_language,
19647            edit_predictions_provider,
19648            is_via_ssh = project.is_via_ssh(),
19649        );
19650    }
19651
19652    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19653    /// with each line being an array of {text, highlight} objects.
19654    fn copy_highlight_json(
19655        &mut self,
19656        _: &CopyHighlightJson,
19657        window: &mut Window,
19658        cx: &mut Context<Self>,
19659    ) {
19660        #[derive(Serialize)]
19661        struct Chunk<'a> {
19662            text: String,
19663            highlight: Option<&'a str>,
19664        }
19665
19666        let snapshot = self.buffer.read(cx).snapshot(cx);
19667        let range = self
19668            .selected_text_range(false, window, cx)
19669            .and_then(|selection| {
19670                if selection.range.is_empty() {
19671                    None
19672                } else {
19673                    Some(selection.range)
19674                }
19675            })
19676            .unwrap_or_else(|| 0..snapshot.len());
19677
19678        let chunks = snapshot.chunks(range, true);
19679        let mut lines = Vec::new();
19680        let mut line: VecDeque<Chunk> = VecDeque::new();
19681
19682        let Some(style) = self.style.as_ref() else {
19683            return;
19684        };
19685
19686        for chunk in chunks {
19687            let highlight = chunk
19688                .syntax_highlight_id
19689                .and_then(|id| id.name(&style.syntax));
19690            let mut chunk_lines = chunk.text.split('\n').peekable();
19691            while let Some(text) = chunk_lines.next() {
19692                let mut merged_with_last_token = false;
19693                if let Some(last_token) = line.back_mut() {
19694                    if last_token.highlight == highlight {
19695                        last_token.text.push_str(text);
19696                        merged_with_last_token = true;
19697                    }
19698                }
19699
19700                if !merged_with_last_token {
19701                    line.push_back(Chunk {
19702                        text: text.into(),
19703                        highlight,
19704                    });
19705                }
19706
19707                if chunk_lines.peek().is_some() {
19708                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19709                        line.pop_front();
19710                    }
19711                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19712                        line.pop_back();
19713                    }
19714
19715                    lines.push(mem::take(&mut line));
19716                }
19717            }
19718        }
19719
19720        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19721            return;
19722        };
19723        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19724    }
19725
19726    pub fn open_context_menu(
19727        &mut self,
19728        _: &OpenContextMenu,
19729        window: &mut Window,
19730        cx: &mut Context<Self>,
19731    ) {
19732        self.request_autoscroll(Autoscroll::newest(), cx);
19733        let position = self.selections.newest_display(cx).start;
19734        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19735    }
19736
19737    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19738        &self.inlay_hint_cache
19739    }
19740
19741    pub fn replay_insert_event(
19742        &mut self,
19743        text: &str,
19744        relative_utf16_range: Option<Range<isize>>,
19745        window: &mut Window,
19746        cx: &mut Context<Self>,
19747    ) {
19748        if !self.input_enabled {
19749            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19750            return;
19751        }
19752        if let Some(relative_utf16_range) = relative_utf16_range {
19753            let selections = self.selections.all::<OffsetUtf16>(cx);
19754            self.change_selections(None, window, cx, |s| {
19755                let new_ranges = selections.into_iter().map(|range| {
19756                    let start = OffsetUtf16(
19757                        range
19758                            .head()
19759                            .0
19760                            .saturating_add_signed(relative_utf16_range.start),
19761                    );
19762                    let end = OffsetUtf16(
19763                        range
19764                            .head()
19765                            .0
19766                            .saturating_add_signed(relative_utf16_range.end),
19767                    );
19768                    start..end
19769                });
19770                s.select_ranges(new_ranges);
19771            });
19772        }
19773
19774        self.handle_input(text, window, cx);
19775    }
19776
19777    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19778        let Some(provider) = self.semantics_provider.as_ref() else {
19779            return false;
19780        };
19781
19782        let mut supports = false;
19783        self.buffer().update(cx, |this, cx| {
19784            this.for_each_buffer(|buffer| {
19785                supports |= provider.supports_inlay_hints(buffer, cx);
19786            });
19787        });
19788
19789        supports
19790    }
19791
19792    pub fn is_focused(&self, window: &Window) -> bool {
19793        self.focus_handle.is_focused(window)
19794    }
19795
19796    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19797        cx.emit(EditorEvent::Focused);
19798
19799        if let Some(descendant) = self
19800            .last_focused_descendant
19801            .take()
19802            .and_then(|descendant| descendant.upgrade())
19803        {
19804            window.focus(&descendant);
19805        } else {
19806            if let Some(blame) = self.blame.as_ref() {
19807                blame.update(cx, GitBlame::focus)
19808            }
19809
19810            self.blink_manager.update(cx, BlinkManager::enable);
19811            self.show_cursor_names(window, cx);
19812            self.buffer.update(cx, |buffer, cx| {
19813                buffer.finalize_last_transaction(cx);
19814                if self.leader_id.is_none() {
19815                    buffer.set_active_selections(
19816                        &self.selections.disjoint_anchors(),
19817                        self.selections.line_mode,
19818                        self.cursor_shape,
19819                        cx,
19820                    );
19821                }
19822            });
19823        }
19824    }
19825
19826    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19827        cx.emit(EditorEvent::FocusedIn)
19828    }
19829
19830    fn handle_focus_out(
19831        &mut self,
19832        event: FocusOutEvent,
19833        _window: &mut Window,
19834        cx: &mut Context<Self>,
19835    ) {
19836        if event.blurred != self.focus_handle {
19837            self.last_focused_descendant = Some(event.blurred);
19838        }
19839        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19840    }
19841
19842    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19843        self.blink_manager.update(cx, BlinkManager::disable);
19844        self.buffer
19845            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19846
19847        if let Some(blame) = self.blame.as_ref() {
19848            blame.update(cx, GitBlame::blur)
19849        }
19850        if !self.hover_state.focused(window, cx) {
19851            hide_hover(self, cx);
19852        }
19853        if !self
19854            .context_menu
19855            .borrow()
19856            .as_ref()
19857            .is_some_and(|context_menu| context_menu.focused(window, cx))
19858        {
19859            self.hide_context_menu(window, cx);
19860        }
19861        self.discard_inline_completion(false, cx);
19862        cx.emit(EditorEvent::Blurred);
19863        cx.notify();
19864    }
19865
19866    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19867        let mut pending: String = window
19868            .pending_input_keystrokes()
19869            .into_iter()
19870            .flatten()
19871            .filter_map(|keystroke| {
19872                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19873                    keystroke.key_char.clone()
19874                } else {
19875                    None
19876                }
19877            })
19878            .collect();
19879
19880        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19881            pending = "".to_string();
19882        }
19883
19884        let existing_pending = self
19885            .text_highlights::<PendingInput>(cx)
19886            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19887        if existing_pending.is_none() && pending.is_empty() {
19888            return;
19889        }
19890        let transaction =
19891            self.transact(window, cx, |this, window, cx| {
19892                let selections = this.selections.all::<usize>(cx);
19893                let edits = selections
19894                    .iter()
19895                    .map(|selection| (selection.end..selection.end, pending.clone()));
19896                this.edit(edits, cx);
19897                this.change_selections(None, window, cx, |s| {
19898                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19899                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19900                    }));
19901                });
19902                if let Some(existing_ranges) = existing_pending {
19903                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19904                    this.edit(edits, cx);
19905                }
19906            });
19907
19908        let snapshot = self.snapshot(window, cx);
19909        let ranges = self
19910            .selections
19911            .all::<usize>(cx)
19912            .into_iter()
19913            .map(|selection| {
19914                snapshot.buffer_snapshot.anchor_after(selection.end)
19915                    ..snapshot
19916                        .buffer_snapshot
19917                        .anchor_before(selection.end + pending.len())
19918            })
19919            .collect();
19920
19921        if pending.is_empty() {
19922            self.clear_highlights::<PendingInput>(cx);
19923        } else {
19924            self.highlight_text::<PendingInput>(
19925                ranges,
19926                HighlightStyle {
19927                    underline: Some(UnderlineStyle {
19928                        thickness: px(1.),
19929                        color: None,
19930                        wavy: false,
19931                    }),
19932                    ..Default::default()
19933                },
19934                cx,
19935            );
19936        }
19937
19938        self.ime_transaction = self.ime_transaction.or(transaction);
19939        if let Some(transaction) = self.ime_transaction {
19940            self.buffer.update(cx, |buffer, cx| {
19941                buffer.group_until_transaction(transaction, cx);
19942            });
19943        }
19944
19945        if self.text_highlights::<PendingInput>(cx).is_none() {
19946            self.ime_transaction.take();
19947        }
19948    }
19949
19950    pub fn register_action_renderer(
19951        &mut self,
19952        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
19953    ) -> Subscription {
19954        let id = self.next_editor_action_id.post_inc();
19955        self.editor_actions
19956            .borrow_mut()
19957            .insert(id, Box::new(listener));
19958
19959        let editor_actions = self.editor_actions.clone();
19960        Subscription::new(move || {
19961            editor_actions.borrow_mut().remove(&id);
19962        })
19963    }
19964
19965    pub fn register_action<A: Action>(
19966        &mut self,
19967        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19968    ) -> Subscription {
19969        let id = self.next_editor_action_id.post_inc();
19970        let listener = Arc::new(listener);
19971        self.editor_actions.borrow_mut().insert(
19972            id,
19973            Box::new(move |_, window, _| {
19974                let listener = listener.clone();
19975                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19976                    let action = action.downcast_ref().unwrap();
19977                    if phase == DispatchPhase::Bubble {
19978                        listener(action, window, cx)
19979                    }
19980                })
19981            }),
19982        );
19983
19984        let editor_actions = self.editor_actions.clone();
19985        Subscription::new(move || {
19986            editor_actions.borrow_mut().remove(&id);
19987        })
19988    }
19989
19990    pub fn file_header_size(&self) -> u32 {
19991        FILE_HEADER_HEIGHT
19992    }
19993
19994    pub fn restore(
19995        &mut self,
19996        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19997        window: &mut Window,
19998        cx: &mut Context<Self>,
19999    ) {
20000        let workspace = self.workspace();
20001        let project = self.project.as_ref();
20002        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20003            let mut tasks = Vec::new();
20004            for (buffer_id, changes) in revert_changes {
20005                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20006                    buffer.update(cx, |buffer, cx| {
20007                        buffer.edit(
20008                            changes
20009                                .into_iter()
20010                                .map(|(range, text)| (range, text.to_string())),
20011                            None,
20012                            cx,
20013                        );
20014                    });
20015
20016                    if let Some(project) =
20017                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20018                    {
20019                        project.update(cx, |project, cx| {
20020                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20021                        })
20022                    }
20023                }
20024            }
20025            tasks
20026        });
20027        cx.spawn_in(window, async move |_, cx| {
20028            for (buffer, task) in save_tasks {
20029                let result = task.await;
20030                if result.is_err() {
20031                    let Some(path) = buffer
20032                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20033                        .ok()
20034                    else {
20035                        continue;
20036                    };
20037                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20038                        let Some(task) = cx
20039                            .update_window_entity(&workspace, |workspace, window, cx| {
20040                                workspace
20041                                    .open_path_preview(path, None, false, false, false, window, cx)
20042                            })
20043                            .ok()
20044                        else {
20045                            continue;
20046                        };
20047                        task.await.log_err();
20048                    }
20049                }
20050            }
20051        })
20052        .detach();
20053        self.change_selections(None, window, cx, |selections| selections.refresh());
20054    }
20055
20056    pub fn to_pixel_point(
20057        &self,
20058        source: multi_buffer::Anchor,
20059        editor_snapshot: &EditorSnapshot,
20060        window: &mut Window,
20061    ) -> Option<gpui::Point<Pixels>> {
20062        let source_point = source.to_display_point(editor_snapshot);
20063        self.display_to_pixel_point(source_point, editor_snapshot, window)
20064    }
20065
20066    pub fn display_to_pixel_point(
20067        &self,
20068        source: DisplayPoint,
20069        editor_snapshot: &EditorSnapshot,
20070        window: &mut Window,
20071    ) -> Option<gpui::Point<Pixels>> {
20072        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20073        let text_layout_details = self.text_layout_details(window);
20074        let scroll_top = text_layout_details
20075            .scroll_anchor
20076            .scroll_position(editor_snapshot)
20077            .y;
20078
20079        if source.row().as_f32() < scroll_top.floor() {
20080            return None;
20081        }
20082        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20083        let source_y = line_height * (source.row().as_f32() - scroll_top);
20084        Some(gpui::Point::new(source_x, source_y))
20085    }
20086
20087    pub fn has_visible_completions_menu(&self) -> bool {
20088        !self.edit_prediction_preview_is_active()
20089            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20090                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20091            })
20092    }
20093
20094    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20095        if self.mode.is_minimap() {
20096            return;
20097        }
20098        self.addons
20099            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20100    }
20101
20102    pub fn unregister_addon<T: Addon>(&mut self) {
20103        self.addons.remove(&std::any::TypeId::of::<T>());
20104    }
20105
20106    pub fn addon<T: Addon>(&self) -> Option<&T> {
20107        let type_id = std::any::TypeId::of::<T>();
20108        self.addons
20109            .get(&type_id)
20110            .and_then(|item| item.to_any().downcast_ref::<T>())
20111    }
20112
20113    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20114        let type_id = std::any::TypeId::of::<T>();
20115        self.addons
20116            .get_mut(&type_id)
20117            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20118    }
20119
20120    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20121        let text_layout_details = self.text_layout_details(window);
20122        let style = &text_layout_details.editor_style;
20123        let font_id = window.text_system().resolve_font(&style.text.font());
20124        let font_size = style.text.font_size.to_pixels(window.rem_size());
20125        let line_height = style.text.line_height_in_pixels(window.rem_size());
20126        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20127
20128        gpui::Size::new(em_width, line_height)
20129    }
20130
20131    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20132        self.load_diff_task.clone()
20133    }
20134
20135    fn read_metadata_from_db(
20136        &mut self,
20137        item_id: u64,
20138        workspace_id: WorkspaceId,
20139        window: &mut Window,
20140        cx: &mut Context<Editor>,
20141    ) {
20142        if self.is_singleton(cx)
20143            && !self.mode.is_minimap()
20144            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20145        {
20146            let buffer_snapshot = OnceCell::new();
20147
20148            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20149                if !folds.is_empty() {
20150                    let snapshot =
20151                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20152                    self.fold_ranges(
20153                        folds
20154                            .into_iter()
20155                            .map(|(start, end)| {
20156                                snapshot.clip_offset(start, Bias::Left)
20157                                    ..snapshot.clip_offset(end, Bias::Right)
20158                            })
20159                            .collect(),
20160                        false,
20161                        window,
20162                        cx,
20163                    );
20164                }
20165            }
20166
20167            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20168                if !selections.is_empty() {
20169                    let snapshot =
20170                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20171                    // skip adding the initial selection to selection history
20172                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20173                    self.change_selections(None, window, cx, |s| {
20174                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20175                            snapshot.clip_offset(start, Bias::Left)
20176                                ..snapshot.clip_offset(end, Bias::Right)
20177                        }));
20178                    });
20179                    self.selection_history.mode = SelectionHistoryMode::Normal;
20180                }
20181            };
20182        }
20183
20184        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20185    }
20186}
20187
20188fn vim_enabled(cx: &App) -> bool {
20189    cx.global::<SettingsStore>()
20190        .raw_user_settings()
20191        .get("vim_mode")
20192        == Some(&serde_json::Value::Bool(true))
20193}
20194
20195fn process_completion_for_edit(
20196    completion: &Completion,
20197    intent: CompletionIntent,
20198    buffer: &Entity<Buffer>,
20199    cursor_position: &text::Anchor,
20200    cx: &mut Context<Editor>,
20201) -> CompletionEdit {
20202    let buffer = buffer.read(cx);
20203    let buffer_snapshot = buffer.snapshot();
20204    let (snippet, new_text) = if completion.is_snippet() {
20205        // Workaround for typescript language server issues so that methods don't expand within
20206        // strings and functions with type expressions. The previous point is used because the query
20207        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20208        let mut snippet_source = completion.new_text.clone();
20209        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20210        previous_point.column = previous_point.column.saturating_sub(1);
20211        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20212            if scope.prefers_label_for_snippet_in_completion() {
20213                if let Some(label) = completion.label() {
20214                    if matches!(
20215                        completion.kind(),
20216                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20217                    ) {
20218                        snippet_source = label;
20219                    }
20220                }
20221            }
20222        }
20223        match Snippet::parse(&snippet_source).log_err() {
20224            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20225            None => (None, completion.new_text.clone()),
20226        }
20227    } else {
20228        (None, completion.new_text.clone())
20229    };
20230
20231    let mut range_to_replace = {
20232        let replace_range = &completion.replace_range;
20233        if let CompletionSource::Lsp {
20234            insert_range: Some(insert_range),
20235            ..
20236        } = &completion.source
20237        {
20238            debug_assert_eq!(
20239                insert_range.start, replace_range.start,
20240                "insert_range and replace_range should start at the same position"
20241            );
20242            debug_assert!(
20243                insert_range
20244                    .start
20245                    .cmp(&cursor_position, &buffer_snapshot)
20246                    .is_le(),
20247                "insert_range should start before or at cursor position"
20248            );
20249            debug_assert!(
20250                replace_range
20251                    .start
20252                    .cmp(&cursor_position, &buffer_snapshot)
20253                    .is_le(),
20254                "replace_range should start before or at cursor position"
20255            );
20256            debug_assert!(
20257                insert_range
20258                    .end
20259                    .cmp(&cursor_position, &buffer_snapshot)
20260                    .is_le(),
20261                "insert_range should end before or at cursor position"
20262            );
20263
20264            let should_replace = match intent {
20265                CompletionIntent::CompleteWithInsert => false,
20266                CompletionIntent::CompleteWithReplace => true,
20267                CompletionIntent::Complete | CompletionIntent::Compose => {
20268                    let insert_mode =
20269                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20270                            .completions
20271                            .lsp_insert_mode;
20272                    match insert_mode {
20273                        LspInsertMode::Insert => false,
20274                        LspInsertMode::Replace => true,
20275                        LspInsertMode::ReplaceSubsequence => {
20276                            let mut text_to_replace = buffer.chars_for_range(
20277                                buffer.anchor_before(replace_range.start)
20278                                    ..buffer.anchor_after(replace_range.end),
20279                            );
20280                            let mut current_needle = text_to_replace.next();
20281                            for haystack_ch in completion.label.text.chars() {
20282                                if let Some(needle_ch) = current_needle {
20283                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20284                                        current_needle = text_to_replace.next();
20285                                    }
20286                                }
20287                            }
20288                            current_needle.is_none()
20289                        }
20290                        LspInsertMode::ReplaceSuffix => {
20291                            if replace_range
20292                                .end
20293                                .cmp(&cursor_position, &buffer_snapshot)
20294                                .is_gt()
20295                            {
20296                                let range_after_cursor = *cursor_position..replace_range.end;
20297                                let text_after_cursor = buffer
20298                                    .text_for_range(
20299                                        buffer.anchor_before(range_after_cursor.start)
20300                                            ..buffer.anchor_after(range_after_cursor.end),
20301                                    )
20302                                    .collect::<String>()
20303                                    .to_ascii_lowercase();
20304                                completion
20305                                    .label
20306                                    .text
20307                                    .to_ascii_lowercase()
20308                                    .ends_with(&text_after_cursor)
20309                            } else {
20310                                true
20311                            }
20312                        }
20313                    }
20314                }
20315            };
20316
20317            if should_replace {
20318                replace_range.clone()
20319            } else {
20320                insert_range.clone()
20321            }
20322        } else {
20323            replace_range.clone()
20324        }
20325    };
20326
20327    if range_to_replace
20328        .end
20329        .cmp(&cursor_position, &buffer_snapshot)
20330        .is_lt()
20331    {
20332        range_to_replace.end = *cursor_position;
20333    }
20334
20335    CompletionEdit {
20336        new_text,
20337        replace_range: range_to_replace.to_offset(&buffer),
20338        snippet,
20339    }
20340}
20341
20342struct CompletionEdit {
20343    new_text: String,
20344    replace_range: Range<usize>,
20345    snippet: Option<Snippet>,
20346}
20347
20348fn insert_extra_newline_brackets(
20349    buffer: &MultiBufferSnapshot,
20350    range: Range<usize>,
20351    language: &language::LanguageScope,
20352) -> bool {
20353    let leading_whitespace_len = buffer
20354        .reversed_chars_at(range.start)
20355        .take_while(|c| c.is_whitespace() && *c != '\n')
20356        .map(|c| c.len_utf8())
20357        .sum::<usize>();
20358    let trailing_whitespace_len = buffer
20359        .chars_at(range.end)
20360        .take_while(|c| c.is_whitespace() && *c != '\n')
20361        .map(|c| c.len_utf8())
20362        .sum::<usize>();
20363    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20364
20365    language.brackets().any(|(pair, enabled)| {
20366        let pair_start = pair.start.trim_end();
20367        let pair_end = pair.end.trim_start();
20368
20369        enabled
20370            && pair.newline
20371            && buffer.contains_str_at(range.end, pair_end)
20372            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20373    })
20374}
20375
20376fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20377    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20378        [(buffer, range, _)] => (*buffer, range.clone()),
20379        _ => return false,
20380    };
20381    let pair = {
20382        let mut result: Option<BracketMatch> = None;
20383
20384        for pair in buffer
20385            .all_bracket_ranges(range.clone())
20386            .filter(move |pair| {
20387                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20388            })
20389        {
20390            let len = pair.close_range.end - pair.open_range.start;
20391
20392            if let Some(existing) = &result {
20393                let existing_len = existing.close_range.end - existing.open_range.start;
20394                if len > existing_len {
20395                    continue;
20396                }
20397            }
20398
20399            result = Some(pair);
20400        }
20401
20402        result
20403    };
20404    let Some(pair) = pair else {
20405        return false;
20406    };
20407    pair.newline_only
20408        && buffer
20409            .chars_for_range(pair.open_range.end..range.start)
20410            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20411            .all(|c| c.is_whitespace() && c != '\n')
20412}
20413
20414fn update_uncommitted_diff_for_buffer(
20415    editor: Entity<Editor>,
20416    project: &Entity<Project>,
20417    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20418    buffer: Entity<MultiBuffer>,
20419    cx: &mut App,
20420) -> Task<()> {
20421    let mut tasks = Vec::new();
20422    project.update(cx, |project, cx| {
20423        for buffer in buffers {
20424            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20425                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20426            }
20427        }
20428    });
20429    cx.spawn(async move |cx| {
20430        let diffs = future::join_all(tasks).await;
20431        if editor
20432            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20433            .unwrap_or(false)
20434        {
20435            return;
20436        }
20437
20438        buffer
20439            .update(cx, |buffer, cx| {
20440                for diff in diffs.into_iter().flatten() {
20441                    buffer.add_diff(diff, cx);
20442                }
20443            })
20444            .ok();
20445    })
20446}
20447
20448fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20449    let tab_size = tab_size.get() as usize;
20450    let mut width = offset;
20451
20452    for ch in text.chars() {
20453        width += if ch == '\t' {
20454            tab_size - (width % tab_size)
20455        } else {
20456            1
20457        };
20458    }
20459
20460    width - offset
20461}
20462
20463#[cfg(test)]
20464mod tests {
20465    use super::*;
20466
20467    #[test]
20468    fn test_string_size_with_expanded_tabs() {
20469        let nz = |val| NonZeroU32::new(val).unwrap();
20470        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20471        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20472        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20473        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20474        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20475        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20476        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20477        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20478    }
20479}
20480
20481/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20482struct WordBreakingTokenizer<'a> {
20483    input: &'a str,
20484}
20485
20486impl<'a> WordBreakingTokenizer<'a> {
20487    fn new(input: &'a str) -> Self {
20488        Self { input }
20489    }
20490}
20491
20492fn is_char_ideographic(ch: char) -> bool {
20493    use unicode_script::Script::*;
20494    use unicode_script::UnicodeScript;
20495    matches!(ch.script(), Han | Tangut | Yi)
20496}
20497
20498fn is_grapheme_ideographic(text: &str) -> bool {
20499    text.chars().any(is_char_ideographic)
20500}
20501
20502fn is_grapheme_whitespace(text: &str) -> bool {
20503    text.chars().any(|x| x.is_whitespace())
20504}
20505
20506fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20507    text.chars().next().map_or(false, |ch| {
20508        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20509    })
20510}
20511
20512#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20513enum WordBreakToken<'a> {
20514    Word { token: &'a str, grapheme_len: usize },
20515    InlineWhitespace { token: &'a str, grapheme_len: usize },
20516    Newline,
20517}
20518
20519impl<'a> Iterator for WordBreakingTokenizer<'a> {
20520    /// Yields a span, the count of graphemes in the token, and whether it was
20521    /// whitespace. Note that it also breaks at word boundaries.
20522    type Item = WordBreakToken<'a>;
20523
20524    fn next(&mut self) -> Option<Self::Item> {
20525        use unicode_segmentation::UnicodeSegmentation;
20526        if self.input.is_empty() {
20527            return None;
20528        }
20529
20530        let mut iter = self.input.graphemes(true).peekable();
20531        let mut offset = 0;
20532        let mut grapheme_len = 0;
20533        if let Some(first_grapheme) = iter.next() {
20534            let is_newline = first_grapheme == "\n";
20535            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20536            offset += first_grapheme.len();
20537            grapheme_len += 1;
20538            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20539                if let Some(grapheme) = iter.peek().copied() {
20540                    if should_stay_with_preceding_ideograph(grapheme) {
20541                        offset += grapheme.len();
20542                        grapheme_len += 1;
20543                    }
20544                }
20545            } else {
20546                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20547                let mut next_word_bound = words.peek().copied();
20548                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20549                    next_word_bound = words.next();
20550                }
20551                while let Some(grapheme) = iter.peek().copied() {
20552                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20553                        break;
20554                    };
20555                    if is_grapheme_whitespace(grapheme) != is_whitespace
20556                        || (grapheme == "\n") != is_newline
20557                    {
20558                        break;
20559                    };
20560                    offset += grapheme.len();
20561                    grapheme_len += 1;
20562                    iter.next();
20563                }
20564            }
20565            let token = &self.input[..offset];
20566            self.input = &self.input[offset..];
20567            if token == "\n" {
20568                Some(WordBreakToken::Newline)
20569            } else if is_whitespace {
20570                Some(WordBreakToken::InlineWhitespace {
20571                    token,
20572                    grapheme_len,
20573                })
20574            } else {
20575                Some(WordBreakToken::Word {
20576                    token,
20577                    grapheme_len,
20578                })
20579            }
20580        } else {
20581            None
20582        }
20583    }
20584}
20585
20586#[test]
20587fn test_word_breaking_tokenizer() {
20588    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20589        ("", &[]),
20590        ("  ", &[whitespace("  ", 2)]),
20591        ("Ʒ", &[word("Ʒ", 1)]),
20592        ("Ǽ", &[word("Ǽ", 1)]),
20593        ("", &[word("", 1)]),
20594        ("⋑⋑", &[word("⋑⋑", 2)]),
20595        (
20596            "原理,进而",
20597            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20598        ),
20599        (
20600            "hello world",
20601            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20602        ),
20603        (
20604            "hello, world",
20605            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20606        ),
20607        (
20608            "  hello world",
20609            &[
20610                whitespace("  ", 2),
20611                word("hello", 5),
20612                whitespace(" ", 1),
20613                word("world", 5),
20614            ],
20615        ),
20616        (
20617            "这是什么 \n 钢笔",
20618            &[
20619                word("", 1),
20620                word("", 1),
20621                word("", 1),
20622                word("", 1),
20623                whitespace(" ", 1),
20624                newline(),
20625                whitespace(" ", 1),
20626                word("", 1),
20627                word("", 1),
20628            ],
20629        ),
20630        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20631    ];
20632
20633    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20634        WordBreakToken::Word {
20635            token,
20636            grapheme_len,
20637        }
20638    }
20639
20640    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20641        WordBreakToken::InlineWhitespace {
20642            token,
20643            grapheme_len,
20644        }
20645    }
20646
20647    fn newline() -> WordBreakToken<'static> {
20648        WordBreakToken::Newline
20649    }
20650
20651    for (input, result) in tests {
20652        assert_eq!(
20653            WordBreakingTokenizer::new(input)
20654                .collect::<Vec<_>>()
20655                .as_slice(),
20656            *result,
20657        );
20658    }
20659}
20660
20661fn wrap_with_prefix(
20662    line_prefix: String,
20663    unwrapped_text: String,
20664    wrap_column: usize,
20665    tab_size: NonZeroU32,
20666    preserve_existing_whitespace: bool,
20667) -> String {
20668    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20669    let mut wrapped_text = String::new();
20670    let mut current_line = line_prefix.clone();
20671
20672    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20673    let mut current_line_len = line_prefix_len;
20674    let mut in_whitespace = false;
20675    for token in tokenizer {
20676        let have_preceding_whitespace = in_whitespace;
20677        match token {
20678            WordBreakToken::Word {
20679                token,
20680                grapheme_len,
20681            } => {
20682                in_whitespace = false;
20683                if current_line_len + grapheme_len > wrap_column
20684                    && current_line_len != line_prefix_len
20685                {
20686                    wrapped_text.push_str(current_line.trim_end());
20687                    wrapped_text.push('\n');
20688                    current_line.truncate(line_prefix.len());
20689                    current_line_len = line_prefix_len;
20690                }
20691                current_line.push_str(token);
20692                current_line_len += grapheme_len;
20693            }
20694            WordBreakToken::InlineWhitespace {
20695                mut token,
20696                mut grapheme_len,
20697            } => {
20698                in_whitespace = true;
20699                if have_preceding_whitespace && !preserve_existing_whitespace {
20700                    continue;
20701                }
20702                if !preserve_existing_whitespace {
20703                    token = " ";
20704                    grapheme_len = 1;
20705                }
20706                if current_line_len + grapheme_len > wrap_column {
20707                    wrapped_text.push_str(current_line.trim_end());
20708                    wrapped_text.push('\n');
20709                    current_line.truncate(line_prefix.len());
20710                    current_line_len = line_prefix_len;
20711                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20712                    current_line.push_str(token);
20713                    current_line_len += grapheme_len;
20714                }
20715            }
20716            WordBreakToken::Newline => {
20717                in_whitespace = true;
20718                if preserve_existing_whitespace {
20719                    wrapped_text.push_str(current_line.trim_end());
20720                    wrapped_text.push('\n');
20721                    current_line.truncate(line_prefix.len());
20722                    current_line_len = line_prefix_len;
20723                } else if have_preceding_whitespace {
20724                    continue;
20725                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20726                {
20727                    wrapped_text.push_str(current_line.trim_end());
20728                    wrapped_text.push('\n');
20729                    current_line.truncate(line_prefix.len());
20730                    current_line_len = line_prefix_len;
20731                } else if current_line_len != line_prefix_len {
20732                    current_line.push(' ');
20733                    current_line_len += 1;
20734                }
20735            }
20736        }
20737    }
20738
20739    if !current_line.is_empty() {
20740        wrapped_text.push_str(&current_line);
20741    }
20742    wrapped_text
20743}
20744
20745#[test]
20746fn test_wrap_with_prefix() {
20747    assert_eq!(
20748        wrap_with_prefix(
20749            "# ".to_string(),
20750            "abcdefg".to_string(),
20751            4,
20752            NonZeroU32::new(4).unwrap(),
20753            false,
20754        ),
20755        "# abcdefg"
20756    );
20757    assert_eq!(
20758        wrap_with_prefix(
20759            "".to_string(),
20760            "\thello world".to_string(),
20761            8,
20762            NonZeroU32::new(4).unwrap(),
20763            false,
20764        ),
20765        "hello\nworld"
20766    );
20767    assert_eq!(
20768        wrap_with_prefix(
20769            "// ".to_string(),
20770            "xx \nyy zz aa bb cc".to_string(),
20771            12,
20772            NonZeroU32::new(4).unwrap(),
20773            false,
20774        ),
20775        "// xx yy zz\n// aa bb cc"
20776    );
20777    assert_eq!(
20778        wrap_with_prefix(
20779            String::new(),
20780            "这是什么 \n 钢笔".to_string(),
20781            3,
20782            NonZeroU32::new(4).unwrap(),
20783            false,
20784        ),
20785        "这是什\n么 钢\n"
20786    );
20787}
20788
20789pub trait CollaborationHub {
20790    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20791    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20792    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20793}
20794
20795impl CollaborationHub for Entity<Project> {
20796    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20797        self.read(cx).collaborators()
20798    }
20799
20800    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20801        self.read(cx).user_store().read(cx).participant_indices()
20802    }
20803
20804    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20805        let this = self.read(cx);
20806        let user_ids = this.collaborators().values().map(|c| c.user_id);
20807        this.user_store().read(cx).participant_names(user_ids, cx)
20808    }
20809}
20810
20811pub trait SemanticsProvider {
20812    fn hover(
20813        &self,
20814        buffer: &Entity<Buffer>,
20815        position: text::Anchor,
20816        cx: &mut App,
20817    ) -> Option<Task<Vec<project::Hover>>>;
20818
20819    fn inline_values(
20820        &self,
20821        buffer_handle: Entity<Buffer>,
20822        range: Range<text::Anchor>,
20823        cx: &mut App,
20824    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20825
20826    fn inlay_hints(
20827        &self,
20828        buffer_handle: Entity<Buffer>,
20829        range: Range<text::Anchor>,
20830        cx: &mut App,
20831    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20832
20833    fn resolve_inlay_hint(
20834        &self,
20835        hint: InlayHint,
20836        buffer_handle: Entity<Buffer>,
20837        server_id: LanguageServerId,
20838        cx: &mut App,
20839    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20840
20841    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20842
20843    fn document_highlights(
20844        &self,
20845        buffer: &Entity<Buffer>,
20846        position: text::Anchor,
20847        cx: &mut App,
20848    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20849
20850    fn definitions(
20851        &self,
20852        buffer: &Entity<Buffer>,
20853        position: text::Anchor,
20854        kind: GotoDefinitionKind,
20855        cx: &mut App,
20856    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20857
20858    fn range_for_rename(
20859        &self,
20860        buffer: &Entity<Buffer>,
20861        position: text::Anchor,
20862        cx: &mut App,
20863    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20864
20865    fn perform_rename(
20866        &self,
20867        buffer: &Entity<Buffer>,
20868        position: text::Anchor,
20869        new_name: String,
20870        cx: &mut App,
20871    ) -> Option<Task<Result<ProjectTransaction>>>;
20872
20873    fn pull_diagnostics_for_buffer(
20874        &self,
20875        buffer: Entity<Buffer>,
20876        cx: &mut App,
20877    ) -> Task<anyhow::Result<()>>;
20878}
20879
20880pub trait CompletionProvider {
20881    fn completions(
20882        &self,
20883        excerpt_id: ExcerptId,
20884        buffer: &Entity<Buffer>,
20885        buffer_position: text::Anchor,
20886        trigger: CompletionContext,
20887        window: &mut Window,
20888        cx: &mut Context<Editor>,
20889    ) -> Task<Result<Vec<CompletionResponse>>>;
20890
20891    fn resolve_completions(
20892        &self,
20893        _buffer: Entity<Buffer>,
20894        _completion_indices: Vec<usize>,
20895        _completions: Rc<RefCell<Box<[Completion]>>>,
20896        _cx: &mut Context<Editor>,
20897    ) -> Task<Result<bool>> {
20898        Task::ready(Ok(false))
20899    }
20900
20901    fn apply_additional_edits_for_completion(
20902        &self,
20903        _buffer: Entity<Buffer>,
20904        _completions: Rc<RefCell<Box<[Completion]>>>,
20905        _completion_index: usize,
20906        _push_to_history: bool,
20907        _cx: &mut Context<Editor>,
20908    ) -> Task<Result<Option<language::Transaction>>> {
20909        Task::ready(Ok(None))
20910    }
20911
20912    fn is_completion_trigger(
20913        &self,
20914        buffer: &Entity<Buffer>,
20915        position: language::Anchor,
20916        text: &str,
20917        trigger_in_words: bool,
20918        menu_is_open: bool,
20919        cx: &mut Context<Editor>,
20920    ) -> bool;
20921
20922    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20923
20924    fn sort_completions(&self) -> bool {
20925        true
20926    }
20927
20928    fn filter_completions(&self) -> bool {
20929        true
20930    }
20931}
20932
20933pub trait CodeActionProvider {
20934    fn id(&self) -> Arc<str>;
20935
20936    fn code_actions(
20937        &self,
20938        buffer: &Entity<Buffer>,
20939        range: Range<text::Anchor>,
20940        window: &mut Window,
20941        cx: &mut App,
20942    ) -> Task<Result<Vec<CodeAction>>>;
20943
20944    fn apply_code_action(
20945        &self,
20946        buffer_handle: Entity<Buffer>,
20947        action: CodeAction,
20948        excerpt_id: ExcerptId,
20949        push_to_history: bool,
20950        window: &mut Window,
20951        cx: &mut App,
20952    ) -> Task<Result<ProjectTransaction>>;
20953}
20954
20955impl CodeActionProvider for Entity<Project> {
20956    fn id(&self) -> Arc<str> {
20957        "project".into()
20958    }
20959
20960    fn code_actions(
20961        &self,
20962        buffer: &Entity<Buffer>,
20963        range: Range<text::Anchor>,
20964        _window: &mut Window,
20965        cx: &mut App,
20966    ) -> Task<Result<Vec<CodeAction>>> {
20967        self.update(cx, |project, cx| {
20968            let code_lens = project.code_lens(buffer, range.clone(), cx);
20969            let code_actions = project.code_actions(buffer, range, None, cx);
20970            cx.background_spawn(async move {
20971                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20972                Ok(code_lens
20973                    .context("code lens fetch")?
20974                    .into_iter()
20975                    .chain(code_actions.context("code action fetch")?)
20976                    .collect())
20977            })
20978        })
20979    }
20980
20981    fn apply_code_action(
20982        &self,
20983        buffer_handle: Entity<Buffer>,
20984        action: CodeAction,
20985        _excerpt_id: ExcerptId,
20986        push_to_history: bool,
20987        _window: &mut Window,
20988        cx: &mut App,
20989    ) -> Task<Result<ProjectTransaction>> {
20990        self.update(cx, |project, cx| {
20991            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20992        })
20993    }
20994}
20995
20996fn snippet_completions(
20997    project: &Project,
20998    buffer: &Entity<Buffer>,
20999    buffer_position: text::Anchor,
21000    cx: &mut App,
21001) -> Task<Result<CompletionResponse>> {
21002    let languages = buffer.read(cx).languages_at(buffer_position);
21003    let snippet_store = project.snippets().read(cx);
21004
21005    let scopes: Vec<_> = languages
21006        .iter()
21007        .filter_map(|language| {
21008            let language_name = language.lsp_id();
21009            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21010
21011            if snippets.is_empty() {
21012                None
21013            } else {
21014                Some((language.default_scope(), snippets))
21015            }
21016        })
21017        .collect();
21018
21019    if scopes.is_empty() {
21020        return Task::ready(Ok(CompletionResponse {
21021            completions: vec![],
21022            is_incomplete: false,
21023        }));
21024    }
21025
21026    let snapshot = buffer.read(cx).text_snapshot();
21027    let chars: String = snapshot
21028        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21029        .collect();
21030    let executor = cx.background_executor().clone();
21031
21032    cx.background_spawn(async move {
21033        let mut is_incomplete = false;
21034        let mut completions: Vec<Completion> = Vec::new();
21035        for (scope, snippets) in scopes.into_iter() {
21036            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21037            let mut last_word = chars
21038                .chars()
21039                .take_while(|c| classifier.is_word(*c))
21040                .collect::<String>();
21041            last_word = last_word.chars().rev().collect();
21042
21043            if last_word.is_empty() {
21044                return Ok(CompletionResponse {
21045                    completions: vec![],
21046                    is_incomplete: true,
21047                });
21048            }
21049
21050            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21051            let to_lsp = |point: &text::Anchor| {
21052                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21053                point_to_lsp(end)
21054            };
21055            let lsp_end = to_lsp(&buffer_position);
21056
21057            let candidates = snippets
21058                .iter()
21059                .enumerate()
21060                .flat_map(|(ix, snippet)| {
21061                    snippet
21062                        .prefix
21063                        .iter()
21064                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21065                })
21066                .collect::<Vec<StringMatchCandidate>>();
21067
21068            const MAX_RESULTS: usize = 100;
21069            let mut matches = fuzzy::match_strings(
21070                &candidates,
21071                &last_word,
21072                last_word.chars().any(|c| c.is_uppercase()),
21073                MAX_RESULTS,
21074                &Default::default(),
21075                executor.clone(),
21076            )
21077            .await;
21078
21079            if matches.len() >= MAX_RESULTS {
21080                is_incomplete = true;
21081            }
21082
21083            // Remove all candidates where the query's start does not match the start of any word in the candidate
21084            if let Some(query_start) = last_word.chars().next() {
21085                matches.retain(|string_match| {
21086                    split_words(&string_match.string).any(|word| {
21087                        // Check that the first codepoint of the word as lowercase matches the first
21088                        // codepoint of the query as lowercase
21089                        word.chars()
21090                            .flat_map(|codepoint| codepoint.to_lowercase())
21091                            .zip(query_start.to_lowercase())
21092                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21093                    })
21094                });
21095            }
21096
21097            let matched_strings = matches
21098                .into_iter()
21099                .map(|m| m.string)
21100                .collect::<HashSet<_>>();
21101
21102            completions.extend(snippets.iter().filter_map(|snippet| {
21103                let matching_prefix = snippet
21104                    .prefix
21105                    .iter()
21106                    .find(|prefix| matched_strings.contains(*prefix))?;
21107                let start = as_offset - last_word.len();
21108                let start = snapshot.anchor_before(start);
21109                let range = start..buffer_position;
21110                let lsp_start = to_lsp(&start);
21111                let lsp_range = lsp::Range {
21112                    start: lsp_start,
21113                    end: lsp_end,
21114                };
21115                Some(Completion {
21116                    replace_range: range,
21117                    new_text: snippet.body.clone(),
21118                    source: CompletionSource::Lsp {
21119                        insert_range: None,
21120                        server_id: LanguageServerId(usize::MAX),
21121                        resolved: true,
21122                        lsp_completion: Box::new(lsp::CompletionItem {
21123                            label: snippet.prefix.first().unwrap().clone(),
21124                            kind: Some(CompletionItemKind::SNIPPET),
21125                            label_details: snippet.description.as_ref().map(|description| {
21126                                lsp::CompletionItemLabelDetails {
21127                                    detail: Some(description.clone()),
21128                                    description: None,
21129                                }
21130                            }),
21131                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21132                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21133                                lsp::InsertReplaceEdit {
21134                                    new_text: snippet.body.clone(),
21135                                    insert: lsp_range,
21136                                    replace: lsp_range,
21137                                },
21138                            )),
21139                            filter_text: Some(snippet.body.clone()),
21140                            sort_text: Some(char::MAX.to_string()),
21141                            ..lsp::CompletionItem::default()
21142                        }),
21143                        lsp_defaults: None,
21144                    },
21145                    label: CodeLabel {
21146                        text: matching_prefix.clone(),
21147                        runs: Vec::new(),
21148                        filter_range: 0..matching_prefix.len(),
21149                    },
21150                    icon_path: None,
21151                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21152                        single_line: snippet.name.clone().into(),
21153                        plain_text: snippet
21154                            .description
21155                            .clone()
21156                            .map(|description| description.into()),
21157                    }),
21158                    insert_text_mode: None,
21159                    confirm: None,
21160                })
21161            }))
21162        }
21163
21164        Ok(CompletionResponse {
21165            completions,
21166            is_incomplete,
21167        })
21168    })
21169}
21170
21171impl CompletionProvider for Entity<Project> {
21172    fn completions(
21173        &self,
21174        _excerpt_id: ExcerptId,
21175        buffer: &Entity<Buffer>,
21176        buffer_position: text::Anchor,
21177        options: CompletionContext,
21178        _window: &mut Window,
21179        cx: &mut Context<Editor>,
21180    ) -> Task<Result<Vec<CompletionResponse>>> {
21181        self.update(cx, |project, cx| {
21182            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21183            let project_completions = project.completions(buffer, buffer_position, options, cx);
21184            cx.background_spawn(async move {
21185                let mut responses = project_completions.await?;
21186                let snippets = snippets.await?;
21187                if !snippets.completions.is_empty() {
21188                    responses.push(snippets);
21189                }
21190                Ok(responses)
21191            })
21192        })
21193    }
21194
21195    fn resolve_completions(
21196        &self,
21197        buffer: Entity<Buffer>,
21198        completion_indices: Vec<usize>,
21199        completions: Rc<RefCell<Box<[Completion]>>>,
21200        cx: &mut Context<Editor>,
21201    ) -> Task<Result<bool>> {
21202        self.update(cx, |project, cx| {
21203            project.lsp_store().update(cx, |lsp_store, cx| {
21204                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21205            })
21206        })
21207    }
21208
21209    fn apply_additional_edits_for_completion(
21210        &self,
21211        buffer: Entity<Buffer>,
21212        completions: Rc<RefCell<Box<[Completion]>>>,
21213        completion_index: usize,
21214        push_to_history: bool,
21215        cx: &mut Context<Editor>,
21216    ) -> Task<Result<Option<language::Transaction>>> {
21217        self.update(cx, |project, cx| {
21218            project.lsp_store().update(cx, |lsp_store, cx| {
21219                lsp_store.apply_additional_edits_for_completion(
21220                    buffer,
21221                    completions,
21222                    completion_index,
21223                    push_to_history,
21224                    cx,
21225                )
21226            })
21227        })
21228    }
21229
21230    fn is_completion_trigger(
21231        &self,
21232        buffer: &Entity<Buffer>,
21233        position: language::Anchor,
21234        text: &str,
21235        trigger_in_words: bool,
21236        menu_is_open: bool,
21237        cx: &mut Context<Editor>,
21238    ) -> bool {
21239        let mut chars = text.chars();
21240        let char = if let Some(char) = chars.next() {
21241            char
21242        } else {
21243            return false;
21244        };
21245        if chars.next().is_some() {
21246            return false;
21247        }
21248
21249        let buffer = buffer.read(cx);
21250        let snapshot = buffer.snapshot();
21251        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21252            return false;
21253        }
21254        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21255        if trigger_in_words && classifier.is_word(char) {
21256            return true;
21257        }
21258
21259        buffer.completion_triggers().contains(text)
21260    }
21261}
21262
21263impl SemanticsProvider for Entity<Project> {
21264    fn hover(
21265        &self,
21266        buffer: &Entity<Buffer>,
21267        position: text::Anchor,
21268        cx: &mut App,
21269    ) -> Option<Task<Vec<project::Hover>>> {
21270        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21271    }
21272
21273    fn document_highlights(
21274        &self,
21275        buffer: &Entity<Buffer>,
21276        position: text::Anchor,
21277        cx: &mut App,
21278    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21279        Some(self.update(cx, |project, cx| {
21280            project.document_highlights(buffer, position, cx)
21281        }))
21282    }
21283
21284    fn definitions(
21285        &self,
21286        buffer: &Entity<Buffer>,
21287        position: text::Anchor,
21288        kind: GotoDefinitionKind,
21289        cx: &mut App,
21290    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21291        Some(self.update(cx, |project, cx| match kind {
21292            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21293            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21294            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21295            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21296        }))
21297    }
21298
21299    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21300        // TODO: make this work for remote projects
21301        self.update(cx, |project, cx| {
21302            if project
21303                .active_debug_session(cx)
21304                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21305            {
21306                return true;
21307            }
21308
21309            buffer.update(cx, |buffer, cx| {
21310                project.any_language_server_supports_inlay_hints(buffer, cx)
21311            })
21312        })
21313    }
21314
21315    fn inline_values(
21316        &self,
21317        buffer_handle: Entity<Buffer>,
21318
21319        range: Range<text::Anchor>,
21320        cx: &mut App,
21321    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21322        self.update(cx, |project, cx| {
21323            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21324
21325            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21326        })
21327    }
21328
21329    fn inlay_hints(
21330        &self,
21331        buffer_handle: Entity<Buffer>,
21332        range: Range<text::Anchor>,
21333        cx: &mut App,
21334    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21335        Some(self.update(cx, |project, cx| {
21336            project.inlay_hints(buffer_handle, range, cx)
21337        }))
21338    }
21339
21340    fn resolve_inlay_hint(
21341        &self,
21342        hint: InlayHint,
21343        buffer_handle: Entity<Buffer>,
21344        server_id: LanguageServerId,
21345        cx: &mut App,
21346    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21347        Some(self.update(cx, |project, cx| {
21348            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21349        }))
21350    }
21351
21352    fn range_for_rename(
21353        &self,
21354        buffer: &Entity<Buffer>,
21355        position: text::Anchor,
21356        cx: &mut App,
21357    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21358        Some(self.update(cx, |project, cx| {
21359            let buffer = buffer.clone();
21360            let task = project.prepare_rename(buffer.clone(), position, cx);
21361            cx.spawn(async move |_, cx| {
21362                Ok(match task.await? {
21363                    PrepareRenameResponse::Success(range) => Some(range),
21364                    PrepareRenameResponse::InvalidPosition => None,
21365                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21366                        // Fallback on using TreeSitter info to determine identifier range
21367                        buffer.read_with(cx, |buffer, _| {
21368                            let snapshot = buffer.snapshot();
21369                            let (range, kind) = snapshot.surrounding_word(position);
21370                            if kind != Some(CharKind::Word) {
21371                                return None;
21372                            }
21373                            Some(
21374                                snapshot.anchor_before(range.start)
21375                                    ..snapshot.anchor_after(range.end),
21376                            )
21377                        })?
21378                    }
21379                })
21380            })
21381        }))
21382    }
21383
21384    fn perform_rename(
21385        &self,
21386        buffer: &Entity<Buffer>,
21387        position: text::Anchor,
21388        new_name: String,
21389        cx: &mut App,
21390    ) -> Option<Task<Result<ProjectTransaction>>> {
21391        Some(self.update(cx, |project, cx| {
21392            project.perform_rename(buffer.clone(), position, new_name, cx)
21393        }))
21394    }
21395
21396    fn pull_diagnostics_for_buffer(
21397        &self,
21398        buffer: Entity<Buffer>,
21399        cx: &mut App,
21400    ) -> Task<anyhow::Result<()>> {
21401        let diagnostics = self.update(cx, |project, cx| {
21402            project
21403                .lsp_store()
21404                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21405        });
21406        let project = self.clone();
21407        cx.spawn(async move |cx| {
21408            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21409            project.update(cx, |project, cx| {
21410                project.lsp_store().update(cx, |lsp_store, cx| {
21411                    for diagnostics_set in diagnostics {
21412                        let LspPullDiagnostics::Response {
21413                            server_id,
21414                            uri,
21415                            diagnostics,
21416                        } = diagnostics_set
21417                        else {
21418                            continue;
21419                        };
21420
21421                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21422                        let disk_based_sources = adapter
21423                            .as_ref()
21424                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21425                            .unwrap_or(&[]);
21426                        match diagnostics {
21427                            PulledDiagnostics::Unchanged { result_id } => {
21428                                lsp_store
21429                                    .merge_diagnostics(
21430                                        server_id,
21431                                        lsp::PublishDiagnosticsParams {
21432                                            uri: uri.clone(),
21433                                            diagnostics: Vec::new(),
21434                                            version: None,
21435                                        },
21436                                        Some(result_id),
21437                                        DiagnosticSourceKind::Pulled,
21438                                        disk_based_sources,
21439                                        |_, _| true,
21440                                        cx,
21441                                    )
21442                                    .log_err();
21443                            }
21444                            PulledDiagnostics::Changed {
21445                                diagnostics,
21446                                result_id,
21447                            } => {
21448                                lsp_store
21449                                    .merge_diagnostics(
21450                                        server_id,
21451                                        lsp::PublishDiagnosticsParams {
21452                                            uri: uri.clone(),
21453                                            diagnostics,
21454                                            version: None,
21455                                        },
21456                                        result_id,
21457                                        DiagnosticSourceKind::Pulled,
21458                                        disk_based_sources,
21459                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21460                                            DiagnosticSourceKind::Pulled => false,
21461                                            DiagnosticSourceKind::Other
21462                                            | DiagnosticSourceKind::Pushed => true,
21463                                        },
21464                                        cx,
21465                                    )
21466                                    .log_err();
21467                            }
21468                        }
21469                    }
21470                })
21471            })
21472        })
21473    }
21474}
21475
21476fn inlay_hint_settings(
21477    location: Anchor,
21478    snapshot: &MultiBufferSnapshot,
21479    cx: &mut Context<Editor>,
21480) -> InlayHintSettings {
21481    let file = snapshot.file_at(location);
21482    let language = snapshot.language_at(location).map(|l| l.name());
21483    language_settings(language, file, cx).inlay_hints
21484}
21485
21486fn consume_contiguous_rows(
21487    contiguous_row_selections: &mut Vec<Selection<Point>>,
21488    selection: &Selection<Point>,
21489    display_map: &DisplaySnapshot,
21490    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21491) -> (MultiBufferRow, MultiBufferRow) {
21492    contiguous_row_selections.push(selection.clone());
21493    let start_row = MultiBufferRow(selection.start.row);
21494    let mut end_row = ending_row(selection, display_map);
21495
21496    while let Some(next_selection) = selections.peek() {
21497        if next_selection.start.row <= end_row.0 {
21498            end_row = ending_row(next_selection, display_map);
21499            contiguous_row_selections.push(selections.next().unwrap().clone());
21500        } else {
21501            break;
21502        }
21503    }
21504    (start_row, end_row)
21505}
21506
21507fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21508    if next_selection.end.column > 0 || next_selection.is_empty() {
21509        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21510    } else {
21511        MultiBufferRow(next_selection.end.row)
21512    }
21513}
21514
21515impl EditorSnapshot {
21516    pub fn remote_selections_in_range<'a>(
21517        &'a self,
21518        range: &'a Range<Anchor>,
21519        collaboration_hub: &dyn CollaborationHub,
21520        cx: &'a App,
21521    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21522        let participant_names = collaboration_hub.user_names(cx);
21523        let participant_indices = collaboration_hub.user_participant_indices(cx);
21524        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21525        let collaborators_by_replica_id = collaborators_by_peer_id
21526            .values()
21527            .map(|collaborator| (collaborator.replica_id, collaborator))
21528            .collect::<HashMap<_, _>>();
21529        self.buffer_snapshot
21530            .selections_in_range(range, false)
21531            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21532                if replica_id == AGENT_REPLICA_ID {
21533                    Some(RemoteSelection {
21534                        replica_id,
21535                        selection,
21536                        cursor_shape,
21537                        line_mode,
21538                        collaborator_id: CollaboratorId::Agent,
21539                        user_name: Some("Agent".into()),
21540                        color: cx.theme().players().agent(),
21541                    })
21542                } else {
21543                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21544                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21545                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21546                    Some(RemoteSelection {
21547                        replica_id,
21548                        selection,
21549                        cursor_shape,
21550                        line_mode,
21551                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21552                        user_name,
21553                        color: if let Some(index) = participant_index {
21554                            cx.theme().players().color_for_participant(index.0)
21555                        } else {
21556                            cx.theme().players().absent()
21557                        },
21558                    })
21559                }
21560            })
21561    }
21562
21563    pub fn hunks_for_ranges(
21564        &self,
21565        ranges: impl IntoIterator<Item = Range<Point>>,
21566    ) -> Vec<MultiBufferDiffHunk> {
21567        let mut hunks = Vec::new();
21568        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21569            HashMap::default();
21570        for query_range in ranges {
21571            let query_rows =
21572                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21573            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21574                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21575            ) {
21576                // Include deleted hunks that are adjacent to the query range, because
21577                // otherwise they would be missed.
21578                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21579                if hunk.status().is_deleted() {
21580                    intersects_range |= hunk.row_range.start == query_rows.end;
21581                    intersects_range |= hunk.row_range.end == query_rows.start;
21582                }
21583                if intersects_range {
21584                    if !processed_buffer_rows
21585                        .entry(hunk.buffer_id)
21586                        .or_default()
21587                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21588                    {
21589                        continue;
21590                    }
21591                    hunks.push(hunk);
21592                }
21593            }
21594        }
21595
21596        hunks
21597    }
21598
21599    fn display_diff_hunks_for_rows<'a>(
21600        &'a self,
21601        display_rows: Range<DisplayRow>,
21602        folded_buffers: &'a HashSet<BufferId>,
21603    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21604        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21605        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21606
21607        self.buffer_snapshot
21608            .diff_hunks_in_range(buffer_start..buffer_end)
21609            .filter_map(|hunk| {
21610                if folded_buffers.contains(&hunk.buffer_id) {
21611                    return None;
21612                }
21613
21614                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21615                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21616
21617                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21618                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21619
21620                let display_hunk = if hunk_display_start.column() != 0 {
21621                    DisplayDiffHunk::Folded {
21622                        display_row: hunk_display_start.row(),
21623                    }
21624                } else {
21625                    let mut end_row = hunk_display_end.row();
21626                    if hunk_display_end.column() > 0 {
21627                        end_row.0 += 1;
21628                    }
21629                    let is_created_file = hunk.is_created_file();
21630                    DisplayDiffHunk::Unfolded {
21631                        status: hunk.status(),
21632                        diff_base_byte_range: hunk.diff_base_byte_range,
21633                        display_row_range: hunk_display_start.row()..end_row,
21634                        multi_buffer_range: Anchor::range_in_buffer(
21635                            hunk.excerpt_id,
21636                            hunk.buffer_id,
21637                            hunk.buffer_range,
21638                        ),
21639                        is_created_file,
21640                    }
21641                };
21642
21643                Some(display_hunk)
21644            })
21645    }
21646
21647    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21648        self.display_snapshot.buffer_snapshot.language_at(position)
21649    }
21650
21651    pub fn is_focused(&self) -> bool {
21652        self.is_focused
21653    }
21654
21655    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21656        self.placeholder_text.as_ref()
21657    }
21658
21659    pub fn scroll_position(&self) -> gpui::Point<f32> {
21660        self.scroll_anchor.scroll_position(&self.display_snapshot)
21661    }
21662
21663    fn gutter_dimensions(
21664        &self,
21665        font_id: FontId,
21666        font_size: Pixels,
21667        max_line_number_width: Pixels,
21668        cx: &App,
21669    ) -> Option<GutterDimensions> {
21670        if !self.show_gutter {
21671            return None;
21672        }
21673
21674        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21675        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21676
21677        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21678            matches!(
21679                ProjectSettings::get_global(cx).git.git_gutter,
21680                Some(GitGutterSetting::TrackedFiles)
21681            )
21682        });
21683        let gutter_settings = EditorSettings::get_global(cx).gutter;
21684        let show_line_numbers = self
21685            .show_line_numbers
21686            .unwrap_or(gutter_settings.line_numbers);
21687        let line_gutter_width = if show_line_numbers {
21688            // Avoid flicker-like gutter resizes when the line number gains another digit by
21689            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21690            let min_width_for_number_on_gutter =
21691                ch_advance * gutter_settings.min_line_number_digits as f32;
21692            max_line_number_width.max(min_width_for_number_on_gutter)
21693        } else {
21694            0.0.into()
21695        };
21696
21697        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21698        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21699
21700        let git_blame_entries_width =
21701            self.git_blame_gutter_max_author_length
21702                .map(|max_author_length| {
21703                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21704                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21705
21706                    /// The number of characters to dedicate to gaps and margins.
21707                    const SPACING_WIDTH: usize = 4;
21708
21709                    let max_char_count = max_author_length.min(renderer.max_author_length())
21710                        + ::git::SHORT_SHA_LENGTH
21711                        + MAX_RELATIVE_TIMESTAMP.len()
21712                        + SPACING_WIDTH;
21713
21714                    ch_advance * max_char_count
21715                });
21716
21717        let is_singleton = self.buffer_snapshot.is_singleton();
21718
21719        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21720        left_padding += if !is_singleton {
21721            ch_width * 4.0
21722        } else if show_runnables || show_breakpoints {
21723            ch_width * 3.0
21724        } else if show_git_gutter && show_line_numbers {
21725            ch_width * 2.0
21726        } else if show_git_gutter || show_line_numbers {
21727            ch_width
21728        } else {
21729            px(0.)
21730        };
21731
21732        let shows_folds = is_singleton && gutter_settings.folds;
21733
21734        let right_padding = if shows_folds && show_line_numbers {
21735            ch_width * 4.0
21736        } else if shows_folds || (!is_singleton && show_line_numbers) {
21737            ch_width * 3.0
21738        } else if show_line_numbers {
21739            ch_width
21740        } else {
21741            px(0.)
21742        };
21743
21744        Some(GutterDimensions {
21745            left_padding,
21746            right_padding,
21747            width: line_gutter_width + left_padding + right_padding,
21748            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21749            git_blame_entries_width,
21750        })
21751    }
21752
21753    pub fn render_crease_toggle(
21754        &self,
21755        buffer_row: MultiBufferRow,
21756        row_contains_cursor: bool,
21757        editor: Entity<Editor>,
21758        window: &mut Window,
21759        cx: &mut App,
21760    ) -> Option<AnyElement> {
21761        let folded = self.is_line_folded(buffer_row);
21762        let mut is_foldable = false;
21763
21764        if let Some(crease) = self
21765            .crease_snapshot
21766            .query_row(buffer_row, &self.buffer_snapshot)
21767        {
21768            is_foldable = true;
21769            match crease {
21770                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21771                    if let Some(render_toggle) = render_toggle {
21772                        let toggle_callback =
21773                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21774                                if folded {
21775                                    editor.update(cx, |editor, cx| {
21776                                        editor.fold_at(buffer_row, window, cx)
21777                                    });
21778                                } else {
21779                                    editor.update(cx, |editor, cx| {
21780                                        editor.unfold_at(buffer_row, window, cx)
21781                                    });
21782                                }
21783                            });
21784                        return Some((render_toggle)(
21785                            buffer_row,
21786                            folded,
21787                            toggle_callback,
21788                            window,
21789                            cx,
21790                        ));
21791                    }
21792                }
21793            }
21794        }
21795
21796        is_foldable |= self.starts_indent(buffer_row);
21797
21798        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21799            Some(
21800                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21801                    .toggle_state(folded)
21802                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21803                        if folded {
21804                            this.unfold_at(buffer_row, window, cx);
21805                        } else {
21806                            this.fold_at(buffer_row, window, cx);
21807                        }
21808                    }))
21809                    .into_any_element(),
21810            )
21811        } else {
21812            None
21813        }
21814    }
21815
21816    pub fn render_crease_trailer(
21817        &self,
21818        buffer_row: MultiBufferRow,
21819        window: &mut Window,
21820        cx: &mut App,
21821    ) -> Option<AnyElement> {
21822        let folded = self.is_line_folded(buffer_row);
21823        if let Crease::Inline { render_trailer, .. } = self
21824            .crease_snapshot
21825            .query_row(buffer_row, &self.buffer_snapshot)?
21826        {
21827            let render_trailer = render_trailer.as_ref()?;
21828            Some(render_trailer(buffer_row, folded, window, cx))
21829        } else {
21830            None
21831        }
21832    }
21833}
21834
21835impl Deref for EditorSnapshot {
21836    type Target = DisplaySnapshot;
21837
21838    fn deref(&self) -> &Self::Target {
21839        &self.display_snapshot
21840    }
21841}
21842
21843#[derive(Clone, Debug, PartialEq, Eq)]
21844pub enum EditorEvent {
21845    InputIgnored {
21846        text: Arc<str>,
21847    },
21848    InputHandled {
21849        utf16_range_to_replace: Option<Range<isize>>,
21850        text: Arc<str>,
21851    },
21852    ExcerptsAdded {
21853        buffer: Entity<Buffer>,
21854        predecessor: ExcerptId,
21855        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21856    },
21857    ExcerptsRemoved {
21858        ids: Vec<ExcerptId>,
21859        removed_buffer_ids: Vec<BufferId>,
21860    },
21861    BufferFoldToggled {
21862        ids: Vec<ExcerptId>,
21863        folded: bool,
21864    },
21865    ExcerptsEdited {
21866        ids: Vec<ExcerptId>,
21867    },
21868    ExcerptsExpanded {
21869        ids: Vec<ExcerptId>,
21870    },
21871    BufferEdited,
21872    Edited {
21873        transaction_id: clock::Lamport,
21874    },
21875    Reparsed(BufferId),
21876    Focused,
21877    FocusedIn,
21878    Blurred,
21879    DirtyChanged,
21880    Saved,
21881    TitleChanged,
21882    DiffBaseChanged,
21883    SelectionsChanged {
21884        local: bool,
21885    },
21886    ScrollPositionChanged {
21887        local: bool,
21888        autoscroll: bool,
21889    },
21890    Closed,
21891    TransactionUndone {
21892        transaction_id: clock::Lamport,
21893    },
21894    TransactionBegun {
21895        transaction_id: clock::Lamport,
21896    },
21897    Reloaded,
21898    CursorShapeChanged,
21899    PushedToNavHistory {
21900        anchor: Anchor,
21901        is_deactivate: bool,
21902    },
21903}
21904
21905impl EventEmitter<EditorEvent> for Editor {}
21906
21907impl Focusable for Editor {
21908    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21909        self.focus_handle.clone()
21910    }
21911}
21912
21913impl Render for Editor {
21914    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21915        let settings = ThemeSettings::get_global(cx);
21916
21917        let mut text_style = match self.mode {
21918            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21919                color: cx.theme().colors().editor_foreground,
21920                font_family: settings.ui_font.family.clone(),
21921                font_features: settings.ui_font.features.clone(),
21922                font_fallbacks: settings.ui_font.fallbacks.clone(),
21923                font_size: rems(0.875).into(),
21924                font_weight: settings.ui_font.weight,
21925                line_height: relative(settings.buffer_line_height.value()),
21926                ..Default::default()
21927            },
21928            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21929                color: cx.theme().colors().editor_foreground,
21930                font_family: settings.buffer_font.family.clone(),
21931                font_features: settings.buffer_font.features.clone(),
21932                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21933                font_size: settings.buffer_font_size(cx).into(),
21934                font_weight: settings.buffer_font.weight,
21935                line_height: relative(settings.buffer_line_height.value()),
21936                ..Default::default()
21937            },
21938        };
21939        if let Some(text_style_refinement) = &self.text_style_refinement {
21940            text_style.refine(text_style_refinement)
21941        }
21942
21943        let background = match self.mode {
21944            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21945            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
21946            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21947            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21948        };
21949
21950        EditorElement::new(
21951            &cx.entity(),
21952            EditorStyle {
21953                background,
21954                local_player: cx.theme().players().local(),
21955                text: text_style,
21956                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21957                syntax: cx.theme().syntax().clone(),
21958                status: cx.theme().status().clone(),
21959                inlay_hints_style: make_inlay_hints_style(cx),
21960                inline_completion_styles: make_suggestion_styles(cx),
21961                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21962                show_underlines: !self.mode.is_minimap(),
21963            },
21964        )
21965    }
21966}
21967
21968impl EntityInputHandler for Editor {
21969    fn text_for_range(
21970        &mut self,
21971        range_utf16: Range<usize>,
21972        adjusted_range: &mut Option<Range<usize>>,
21973        _: &mut Window,
21974        cx: &mut Context<Self>,
21975    ) -> Option<String> {
21976        let snapshot = self.buffer.read(cx).read(cx);
21977        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21978        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21979        if (start.0..end.0) != range_utf16 {
21980            adjusted_range.replace(start.0..end.0);
21981        }
21982        Some(snapshot.text_for_range(start..end).collect())
21983    }
21984
21985    fn selected_text_range(
21986        &mut self,
21987        ignore_disabled_input: bool,
21988        _: &mut Window,
21989        cx: &mut Context<Self>,
21990    ) -> Option<UTF16Selection> {
21991        // Prevent the IME menu from appearing when holding down an alphabetic key
21992        // while input is disabled.
21993        if !ignore_disabled_input && !self.input_enabled {
21994            return None;
21995        }
21996
21997        let selection = self.selections.newest::<OffsetUtf16>(cx);
21998        let range = selection.range();
21999
22000        Some(UTF16Selection {
22001            range: range.start.0..range.end.0,
22002            reversed: selection.reversed,
22003        })
22004    }
22005
22006    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22007        let snapshot = self.buffer.read(cx).read(cx);
22008        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22009        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22010    }
22011
22012    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22013        self.clear_highlights::<InputComposition>(cx);
22014        self.ime_transaction.take();
22015    }
22016
22017    fn replace_text_in_range(
22018        &mut self,
22019        range_utf16: Option<Range<usize>>,
22020        text: &str,
22021        window: &mut Window,
22022        cx: &mut Context<Self>,
22023    ) {
22024        if !self.input_enabled {
22025            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22026            return;
22027        }
22028
22029        self.transact(window, cx, |this, window, cx| {
22030            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22031                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22032                Some(this.selection_replacement_ranges(range_utf16, cx))
22033            } else {
22034                this.marked_text_ranges(cx)
22035            };
22036
22037            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22038                let newest_selection_id = this.selections.newest_anchor().id;
22039                this.selections
22040                    .all::<OffsetUtf16>(cx)
22041                    .iter()
22042                    .zip(ranges_to_replace.iter())
22043                    .find_map(|(selection, range)| {
22044                        if selection.id == newest_selection_id {
22045                            Some(
22046                                (range.start.0 as isize - selection.head().0 as isize)
22047                                    ..(range.end.0 as isize - selection.head().0 as isize),
22048                            )
22049                        } else {
22050                            None
22051                        }
22052                    })
22053            });
22054
22055            cx.emit(EditorEvent::InputHandled {
22056                utf16_range_to_replace: range_to_replace,
22057                text: text.into(),
22058            });
22059
22060            if let Some(new_selected_ranges) = new_selected_ranges {
22061                this.change_selections(None, window, cx, |selections| {
22062                    selections.select_ranges(new_selected_ranges)
22063                });
22064                this.backspace(&Default::default(), window, cx);
22065            }
22066
22067            this.handle_input(text, window, cx);
22068        });
22069
22070        if let Some(transaction) = self.ime_transaction {
22071            self.buffer.update(cx, |buffer, cx| {
22072                buffer.group_until_transaction(transaction, cx);
22073            });
22074        }
22075
22076        self.unmark_text(window, cx);
22077    }
22078
22079    fn replace_and_mark_text_in_range(
22080        &mut self,
22081        range_utf16: Option<Range<usize>>,
22082        text: &str,
22083        new_selected_range_utf16: Option<Range<usize>>,
22084        window: &mut Window,
22085        cx: &mut Context<Self>,
22086    ) {
22087        if !self.input_enabled {
22088            return;
22089        }
22090
22091        let transaction = self.transact(window, cx, |this, window, cx| {
22092            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22093                let snapshot = this.buffer.read(cx).read(cx);
22094                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22095                    for marked_range in &mut marked_ranges {
22096                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22097                        marked_range.start.0 += relative_range_utf16.start;
22098                        marked_range.start =
22099                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22100                        marked_range.end =
22101                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22102                    }
22103                }
22104                Some(marked_ranges)
22105            } else if let Some(range_utf16) = range_utf16 {
22106                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22107                Some(this.selection_replacement_ranges(range_utf16, cx))
22108            } else {
22109                None
22110            };
22111
22112            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22113                let newest_selection_id = this.selections.newest_anchor().id;
22114                this.selections
22115                    .all::<OffsetUtf16>(cx)
22116                    .iter()
22117                    .zip(ranges_to_replace.iter())
22118                    .find_map(|(selection, range)| {
22119                        if selection.id == newest_selection_id {
22120                            Some(
22121                                (range.start.0 as isize - selection.head().0 as isize)
22122                                    ..(range.end.0 as isize - selection.head().0 as isize),
22123                            )
22124                        } else {
22125                            None
22126                        }
22127                    })
22128            });
22129
22130            cx.emit(EditorEvent::InputHandled {
22131                utf16_range_to_replace: range_to_replace,
22132                text: text.into(),
22133            });
22134
22135            if let Some(ranges) = ranges_to_replace {
22136                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22137            }
22138
22139            let marked_ranges = {
22140                let snapshot = this.buffer.read(cx).read(cx);
22141                this.selections
22142                    .disjoint_anchors()
22143                    .iter()
22144                    .map(|selection| {
22145                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22146                    })
22147                    .collect::<Vec<_>>()
22148            };
22149
22150            if text.is_empty() {
22151                this.unmark_text(window, cx);
22152            } else {
22153                this.highlight_text::<InputComposition>(
22154                    marked_ranges.clone(),
22155                    HighlightStyle {
22156                        underline: Some(UnderlineStyle {
22157                            thickness: px(1.),
22158                            color: None,
22159                            wavy: false,
22160                        }),
22161                        ..Default::default()
22162                    },
22163                    cx,
22164                );
22165            }
22166
22167            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22168            let use_autoclose = this.use_autoclose;
22169            let use_auto_surround = this.use_auto_surround;
22170            this.set_use_autoclose(false);
22171            this.set_use_auto_surround(false);
22172            this.handle_input(text, window, cx);
22173            this.set_use_autoclose(use_autoclose);
22174            this.set_use_auto_surround(use_auto_surround);
22175
22176            if let Some(new_selected_range) = new_selected_range_utf16 {
22177                let snapshot = this.buffer.read(cx).read(cx);
22178                let new_selected_ranges = marked_ranges
22179                    .into_iter()
22180                    .map(|marked_range| {
22181                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22182                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22183                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22184                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22185                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22186                    })
22187                    .collect::<Vec<_>>();
22188
22189                drop(snapshot);
22190                this.change_selections(None, window, cx, |selections| {
22191                    selections.select_ranges(new_selected_ranges)
22192                });
22193            }
22194        });
22195
22196        self.ime_transaction = self.ime_transaction.or(transaction);
22197        if let Some(transaction) = self.ime_transaction {
22198            self.buffer.update(cx, |buffer, cx| {
22199                buffer.group_until_transaction(transaction, cx);
22200            });
22201        }
22202
22203        if self.text_highlights::<InputComposition>(cx).is_none() {
22204            self.ime_transaction.take();
22205        }
22206    }
22207
22208    fn bounds_for_range(
22209        &mut self,
22210        range_utf16: Range<usize>,
22211        element_bounds: gpui::Bounds<Pixels>,
22212        window: &mut Window,
22213        cx: &mut Context<Self>,
22214    ) -> Option<gpui::Bounds<Pixels>> {
22215        let text_layout_details = self.text_layout_details(window);
22216        let gpui::Size {
22217            width: em_width,
22218            height: line_height,
22219        } = self.character_size(window);
22220
22221        let snapshot = self.snapshot(window, cx);
22222        let scroll_position = snapshot.scroll_position();
22223        let scroll_left = scroll_position.x * em_width;
22224
22225        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22226        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22227            + self.gutter_dimensions.width
22228            + self.gutter_dimensions.margin;
22229        let y = line_height * (start.row().as_f32() - scroll_position.y);
22230
22231        Some(Bounds {
22232            origin: element_bounds.origin + point(x, y),
22233            size: size(em_width, line_height),
22234        })
22235    }
22236
22237    fn character_index_for_point(
22238        &mut self,
22239        point: gpui::Point<Pixels>,
22240        _window: &mut Window,
22241        _cx: &mut Context<Self>,
22242    ) -> Option<usize> {
22243        let position_map = self.last_position_map.as_ref()?;
22244        if !position_map.text_hitbox.contains(&point) {
22245            return None;
22246        }
22247        let display_point = position_map.point_for_position(point).previous_valid;
22248        let anchor = position_map
22249            .snapshot
22250            .display_point_to_anchor(display_point, Bias::Left);
22251        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22252        Some(utf16_offset.0)
22253    }
22254}
22255
22256trait SelectionExt {
22257    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22258    fn spanned_rows(
22259        &self,
22260        include_end_if_at_line_start: bool,
22261        map: &DisplaySnapshot,
22262    ) -> Range<MultiBufferRow>;
22263}
22264
22265impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22266    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22267        let start = self
22268            .start
22269            .to_point(&map.buffer_snapshot)
22270            .to_display_point(map);
22271        let end = self
22272            .end
22273            .to_point(&map.buffer_snapshot)
22274            .to_display_point(map);
22275        if self.reversed {
22276            end..start
22277        } else {
22278            start..end
22279        }
22280    }
22281
22282    fn spanned_rows(
22283        &self,
22284        include_end_if_at_line_start: bool,
22285        map: &DisplaySnapshot,
22286    ) -> Range<MultiBufferRow> {
22287        let start = self.start.to_point(&map.buffer_snapshot);
22288        let mut end = self.end.to_point(&map.buffer_snapshot);
22289        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22290            end.row -= 1;
22291        }
22292
22293        let buffer_start = map.prev_line_boundary(start).0;
22294        let buffer_end = map.next_line_boundary(end).0;
22295        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22296    }
22297}
22298
22299impl<T: InvalidationRegion> InvalidationStack<T> {
22300    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22301    where
22302        S: Clone + ToOffset,
22303    {
22304        while let Some(region) = self.last() {
22305            let all_selections_inside_invalidation_ranges =
22306                if selections.len() == region.ranges().len() {
22307                    selections
22308                        .iter()
22309                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22310                        .all(|(selection, invalidation_range)| {
22311                            let head = selection.head().to_offset(buffer);
22312                            invalidation_range.start <= head && invalidation_range.end >= head
22313                        })
22314                } else {
22315                    false
22316                };
22317
22318            if all_selections_inside_invalidation_ranges {
22319                break;
22320            } else {
22321                self.pop();
22322            }
22323        }
22324    }
22325}
22326
22327impl<T> Default for InvalidationStack<T> {
22328    fn default() -> Self {
22329        Self(Default::default())
22330    }
22331}
22332
22333impl<T> Deref for InvalidationStack<T> {
22334    type Target = Vec<T>;
22335
22336    fn deref(&self) -> &Self::Target {
22337        &self.0
22338    }
22339}
22340
22341impl<T> DerefMut for InvalidationStack<T> {
22342    fn deref_mut(&mut self) -> &mut Self::Target {
22343        &mut self.0
22344    }
22345}
22346
22347impl InvalidationRegion for SnippetState {
22348    fn ranges(&self) -> &[Range<Anchor>] {
22349        &self.ranges[self.active_index]
22350    }
22351}
22352
22353fn inline_completion_edit_text(
22354    current_snapshot: &BufferSnapshot,
22355    edits: &[(Range<Anchor>, String)],
22356    edit_preview: &EditPreview,
22357    include_deletions: bool,
22358    cx: &App,
22359) -> HighlightedText {
22360    let edits = edits
22361        .iter()
22362        .map(|(anchor, text)| {
22363            (
22364                anchor.start.text_anchor..anchor.end.text_anchor,
22365                text.clone(),
22366            )
22367        })
22368        .collect::<Vec<_>>();
22369
22370    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22371}
22372
22373pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22374    match severity {
22375        lsp::DiagnosticSeverity::ERROR => colors.error,
22376        lsp::DiagnosticSeverity::WARNING => colors.warning,
22377        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22378        lsp::DiagnosticSeverity::HINT => colors.info,
22379        _ => colors.ignored,
22380    }
22381}
22382
22383pub fn styled_runs_for_code_label<'a>(
22384    label: &'a CodeLabel,
22385    syntax_theme: &'a theme::SyntaxTheme,
22386) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22387    let fade_out = HighlightStyle {
22388        fade_out: Some(0.35),
22389        ..Default::default()
22390    };
22391
22392    let mut prev_end = label.filter_range.end;
22393    label
22394        .runs
22395        .iter()
22396        .enumerate()
22397        .flat_map(move |(ix, (range, highlight_id))| {
22398            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22399                style
22400            } else {
22401                return Default::default();
22402            };
22403            let mut muted_style = style;
22404            muted_style.highlight(fade_out);
22405
22406            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22407            if range.start >= label.filter_range.end {
22408                if range.start > prev_end {
22409                    runs.push((prev_end..range.start, fade_out));
22410                }
22411                runs.push((range.clone(), muted_style));
22412            } else if range.end <= label.filter_range.end {
22413                runs.push((range.clone(), style));
22414            } else {
22415                runs.push((range.start..label.filter_range.end, style));
22416                runs.push((label.filter_range.end..range.end, muted_style));
22417            }
22418            prev_end = cmp::max(prev_end, range.end);
22419
22420            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22421                runs.push((prev_end..label.text.len(), fade_out));
22422            }
22423
22424            runs
22425        })
22426}
22427
22428pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22429    let mut prev_index = 0;
22430    let mut prev_codepoint: Option<char> = None;
22431    text.char_indices()
22432        .chain([(text.len(), '\0')])
22433        .filter_map(move |(index, codepoint)| {
22434            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22435            let is_boundary = index == text.len()
22436                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22437                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22438            if is_boundary {
22439                let chunk = &text[prev_index..index];
22440                prev_index = index;
22441                Some(chunk)
22442            } else {
22443                None
22444            }
22445        })
22446}
22447
22448pub trait RangeToAnchorExt: Sized {
22449    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22450
22451    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22452        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22453        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22454    }
22455}
22456
22457impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22458    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22459        let start_offset = self.start.to_offset(snapshot);
22460        let end_offset = self.end.to_offset(snapshot);
22461        if start_offset == end_offset {
22462            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22463        } else {
22464            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22465        }
22466    }
22467}
22468
22469pub trait RowExt {
22470    fn as_f32(&self) -> f32;
22471
22472    fn next_row(&self) -> Self;
22473
22474    fn previous_row(&self) -> Self;
22475
22476    fn minus(&self, other: Self) -> u32;
22477}
22478
22479impl RowExt for DisplayRow {
22480    fn as_f32(&self) -> f32 {
22481        self.0 as f32
22482    }
22483
22484    fn next_row(&self) -> Self {
22485        Self(self.0 + 1)
22486    }
22487
22488    fn previous_row(&self) -> Self {
22489        Self(self.0.saturating_sub(1))
22490    }
22491
22492    fn minus(&self, other: Self) -> u32 {
22493        self.0 - other.0
22494    }
22495}
22496
22497impl RowExt for MultiBufferRow {
22498    fn as_f32(&self) -> f32 {
22499        self.0 as f32
22500    }
22501
22502    fn next_row(&self) -> Self {
22503        Self(self.0 + 1)
22504    }
22505
22506    fn previous_row(&self) -> Self {
22507        Self(self.0.saturating_sub(1))
22508    }
22509
22510    fn minus(&self, other: Self) -> u32 {
22511        self.0 - other.0
22512    }
22513}
22514
22515trait RowRangeExt {
22516    type Row;
22517
22518    fn len(&self) -> usize;
22519
22520    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22521}
22522
22523impl RowRangeExt for Range<MultiBufferRow> {
22524    type Row = MultiBufferRow;
22525
22526    fn len(&self) -> usize {
22527        (self.end.0 - self.start.0) as usize
22528    }
22529
22530    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22531        (self.start.0..self.end.0).map(MultiBufferRow)
22532    }
22533}
22534
22535impl RowRangeExt for Range<DisplayRow> {
22536    type Row = DisplayRow;
22537
22538    fn len(&self) -> usize {
22539        (self.end.0 - self.start.0) as usize
22540    }
22541
22542    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22543        (self.start.0..self.end.0).map(DisplayRow)
22544    }
22545}
22546
22547/// If select range has more than one line, we
22548/// just point the cursor to range.start.
22549fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22550    if range.start.row == range.end.row {
22551        range
22552    } else {
22553        range.start..range.start
22554    }
22555}
22556pub struct KillRing(ClipboardItem);
22557impl Global for KillRing {}
22558
22559const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22560
22561enum BreakpointPromptEditAction {
22562    Log,
22563    Condition,
22564    HitCondition,
22565}
22566
22567struct BreakpointPromptEditor {
22568    pub(crate) prompt: Entity<Editor>,
22569    editor: WeakEntity<Editor>,
22570    breakpoint_anchor: Anchor,
22571    breakpoint: Breakpoint,
22572    edit_action: BreakpointPromptEditAction,
22573    block_ids: HashSet<CustomBlockId>,
22574    editor_margins: Arc<Mutex<EditorMargins>>,
22575    _subscriptions: Vec<Subscription>,
22576}
22577
22578impl BreakpointPromptEditor {
22579    const MAX_LINES: u8 = 4;
22580
22581    fn new(
22582        editor: WeakEntity<Editor>,
22583        breakpoint_anchor: Anchor,
22584        breakpoint: Breakpoint,
22585        edit_action: BreakpointPromptEditAction,
22586        window: &mut Window,
22587        cx: &mut Context<Self>,
22588    ) -> Self {
22589        let base_text = match edit_action {
22590            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22591            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22592            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22593        }
22594        .map(|msg| msg.to_string())
22595        .unwrap_or_default();
22596
22597        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22598        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22599
22600        let prompt = cx.new(|cx| {
22601            let mut prompt = Editor::new(
22602                EditorMode::AutoHeight {
22603                    min_lines: 1,
22604                    max_lines: Self::MAX_LINES as usize,
22605                },
22606                buffer,
22607                None,
22608                window,
22609                cx,
22610            );
22611            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22612            prompt.set_show_cursor_when_unfocused(false, cx);
22613            prompt.set_placeholder_text(
22614                match edit_action {
22615                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22616                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22617                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22618                },
22619                cx,
22620            );
22621
22622            prompt
22623        });
22624
22625        Self {
22626            prompt,
22627            editor,
22628            breakpoint_anchor,
22629            breakpoint,
22630            edit_action,
22631            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22632            block_ids: Default::default(),
22633            _subscriptions: vec![],
22634        }
22635    }
22636
22637    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22638        self.block_ids.extend(block_ids)
22639    }
22640
22641    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22642        if let Some(editor) = self.editor.upgrade() {
22643            let message = self
22644                .prompt
22645                .read(cx)
22646                .buffer
22647                .read(cx)
22648                .as_singleton()
22649                .expect("A multi buffer in breakpoint prompt isn't possible")
22650                .read(cx)
22651                .as_rope()
22652                .to_string();
22653
22654            editor.update(cx, |editor, cx| {
22655                editor.edit_breakpoint_at_anchor(
22656                    self.breakpoint_anchor,
22657                    self.breakpoint.clone(),
22658                    match self.edit_action {
22659                        BreakpointPromptEditAction::Log => {
22660                            BreakpointEditAction::EditLogMessage(message.into())
22661                        }
22662                        BreakpointPromptEditAction::Condition => {
22663                            BreakpointEditAction::EditCondition(message.into())
22664                        }
22665                        BreakpointPromptEditAction::HitCondition => {
22666                            BreakpointEditAction::EditHitCondition(message.into())
22667                        }
22668                    },
22669                    cx,
22670                );
22671
22672                editor.remove_blocks(self.block_ids.clone(), None, cx);
22673                cx.focus_self(window);
22674            });
22675        }
22676    }
22677
22678    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22679        self.editor
22680            .update(cx, |editor, cx| {
22681                editor.remove_blocks(self.block_ids.clone(), None, cx);
22682                window.focus(&editor.focus_handle);
22683            })
22684            .log_err();
22685    }
22686
22687    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22688        let settings = ThemeSettings::get_global(cx);
22689        let text_style = TextStyle {
22690            color: if self.prompt.read(cx).read_only(cx) {
22691                cx.theme().colors().text_disabled
22692            } else {
22693                cx.theme().colors().text
22694            },
22695            font_family: settings.buffer_font.family.clone(),
22696            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22697            font_size: settings.buffer_font_size(cx).into(),
22698            font_weight: settings.buffer_font.weight,
22699            line_height: relative(settings.buffer_line_height.value()),
22700            ..Default::default()
22701        };
22702        EditorElement::new(
22703            &self.prompt,
22704            EditorStyle {
22705                background: cx.theme().colors().editor_background,
22706                local_player: cx.theme().players().local(),
22707                text: text_style,
22708                ..Default::default()
22709            },
22710        )
22711    }
22712}
22713
22714impl Render for BreakpointPromptEditor {
22715    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22716        let editor_margins = *self.editor_margins.lock();
22717        let gutter_dimensions = editor_margins.gutter;
22718        h_flex()
22719            .key_context("Editor")
22720            .bg(cx.theme().colors().editor_background)
22721            .border_y_1()
22722            .border_color(cx.theme().status().info_border)
22723            .size_full()
22724            .py(window.line_height() / 2.5)
22725            .on_action(cx.listener(Self::confirm))
22726            .on_action(cx.listener(Self::cancel))
22727            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22728            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22729    }
22730}
22731
22732impl Focusable for BreakpointPromptEditor {
22733    fn focus_handle(&self, cx: &App) -> FocusHandle {
22734        self.prompt.focus_handle(cx)
22735    }
22736}
22737
22738fn all_edits_insertions_or_deletions(
22739    edits: &Vec<(Range<Anchor>, String)>,
22740    snapshot: &MultiBufferSnapshot,
22741) -> bool {
22742    let mut all_insertions = true;
22743    let mut all_deletions = true;
22744
22745    for (range, new_text) in edits.iter() {
22746        let range_is_empty = range.to_offset(&snapshot).is_empty();
22747        let text_is_empty = new_text.is_empty();
22748
22749        if range_is_empty != text_is_empty {
22750            if range_is_empty {
22751                all_deletions = false;
22752            } else {
22753                all_insertions = false;
22754            }
22755        } else {
22756            return false;
22757        }
22758
22759        if !all_insertions && !all_deletions {
22760            return false;
22761        }
22762    }
22763    all_insertions || all_deletions
22764}
22765
22766struct MissingEditPredictionKeybindingTooltip;
22767
22768impl Render for MissingEditPredictionKeybindingTooltip {
22769    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22770        ui::tooltip_container(window, cx, |container, _, cx| {
22771            container
22772                .flex_shrink_0()
22773                .max_w_80()
22774                .min_h(rems_from_px(124.))
22775                .justify_between()
22776                .child(
22777                    v_flex()
22778                        .flex_1()
22779                        .text_ui_sm(cx)
22780                        .child(Label::new("Conflict with Accept Keybinding"))
22781                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22782                )
22783                .child(
22784                    h_flex()
22785                        .pb_1()
22786                        .gap_1()
22787                        .items_end()
22788                        .w_full()
22789                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22790                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22791                        }))
22792                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22793                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22794                        })),
22795                )
22796        })
22797    }
22798}
22799
22800#[derive(Debug, Clone, Copy, PartialEq)]
22801pub struct LineHighlight {
22802    pub background: Background,
22803    pub border: Option<gpui::Hsla>,
22804    pub include_gutter: bool,
22805    pub type_id: Option<TypeId>,
22806}
22807
22808fn render_diff_hunk_controls(
22809    row: u32,
22810    status: &DiffHunkStatus,
22811    hunk_range: Range<Anchor>,
22812    is_created_file: bool,
22813    line_height: Pixels,
22814    editor: &Entity<Editor>,
22815    _window: &mut Window,
22816    cx: &mut App,
22817) -> AnyElement {
22818    h_flex()
22819        .h(line_height)
22820        .mr_1()
22821        .gap_1()
22822        .px_0p5()
22823        .pb_1()
22824        .border_x_1()
22825        .border_b_1()
22826        .border_color(cx.theme().colors().border_variant)
22827        .rounded_b_lg()
22828        .bg(cx.theme().colors().editor_background)
22829        .gap_1()
22830        .block_mouse_except_scroll()
22831        .shadow_md()
22832        .child(if status.has_secondary_hunk() {
22833            Button::new(("stage", row as u64), "Stage")
22834                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22835                .tooltip({
22836                    let focus_handle = editor.focus_handle(cx);
22837                    move |window, cx| {
22838                        Tooltip::for_action_in(
22839                            "Stage Hunk",
22840                            &::git::ToggleStaged,
22841                            &focus_handle,
22842                            window,
22843                            cx,
22844                        )
22845                    }
22846                })
22847                .on_click({
22848                    let editor = editor.clone();
22849                    move |_event, _window, cx| {
22850                        editor.update(cx, |editor, cx| {
22851                            editor.stage_or_unstage_diff_hunks(
22852                                true,
22853                                vec![hunk_range.start..hunk_range.start],
22854                                cx,
22855                            );
22856                        });
22857                    }
22858                })
22859        } else {
22860            Button::new(("unstage", row as u64), "Unstage")
22861                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22862                .tooltip({
22863                    let focus_handle = editor.focus_handle(cx);
22864                    move |window, cx| {
22865                        Tooltip::for_action_in(
22866                            "Unstage Hunk",
22867                            &::git::ToggleStaged,
22868                            &focus_handle,
22869                            window,
22870                            cx,
22871                        )
22872                    }
22873                })
22874                .on_click({
22875                    let editor = editor.clone();
22876                    move |_event, _window, cx| {
22877                        editor.update(cx, |editor, cx| {
22878                            editor.stage_or_unstage_diff_hunks(
22879                                false,
22880                                vec![hunk_range.start..hunk_range.start],
22881                                cx,
22882                            );
22883                        });
22884                    }
22885                })
22886        })
22887        .child(
22888            Button::new(("restore", row as u64), "Restore")
22889                .tooltip({
22890                    let focus_handle = editor.focus_handle(cx);
22891                    move |window, cx| {
22892                        Tooltip::for_action_in(
22893                            "Restore Hunk",
22894                            &::git::Restore,
22895                            &focus_handle,
22896                            window,
22897                            cx,
22898                        )
22899                    }
22900                })
22901                .on_click({
22902                    let editor = editor.clone();
22903                    move |_event, window, cx| {
22904                        editor.update(cx, |editor, cx| {
22905                            let snapshot = editor.snapshot(window, cx);
22906                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22907                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22908                        });
22909                    }
22910                })
22911                .disabled(is_created_file),
22912        )
22913        .when(
22914            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22915            |el| {
22916                el.child(
22917                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22918                        .shape(IconButtonShape::Square)
22919                        .icon_size(IconSize::Small)
22920                        // .disabled(!has_multiple_hunks)
22921                        .tooltip({
22922                            let focus_handle = editor.focus_handle(cx);
22923                            move |window, cx| {
22924                                Tooltip::for_action_in(
22925                                    "Next Hunk",
22926                                    &GoToHunk,
22927                                    &focus_handle,
22928                                    window,
22929                                    cx,
22930                                )
22931                            }
22932                        })
22933                        .on_click({
22934                            let editor = editor.clone();
22935                            move |_event, window, cx| {
22936                                editor.update(cx, |editor, cx| {
22937                                    let snapshot = editor.snapshot(window, cx);
22938                                    let position =
22939                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22940                                    editor.go_to_hunk_before_or_after_position(
22941                                        &snapshot,
22942                                        position,
22943                                        Direction::Next,
22944                                        window,
22945                                        cx,
22946                                    );
22947                                    editor.expand_selected_diff_hunks(cx);
22948                                });
22949                            }
22950                        }),
22951                )
22952                .child(
22953                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22954                        .shape(IconButtonShape::Square)
22955                        .icon_size(IconSize::Small)
22956                        // .disabled(!has_multiple_hunks)
22957                        .tooltip({
22958                            let focus_handle = editor.focus_handle(cx);
22959                            move |window, cx| {
22960                                Tooltip::for_action_in(
22961                                    "Previous Hunk",
22962                                    &GoToPreviousHunk,
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 =
22975                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22976                                    editor.go_to_hunk_before_or_after_position(
22977                                        &snapshot,
22978                                        point,
22979                                        Direction::Prev,
22980                                        window,
22981                                        cx,
22982                                    );
22983                                    editor.expand_selected_diff_hunks(cx);
22984                                });
22985                            }
22986                        }),
22987                )
22988            },
22989        )
22990        .into_any_element()
22991}