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,
   78    future::{self, Shared, join},
   79};
   80use fuzzy::{StringMatch, StringMatchCandidate};
   81
   82use ::git::blame::BlameEntry;
   83use ::git::{Restore, blame::ParsedCommitMessage};
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use git::blame::{GitBlame, GlobalBlameRenderer};
   89use gpui::{
   90    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   91    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   92    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   93    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   94    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   95    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   96    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   97    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   98};
   99use highlight_matching_bracket::refresh_matching_bracket_highlights;
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  101pub use hover_popover::hover_markdown_style;
  102use hover_popover::{HoverState, hide_hover};
  103use indent_guides::ActiveIndentGuidesState;
  104use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  105pub use inline_completion::Direction;
  106use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  107pub use items::MAX_TAB_TITLE_LEN;
  108use itertools::Itertools;
  109use language::{
  110    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  111    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  112    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  113    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  114    language_settings::{
  115        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  116        all_language_settings, language_settings,
  117    },
  118    point_from_lsp, text_diff_with_options,
  119};
  120use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  121use linked_editing_ranges::refresh_linked_ranges;
  122use markdown::Markdown;
  123use mouse_context_menu::MouseContextMenu;
  124use persistence::DB;
  125use project::{
  126    BreakpointWithPosition, ProjectPath,
  127    debugger::{
  128        breakpoint_store::{
  129            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  130            BreakpointStoreEvent,
  131        },
  132        session::{Session, SessionEvent},
  133    },
  134    project_settings::DiagnosticSeverity,
  135};
  136
  137pub use git::blame::BlameRenderer;
  138pub use proposed_changes_editor::{
  139    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  140};
  141use std::{cell::OnceCell, iter::Peekable, ops::Not};
  142use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  143
  144pub use lsp::CompletionContext;
  145use lsp::{
  146    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  147    LanguageServerId, LanguageServerName,
  148};
  149
  150use language::BufferSnapshot;
  151pub use lsp_ext::lsp_tasks;
  152use movement::TextLayoutDetails;
  153pub use multi_buffer::{
  154    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  155    RowInfo, ToOffset, ToPoint,
  156};
  157use multi_buffer::{
  158    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  159    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  160};
  161use parking_lot::Mutex;
  162use project::{
  163    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  164    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  165    TaskSourceKind,
  166    debugger::breakpoint_store::Breakpoint,
  167    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  168    project_settings::{GitGutterSetting, ProjectSettings},
  169};
  170use rand::prelude::*;
  171use rpc::{ErrorExt, proto::*};
  172use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  173use selections_collection::{
  174    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  175};
  176use serde::{Deserialize, Serialize};
  177use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  178use smallvec::{SmallVec, smallvec};
  179use snippet::Snippet;
  180use std::sync::Arc;
  181use std::{
  182    any::TypeId,
  183    borrow::Cow,
  184    cell::RefCell,
  185    cmp::{self, Ordering, Reverse},
  186    mem,
  187    num::NonZeroU32,
  188    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  189    path::{Path, PathBuf},
  190    rc::Rc,
  191    time::{Duration, Instant},
  192};
  193pub use sum_tree::Bias;
  194use sum_tree::TreeMap;
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  196use theme::{
  197    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc, wrap_with_prefix};
  205use workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{ItemHandle, PreviewTabsSettings},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::SearchEvent,
  212};
  213
  214use crate::hover_links::{find_url, find_url_from_range};
  215use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  216
  217pub const FILE_HEADER_HEIGHT: u32 = 2;
  218pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  219pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  220const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  221const MAX_LINE_LEN: usize = 1024;
  222const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  223const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  224pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  225#[doc(hidden)]
  226pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  227const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  228
  229pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  232
  233pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  234pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  235pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  236pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  237
  238pub type RenderDiffHunkControlsFn = Arc<
  239    dyn Fn(
  240        u32,
  241        &DiffHunkStatus,
  242        Range<Anchor>,
  243        bool,
  244        Pixels,
  245        &Entity<Editor>,
  246        &mut Window,
  247        &mut App,
  248    ) -> AnyElement,
  249>;
  250
  251const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  252    alt: true,
  253    shift: true,
  254    control: false,
  255    platform: false,
  256    function: false,
  257};
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    Hint(usize),
  279    DebuggerValue(usize),
  280}
  281
  282impl InlayId {
  283    fn id(&self) -> usize {
  284        match self {
  285            Self::InlineCompletion(id) => *id,
  286            Self::Hint(id) => *id,
  287            Self::DebuggerValue(id) => *id,
  288        }
  289    }
  290}
  291
  292pub enum ActiveDebugLine {}
  293pub enum DebugStackFrameLine {}
  294enum DocumentHighlightRead {}
  295enum DocumentHighlightWrite {}
  296enum InputComposition {}
  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        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug)]
  465pub enum SelectMode {
  466    Character,
  467    Word(Range<Anchor>),
  468    Line(Range<Anchor>),
  469    All,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine {
  475        auto_width: bool,
  476    },
  477    AutoHeight {
  478        max_lines: usize,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// When set to `true`, the editor's height will be determined by its content.
  486        sized_by_content: bool,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sized_by_content: false,
  499        }
  500    }
  501
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub local_player: PlayerColor,
  532    pub text: TextStyle,
  533    pub scrollbar_width: Pixels,
  534    pub syntax: Arc<SyntaxTheme>,
  535    pub status: StatusColors,
  536    pub inlay_hints_style: HighlightStyle,
  537    pub inline_completion_styles: InlineCompletionStyles,
  538    pub unnecessary_code_fade: f32,
  539    pub show_underlines: bool,
  540}
  541
  542impl Default for EditorStyle {
  543    fn default() -> Self {
  544        Self {
  545            background: Hsla::default(),
  546            local_player: PlayerColor::default(),
  547            text: TextStyle::default(),
  548            scrollbar_width: Pixels::default(),
  549            syntax: Default::default(),
  550            // HACK: Status colors don't have a real default.
  551            // We should look into removing the status colors from the editor
  552            // style and retrieve them directly from the theme.
  553            status: StatusColors::dark(),
  554            inlay_hints_style: HighlightStyle::default(),
  555            inline_completion_styles: InlineCompletionStyles {
  556                insertion: HighlightStyle::default(),
  557                whitespace: HighlightStyle::default(),
  558            },
  559            unnecessary_code_fade: Default::default(),
  560            show_underlines: true,
  561        }
  562    }
  563}
  564
  565pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  566    let show_background = language_settings::language_settings(None, None, cx)
  567        .inlay_hints
  568        .show_background;
  569
  570    HighlightStyle {
  571        color: Some(cx.theme().status().hint),
  572        background_color: show_background.then(|| cx.theme().status().hint_background),
  573        ..HighlightStyle::default()
  574    }
  575}
  576
  577pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  578    InlineCompletionStyles {
  579        insertion: HighlightStyle {
  580            color: Some(cx.theme().status().predictive),
  581            ..HighlightStyle::default()
  582        },
  583        whitespace: HighlightStyle {
  584            background_color: Some(cx.theme().status().created_background),
  585            ..HighlightStyle::default()
  586        },
  587    }
  588}
  589
  590type CompletionId = usize;
  591
  592pub(crate) enum EditDisplayMode {
  593    TabAccept,
  594    DiffPopover,
  595    Inline,
  596}
  597
  598enum InlineCompletion {
  599    Edit {
  600        edits: Vec<(Range<Anchor>, String)>,
  601        edit_preview: Option<EditPreview>,
  602        display_mode: EditDisplayMode,
  603        snapshot: BufferSnapshot,
  604    },
  605    Move {
  606        target: Anchor,
  607        snapshot: BufferSnapshot,
  608    },
  609}
  610
  611struct InlineCompletionState {
  612    inlay_ids: Vec<InlayId>,
  613    completion: InlineCompletion,
  614    completion_id: Option<SharedString>,
  615    invalidation_range: Range<Anchor>,
  616}
  617
  618enum EditPredictionSettings {
  619    Disabled,
  620    Enabled {
  621        show_in_menu: bool,
  622        preview_requires_modifier: bool,
  623    },
  624}
  625
  626enum InlineCompletionHighlight {}
  627
  628#[derive(Debug, Clone)]
  629struct InlineDiagnostic {
  630    message: SharedString,
  631    group_id: usize,
  632    is_primary: bool,
  633    start: Point,
  634    severity: lsp::DiagnosticSeverity,
  635}
  636
  637pub enum MenuInlineCompletionsPolicy {
  638    Never,
  639    ByProvider,
  640}
  641
  642pub enum EditPredictionPreview {
  643    /// Modifier is not pressed
  644    Inactive { released_too_fast: bool },
  645    /// Modifier pressed
  646    Active {
  647        since: Instant,
  648        previous_scroll_position: Option<ScrollAnchor>,
  649    },
  650}
  651
  652impl EditPredictionPreview {
  653    pub fn released_too_fast(&self) -> bool {
  654        match self {
  655            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  656            EditPredictionPreview::Active { .. } => false,
  657        }
  658    }
  659
  660    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  661        if let EditPredictionPreview::Active {
  662            previous_scroll_position,
  663            ..
  664        } = self
  665        {
  666            *previous_scroll_position = scroll_position;
  667        }
  668    }
  669}
  670
  671pub struct ContextMenuOptions {
  672    pub min_entries_visible: usize,
  673    pub max_entries_visible: usize,
  674    pub placement: Option<ContextMenuPlacement>,
  675}
  676
  677#[derive(Debug, Clone, PartialEq, Eq)]
  678pub enum ContextMenuPlacement {
  679    Above,
  680    Below,
  681}
  682
  683#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  684struct EditorActionId(usize);
  685
  686impl EditorActionId {
  687    pub fn post_inc(&mut self) -> Self {
  688        let answer = self.0;
  689
  690        *self = Self(answer + 1);
  691
  692        Self(answer)
  693    }
  694}
  695
  696// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  697// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  698
  699type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  700type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  701
  702#[derive(Default)]
  703struct ScrollbarMarkerState {
  704    scrollbar_size: Size<Pixels>,
  705    dirty: bool,
  706    markers: Arc<[PaintQuad]>,
  707    pending_refresh: Option<Task<Result<()>>>,
  708}
  709
  710impl ScrollbarMarkerState {
  711    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  712        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  713    }
  714}
  715
  716#[derive(Clone, Copy, PartialEq, Eq)]
  717pub enum MinimapVisibility {
  718    Disabled,
  719    Enabled {
  720        /// The configuration currently present in the users settings.
  721        setting_configuration: bool,
  722        /// Whether to override the currently set visibility from the users setting.
  723        toggle_override: bool,
  724    },
  725}
  726
  727impl MinimapVisibility {
  728    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  729        if mode.is_full() {
  730            Self::Enabled {
  731                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  732                toggle_override: false,
  733            }
  734        } else {
  735            Self::Disabled
  736        }
  737    }
  738
  739    fn hidden(&self) -> Self {
  740        match *self {
  741            Self::Enabled {
  742                setting_configuration,
  743                ..
  744            } => Self::Enabled {
  745                setting_configuration,
  746                toggle_override: setting_configuration,
  747            },
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751
  752    fn disabled(&self) -> bool {
  753        match *self {
  754            Self::Disabled => true,
  755            _ => false,
  756        }
  757    }
  758
  759    fn settings_visibility(&self) -> bool {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => setting_configuration,
  765            _ => false,
  766        }
  767    }
  768
  769    fn visible(&self) -> bool {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                toggle_override,
  774            } => setting_configuration ^ toggle_override,
  775            _ => false,
  776        }
  777    }
  778
  779    fn toggle_visibility(&self) -> Self {
  780        match *self {
  781            Self::Enabled {
  782                toggle_override,
  783                setting_configuration,
  784            } => Self::Enabled {
  785                setting_configuration,
  786                toggle_override: !toggle_override,
  787            },
  788            Self::Disabled => Self::Disabled,
  789        }
  790    }
  791}
  792
  793#[derive(Clone, Debug)]
  794struct RunnableTasks {
  795    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  796    offset: multi_buffer::Anchor,
  797    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  798    column: u32,
  799    // Values of all named captures, including those starting with '_'
  800    extra_variables: HashMap<String, String>,
  801    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  802    context_range: Range<BufferOffset>,
  803}
  804
  805impl RunnableTasks {
  806    fn resolve<'a>(
  807        &'a self,
  808        cx: &'a task::TaskContext,
  809    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  810        self.templates.iter().filter_map(|(kind, template)| {
  811            template
  812                .resolve_task(&kind.to_id_base(), cx)
  813                .map(|task| (kind.clone(), task))
  814        })
  815    }
  816}
  817
  818#[derive(Clone)]
  819pub struct ResolvedTasks {
  820    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  821    position: Anchor,
  822}
  823
  824#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  825struct BufferOffset(usize);
  826
  827// Addons allow storing per-editor state in other crates (e.g. Vim)
  828pub trait Addon: 'static {
  829    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  830
  831    fn render_buffer_header_controls(
  832        &self,
  833        _: &ExcerptInfo,
  834        _: &Window,
  835        _: &App,
  836    ) -> Option<AnyElement> {
  837        None
  838    }
  839
  840    fn to_any(&self) -> &dyn std::any::Any;
  841
  842    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  843        None
  844    }
  845}
  846
  847/// A set of caret positions, registered when the editor was edited.
  848pub struct ChangeList {
  849    changes: Vec<Vec<Anchor>>,
  850    /// Currently "selected" change.
  851    position: Option<usize>,
  852}
  853
  854impl ChangeList {
  855    pub fn new() -> Self {
  856        Self {
  857            changes: Vec::new(),
  858            position: None,
  859        }
  860    }
  861
  862    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  863    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  864    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  865        if self.changes.is_empty() {
  866            return None;
  867        }
  868
  869        let prev = self.position.unwrap_or(self.changes.len());
  870        let next = if direction == Direction::Prev {
  871            prev.saturating_sub(count)
  872        } else {
  873            (prev + count).min(self.changes.len() - 1)
  874        };
  875        self.position = Some(next);
  876        self.changes.get(next).map(|anchors| anchors.as_slice())
  877    }
  878
  879    /// Adds a new change to the list, resetting the change list position.
  880    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  881        self.position.take();
  882        if pop_state {
  883            self.changes.pop();
  884        }
  885        self.changes.push(new_positions.clone());
  886    }
  887
  888    pub fn last(&self) -> Option<&[Anchor]> {
  889        self.changes.last().map(|anchors| anchors.as_slice())
  890    }
  891}
  892
  893#[derive(Clone)]
  894struct InlineBlamePopoverState {
  895    scroll_handle: ScrollHandle,
  896    commit_message: Option<ParsedCommitMessage>,
  897    markdown: Entity<Markdown>,
  898}
  899
  900struct InlineBlamePopover {
  901    position: gpui::Point<Pixels>,
  902    show_task: Option<Task<()>>,
  903    hide_task: Option<Task<()>>,
  904    popover_bounds: Option<Bounds<Pixels>>,
  905    popover_state: InlineBlamePopoverState,
  906}
  907
  908/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  909/// a breakpoint on them.
  910#[derive(Clone, Copy, Debug)]
  911struct PhantomBreakpointIndicator {
  912    display_row: DisplayRow,
  913    /// There's a small debounce between hovering over the line and showing the indicator.
  914    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  915    is_active: bool,
  916    collides_with_existing_breakpoint: bool,
  917}
  918/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  919///
  920/// See the [module level documentation](self) for more information.
  921pub struct Editor {
  922    focus_handle: FocusHandle,
  923    last_focused_descendant: Option<WeakFocusHandle>,
  924    /// The text buffer being edited
  925    buffer: Entity<MultiBuffer>,
  926    /// Map of how text in the buffer should be displayed.
  927    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  928    pub display_map: Entity<DisplayMap>,
  929    pub selections: SelectionsCollection,
  930    pub scroll_manager: ScrollManager,
  931    /// When inline assist editors are linked, they all render cursors because
  932    /// typing enters text into each of them, even the ones that aren't focused.
  933    pub(crate) show_cursor_when_unfocused: bool,
  934    columnar_selection_tail: Option<Anchor>,
  935    add_selections_state: Option<AddSelectionsState>,
  936    select_next_state: Option<SelectNextState>,
  937    select_prev_state: Option<SelectNextState>,
  938    selection_history: SelectionHistory,
  939    autoclose_regions: Vec<AutocloseRegion>,
  940    snippet_stack: InvalidationStack<SnippetState>,
  941    select_syntax_node_history: SelectSyntaxNodeHistory,
  942    ime_transaction: Option<TransactionId>,
  943    pub diagnostics_max_severity: DiagnosticSeverity,
  944    active_diagnostics: ActiveDiagnostic,
  945    show_inline_diagnostics: bool,
  946    inline_diagnostics_update: Task<()>,
  947    inline_diagnostics_enabled: bool,
  948    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  949    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  950    hard_wrap: Option<usize>,
  951
  952    // TODO: make this a access method
  953    pub project: Option<Entity<Project>>,
  954    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  955    completion_provider: Option<Rc<dyn CompletionProvider>>,
  956    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  957    blink_manager: Entity<BlinkManager>,
  958    show_cursor_names: bool,
  959    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  960    pub show_local_selections: bool,
  961    mode: EditorMode,
  962    show_breadcrumbs: bool,
  963    show_gutter: bool,
  964    show_scrollbars: ScrollbarAxes,
  965    minimap_visibility: MinimapVisibility,
  966    offset_content: bool,
  967    disable_expand_excerpt_buttons: bool,
  968    show_line_numbers: Option<bool>,
  969    use_relative_line_numbers: Option<bool>,
  970    show_git_diff_gutter: Option<bool>,
  971    show_code_actions: Option<bool>,
  972    show_runnables: Option<bool>,
  973    show_breakpoints: Option<bool>,
  974    show_wrap_guides: Option<bool>,
  975    show_indent_guides: Option<bool>,
  976    placeholder_text: Option<Arc<str>>,
  977    highlight_order: usize,
  978    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  979    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  980    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  981    scrollbar_marker_state: ScrollbarMarkerState,
  982    active_indent_guides_state: ActiveIndentGuidesState,
  983    nav_history: Option<ItemNavHistory>,
  984    context_menu: RefCell<Option<CodeContextMenu>>,
  985    context_menu_options: Option<ContextMenuOptions>,
  986    mouse_context_menu: Option<MouseContextMenu>,
  987    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  988    inline_blame_popover: Option<InlineBlamePopover>,
  989    signature_help_state: SignatureHelpState,
  990    auto_signature_help: Option<bool>,
  991    find_all_references_task_sources: Vec<Anchor>,
  992    next_completion_id: CompletionId,
  993    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  994    code_actions_task: Option<Task<Result<()>>>,
  995    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  996    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  997    document_highlights_task: Option<Task<()>>,
  998    linked_editing_range_task: Option<Task<Option<()>>>,
  999    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1000    pending_rename: Option<RenameState>,
 1001    searchable: bool,
 1002    cursor_shape: CursorShape,
 1003    current_line_highlight: Option<CurrentLineHighlight>,
 1004    collapse_matches: bool,
 1005    autoindent_mode: Option<AutoindentMode>,
 1006    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1007    input_enabled: bool,
 1008    use_modal_editing: bool,
 1009    read_only: bool,
 1010    leader_id: Option<CollaboratorId>,
 1011    remote_id: Option<ViewId>,
 1012    pub hover_state: HoverState,
 1013    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1014    gutter_hovered: bool,
 1015    hovered_link_state: Option<HoveredLinkState>,
 1016    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1017    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1018    active_inline_completion: Option<InlineCompletionState>,
 1019    /// Used to prevent flickering as the user types while the menu is open
 1020    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1021    edit_prediction_settings: EditPredictionSettings,
 1022    inline_completions_hidden_for_vim_mode: bool,
 1023    show_inline_completions_override: Option<bool>,
 1024    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1025    edit_prediction_preview: EditPredictionPreview,
 1026    edit_prediction_indent_conflict: bool,
 1027    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1028    inlay_hint_cache: InlayHintCache,
 1029    next_inlay_id: usize,
 1030    _subscriptions: Vec<Subscription>,
 1031    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1032    gutter_dimensions: GutterDimensions,
 1033    style: Option<EditorStyle>,
 1034    text_style_refinement: Option<TextStyleRefinement>,
 1035    next_editor_action_id: EditorActionId,
 1036    editor_actions:
 1037        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1038    use_autoclose: bool,
 1039    use_auto_surround: bool,
 1040    auto_replace_emoji_shortcode: bool,
 1041    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1042    show_git_blame_gutter: bool,
 1043    show_git_blame_inline: bool,
 1044    show_git_blame_inline_delay_task: Option<Task<()>>,
 1045    git_blame_inline_enabled: bool,
 1046    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1047    serialize_dirty_buffers: bool,
 1048    show_selection_menu: Option<bool>,
 1049    blame: Option<Entity<GitBlame>>,
 1050    blame_subscription: Option<Subscription>,
 1051    custom_context_menu: Option<
 1052        Box<
 1053            dyn 'static
 1054                + Fn(
 1055                    &mut Self,
 1056                    DisplayPoint,
 1057                    &mut Window,
 1058                    &mut Context<Self>,
 1059                ) -> Option<Entity<ui::ContextMenu>>,
 1060        >,
 1061    >,
 1062    last_bounds: Option<Bounds<Pixels>>,
 1063    last_position_map: Option<Rc<PositionMap>>,
 1064    expect_bounds_change: Option<Bounds<Pixels>>,
 1065    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1066    tasks_update_task: Option<Task<()>>,
 1067    breakpoint_store: Option<Entity<BreakpointStore>>,
 1068    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1069    in_project_search: bool,
 1070    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1071    breadcrumb_header: Option<String>,
 1072    focused_block: Option<FocusedBlock>,
 1073    next_scroll_position: NextScrollCursorCenterTopBottom,
 1074    addons: HashMap<TypeId, Box<dyn Addon>>,
 1075    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1076    load_diff_task: Option<Shared<Task<()>>>,
 1077    /// Whether we are temporarily displaying a diff other than git's
 1078    temporary_diff_override: bool,
 1079    selection_mark_mode: bool,
 1080    toggle_fold_multiple_buffers: Task<()>,
 1081    _scroll_cursor_center_top_bottom_task: Task<()>,
 1082    serialize_selections: Task<()>,
 1083    serialize_folds: Task<()>,
 1084    mouse_cursor_hidden: bool,
 1085    minimap: Option<Entity<Self>>,
 1086    hide_mouse_mode: HideMouseMode,
 1087    pub change_list: ChangeList,
 1088    inline_value_cache: InlineValueCache,
 1089}
 1090
 1091#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1092enum NextScrollCursorCenterTopBottom {
 1093    #[default]
 1094    Center,
 1095    Top,
 1096    Bottom,
 1097}
 1098
 1099impl NextScrollCursorCenterTopBottom {
 1100    fn next(&self) -> Self {
 1101        match self {
 1102            Self::Center => Self::Top,
 1103            Self::Top => Self::Bottom,
 1104            Self::Bottom => Self::Center,
 1105        }
 1106    }
 1107}
 1108
 1109#[derive(Clone)]
 1110pub struct EditorSnapshot {
 1111    pub mode: EditorMode,
 1112    show_gutter: bool,
 1113    show_line_numbers: Option<bool>,
 1114    show_git_diff_gutter: Option<bool>,
 1115    show_code_actions: Option<bool>,
 1116    show_runnables: Option<bool>,
 1117    show_breakpoints: Option<bool>,
 1118    git_blame_gutter_max_author_length: Option<usize>,
 1119    pub display_snapshot: DisplaySnapshot,
 1120    pub placeholder_text: Option<Arc<str>>,
 1121    is_focused: bool,
 1122    scroll_anchor: ScrollAnchor,
 1123    ongoing_scroll: OngoingScroll,
 1124    current_line_highlight: CurrentLineHighlight,
 1125    gutter_hovered: bool,
 1126}
 1127
 1128#[derive(Default, Debug, Clone, Copy)]
 1129pub struct GutterDimensions {
 1130    pub left_padding: Pixels,
 1131    pub right_padding: Pixels,
 1132    pub width: Pixels,
 1133    pub margin: Pixels,
 1134    pub git_blame_entries_width: Option<Pixels>,
 1135}
 1136
 1137impl GutterDimensions {
 1138    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1139        Self {
 1140            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1141            ..Default::default()
 1142        }
 1143    }
 1144
 1145    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1146        -cx.text_system().descent(font_id, font_size)
 1147    }
 1148    /// The full width of the space taken up by the gutter.
 1149    pub fn full_width(&self) -> Pixels {
 1150        self.margin + self.width
 1151    }
 1152
 1153    /// The width of the space reserved for the fold indicators,
 1154    /// use alongside 'justify_end' and `gutter_width` to
 1155    /// right align content with the line numbers
 1156    pub fn fold_area_width(&self) -> Pixels {
 1157        self.margin + self.right_padding
 1158    }
 1159}
 1160
 1161#[derive(Debug)]
 1162pub struct RemoteSelection {
 1163    pub replica_id: ReplicaId,
 1164    pub selection: Selection<Anchor>,
 1165    pub cursor_shape: CursorShape,
 1166    pub collaborator_id: CollaboratorId,
 1167    pub line_mode: bool,
 1168    pub user_name: Option<SharedString>,
 1169    pub color: PlayerColor,
 1170}
 1171
 1172#[derive(Clone, Debug)]
 1173struct SelectionHistoryEntry {
 1174    selections: Arc<[Selection<Anchor>]>,
 1175    select_next_state: Option<SelectNextState>,
 1176    select_prev_state: Option<SelectNextState>,
 1177    add_selections_state: Option<AddSelectionsState>,
 1178}
 1179
 1180enum SelectionHistoryMode {
 1181    Normal,
 1182    Undoing,
 1183    Redoing,
 1184}
 1185
 1186#[derive(Clone, PartialEq, Eq, Hash)]
 1187struct HoveredCursor {
 1188    replica_id: u16,
 1189    selection_id: usize,
 1190}
 1191
 1192impl Default for SelectionHistoryMode {
 1193    fn default() -> Self {
 1194        Self::Normal
 1195    }
 1196}
 1197
 1198#[derive(Default)]
 1199struct SelectionHistory {
 1200    #[allow(clippy::type_complexity)]
 1201    selections_by_transaction:
 1202        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1203    mode: SelectionHistoryMode,
 1204    undo_stack: VecDeque<SelectionHistoryEntry>,
 1205    redo_stack: VecDeque<SelectionHistoryEntry>,
 1206}
 1207
 1208impl SelectionHistory {
 1209    fn insert_transaction(
 1210        &mut self,
 1211        transaction_id: TransactionId,
 1212        selections: Arc<[Selection<Anchor>]>,
 1213    ) {
 1214        self.selections_by_transaction
 1215            .insert(transaction_id, (selections, None));
 1216    }
 1217
 1218    #[allow(clippy::type_complexity)]
 1219    fn transaction(
 1220        &self,
 1221        transaction_id: TransactionId,
 1222    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1223        self.selections_by_transaction.get(&transaction_id)
 1224    }
 1225
 1226    #[allow(clippy::type_complexity)]
 1227    fn transaction_mut(
 1228        &mut self,
 1229        transaction_id: TransactionId,
 1230    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1231        self.selections_by_transaction.get_mut(&transaction_id)
 1232    }
 1233
 1234    fn push(&mut self, entry: SelectionHistoryEntry) {
 1235        if !entry.selections.is_empty() {
 1236            match self.mode {
 1237                SelectionHistoryMode::Normal => {
 1238                    self.push_undo(entry);
 1239                    self.redo_stack.clear();
 1240                }
 1241                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1242                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1243            }
 1244        }
 1245    }
 1246
 1247    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1248        if self
 1249            .undo_stack
 1250            .back()
 1251            .map_or(true, |e| e.selections != entry.selections)
 1252        {
 1253            self.undo_stack.push_back(entry);
 1254            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1255                self.undo_stack.pop_front();
 1256            }
 1257        }
 1258    }
 1259
 1260    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1261        if self
 1262            .redo_stack
 1263            .back()
 1264            .map_or(true, |e| e.selections != entry.selections)
 1265        {
 1266            self.redo_stack.push_back(entry);
 1267            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1268                self.redo_stack.pop_front();
 1269            }
 1270        }
 1271    }
 1272}
 1273
 1274#[derive(Clone, Copy)]
 1275pub struct RowHighlightOptions {
 1276    pub autoscroll: bool,
 1277    pub include_gutter: bool,
 1278}
 1279
 1280impl Default for RowHighlightOptions {
 1281    fn default() -> Self {
 1282        Self {
 1283            autoscroll: Default::default(),
 1284            include_gutter: true,
 1285        }
 1286    }
 1287}
 1288
 1289struct RowHighlight {
 1290    index: usize,
 1291    range: Range<Anchor>,
 1292    color: Hsla,
 1293    options: RowHighlightOptions,
 1294    type_id: TypeId,
 1295}
 1296
 1297#[derive(Clone, Debug)]
 1298struct AddSelectionsState {
 1299    above: bool,
 1300    stack: Vec<usize>,
 1301}
 1302
 1303#[derive(Clone)]
 1304struct SelectNextState {
 1305    query: AhoCorasick,
 1306    wordwise: bool,
 1307    done: bool,
 1308}
 1309
 1310impl std::fmt::Debug for SelectNextState {
 1311    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1312        f.debug_struct(std::any::type_name::<Self>())
 1313            .field("wordwise", &self.wordwise)
 1314            .field("done", &self.done)
 1315            .finish()
 1316    }
 1317}
 1318
 1319#[derive(Debug)]
 1320struct AutocloseRegion {
 1321    selection_id: usize,
 1322    range: Range<Anchor>,
 1323    pair: BracketPair,
 1324}
 1325
 1326#[derive(Debug)]
 1327struct SnippetState {
 1328    ranges: Vec<Vec<Range<Anchor>>>,
 1329    active_index: usize,
 1330    choices: Vec<Option<Vec<String>>>,
 1331}
 1332
 1333#[doc(hidden)]
 1334pub struct RenameState {
 1335    pub range: Range<Anchor>,
 1336    pub old_name: Arc<str>,
 1337    pub editor: Entity<Editor>,
 1338    block_id: CustomBlockId,
 1339}
 1340
 1341struct InvalidationStack<T>(Vec<T>);
 1342
 1343struct RegisteredInlineCompletionProvider {
 1344    provider: Arc<dyn InlineCompletionProviderHandle>,
 1345    _subscription: Subscription,
 1346}
 1347
 1348#[derive(Debug, PartialEq, Eq)]
 1349pub struct ActiveDiagnosticGroup {
 1350    pub active_range: Range<Anchor>,
 1351    pub active_message: String,
 1352    pub group_id: usize,
 1353    pub blocks: HashSet<CustomBlockId>,
 1354}
 1355
 1356#[derive(Debug, PartialEq, Eq)]
 1357
 1358pub(crate) enum ActiveDiagnostic {
 1359    None,
 1360    All,
 1361    Group(ActiveDiagnosticGroup),
 1362}
 1363
 1364#[derive(Serialize, Deserialize, Clone, Debug)]
 1365pub struct ClipboardSelection {
 1366    /// The number of bytes in this selection.
 1367    pub len: usize,
 1368    /// Whether this was a full-line selection.
 1369    pub is_entire_line: bool,
 1370    /// The indentation of the first line when this content was originally copied.
 1371    pub first_line_indent: u32,
 1372}
 1373
 1374// selections, scroll behavior, was newest selection reversed
 1375type SelectSyntaxNodeHistoryState = (
 1376    Box<[Selection<usize>]>,
 1377    SelectSyntaxNodeScrollBehavior,
 1378    bool,
 1379);
 1380
 1381#[derive(Default)]
 1382struct SelectSyntaxNodeHistory {
 1383    stack: Vec<SelectSyntaxNodeHistoryState>,
 1384    // disable temporarily to allow changing selections without losing the stack
 1385    pub disable_clearing: bool,
 1386}
 1387
 1388impl SelectSyntaxNodeHistory {
 1389    pub fn try_clear(&mut self) {
 1390        if !self.disable_clearing {
 1391            self.stack.clear();
 1392        }
 1393    }
 1394
 1395    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1396        self.stack.push(selection);
 1397    }
 1398
 1399    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1400        self.stack.pop()
 1401    }
 1402}
 1403
 1404enum SelectSyntaxNodeScrollBehavior {
 1405    CursorTop,
 1406    FitSelection,
 1407    CursorBottom,
 1408}
 1409
 1410#[derive(Debug)]
 1411pub(crate) struct NavigationData {
 1412    cursor_anchor: Anchor,
 1413    cursor_position: Point,
 1414    scroll_anchor: ScrollAnchor,
 1415    scroll_top_row: u32,
 1416}
 1417
 1418#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1419pub enum GotoDefinitionKind {
 1420    Symbol,
 1421    Declaration,
 1422    Type,
 1423    Implementation,
 1424}
 1425
 1426#[derive(Debug, Clone)]
 1427enum InlayHintRefreshReason {
 1428    ModifiersChanged(bool),
 1429    Toggle(bool),
 1430    SettingsChange(InlayHintSettings),
 1431    NewLinesShown,
 1432    BufferEdited(HashSet<Arc<Language>>),
 1433    RefreshRequested,
 1434    ExcerptsRemoved(Vec<ExcerptId>),
 1435}
 1436
 1437impl InlayHintRefreshReason {
 1438    fn description(&self) -> &'static str {
 1439        match self {
 1440            Self::ModifiersChanged(_) => "modifiers changed",
 1441            Self::Toggle(_) => "toggle",
 1442            Self::SettingsChange(_) => "settings change",
 1443            Self::NewLinesShown => "new lines shown",
 1444            Self::BufferEdited(_) => "buffer edited",
 1445            Self::RefreshRequested => "refresh requested",
 1446            Self::ExcerptsRemoved(_) => "excerpts removed",
 1447        }
 1448    }
 1449}
 1450
 1451pub enum FormatTarget {
 1452    Buffers,
 1453    Ranges(Vec<Range<MultiBufferPoint>>),
 1454}
 1455
 1456pub(crate) struct FocusedBlock {
 1457    id: BlockId,
 1458    focus_handle: WeakFocusHandle,
 1459}
 1460
 1461#[derive(Clone)]
 1462enum JumpData {
 1463    MultiBufferRow {
 1464        row: MultiBufferRow,
 1465        line_offset_from_top: u32,
 1466    },
 1467    MultiBufferPoint {
 1468        excerpt_id: ExcerptId,
 1469        position: Point,
 1470        anchor: text::Anchor,
 1471        line_offset_from_top: u32,
 1472    },
 1473}
 1474
 1475pub enum MultibufferSelectionMode {
 1476    First,
 1477    All,
 1478}
 1479
 1480#[derive(Clone, Copy, Debug, Default)]
 1481pub struct RewrapOptions {
 1482    pub override_language_settings: bool,
 1483    pub preserve_existing_whitespace: bool,
 1484}
 1485
 1486impl Editor {
 1487    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1488        let buffer = cx.new(|cx| Buffer::local("", cx));
 1489        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1490        Self::new(
 1491            EditorMode::SingleLine { auto_width: false },
 1492            buffer,
 1493            None,
 1494            window,
 1495            cx,
 1496        )
 1497    }
 1498
 1499    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1500        let buffer = cx.new(|cx| Buffer::local("", cx));
 1501        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1502        Self::new(EditorMode::full(), buffer, None, window, cx)
 1503    }
 1504
 1505    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1506        let buffer = cx.new(|cx| Buffer::local("", cx));
 1507        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1508        Self::new(
 1509            EditorMode::SingleLine { auto_width: true },
 1510            buffer,
 1511            None,
 1512            window,
 1513            cx,
 1514        )
 1515    }
 1516
 1517    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1518        let buffer = cx.new(|cx| Buffer::local("", cx));
 1519        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1520        Self::new(
 1521            EditorMode::AutoHeight { max_lines },
 1522            buffer,
 1523            None,
 1524            window,
 1525            cx,
 1526        )
 1527    }
 1528
 1529    pub fn for_buffer(
 1530        buffer: Entity<Buffer>,
 1531        project: Option<Entity<Project>>,
 1532        window: &mut Window,
 1533        cx: &mut Context<Self>,
 1534    ) -> Self {
 1535        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1536        Self::new(EditorMode::full(), buffer, project, window, cx)
 1537    }
 1538
 1539    pub fn for_multibuffer(
 1540        buffer: Entity<MultiBuffer>,
 1541        project: Option<Entity<Project>>,
 1542        window: &mut Window,
 1543        cx: &mut Context<Self>,
 1544    ) -> Self {
 1545        Self::new(EditorMode::full(), buffer, project, window, cx)
 1546    }
 1547
 1548    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1549        let mut clone = Self::new(
 1550            self.mode.clone(),
 1551            self.buffer.clone(),
 1552            self.project.clone(),
 1553            window,
 1554            cx,
 1555        );
 1556        self.display_map.update(cx, |display_map, cx| {
 1557            let snapshot = display_map.snapshot(cx);
 1558            clone.display_map.update(cx, |display_map, cx| {
 1559                display_map.set_state(&snapshot, cx);
 1560            });
 1561        });
 1562        clone.folds_did_change(cx);
 1563        clone.selections.clone_state(&self.selections);
 1564        clone.scroll_manager.clone_state(&self.scroll_manager);
 1565        clone.searchable = self.searchable;
 1566        clone.read_only = self.read_only;
 1567        clone
 1568    }
 1569
 1570    pub fn new(
 1571        mode: EditorMode,
 1572        buffer: Entity<MultiBuffer>,
 1573        project: Option<Entity<Project>>,
 1574        window: &mut Window,
 1575        cx: &mut Context<Self>,
 1576    ) -> Self {
 1577        Editor::new_internal(mode, buffer, project, None, window, cx)
 1578    }
 1579
 1580    fn new_internal(
 1581        mode: EditorMode,
 1582        buffer: Entity<MultiBuffer>,
 1583        project: Option<Entity<Project>>,
 1584        display_map: Option<Entity<DisplayMap>>,
 1585        window: &mut Window,
 1586        cx: &mut Context<Self>,
 1587    ) -> Self {
 1588        debug_assert!(
 1589            display_map.is_none() || mode.is_minimap(),
 1590            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1591        );
 1592
 1593        let full_mode = mode.is_full();
 1594        let diagnostics_max_severity = if full_mode {
 1595            EditorSettings::get_global(cx)
 1596                .diagnostics_max_severity
 1597                .unwrap_or(DiagnosticSeverity::Hint)
 1598        } else {
 1599            DiagnosticSeverity::Off
 1600        };
 1601        let style = window.text_style();
 1602        let font_size = style.font_size.to_pixels(window.rem_size());
 1603        let editor = cx.entity().downgrade();
 1604        let fold_placeholder = FoldPlaceholder {
 1605            constrain_width: true,
 1606            render: Arc::new(move |fold_id, fold_range, cx| {
 1607                let editor = editor.clone();
 1608                div()
 1609                    .id(fold_id)
 1610                    .bg(cx.theme().colors().ghost_element_background)
 1611                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1612                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1613                    .rounded_xs()
 1614                    .size_full()
 1615                    .cursor_pointer()
 1616                    .child("")
 1617                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1618                    .on_click(move |_, _window, cx| {
 1619                        editor
 1620                            .update(cx, |editor, cx| {
 1621                                editor.unfold_ranges(
 1622                                    &[fold_range.start..fold_range.end],
 1623                                    true,
 1624                                    false,
 1625                                    cx,
 1626                                );
 1627                                cx.stop_propagation();
 1628                            })
 1629                            .ok();
 1630                    })
 1631                    .into_any()
 1632            }),
 1633            merge_adjacent: true,
 1634            ..FoldPlaceholder::default()
 1635        };
 1636        let display_map = display_map.unwrap_or_else(|| {
 1637            cx.new(|cx| {
 1638                DisplayMap::new(
 1639                    buffer.clone(),
 1640                    style.font(),
 1641                    font_size,
 1642                    None,
 1643                    FILE_HEADER_HEIGHT,
 1644                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1645                    fold_placeholder,
 1646                    diagnostics_max_severity,
 1647                    cx,
 1648                )
 1649            })
 1650        });
 1651
 1652        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1653
 1654        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1655
 1656        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1657            .then(|| language_settings::SoftWrap::None);
 1658
 1659        let mut project_subscriptions = Vec::new();
 1660        if mode.is_full() {
 1661            if let Some(project) = project.as_ref() {
 1662                project_subscriptions.push(cx.subscribe_in(
 1663                    project,
 1664                    window,
 1665                    |editor, _, event, window, cx| match event {
 1666                        project::Event::RefreshCodeLens => {
 1667                            // we always query lens with actions, without storing them, always refreshing them
 1668                        }
 1669                        project::Event::RefreshInlayHints => {
 1670                            editor
 1671                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1672                        }
 1673                        project::Event::SnippetEdit(id, snippet_edits) => {
 1674                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1675                                let focus_handle = editor.focus_handle(cx);
 1676                                if focus_handle.is_focused(window) {
 1677                                    let snapshot = buffer.read(cx).snapshot();
 1678                                    for (range, snippet) in snippet_edits {
 1679                                        let editor_range =
 1680                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1681                                        editor
 1682                                            .insert_snippet(
 1683                                                &[editor_range],
 1684                                                snippet.clone(),
 1685                                                window,
 1686                                                cx,
 1687                                            )
 1688                                            .ok();
 1689                                    }
 1690                                }
 1691                            }
 1692                        }
 1693                        _ => {}
 1694                    },
 1695                ));
 1696                if let Some(task_inventory) = project
 1697                    .read(cx)
 1698                    .task_store()
 1699                    .read(cx)
 1700                    .task_inventory()
 1701                    .cloned()
 1702                {
 1703                    project_subscriptions.push(cx.observe_in(
 1704                        &task_inventory,
 1705                        window,
 1706                        |editor, _, window, cx| {
 1707                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1708                        },
 1709                    ));
 1710                };
 1711
 1712                project_subscriptions.push(cx.subscribe_in(
 1713                    &project.read(cx).breakpoint_store(),
 1714                    window,
 1715                    |editor, _, event, window, cx| match event {
 1716                        BreakpointStoreEvent::ClearDebugLines => {
 1717                            editor.clear_row_highlights::<ActiveDebugLine>();
 1718                            editor.refresh_inline_values(cx);
 1719                        }
 1720                        BreakpointStoreEvent::SetDebugLine => {
 1721                            if editor.go_to_active_debug_line(window, cx) {
 1722                                cx.stop_propagation();
 1723                            }
 1724
 1725                            editor.refresh_inline_values(cx);
 1726                        }
 1727                        _ => {}
 1728                    },
 1729                ));
 1730            }
 1731        }
 1732
 1733        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1734
 1735        let inlay_hint_settings =
 1736            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1737        let focus_handle = cx.focus_handle();
 1738        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1739            .detach();
 1740        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1741            .detach();
 1742        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1743            .detach();
 1744        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1745            .detach();
 1746
 1747        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1748            Some(false)
 1749        } else {
 1750            None
 1751        };
 1752
 1753        let breakpoint_store = match (&mode, project.as_ref()) {
 1754            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1755            _ => None,
 1756        };
 1757
 1758        let mut code_action_providers = Vec::new();
 1759        let mut load_uncommitted_diff = None;
 1760        if let Some(project) = project.clone() {
 1761            load_uncommitted_diff = Some(
 1762                update_uncommitted_diff_for_buffer(
 1763                    cx.entity(),
 1764                    &project,
 1765                    buffer.read(cx).all_buffers(),
 1766                    buffer.clone(),
 1767                    cx,
 1768                )
 1769                .shared(),
 1770            );
 1771            code_action_providers.push(Rc::new(project) as Rc<_>);
 1772        }
 1773
 1774        let mut this = Self {
 1775            focus_handle,
 1776            show_cursor_when_unfocused: false,
 1777            last_focused_descendant: None,
 1778            buffer: buffer.clone(),
 1779            display_map: display_map.clone(),
 1780            selections,
 1781            scroll_manager: ScrollManager::new(cx),
 1782            columnar_selection_tail: None,
 1783            add_selections_state: None,
 1784            select_next_state: None,
 1785            select_prev_state: None,
 1786            selection_history: SelectionHistory::default(),
 1787            autoclose_regions: Vec::new(),
 1788            snippet_stack: InvalidationStack::default(),
 1789            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1790            ime_transaction: None,
 1791            active_diagnostics: ActiveDiagnostic::None,
 1792            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1793            inline_diagnostics_update: Task::ready(()),
 1794            inline_diagnostics: Vec::new(),
 1795            soft_wrap_mode_override,
 1796            diagnostics_max_severity,
 1797            hard_wrap: None,
 1798            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1799            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1800            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1801            project,
 1802            blink_manager: blink_manager.clone(),
 1803            show_local_selections: true,
 1804            show_scrollbars: ScrollbarAxes {
 1805                horizontal: full_mode,
 1806                vertical: full_mode,
 1807            },
 1808            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1809            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1810            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1811            show_gutter: mode.is_full(),
 1812            show_line_numbers: None,
 1813            use_relative_line_numbers: None,
 1814            disable_expand_excerpt_buttons: false,
 1815            show_git_diff_gutter: None,
 1816            show_code_actions: None,
 1817            show_runnables: None,
 1818            show_breakpoints: None,
 1819            show_wrap_guides: None,
 1820            show_indent_guides,
 1821            placeholder_text: None,
 1822            highlight_order: 0,
 1823            highlighted_rows: HashMap::default(),
 1824            background_highlights: TreeMap::default(),
 1825            gutter_highlights: TreeMap::default(),
 1826            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1827            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1828            nav_history: None,
 1829            context_menu: RefCell::new(None),
 1830            context_menu_options: None,
 1831            mouse_context_menu: None,
 1832            completion_tasks: Vec::new(),
 1833            inline_blame_popover: None,
 1834            signature_help_state: SignatureHelpState::default(),
 1835            auto_signature_help: None,
 1836            find_all_references_task_sources: Vec::new(),
 1837            next_completion_id: 0,
 1838            next_inlay_id: 0,
 1839            code_action_providers,
 1840            available_code_actions: None,
 1841            code_actions_task: None,
 1842            quick_selection_highlight_task: None,
 1843            debounced_selection_highlight_task: None,
 1844            document_highlights_task: None,
 1845            linked_editing_range_task: None,
 1846            pending_rename: None,
 1847            searchable: true,
 1848            cursor_shape: EditorSettings::get_global(cx)
 1849                .cursor_shape
 1850                .unwrap_or_default(),
 1851            current_line_highlight: None,
 1852            autoindent_mode: Some(AutoindentMode::EachLine),
 1853            collapse_matches: false,
 1854            workspace: None,
 1855            input_enabled: true,
 1856            use_modal_editing: mode.is_full(),
 1857            read_only: mode.is_minimap(),
 1858            use_autoclose: true,
 1859            use_auto_surround: true,
 1860            auto_replace_emoji_shortcode: false,
 1861            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1862            leader_id: None,
 1863            remote_id: None,
 1864            hover_state: HoverState::default(),
 1865            pending_mouse_down: None,
 1866            hovered_link_state: None,
 1867            edit_prediction_provider: None,
 1868            active_inline_completion: None,
 1869            stale_inline_completion_in_menu: None,
 1870            edit_prediction_preview: EditPredictionPreview::Inactive {
 1871                released_too_fast: false,
 1872            },
 1873            inline_diagnostics_enabled: mode.is_full(),
 1874            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1875            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1876
 1877            gutter_hovered: false,
 1878            pixel_position_of_newest_cursor: None,
 1879            last_bounds: None,
 1880            last_position_map: None,
 1881            expect_bounds_change: None,
 1882            gutter_dimensions: GutterDimensions::default(),
 1883            style: None,
 1884            show_cursor_names: false,
 1885            hovered_cursors: HashMap::default(),
 1886            next_editor_action_id: EditorActionId::default(),
 1887            editor_actions: Rc::default(),
 1888            inline_completions_hidden_for_vim_mode: false,
 1889            show_inline_completions_override: None,
 1890            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1891            edit_prediction_settings: EditPredictionSettings::Disabled,
 1892            edit_prediction_indent_conflict: false,
 1893            edit_prediction_requires_modifier_in_indent_conflict: true,
 1894            custom_context_menu: None,
 1895            show_git_blame_gutter: false,
 1896            show_git_blame_inline: false,
 1897            show_selection_menu: None,
 1898            show_git_blame_inline_delay_task: None,
 1899            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1900            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1901            serialize_dirty_buffers: !mode.is_minimap()
 1902                && ProjectSettings::get_global(cx)
 1903                    .session
 1904                    .restore_unsaved_buffers,
 1905            blame: None,
 1906            blame_subscription: None,
 1907            tasks: BTreeMap::default(),
 1908
 1909            breakpoint_store,
 1910            gutter_breakpoint_indicator: (None, None),
 1911            _subscriptions: vec![
 1912                cx.observe(&buffer, Self::on_buffer_changed),
 1913                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1914                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1915                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1916                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1917                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1918                cx.observe_window_activation(window, |editor, window, cx| {
 1919                    let active = window.is_window_active();
 1920                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1921                        if active {
 1922                            blink_manager.enable(cx);
 1923                        } else {
 1924                            blink_manager.disable(cx);
 1925                        }
 1926                    });
 1927                    if active {
 1928                        editor.show_mouse_cursor();
 1929                    }
 1930                }),
 1931            ],
 1932            tasks_update_task: None,
 1933            linked_edit_ranges: Default::default(),
 1934            in_project_search: false,
 1935            previous_search_ranges: None,
 1936            breadcrumb_header: None,
 1937            focused_block: None,
 1938            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1939            addons: HashMap::default(),
 1940            registered_buffers: HashMap::default(),
 1941            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1942            selection_mark_mode: false,
 1943            toggle_fold_multiple_buffers: Task::ready(()),
 1944            serialize_selections: Task::ready(()),
 1945            serialize_folds: Task::ready(()),
 1946            text_style_refinement: None,
 1947            load_diff_task: load_uncommitted_diff,
 1948            temporary_diff_override: false,
 1949            mouse_cursor_hidden: false,
 1950            minimap: None,
 1951            hide_mouse_mode: EditorSettings::get_global(cx)
 1952                .hide_mouse
 1953                .unwrap_or_default(),
 1954            change_list: ChangeList::new(),
 1955            mode,
 1956        };
 1957        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1958            this._subscriptions
 1959                .push(cx.observe(breakpoints, |_, _, cx| {
 1960                    cx.notify();
 1961                }));
 1962        }
 1963        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1964        this._subscriptions.extend(project_subscriptions);
 1965
 1966        this._subscriptions.push(cx.subscribe_in(
 1967            &cx.entity(),
 1968            window,
 1969            |editor, _, e: &EditorEvent, window, cx| match e {
 1970                EditorEvent::ScrollPositionChanged { local, .. } => {
 1971                    if *local {
 1972                        let new_anchor = editor.scroll_manager.anchor();
 1973                        let snapshot = editor.snapshot(window, cx);
 1974                        editor.update_restoration_data(cx, move |data| {
 1975                            data.scroll_position = (
 1976                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1977                                new_anchor.offset,
 1978                            );
 1979                        });
 1980                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1981                        editor.inline_blame_popover.take();
 1982                    }
 1983                }
 1984                EditorEvent::Edited { .. } => {
 1985                    if !vim_enabled(cx) {
 1986                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1987                        let pop_state = editor
 1988                            .change_list
 1989                            .last()
 1990                            .map(|previous| {
 1991                                previous.len() == selections.len()
 1992                                    && previous.iter().enumerate().all(|(ix, p)| {
 1993                                        p.to_display_point(&map).row()
 1994                                            == selections[ix].head().row()
 1995                                    })
 1996                            })
 1997                            .unwrap_or(false);
 1998                        let new_positions = selections
 1999                            .into_iter()
 2000                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2001                            .collect();
 2002                        editor
 2003                            .change_list
 2004                            .push_to_change_list(pop_state, new_positions);
 2005                    }
 2006                }
 2007                _ => (),
 2008            },
 2009        ));
 2010
 2011        if let Some(dap_store) = this
 2012            .project
 2013            .as_ref()
 2014            .map(|project| project.read(cx).dap_store())
 2015        {
 2016            let weak_editor = cx.weak_entity();
 2017
 2018            this._subscriptions
 2019                .push(
 2020                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2021                        let session_entity = cx.entity();
 2022                        weak_editor
 2023                            .update(cx, |editor, cx| {
 2024                                editor._subscriptions.push(
 2025                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2026                                );
 2027                            })
 2028                            .ok();
 2029                    }),
 2030                );
 2031
 2032            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2033                this._subscriptions
 2034                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2035            }
 2036        }
 2037
 2038        this.end_selection(window, cx);
 2039        this.scroll_manager.show_scrollbars(window, cx);
 2040        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 2041
 2042        if full_mode {
 2043            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2044            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2045
 2046            if this.git_blame_inline_enabled {
 2047                this.start_git_blame_inline(false, window, cx);
 2048            }
 2049
 2050            this.go_to_active_debug_line(window, cx);
 2051
 2052            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2053                if let Some(project) = this.project.as_ref() {
 2054                    let handle = project.update(cx, |project, cx| {
 2055                        project.register_buffer_with_language_servers(&buffer, cx)
 2056                    });
 2057                    this.registered_buffers
 2058                        .insert(buffer.read(cx).remote_id(), handle);
 2059                }
 2060            }
 2061
 2062            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2063        }
 2064
 2065        this.report_editor_event("Editor Opened", None, cx);
 2066        this
 2067    }
 2068
 2069    pub fn deploy_mouse_context_menu(
 2070        &mut self,
 2071        position: gpui::Point<Pixels>,
 2072        context_menu: Entity<ContextMenu>,
 2073        window: &mut Window,
 2074        cx: &mut Context<Self>,
 2075    ) {
 2076        self.mouse_context_menu = Some(MouseContextMenu::new(
 2077            self,
 2078            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2079            context_menu,
 2080            window,
 2081            cx,
 2082        ));
 2083    }
 2084
 2085    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2086        self.mouse_context_menu
 2087            .as_ref()
 2088            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2089    }
 2090
 2091    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2092        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2093    }
 2094
 2095    fn key_context_internal(
 2096        &self,
 2097        has_active_edit_prediction: bool,
 2098        window: &Window,
 2099        cx: &App,
 2100    ) -> KeyContext {
 2101        let mut key_context = KeyContext::new_with_defaults();
 2102        key_context.add("Editor");
 2103        let mode = match self.mode {
 2104            EditorMode::SingleLine { .. } => "single_line",
 2105            EditorMode::AutoHeight { .. } => "auto_height",
 2106            EditorMode::Minimap { .. } => "minimap",
 2107            EditorMode::Full { .. } => "full",
 2108        };
 2109
 2110        if EditorSettings::jupyter_enabled(cx) {
 2111            key_context.add("jupyter");
 2112        }
 2113
 2114        key_context.set("mode", mode);
 2115        if self.pending_rename.is_some() {
 2116            key_context.add("renaming");
 2117        }
 2118
 2119        match self.context_menu.borrow().as_ref() {
 2120            Some(CodeContextMenu::Completions(_)) => {
 2121                key_context.add("menu");
 2122                key_context.add("showing_completions");
 2123            }
 2124            Some(CodeContextMenu::CodeActions(_)) => {
 2125                key_context.add("menu");
 2126                key_context.add("showing_code_actions")
 2127            }
 2128            None => {}
 2129        }
 2130
 2131        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2132        if !self.focus_handle(cx).contains_focused(window, cx)
 2133            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2134        {
 2135            for addon in self.addons.values() {
 2136                addon.extend_key_context(&mut key_context, cx)
 2137            }
 2138        }
 2139
 2140        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2141            if let Some(extension) = singleton_buffer
 2142                .read(cx)
 2143                .file()
 2144                .and_then(|file| file.path().extension()?.to_str())
 2145            {
 2146                key_context.set("extension", extension.to_string());
 2147            }
 2148        } else {
 2149            key_context.add("multibuffer");
 2150        }
 2151
 2152        if has_active_edit_prediction {
 2153            if self.edit_prediction_in_conflict() {
 2154                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2155            } else {
 2156                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2157                key_context.add("copilot_suggestion");
 2158            }
 2159        }
 2160
 2161        if self.selection_mark_mode {
 2162            key_context.add("selection_mode");
 2163        }
 2164
 2165        key_context
 2166    }
 2167
 2168    fn show_mouse_cursor(&mut self) {
 2169        self.mouse_cursor_hidden = false;
 2170    }
 2171
 2172    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2173        self.mouse_cursor_hidden = match origin {
 2174            HideMouseCursorOrigin::TypingAction => {
 2175                matches!(
 2176                    self.hide_mouse_mode,
 2177                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2178                )
 2179            }
 2180            HideMouseCursorOrigin::MovementAction => {
 2181                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2182            }
 2183        };
 2184    }
 2185
 2186    pub fn edit_prediction_in_conflict(&self) -> bool {
 2187        if !self.show_edit_predictions_in_menu() {
 2188            return false;
 2189        }
 2190
 2191        let showing_completions = self
 2192            .context_menu
 2193            .borrow()
 2194            .as_ref()
 2195            .map_or(false, |context| {
 2196                matches!(context, CodeContextMenu::Completions(_))
 2197            });
 2198
 2199        showing_completions
 2200            || self.edit_prediction_requires_modifier()
 2201            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2202            // bindings to insert tab characters.
 2203            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2204    }
 2205
 2206    pub fn accept_edit_prediction_keybind(
 2207        &self,
 2208        window: &Window,
 2209        cx: &App,
 2210    ) -> AcceptEditPredictionBinding {
 2211        let key_context = self.key_context_internal(true, window, cx);
 2212        let in_conflict = self.edit_prediction_in_conflict();
 2213
 2214        AcceptEditPredictionBinding(
 2215            window
 2216                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2217                .into_iter()
 2218                .filter(|binding| {
 2219                    !in_conflict
 2220                        || binding
 2221                            .keystrokes()
 2222                            .first()
 2223                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2224                })
 2225                .rev()
 2226                .min_by_key(|binding| {
 2227                    binding
 2228                        .keystrokes()
 2229                        .first()
 2230                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2231                }),
 2232        )
 2233    }
 2234
 2235    pub fn new_file(
 2236        workspace: &mut Workspace,
 2237        _: &workspace::NewFile,
 2238        window: &mut Window,
 2239        cx: &mut Context<Workspace>,
 2240    ) {
 2241        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2242            "Failed to create buffer",
 2243            window,
 2244            cx,
 2245            |e, _, _| match e.error_code() {
 2246                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2247                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2248                e.error_tag("required").unwrap_or("the latest version")
 2249            )),
 2250                _ => None,
 2251            },
 2252        );
 2253    }
 2254
 2255    pub fn new_in_workspace(
 2256        workspace: &mut Workspace,
 2257        window: &mut Window,
 2258        cx: &mut Context<Workspace>,
 2259    ) -> Task<Result<Entity<Editor>>> {
 2260        let project = workspace.project().clone();
 2261        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2262
 2263        cx.spawn_in(window, async move |workspace, cx| {
 2264            let buffer = create.await?;
 2265            workspace.update_in(cx, |workspace, window, cx| {
 2266                let editor =
 2267                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2268                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2269                editor
 2270            })
 2271        })
 2272    }
 2273
 2274    fn new_file_vertical(
 2275        workspace: &mut Workspace,
 2276        _: &workspace::NewFileSplitVertical,
 2277        window: &mut Window,
 2278        cx: &mut Context<Workspace>,
 2279    ) {
 2280        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2281    }
 2282
 2283    fn new_file_horizontal(
 2284        workspace: &mut Workspace,
 2285        _: &workspace::NewFileSplitHorizontal,
 2286        window: &mut Window,
 2287        cx: &mut Context<Workspace>,
 2288    ) {
 2289        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2290    }
 2291
 2292    fn new_file_in_direction(
 2293        workspace: &mut Workspace,
 2294        direction: SplitDirection,
 2295        window: &mut Window,
 2296        cx: &mut Context<Workspace>,
 2297    ) {
 2298        let project = workspace.project().clone();
 2299        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2300
 2301        cx.spawn_in(window, async move |workspace, cx| {
 2302            let buffer = create.await?;
 2303            workspace.update_in(cx, move |workspace, window, cx| {
 2304                workspace.split_item(
 2305                    direction,
 2306                    Box::new(
 2307                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2308                    ),
 2309                    window,
 2310                    cx,
 2311                )
 2312            })?;
 2313            anyhow::Ok(())
 2314        })
 2315        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2316            match e.error_code() {
 2317                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2318                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2319                e.error_tag("required").unwrap_or("the latest version")
 2320            )),
 2321                _ => None,
 2322            }
 2323        });
 2324    }
 2325
 2326    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2327        self.leader_id
 2328    }
 2329
 2330    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2331        &self.buffer
 2332    }
 2333
 2334    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2335        self.workspace.as_ref()?.0.upgrade()
 2336    }
 2337
 2338    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2339        self.buffer().read(cx).title(cx)
 2340    }
 2341
 2342    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2343        let git_blame_gutter_max_author_length = self
 2344            .render_git_blame_gutter(cx)
 2345            .then(|| {
 2346                if let Some(blame) = self.blame.as_ref() {
 2347                    let max_author_length =
 2348                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2349                    Some(max_author_length)
 2350                } else {
 2351                    None
 2352                }
 2353            })
 2354            .flatten();
 2355
 2356        EditorSnapshot {
 2357            mode: self.mode.clone(),
 2358            show_gutter: self.show_gutter,
 2359            show_line_numbers: self.show_line_numbers,
 2360            show_git_diff_gutter: self.show_git_diff_gutter,
 2361            show_code_actions: self.show_code_actions,
 2362            show_runnables: self.show_runnables,
 2363            show_breakpoints: self.show_breakpoints,
 2364            git_blame_gutter_max_author_length,
 2365            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2366            scroll_anchor: self.scroll_manager.anchor(),
 2367            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2368            placeholder_text: self.placeholder_text.clone(),
 2369            is_focused: self.focus_handle.is_focused(window),
 2370            current_line_highlight: self
 2371                .current_line_highlight
 2372                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2373            gutter_hovered: self.gutter_hovered,
 2374        }
 2375    }
 2376
 2377    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2378        self.buffer.read(cx).language_at(point, cx)
 2379    }
 2380
 2381    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2382        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2383    }
 2384
 2385    pub fn active_excerpt(
 2386        &self,
 2387        cx: &App,
 2388    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2389        self.buffer
 2390            .read(cx)
 2391            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2392    }
 2393
 2394    pub fn mode(&self) -> &EditorMode {
 2395        &self.mode
 2396    }
 2397
 2398    pub fn set_mode(&mut self, mode: EditorMode) {
 2399        self.mode = mode;
 2400    }
 2401
 2402    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2403        self.collaboration_hub.as_deref()
 2404    }
 2405
 2406    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2407        self.collaboration_hub = Some(hub);
 2408    }
 2409
 2410    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2411        self.in_project_search = in_project_search;
 2412    }
 2413
 2414    pub fn set_custom_context_menu(
 2415        &mut self,
 2416        f: impl 'static
 2417        + Fn(
 2418            &mut Self,
 2419            DisplayPoint,
 2420            &mut Window,
 2421            &mut Context<Self>,
 2422        ) -> Option<Entity<ui::ContextMenu>>,
 2423    ) {
 2424        self.custom_context_menu = Some(Box::new(f))
 2425    }
 2426
 2427    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2428        self.completion_provider = provider;
 2429    }
 2430
 2431    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2432        self.semantics_provider.clone()
 2433    }
 2434
 2435    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2436        self.semantics_provider = provider;
 2437    }
 2438
 2439    pub fn set_edit_prediction_provider<T>(
 2440        &mut self,
 2441        provider: Option<Entity<T>>,
 2442        window: &mut Window,
 2443        cx: &mut Context<Self>,
 2444    ) where
 2445        T: EditPredictionProvider,
 2446    {
 2447        self.edit_prediction_provider =
 2448            provider.map(|provider| RegisteredInlineCompletionProvider {
 2449                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2450                    if this.focus_handle.is_focused(window) {
 2451                        this.update_visible_inline_completion(window, cx);
 2452                    }
 2453                }),
 2454                provider: Arc::new(provider),
 2455            });
 2456        self.update_edit_prediction_settings(cx);
 2457        self.refresh_inline_completion(false, false, window, cx);
 2458    }
 2459
 2460    pub fn placeholder_text(&self) -> Option<&str> {
 2461        self.placeholder_text.as_deref()
 2462    }
 2463
 2464    pub fn set_placeholder_text(
 2465        &mut self,
 2466        placeholder_text: impl Into<Arc<str>>,
 2467        cx: &mut Context<Self>,
 2468    ) {
 2469        let placeholder_text = Some(placeholder_text.into());
 2470        if self.placeholder_text != placeholder_text {
 2471            self.placeholder_text = placeholder_text;
 2472            cx.notify();
 2473        }
 2474    }
 2475
 2476    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2477        self.cursor_shape = cursor_shape;
 2478
 2479        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2480        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2481
 2482        cx.notify();
 2483    }
 2484
 2485    pub fn set_current_line_highlight(
 2486        &mut self,
 2487        current_line_highlight: Option<CurrentLineHighlight>,
 2488    ) {
 2489        self.current_line_highlight = current_line_highlight;
 2490    }
 2491
 2492    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2493        self.collapse_matches = collapse_matches;
 2494    }
 2495
 2496    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2497        let buffers = self.buffer.read(cx).all_buffers();
 2498        let Some(project) = self.project.as_ref() else {
 2499            return;
 2500        };
 2501        project.update(cx, |project, cx| {
 2502            for buffer in buffers {
 2503                self.registered_buffers
 2504                    .entry(buffer.read(cx).remote_id())
 2505                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2506            }
 2507        })
 2508    }
 2509
 2510    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2511        if self.collapse_matches {
 2512            return range.start..range.start;
 2513        }
 2514        range.clone()
 2515    }
 2516
 2517    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2518        if self.display_map.read(cx).clip_at_line_ends != clip {
 2519            self.display_map
 2520                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2521        }
 2522    }
 2523
 2524    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2525        self.input_enabled = input_enabled;
 2526    }
 2527
 2528    pub fn set_inline_completions_hidden_for_vim_mode(
 2529        &mut self,
 2530        hidden: bool,
 2531        window: &mut Window,
 2532        cx: &mut Context<Self>,
 2533    ) {
 2534        if hidden != self.inline_completions_hidden_for_vim_mode {
 2535            self.inline_completions_hidden_for_vim_mode = hidden;
 2536            if hidden {
 2537                self.update_visible_inline_completion(window, cx);
 2538            } else {
 2539                self.refresh_inline_completion(true, false, window, cx);
 2540            }
 2541        }
 2542    }
 2543
 2544    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2545        self.menu_inline_completions_policy = value;
 2546    }
 2547
 2548    pub fn set_autoindent(&mut self, autoindent: bool) {
 2549        if autoindent {
 2550            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2551        } else {
 2552            self.autoindent_mode = None;
 2553        }
 2554    }
 2555
 2556    pub fn read_only(&self, cx: &App) -> bool {
 2557        self.read_only || self.buffer.read(cx).read_only()
 2558    }
 2559
 2560    pub fn set_read_only(&mut self, read_only: bool) {
 2561        self.read_only = read_only;
 2562    }
 2563
 2564    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2565        self.use_autoclose = autoclose;
 2566    }
 2567
 2568    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2569        self.use_auto_surround = auto_surround;
 2570    }
 2571
 2572    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2573        self.auto_replace_emoji_shortcode = auto_replace;
 2574    }
 2575
 2576    pub fn toggle_edit_predictions(
 2577        &mut self,
 2578        _: &ToggleEditPrediction,
 2579        window: &mut Window,
 2580        cx: &mut Context<Self>,
 2581    ) {
 2582        if self.show_inline_completions_override.is_some() {
 2583            self.set_show_edit_predictions(None, window, cx);
 2584        } else {
 2585            let show_edit_predictions = !self.edit_predictions_enabled();
 2586            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2587        }
 2588    }
 2589
 2590    pub fn set_show_edit_predictions(
 2591        &mut self,
 2592        show_edit_predictions: Option<bool>,
 2593        window: &mut Window,
 2594        cx: &mut Context<Self>,
 2595    ) {
 2596        self.show_inline_completions_override = show_edit_predictions;
 2597        self.update_edit_prediction_settings(cx);
 2598
 2599        if let Some(false) = show_edit_predictions {
 2600            self.discard_inline_completion(false, cx);
 2601        } else {
 2602            self.refresh_inline_completion(false, true, window, cx);
 2603        }
 2604    }
 2605
 2606    fn inline_completions_disabled_in_scope(
 2607        &self,
 2608        buffer: &Entity<Buffer>,
 2609        buffer_position: language::Anchor,
 2610        cx: &App,
 2611    ) -> bool {
 2612        let snapshot = buffer.read(cx).snapshot();
 2613        let settings = snapshot.settings_at(buffer_position, cx);
 2614
 2615        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2616            return false;
 2617        };
 2618
 2619        scope.override_name().map_or(false, |scope_name| {
 2620            settings
 2621                .edit_predictions_disabled_in
 2622                .iter()
 2623                .any(|s| s == scope_name)
 2624        })
 2625    }
 2626
 2627    pub fn set_use_modal_editing(&mut self, to: bool) {
 2628        self.use_modal_editing = to;
 2629    }
 2630
 2631    pub fn use_modal_editing(&self) -> bool {
 2632        self.use_modal_editing
 2633    }
 2634
 2635    fn selections_did_change(
 2636        &mut self,
 2637        local: bool,
 2638        old_cursor_position: &Anchor,
 2639        show_completions: bool,
 2640        window: &mut Window,
 2641        cx: &mut Context<Self>,
 2642    ) {
 2643        window.invalidate_character_coordinates();
 2644
 2645        // Copy selections to primary selection buffer
 2646        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2647        if local {
 2648            let selections = self.selections.all::<usize>(cx);
 2649            let buffer_handle = self.buffer.read(cx).read(cx);
 2650
 2651            let mut text = String::new();
 2652            for (index, selection) in selections.iter().enumerate() {
 2653                let text_for_selection = buffer_handle
 2654                    .text_for_range(selection.start..selection.end)
 2655                    .collect::<String>();
 2656
 2657                text.push_str(&text_for_selection);
 2658                if index != selections.len() - 1 {
 2659                    text.push('\n');
 2660                }
 2661            }
 2662
 2663            if !text.is_empty() {
 2664                cx.write_to_primary(ClipboardItem::new_string(text));
 2665            }
 2666        }
 2667
 2668        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2669            self.buffer.update(cx, |buffer, cx| {
 2670                buffer.set_active_selections(
 2671                    &self.selections.disjoint_anchors(),
 2672                    self.selections.line_mode,
 2673                    self.cursor_shape,
 2674                    cx,
 2675                )
 2676            });
 2677        }
 2678        let display_map = self
 2679            .display_map
 2680            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2681        let buffer = &display_map.buffer_snapshot;
 2682        self.add_selections_state = None;
 2683        self.select_next_state = None;
 2684        self.select_prev_state = None;
 2685        self.select_syntax_node_history.try_clear();
 2686        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2687        self.snippet_stack
 2688            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2689        self.take_rename(false, window, cx);
 2690
 2691        let new_cursor_position = self.selections.newest_anchor().head();
 2692
 2693        self.push_to_nav_history(
 2694            *old_cursor_position,
 2695            Some(new_cursor_position.to_point(buffer)),
 2696            false,
 2697            cx,
 2698        );
 2699
 2700        if local {
 2701            let new_cursor_position = self.selections.newest_anchor().head();
 2702            let mut context_menu = self.context_menu.borrow_mut();
 2703            let completion_menu = match context_menu.as_ref() {
 2704                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2705                _ => {
 2706                    *context_menu = None;
 2707                    None
 2708                }
 2709            };
 2710            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2711                if !self.registered_buffers.contains_key(&buffer_id) {
 2712                    if let Some(project) = self.project.as_ref() {
 2713                        project.update(cx, |project, cx| {
 2714                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2715                                return;
 2716                            };
 2717                            self.registered_buffers.insert(
 2718                                buffer_id,
 2719                                project.register_buffer_with_language_servers(&buffer, cx),
 2720                            );
 2721                        })
 2722                    }
 2723                }
 2724            }
 2725
 2726            if let Some(completion_menu) = completion_menu {
 2727                let cursor_position = new_cursor_position.to_offset(buffer);
 2728                let (word_range, kind) =
 2729                    buffer.surrounding_word(completion_menu.initial_position, true);
 2730                if kind == Some(CharKind::Word)
 2731                    && word_range.to_inclusive().contains(&cursor_position)
 2732                {
 2733                    let mut completion_menu = completion_menu.clone();
 2734                    drop(context_menu);
 2735
 2736                    let query = Self::completion_query(buffer, cursor_position);
 2737                    let completion_provider = self.completion_provider.clone();
 2738                    cx.spawn_in(window, async move |this, cx| {
 2739                        completion_menu
 2740                            .filter(query.as_deref(), completion_provider, this.clone(), cx)
 2741                            .await;
 2742
 2743                        this.update(cx, |this, cx| {
 2744                            let mut context_menu = this.context_menu.borrow_mut();
 2745                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2746                            else {
 2747                                return;
 2748                            };
 2749
 2750                            if menu.id > completion_menu.id {
 2751                                return;
 2752                            }
 2753
 2754                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2755                            drop(context_menu);
 2756                            cx.notify();
 2757                        })
 2758                    })
 2759                    .detach();
 2760
 2761                    if show_completions {
 2762                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2763                    }
 2764                } else {
 2765                    drop(context_menu);
 2766                    self.hide_context_menu(window, cx);
 2767                }
 2768            } else {
 2769                drop(context_menu);
 2770            }
 2771
 2772            hide_hover(self, cx);
 2773
 2774            if old_cursor_position.to_display_point(&display_map).row()
 2775                != new_cursor_position.to_display_point(&display_map).row()
 2776            {
 2777                self.available_code_actions.take();
 2778            }
 2779            self.refresh_code_actions(window, cx);
 2780            self.refresh_document_highlights(cx);
 2781            self.refresh_selected_text_highlights(false, window, cx);
 2782            refresh_matching_bracket_highlights(self, window, cx);
 2783            self.update_visible_inline_completion(window, cx);
 2784            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2785            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2786            self.inline_blame_popover.take();
 2787            if self.git_blame_inline_enabled {
 2788                self.start_inline_blame_timer(window, cx);
 2789            }
 2790        }
 2791
 2792        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2793        cx.emit(EditorEvent::SelectionsChanged { local });
 2794
 2795        let selections = &self.selections.disjoint;
 2796        if selections.len() == 1 {
 2797            cx.emit(SearchEvent::ActiveMatchChanged)
 2798        }
 2799        if local {
 2800            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2801                let inmemory_selections = selections
 2802                    .iter()
 2803                    .map(|s| {
 2804                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2805                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2806                    })
 2807                    .collect();
 2808                self.update_restoration_data(cx, |data| {
 2809                    data.selections = inmemory_selections;
 2810                });
 2811
 2812                if WorkspaceSettings::get(None, cx).restore_on_startup
 2813                    != RestoreOnStartupBehavior::None
 2814                {
 2815                    if let Some(workspace_id) =
 2816                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2817                    {
 2818                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2819                        let selections = selections.clone();
 2820                        let background_executor = cx.background_executor().clone();
 2821                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2822                        self.serialize_selections = cx.background_spawn(async move {
 2823                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2824                    let db_selections = selections
 2825                        .iter()
 2826                        .map(|selection| {
 2827                            (
 2828                                selection.start.to_offset(&snapshot),
 2829                                selection.end.to_offset(&snapshot),
 2830                            )
 2831                        })
 2832                        .collect();
 2833
 2834                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2835                        .await
 2836                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2837                        .log_err();
 2838                });
 2839                    }
 2840                }
 2841            }
 2842        }
 2843
 2844        cx.notify();
 2845    }
 2846
 2847    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2848        use text::ToOffset as _;
 2849        use text::ToPoint as _;
 2850
 2851        if self.mode.is_minimap()
 2852            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2853        {
 2854            return;
 2855        }
 2856
 2857        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2858            return;
 2859        };
 2860
 2861        let snapshot = singleton.read(cx).snapshot();
 2862        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2863            let display_snapshot = display_map.snapshot(cx);
 2864
 2865            display_snapshot
 2866                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2867                .map(|fold| {
 2868                    fold.range.start.text_anchor.to_point(&snapshot)
 2869                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2870                })
 2871                .collect()
 2872        });
 2873        self.update_restoration_data(cx, |data| {
 2874            data.folds = inmemory_folds;
 2875        });
 2876
 2877        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2878            return;
 2879        };
 2880        let background_executor = cx.background_executor().clone();
 2881        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2882        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2883            display_map
 2884                .snapshot(cx)
 2885                .folds_in_range(0..snapshot.len())
 2886                .map(|fold| {
 2887                    (
 2888                        fold.range.start.text_anchor.to_offset(&snapshot),
 2889                        fold.range.end.text_anchor.to_offset(&snapshot),
 2890                    )
 2891                })
 2892                .collect()
 2893        });
 2894        self.serialize_folds = cx.background_spawn(async move {
 2895            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2896            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2897                .await
 2898                .with_context(|| {
 2899                    format!(
 2900                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2901                    )
 2902                })
 2903                .log_err();
 2904        });
 2905    }
 2906
 2907    pub fn sync_selections(
 2908        &mut self,
 2909        other: Entity<Editor>,
 2910        cx: &mut Context<Self>,
 2911    ) -> gpui::Subscription {
 2912        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2913        self.selections.change_with(cx, |selections| {
 2914            selections.select_anchors(other_selections);
 2915        });
 2916
 2917        let other_subscription =
 2918            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2919                EditorEvent::SelectionsChanged { local: true } => {
 2920                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2921                    if other_selections.is_empty() {
 2922                        return;
 2923                    }
 2924                    this.selections.change_with(cx, |selections| {
 2925                        selections.select_anchors(other_selections);
 2926                    });
 2927                }
 2928                _ => {}
 2929            });
 2930
 2931        let this_subscription =
 2932            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2933                EditorEvent::SelectionsChanged { local: true } => {
 2934                    let these_selections = this.selections.disjoint.to_vec();
 2935                    if these_selections.is_empty() {
 2936                        return;
 2937                    }
 2938                    other.update(cx, |other_editor, cx| {
 2939                        other_editor.selections.change_with(cx, |selections| {
 2940                            selections.select_anchors(these_selections);
 2941                        })
 2942                    });
 2943                }
 2944                _ => {}
 2945            });
 2946
 2947        Subscription::join(other_subscription, this_subscription)
 2948    }
 2949
 2950    pub fn change_selections<R>(
 2951        &mut self,
 2952        autoscroll: Option<Autoscroll>,
 2953        window: &mut Window,
 2954        cx: &mut Context<Self>,
 2955        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2956    ) -> R {
 2957        self.change_selections_inner(autoscroll, true, window, cx, change)
 2958    }
 2959
 2960    fn change_selections_inner<R>(
 2961        &mut self,
 2962        autoscroll: Option<Autoscroll>,
 2963        request_completions: bool,
 2964        window: &mut Window,
 2965        cx: &mut Context<Self>,
 2966        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2967    ) -> R {
 2968        let old_cursor_position = self.selections.newest_anchor().head();
 2969        self.push_to_selection_history();
 2970
 2971        let (changed, result) = self.selections.change_with(cx, change);
 2972
 2973        if changed {
 2974            if let Some(autoscroll) = autoscroll {
 2975                self.request_autoscroll(autoscroll, cx);
 2976            }
 2977            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2978
 2979            if self.should_open_signature_help_automatically(
 2980                &old_cursor_position,
 2981                self.signature_help_state.backspace_pressed(),
 2982                cx,
 2983            ) {
 2984                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2985            }
 2986            self.signature_help_state.set_backspace_pressed(false);
 2987        }
 2988
 2989        result
 2990    }
 2991
 2992    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2993    where
 2994        I: IntoIterator<Item = (Range<S>, T)>,
 2995        S: ToOffset,
 2996        T: Into<Arc<str>>,
 2997    {
 2998        if self.read_only(cx) {
 2999            return;
 3000        }
 3001
 3002        self.buffer
 3003            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3004    }
 3005
 3006    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3007    where
 3008        I: IntoIterator<Item = (Range<S>, T)>,
 3009        S: ToOffset,
 3010        T: Into<Arc<str>>,
 3011    {
 3012        if self.read_only(cx) {
 3013            return;
 3014        }
 3015
 3016        self.buffer.update(cx, |buffer, cx| {
 3017            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3018        });
 3019    }
 3020
 3021    pub fn edit_with_block_indent<I, S, T>(
 3022        &mut self,
 3023        edits: I,
 3024        original_indent_columns: Vec<Option<u32>>,
 3025        cx: &mut Context<Self>,
 3026    ) where
 3027        I: IntoIterator<Item = (Range<S>, T)>,
 3028        S: ToOffset,
 3029        T: Into<Arc<str>>,
 3030    {
 3031        if self.read_only(cx) {
 3032            return;
 3033        }
 3034
 3035        self.buffer.update(cx, |buffer, cx| {
 3036            buffer.edit(
 3037                edits,
 3038                Some(AutoindentMode::Block {
 3039                    original_indent_columns,
 3040                }),
 3041                cx,
 3042            )
 3043        });
 3044    }
 3045
 3046    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3047        self.hide_context_menu(window, cx);
 3048
 3049        match phase {
 3050            SelectPhase::Begin {
 3051                position,
 3052                add,
 3053                click_count,
 3054            } => self.begin_selection(position, add, click_count, window, cx),
 3055            SelectPhase::BeginColumnar {
 3056                position,
 3057                goal_column,
 3058                reset,
 3059            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3060            SelectPhase::Extend {
 3061                position,
 3062                click_count,
 3063            } => self.extend_selection(position, click_count, window, cx),
 3064            SelectPhase::Update {
 3065                position,
 3066                goal_column,
 3067                scroll_delta,
 3068            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3069            SelectPhase::End => self.end_selection(window, cx),
 3070        }
 3071    }
 3072
 3073    fn extend_selection(
 3074        &mut self,
 3075        position: DisplayPoint,
 3076        click_count: usize,
 3077        window: &mut Window,
 3078        cx: &mut Context<Self>,
 3079    ) {
 3080        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3081        let tail = self.selections.newest::<usize>(cx).tail();
 3082        self.begin_selection(position, false, click_count, window, cx);
 3083
 3084        let position = position.to_offset(&display_map, Bias::Left);
 3085        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3086
 3087        let mut pending_selection = self
 3088            .selections
 3089            .pending_anchor()
 3090            .expect("extend_selection not called with pending selection");
 3091        if position >= tail {
 3092            pending_selection.start = tail_anchor;
 3093        } else {
 3094            pending_selection.end = tail_anchor;
 3095            pending_selection.reversed = true;
 3096        }
 3097
 3098        let mut pending_mode = self.selections.pending_mode().unwrap();
 3099        match &mut pending_mode {
 3100            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3101            _ => {}
 3102        }
 3103
 3104        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3105
 3106        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3107            s.set_pending(pending_selection, pending_mode)
 3108        });
 3109    }
 3110
 3111    fn begin_selection(
 3112        &mut self,
 3113        position: DisplayPoint,
 3114        add: bool,
 3115        click_count: usize,
 3116        window: &mut Window,
 3117        cx: &mut Context<Self>,
 3118    ) {
 3119        if !self.focus_handle.is_focused(window) {
 3120            self.last_focused_descendant = None;
 3121            window.focus(&self.focus_handle);
 3122        }
 3123
 3124        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3125        let buffer = &display_map.buffer_snapshot;
 3126        let position = display_map.clip_point(position, Bias::Left);
 3127
 3128        let start;
 3129        let end;
 3130        let mode;
 3131        let mut auto_scroll;
 3132        match click_count {
 3133            1 => {
 3134                start = buffer.anchor_before(position.to_point(&display_map));
 3135                end = start;
 3136                mode = SelectMode::Character;
 3137                auto_scroll = true;
 3138            }
 3139            2 => {
 3140                let range = movement::surrounding_word(&display_map, position);
 3141                start = buffer.anchor_before(range.start.to_point(&display_map));
 3142                end = buffer.anchor_before(range.end.to_point(&display_map));
 3143                mode = SelectMode::Word(start..end);
 3144                auto_scroll = true;
 3145            }
 3146            3 => {
 3147                let position = display_map
 3148                    .clip_point(position, Bias::Left)
 3149                    .to_point(&display_map);
 3150                let line_start = display_map.prev_line_boundary(position).0;
 3151                let next_line_start = buffer.clip_point(
 3152                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3153                    Bias::Left,
 3154                );
 3155                start = buffer.anchor_before(line_start);
 3156                end = buffer.anchor_before(next_line_start);
 3157                mode = SelectMode::Line(start..end);
 3158                auto_scroll = true;
 3159            }
 3160            _ => {
 3161                start = buffer.anchor_before(0);
 3162                end = buffer.anchor_before(buffer.len());
 3163                mode = SelectMode::All;
 3164                auto_scroll = false;
 3165            }
 3166        }
 3167        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3168
 3169        let point_to_delete: Option<usize> = {
 3170            let selected_points: Vec<Selection<Point>> =
 3171                self.selections.disjoint_in_range(start..end, cx);
 3172
 3173            if !add || click_count > 1 {
 3174                None
 3175            } else if !selected_points.is_empty() {
 3176                Some(selected_points[0].id)
 3177            } else {
 3178                let clicked_point_already_selected =
 3179                    self.selections.disjoint.iter().find(|selection| {
 3180                        selection.start.to_point(buffer) == start.to_point(buffer)
 3181                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3182                    });
 3183
 3184                clicked_point_already_selected.map(|selection| selection.id)
 3185            }
 3186        };
 3187
 3188        let selections_count = self.selections.count();
 3189
 3190        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3191            if let Some(point_to_delete) = point_to_delete {
 3192                s.delete(point_to_delete);
 3193
 3194                if selections_count == 1 {
 3195                    s.set_pending_anchor_range(start..end, mode);
 3196                }
 3197            } else {
 3198                if !add {
 3199                    s.clear_disjoint();
 3200                }
 3201
 3202                s.set_pending_anchor_range(start..end, mode);
 3203            }
 3204        });
 3205    }
 3206
 3207    fn begin_columnar_selection(
 3208        &mut self,
 3209        position: DisplayPoint,
 3210        goal_column: u32,
 3211        reset: bool,
 3212        window: &mut Window,
 3213        cx: &mut Context<Self>,
 3214    ) {
 3215        if !self.focus_handle.is_focused(window) {
 3216            self.last_focused_descendant = None;
 3217            window.focus(&self.focus_handle);
 3218        }
 3219
 3220        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3221
 3222        if reset {
 3223            let pointer_position = display_map
 3224                .buffer_snapshot
 3225                .anchor_before(position.to_point(&display_map));
 3226
 3227            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3228                s.clear_disjoint();
 3229                s.set_pending_anchor_range(
 3230                    pointer_position..pointer_position,
 3231                    SelectMode::Character,
 3232                );
 3233            });
 3234        }
 3235
 3236        let tail = self.selections.newest::<Point>(cx).tail();
 3237        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3238
 3239        if !reset {
 3240            self.select_columns(
 3241                tail.to_display_point(&display_map),
 3242                position,
 3243                goal_column,
 3244                &display_map,
 3245                window,
 3246                cx,
 3247            );
 3248        }
 3249    }
 3250
 3251    fn update_selection(
 3252        &mut self,
 3253        position: DisplayPoint,
 3254        goal_column: u32,
 3255        scroll_delta: gpui::Point<f32>,
 3256        window: &mut Window,
 3257        cx: &mut Context<Self>,
 3258    ) {
 3259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3260
 3261        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3262            let tail = tail.to_display_point(&display_map);
 3263            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3264        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3265            let buffer = self.buffer.read(cx).snapshot(cx);
 3266            let head;
 3267            let tail;
 3268            let mode = self.selections.pending_mode().unwrap();
 3269            match &mode {
 3270                SelectMode::Character => {
 3271                    head = position.to_point(&display_map);
 3272                    tail = pending.tail().to_point(&buffer);
 3273                }
 3274                SelectMode::Word(original_range) => {
 3275                    let original_display_range = original_range.start.to_display_point(&display_map)
 3276                        ..original_range.end.to_display_point(&display_map);
 3277                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3278                        ..original_display_range.end.to_point(&display_map);
 3279                    if movement::is_inside_word(&display_map, position)
 3280                        || original_display_range.contains(&position)
 3281                    {
 3282                        let word_range = movement::surrounding_word(&display_map, position);
 3283                        if word_range.start < original_display_range.start {
 3284                            head = word_range.start.to_point(&display_map);
 3285                        } else {
 3286                            head = word_range.end.to_point(&display_map);
 3287                        }
 3288                    } else {
 3289                        head = position.to_point(&display_map);
 3290                    }
 3291
 3292                    if head <= original_buffer_range.start {
 3293                        tail = original_buffer_range.end;
 3294                    } else {
 3295                        tail = original_buffer_range.start;
 3296                    }
 3297                }
 3298                SelectMode::Line(original_range) => {
 3299                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3300
 3301                    let position = display_map
 3302                        .clip_point(position, Bias::Left)
 3303                        .to_point(&display_map);
 3304                    let line_start = display_map.prev_line_boundary(position).0;
 3305                    let next_line_start = buffer.clip_point(
 3306                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3307                        Bias::Left,
 3308                    );
 3309
 3310                    if line_start < original_range.start {
 3311                        head = line_start
 3312                    } else {
 3313                        head = next_line_start
 3314                    }
 3315
 3316                    if head <= original_range.start {
 3317                        tail = original_range.end;
 3318                    } else {
 3319                        tail = original_range.start;
 3320                    }
 3321                }
 3322                SelectMode::All => {
 3323                    return;
 3324                }
 3325            };
 3326
 3327            if head < tail {
 3328                pending.start = buffer.anchor_before(head);
 3329                pending.end = buffer.anchor_before(tail);
 3330                pending.reversed = true;
 3331            } else {
 3332                pending.start = buffer.anchor_before(tail);
 3333                pending.end = buffer.anchor_before(head);
 3334                pending.reversed = false;
 3335            }
 3336
 3337            self.change_selections(None, window, cx, |s| {
 3338                s.set_pending(pending, mode);
 3339            });
 3340        } else {
 3341            log::error!("update_selection dispatched with no pending selection");
 3342            return;
 3343        }
 3344
 3345        self.apply_scroll_delta(scroll_delta, window, cx);
 3346        cx.notify();
 3347    }
 3348
 3349    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3350        self.columnar_selection_tail.take();
 3351        if self.selections.pending_anchor().is_some() {
 3352            let selections = self.selections.all::<usize>(cx);
 3353            self.change_selections(None, window, cx, |s| {
 3354                s.select(selections);
 3355                s.clear_pending();
 3356            });
 3357        }
 3358    }
 3359
 3360    fn select_columns(
 3361        &mut self,
 3362        tail: DisplayPoint,
 3363        head: DisplayPoint,
 3364        goal_column: u32,
 3365        display_map: &DisplaySnapshot,
 3366        window: &mut Window,
 3367        cx: &mut Context<Self>,
 3368    ) {
 3369        let start_row = cmp::min(tail.row(), head.row());
 3370        let end_row = cmp::max(tail.row(), head.row());
 3371        let start_column = cmp::min(tail.column(), goal_column);
 3372        let end_column = cmp::max(tail.column(), goal_column);
 3373        let reversed = start_column < tail.column();
 3374
 3375        let selection_ranges = (start_row.0..=end_row.0)
 3376            .map(DisplayRow)
 3377            .filter_map(|row| {
 3378                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3379                    let start = display_map
 3380                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3381                        .to_point(display_map);
 3382                    let end = display_map
 3383                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3384                        .to_point(display_map);
 3385                    if reversed {
 3386                        Some(end..start)
 3387                    } else {
 3388                        Some(start..end)
 3389                    }
 3390                } else {
 3391                    None
 3392                }
 3393            })
 3394            .collect::<Vec<_>>();
 3395
 3396        self.change_selections(None, window, cx, |s| {
 3397            s.select_ranges(selection_ranges);
 3398        });
 3399        cx.notify();
 3400    }
 3401
 3402    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3403        self.selections
 3404            .all_adjusted(cx)
 3405            .iter()
 3406            .any(|selection| !selection.is_empty())
 3407    }
 3408
 3409    pub fn has_pending_nonempty_selection(&self) -> bool {
 3410        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3411            Some(Selection { start, end, .. }) => start != end,
 3412            None => false,
 3413        };
 3414
 3415        pending_nonempty_selection
 3416            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3417    }
 3418
 3419    pub fn has_pending_selection(&self) -> bool {
 3420        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3421    }
 3422
 3423    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3424        self.selection_mark_mode = false;
 3425
 3426        if self.clear_expanded_diff_hunks(cx) {
 3427            cx.notify();
 3428            return;
 3429        }
 3430        if self.dismiss_menus_and_popups(true, window, cx) {
 3431            return;
 3432        }
 3433
 3434        if self.mode.is_full()
 3435            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3436        {
 3437            return;
 3438        }
 3439
 3440        cx.propagate();
 3441    }
 3442
 3443    pub fn dismiss_menus_and_popups(
 3444        &mut self,
 3445        is_user_requested: bool,
 3446        window: &mut Window,
 3447        cx: &mut Context<Self>,
 3448    ) -> bool {
 3449        if self.take_rename(false, window, cx).is_some() {
 3450            return true;
 3451        }
 3452
 3453        if hide_hover(self, cx) {
 3454            return true;
 3455        }
 3456
 3457        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3458            return true;
 3459        }
 3460
 3461        if self.hide_context_menu(window, cx).is_some() {
 3462            return true;
 3463        }
 3464
 3465        if self.mouse_context_menu.take().is_some() {
 3466            return true;
 3467        }
 3468
 3469        if is_user_requested && self.discard_inline_completion(true, cx) {
 3470            return true;
 3471        }
 3472
 3473        if self.snippet_stack.pop().is_some() {
 3474            return true;
 3475        }
 3476
 3477        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3478            self.dismiss_diagnostics(cx);
 3479            return true;
 3480        }
 3481
 3482        false
 3483    }
 3484
 3485    fn linked_editing_ranges_for(
 3486        &self,
 3487        selection: Range<text::Anchor>,
 3488        cx: &App,
 3489    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3490        if self.linked_edit_ranges.is_empty() {
 3491            return None;
 3492        }
 3493        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3494            selection.end.buffer_id.and_then(|end_buffer_id| {
 3495                if selection.start.buffer_id != Some(end_buffer_id) {
 3496                    return None;
 3497                }
 3498                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3499                let snapshot = buffer.read(cx).snapshot();
 3500                self.linked_edit_ranges
 3501                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3502                    .map(|ranges| (ranges, snapshot, buffer))
 3503            })?;
 3504        use text::ToOffset as TO;
 3505        // find offset from the start of current range to current cursor position
 3506        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3507
 3508        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3509        let start_difference = start_offset - start_byte_offset;
 3510        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3511        let end_difference = end_offset - start_byte_offset;
 3512        // Current range has associated linked ranges.
 3513        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3514        for range in linked_ranges.iter() {
 3515            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3516            let end_offset = start_offset + end_difference;
 3517            let start_offset = start_offset + start_difference;
 3518            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3519                continue;
 3520            }
 3521            if self.selections.disjoint_anchor_ranges().any(|s| {
 3522                if s.start.buffer_id != selection.start.buffer_id
 3523                    || s.end.buffer_id != selection.end.buffer_id
 3524                {
 3525                    return false;
 3526                }
 3527                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3528                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3529            }) {
 3530                continue;
 3531            }
 3532            let start = buffer_snapshot.anchor_after(start_offset);
 3533            let end = buffer_snapshot.anchor_after(end_offset);
 3534            linked_edits
 3535                .entry(buffer.clone())
 3536                .or_default()
 3537                .push(start..end);
 3538        }
 3539        Some(linked_edits)
 3540    }
 3541
 3542    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3543        let text: Arc<str> = text.into();
 3544
 3545        if self.read_only(cx) {
 3546            return;
 3547        }
 3548
 3549        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3550
 3551        let selections = self.selections.all_adjusted(cx);
 3552        let mut bracket_inserted = false;
 3553        let mut edits = Vec::new();
 3554        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3555        let mut new_selections = Vec::with_capacity(selections.len());
 3556        let mut new_autoclose_regions = Vec::new();
 3557        let snapshot = self.buffer.read(cx).read(cx);
 3558        let mut clear_linked_edit_ranges = false;
 3559
 3560        for (selection, autoclose_region) in
 3561            self.selections_with_autoclose_regions(selections, &snapshot)
 3562        {
 3563            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3564                // Determine if the inserted text matches the opening or closing
 3565                // bracket of any of this language's bracket pairs.
 3566                let mut bracket_pair = None;
 3567                let mut is_bracket_pair_start = false;
 3568                let mut is_bracket_pair_end = false;
 3569                if !text.is_empty() {
 3570                    let mut bracket_pair_matching_end = None;
 3571                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3572                    //  and they are removing the character that triggered IME popup.
 3573                    for (pair, enabled) in scope.brackets() {
 3574                        if !pair.close && !pair.surround {
 3575                            continue;
 3576                        }
 3577
 3578                        if enabled && pair.start.ends_with(text.as_ref()) {
 3579                            let prefix_len = pair.start.len() - text.len();
 3580                            let preceding_text_matches_prefix = prefix_len == 0
 3581                                || (selection.start.column >= (prefix_len as u32)
 3582                                    && snapshot.contains_str_at(
 3583                                        Point::new(
 3584                                            selection.start.row,
 3585                                            selection.start.column - (prefix_len as u32),
 3586                                        ),
 3587                                        &pair.start[..prefix_len],
 3588                                    ));
 3589                            if preceding_text_matches_prefix {
 3590                                bracket_pair = Some(pair.clone());
 3591                                is_bracket_pair_start = true;
 3592                                break;
 3593                            }
 3594                        }
 3595                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3596                        {
 3597                            // take first bracket pair matching end, but don't break in case a later bracket
 3598                            // pair matches start
 3599                            bracket_pair_matching_end = Some(pair.clone());
 3600                        }
 3601                    }
 3602                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3603                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3604                        is_bracket_pair_end = true;
 3605                    }
 3606                }
 3607
 3608                if let Some(bracket_pair) = bracket_pair {
 3609                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3610                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3611                    let auto_surround =
 3612                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3613                    if selection.is_empty() {
 3614                        if is_bracket_pair_start {
 3615                            // If the inserted text is a suffix of an opening bracket and the
 3616                            // selection is preceded by the rest of the opening bracket, then
 3617                            // insert the closing bracket.
 3618                            let following_text_allows_autoclose = snapshot
 3619                                .chars_at(selection.start)
 3620                                .next()
 3621                                .map_or(true, |c| scope.should_autoclose_before(c));
 3622
 3623                            let preceding_text_allows_autoclose = selection.start.column == 0
 3624                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3625                                    true,
 3626                                    |c| {
 3627                                        bracket_pair.start != bracket_pair.end
 3628                                            || !snapshot
 3629                                                .char_classifier_at(selection.start)
 3630                                                .is_word(c)
 3631                                    },
 3632                                );
 3633
 3634                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3635                                && bracket_pair.start.len() == 1
 3636                            {
 3637                                let target = bracket_pair.start.chars().next().unwrap();
 3638                                let current_line_count = snapshot
 3639                                    .reversed_chars_at(selection.start)
 3640                                    .take_while(|&c| c != '\n')
 3641                                    .filter(|&c| c == target)
 3642                                    .count();
 3643                                current_line_count % 2 == 1
 3644                            } else {
 3645                                false
 3646                            };
 3647
 3648                            if autoclose
 3649                                && bracket_pair.close
 3650                                && following_text_allows_autoclose
 3651                                && preceding_text_allows_autoclose
 3652                                && !is_closing_quote
 3653                            {
 3654                                let anchor = snapshot.anchor_before(selection.end);
 3655                                new_selections.push((selection.map(|_| anchor), text.len()));
 3656                                new_autoclose_regions.push((
 3657                                    anchor,
 3658                                    text.len(),
 3659                                    selection.id,
 3660                                    bracket_pair.clone(),
 3661                                ));
 3662                                edits.push((
 3663                                    selection.range(),
 3664                                    format!("{}{}", text, bracket_pair.end).into(),
 3665                                ));
 3666                                bracket_inserted = true;
 3667                                continue;
 3668                            }
 3669                        }
 3670
 3671                        if let Some(region) = autoclose_region {
 3672                            // If the selection is followed by an auto-inserted closing bracket,
 3673                            // then don't insert that closing bracket again; just move the selection
 3674                            // past the closing bracket.
 3675                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3676                                && text.as_ref() == region.pair.end.as_str();
 3677                            if should_skip {
 3678                                let anchor = snapshot.anchor_after(selection.end);
 3679                                new_selections
 3680                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3681                                continue;
 3682                            }
 3683                        }
 3684
 3685                        let always_treat_brackets_as_autoclosed = snapshot
 3686                            .language_settings_at(selection.start, cx)
 3687                            .always_treat_brackets_as_autoclosed;
 3688                        if always_treat_brackets_as_autoclosed
 3689                            && is_bracket_pair_end
 3690                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3691                        {
 3692                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3693                            // and the inserted text is a closing bracket and the selection is followed
 3694                            // by the closing bracket then move the selection past the closing bracket.
 3695                            let anchor = snapshot.anchor_after(selection.end);
 3696                            new_selections.push((selection.map(|_| anchor), text.len()));
 3697                            continue;
 3698                        }
 3699                    }
 3700                    // If an opening bracket is 1 character long and is typed while
 3701                    // text is selected, then surround that text with the bracket pair.
 3702                    else if auto_surround
 3703                        && bracket_pair.surround
 3704                        && is_bracket_pair_start
 3705                        && bracket_pair.start.chars().count() == 1
 3706                    {
 3707                        edits.push((selection.start..selection.start, text.clone()));
 3708                        edits.push((
 3709                            selection.end..selection.end,
 3710                            bracket_pair.end.as_str().into(),
 3711                        ));
 3712                        bracket_inserted = true;
 3713                        new_selections.push((
 3714                            Selection {
 3715                                id: selection.id,
 3716                                start: snapshot.anchor_after(selection.start),
 3717                                end: snapshot.anchor_before(selection.end),
 3718                                reversed: selection.reversed,
 3719                                goal: selection.goal,
 3720                            },
 3721                            0,
 3722                        ));
 3723                        continue;
 3724                    }
 3725                }
 3726            }
 3727
 3728            if self.auto_replace_emoji_shortcode
 3729                && selection.is_empty()
 3730                && text.as_ref().ends_with(':')
 3731            {
 3732                if let Some(possible_emoji_short_code) =
 3733                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3734                {
 3735                    if !possible_emoji_short_code.is_empty() {
 3736                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3737                            let emoji_shortcode_start = Point::new(
 3738                                selection.start.row,
 3739                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3740                            );
 3741
 3742                            // Remove shortcode from buffer
 3743                            edits.push((
 3744                                emoji_shortcode_start..selection.start,
 3745                                "".to_string().into(),
 3746                            ));
 3747                            new_selections.push((
 3748                                Selection {
 3749                                    id: selection.id,
 3750                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3751                                    end: snapshot.anchor_before(selection.start),
 3752                                    reversed: selection.reversed,
 3753                                    goal: selection.goal,
 3754                                },
 3755                                0,
 3756                            ));
 3757
 3758                            // Insert emoji
 3759                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3760                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3761                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3762
 3763                            continue;
 3764                        }
 3765                    }
 3766                }
 3767            }
 3768
 3769            // If not handling any auto-close operation, then just replace the selected
 3770            // text with the given input and move the selection to the end of the
 3771            // newly inserted text.
 3772            let anchor = snapshot.anchor_after(selection.end);
 3773            if !self.linked_edit_ranges.is_empty() {
 3774                let start_anchor = snapshot.anchor_before(selection.start);
 3775
 3776                let is_word_char = text.chars().next().map_or(true, |char| {
 3777                    let classifier = snapshot
 3778                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3779                        .ignore_punctuation(true);
 3780                    classifier.is_word(char)
 3781                });
 3782
 3783                if is_word_char {
 3784                    if let Some(ranges) = self
 3785                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3786                    {
 3787                        for (buffer, edits) in ranges {
 3788                            linked_edits
 3789                                .entry(buffer.clone())
 3790                                .or_default()
 3791                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3792                        }
 3793                    }
 3794                } else {
 3795                    clear_linked_edit_ranges = true;
 3796                }
 3797            }
 3798
 3799            new_selections.push((selection.map(|_| anchor), 0));
 3800            edits.push((selection.start..selection.end, text.clone()));
 3801        }
 3802
 3803        drop(snapshot);
 3804
 3805        self.transact(window, cx, |this, window, cx| {
 3806            if clear_linked_edit_ranges {
 3807                this.linked_edit_ranges.clear();
 3808            }
 3809            let initial_buffer_versions =
 3810                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3811
 3812            this.buffer.update(cx, |buffer, cx| {
 3813                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3814            });
 3815            for (buffer, edits) in linked_edits {
 3816                buffer.update(cx, |buffer, cx| {
 3817                    let snapshot = buffer.snapshot();
 3818                    let edits = edits
 3819                        .into_iter()
 3820                        .map(|(range, text)| {
 3821                            use text::ToPoint as TP;
 3822                            let end_point = TP::to_point(&range.end, &snapshot);
 3823                            let start_point = TP::to_point(&range.start, &snapshot);
 3824                            (start_point..end_point, text)
 3825                        })
 3826                        .sorted_by_key(|(range, _)| range.start);
 3827                    buffer.edit(edits, None, cx);
 3828                })
 3829            }
 3830            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3831            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3832            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3833            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3834                .zip(new_selection_deltas)
 3835                .map(|(selection, delta)| Selection {
 3836                    id: selection.id,
 3837                    start: selection.start + delta,
 3838                    end: selection.end + delta,
 3839                    reversed: selection.reversed,
 3840                    goal: SelectionGoal::None,
 3841                })
 3842                .collect::<Vec<_>>();
 3843
 3844            let mut i = 0;
 3845            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3846                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3847                let start = map.buffer_snapshot.anchor_before(position);
 3848                let end = map.buffer_snapshot.anchor_after(position);
 3849                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3850                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3851                        Ordering::Less => i += 1,
 3852                        Ordering::Greater => break,
 3853                        Ordering::Equal => {
 3854                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3855                                Ordering::Less => i += 1,
 3856                                Ordering::Equal => break,
 3857                                Ordering::Greater => break,
 3858                            }
 3859                        }
 3860                    }
 3861                }
 3862                this.autoclose_regions.insert(
 3863                    i,
 3864                    AutocloseRegion {
 3865                        selection_id,
 3866                        range: start..end,
 3867                        pair,
 3868                    },
 3869                );
 3870            }
 3871
 3872            let had_active_inline_completion = this.has_active_inline_completion();
 3873            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3874                s.select(new_selections)
 3875            });
 3876
 3877            if !bracket_inserted {
 3878                if let Some(on_type_format_task) =
 3879                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3880                {
 3881                    on_type_format_task.detach_and_log_err(cx);
 3882                }
 3883            }
 3884
 3885            let editor_settings = EditorSettings::get_global(cx);
 3886            if bracket_inserted
 3887                && (editor_settings.auto_signature_help
 3888                    || editor_settings.show_signature_help_after_edits)
 3889            {
 3890                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3891            }
 3892
 3893            let trigger_in_words =
 3894                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3895            if this.hard_wrap.is_some() {
 3896                let latest: Range<Point> = this.selections.newest(cx).range();
 3897                if latest.is_empty()
 3898                    && this
 3899                        .buffer()
 3900                        .read(cx)
 3901                        .snapshot(cx)
 3902                        .line_len(MultiBufferRow(latest.start.row))
 3903                        == latest.start.column
 3904                {
 3905                    this.rewrap_impl(
 3906                        RewrapOptions {
 3907                            override_language_settings: true,
 3908                            preserve_existing_whitespace: true,
 3909                        },
 3910                        cx,
 3911                    )
 3912                }
 3913            }
 3914            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3915            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3916            this.refresh_inline_completion(true, false, window, cx);
 3917            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3918        });
 3919    }
 3920
 3921    fn find_possible_emoji_shortcode_at_position(
 3922        snapshot: &MultiBufferSnapshot,
 3923        position: Point,
 3924    ) -> Option<String> {
 3925        let mut chars = Vec::new();
 3926        let mut found_colon = false;
 3927        for char in snapshot.reversed_chars_at(position).take(100) {
 3928            // Found a possible emoji shortcode in the middle of the buffer
 3929            if found_colon {
 3930                if char.is_whitespace() {
 3931                    chars.reverse();
 3932                    return Some(chars.iter().collect());
 3933                }
 3934                // If the previous character is not a whitespace, we are in the middle of a word
 3935                // and we only want to complete the shortcode if the word is made up of other emojis
 3936                let mut containing_word = String::new();
 3937                for ch in snapshot
 3938                    .reversed_chars_at(position)
 3939                    .skip(chars.len() + 1)
 3940                    .take(100)
 3941                {
 3942                    if ch.is_whitespace() {
 3943                        break;
 3944                    }
 3945                    containing_word.push(ch);
 3946                }
 3947                let containing_word = containing_word.chars().rev().collect::<String>();
 3948                if util::word_consists_of_emojis(containing_word.as_str()) {
 3949                    chars.reverse();
 3950                    return Some(chars.iter().collect());
 3951                }
 3952            }
 3953
 3954            if char.is_whitespace() || !char.is_ascii() {
 3955                return None;
 3956            }
 3957            if char == ':' {
 3958                found_colon = true;
 3959            } else {
 3960                chars.push(char);
 3961            }
 3962        }
 3963        // Found a possible emoji shortcode at the beginning of the buffer
 3964        chars.reverse();
 3965        Some(chars.iter().collect())
 3966    }
 3967
 3968    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3969        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3970        self.transact(window, cx, |this, window, cx| {
 3971            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3972                let selections = this.selections.all::<usize>(cx);
 3973                let multi_buffer = this.buffer.read(cx);
 3974                let buffer = multi_buffer.snapshot(cx);
 3975                selections
 3976                    .iter()
 3977                    .map(|selection| {
 3978                        let start_point = selection.start.to_point(&buffer);
 3979                        let mut existing_indent =
 3980                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3981                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3982                        let start = selection.start;
 3983                        let end = selection.end;
 3984                        let selection_is_empty = start == end;
 3985                        let language_scope = buffer.language_scope_at(start);
 3986                        let (
 3987                            comment_delimiter,
 3988                            doc_delimiter,
 3989                            insert_extra_newline,
 3990                            indent_on_newline,
 3991                            indent_on_extra_newline,
 3992                        ) = if let Some(language) = &language_scope {
 3993                            let mut insert_extra_newline =
 3994                                insert_extra_newline_brackets(&buffer, start..end, language)
 3995                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3996
 3997                            // Comment extension on newline is allowed only for cursor selections
 3998                            let comment_delimiter = maybe!({
 3999                                if !selection_is_empty {
 4000                                    return None;
 4001                                }
 4002
 4003                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4004                                    return None;
 4005                                }
 4006
 4007                                let delimiters = language.line_comment_prefixes();
 4008                                let max_len_of_delimiter =
 4009                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4010                                let (snapshot, range) =
 4011                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4012
 4013                                let num_of_whitespaces = snapshot
 4014                                    .chars_for_range(range.clone())
 4015                                    .take_while(|c| c.is_whitespace())
 4016                                    .count();
 4017                                let comment_candidate = snapshot
 4018                                    .chars_for_range(range)
 4019                                    .skip(num_of_whitespaces)
 4020                                    .take(max_len_of_delimiter)
 4021                                    .collect::<String>();
 4022                                let (delimiter, trimmed_len) = delimiters
 4023                                    .iter()
 4024                                    .filter_map(|delimiter| {
 4025                                        let prefix = delimiter.trim_end();
 4026                                        if comment_candidate.starts_with(prefix) {
 4027                                            Some((delimiter, prefix.len()))
 4028                                        } else {
 4029                                            None
 4030                                        }
 4031                                    })
 4032                                    .max_by_key(|(_, len)| *len)?;
 4033
 4034                                let cursor_is_placed_after_comment_marker =
 4035                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4036                                if cursor_is_placed_after_comment_marker {
 4037                                    Some(delimiter.clone())
 4038                                } else {
 4039                                    None
 4040                                }
 4041                            });
 4042
 4043                            let mut indent_on_newline = IndentSize::spaces(0);
 4044                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4045
 4046                            let doc_delimiter = maybe!({
 4047                                if !selection_is_empty {
 4048                                    return None;
 4049                                }
 4050
 4051                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4052                                    return None;
 4053                                }
 4054
 4055                                let DocumentationConfig {
 4056                                    start: start_tag,
 4057                                    end: end_tag,
 4058                                    prefix: delimiter,
 4059                                    tab_size: len,
 4060                                } = language.documentation()?;
 4061
 4062                                let is_within_block_comment = buffer
 4063                                    .language_scope_at(start_point)
 4064                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4065                                if !is_within_block_comment {
 4066                                    return None;
 4067                                }
 4068
 4069                                let (snapshot, range) =
 4070                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4071
 4072                                let num_of_whitespaces = snapshot
 4073                                    .chars_for_range(range.clone())
 4074                                    .take_while(|c| c.is_whitespace())
 4075                                    .count();
 4076
 4077                                // 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.
 4078                                let column = start_point.column;
 4079                                let cursor_is_after_start_tag = {
 4080                                    let start_tag_len = start_tag.len();
 4081                                    let start_tag_line = snapshot
 4082                                        .chars_for_range(range.clone())
 4083                                        .skip(num_of_whitespaces)
 4084                                        .take(start_tag_len)
 4085                                        .collect::<String>();
 4086                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4087                                        num_of_whitespaces + start_tag_len <= column as usize
 4088                                    } else {
 4089                                        false
 4090                                    }
 4091                                };
 4092
 4093                                let cursor_is_after_delimiter = {
 4094                                    let delimiter_trim = delimiter.trim_end();
 4095                                    let delimiter_line = snapshot
 4096                                        .chars_for_range(range.clone())
 4097                                        .skip(num_of_whitespaces)
 4098                                        .take(delimiter_trim.len())
 4099                                        .collect::<String>();
 4100                                    if delimiter_line.starts_with(delimiter_trim) {
 4101                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4102                                    } else {
 4103                                        false
 4104                                    }
 4105                                };
 4106
 4107                                let cursor_is_before_end_tag_if_exists = {
 4108                                    let mut char_position = 0u32;
 4109                                    let mut end_tag_offset = None;
 4110
 4111                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4112                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4113                                            let chars_before_match =
 4114                                                chunk[..byte_pos].chars().count() as u32;
 4115                                            end_tag_offset =
 4116                                                Some(char_position + chars_before_match);
 4117                                            break 'outer;
 4118                                        }
 4119                                        char_position += chunk.chars().count() as u32;
 4120                                    }
 4121
 4122                                    if let Some(end_tag_offset) = end_tag_offset {
 4123                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4124                                        if cursor_is_after_start_tag {
 4125                                            if cursor_is_before_end_tag {
 4126                                                insert_extra_newline = true;
 4127                                            }
 4128                                            let cursor_is_at_start_of_end_tag =
 4129                                                column == end_tag_offset;
 4130                                            if cursor_is_at_start_of_end_tag {
 4131                                                indent_on_extra_newline.len = (*len).into();
 4132                                            }
 4133                                        }
 4134                                        cursor_is_before_end_tag
 4135                                    } else {
 4136                                        true
 4137                                    }
 4138                                };
 4139
 4140                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4141                                    && cursor_is_before_end_tag_if_exists
 4142                                {
 4143                                    if cursor_is_after_start_tag {
 4144                                        indent_on_newline.len = (*len).into();
 4145                                    }
 4146                                    Some(delimiter.clone())
 4147                                } else {
 4148                                    None
 4149                                }
 4150                            });
 4151
 4152                            (
 4153                                comment_delimiter,
 4154                                doc_delimiter,
 4155                                insert_extra_newline,
 4156                                indent_on_newline,
 4157                                indent_on_extra_newline,
 4158                            )
 4159                        } else {
 4160                            (
 4161                                None,
 4162                                None,
 4163                                false,
 4164                                IndentSize::default(),
 4165                                IndentSize::default(),
 4166                            )
 4167                        };
 4168
 4169                        let prevent_auto_indent = doc_delimiter.is_some();
 4170                        let delimiter = comment_delimiter.or(doc_delimiter);
 4171
 4172                        let capacity_for_delimiter =
 4173                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4174                        let mut new_text = String::with_capacity(
 4175                            1 + capacity_for_delimiter
 4176                                + existing_indent.len as usize
 4177                                + indent_on_newline.len as usize
 4178                                + indent_on_extra_newline.len as usize,
 4179                        );
 4180                        new_text.push('\n');
 4181                        new_text.extend(existing_indent.chars());
 4182                        new_text.extend(indent_on_newline.chars());
 4183
 4184                        if let Some(delimiter) = &delimiter {
 4185                            new_text.push_str(delimiter);
 4186                        }
 4187
 4188                        if insert_extra_newline {
 4189                            new_text.push('\n');
 4190                            new_text.extend(existing_indent.chars());
 4191                            new_text.extend(indent_on_extra_newline.chars());
 4192                        }
 4193
 4194                        let anchor = buffer.anchor_after(end);
 4195                        let new_selection = selection.map(|_| anchor);
 4196                        (
 4197                            ((start..end, new_text), prevent_auto_indent),
 4198                            (insert_extra_newline, new_selection),
 4199                        )
 4200                    })
 4201                    .unzip()
 4202            };
 4203
 4204            let mut auto_indent_edits = Vec::new();
 4205            let mut edits = Vec::new();
 4206            for (edit, prevent_auto_indent) in edits_with_flags {
 4207                if prevent_auto_indent {
 4208                    edits.push(edit);
 4209                } else {
 4210                    auto_indent_edits.push(edit);
 4211                }
 4212            }
 4213            if !edits.is_empty() {
 4214                this.edit(edits, cx);
 4215            }
 4216            if !auto_indent_edits.is_empty() {
 4217                this.edit_with_autoindent(auto_indent_edits, cx);
 4218            }
 4219
 4220            let buffer = this.buffer.read(cx).snapshot(cx);
 4221            let new_selections = selection_info
 4222                .into_iter()
 4223                .map(|(extra_newline_inserted, new_selection)| {
 4224                    let mut cursor = new_selection.end.to_point(&buffer);
 4225                    if extra_newline_inserted {
 4226                        cursor.row -= 1;
 4227                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4228                    }
 4229                    new_selection.map(|_| cursor)
 4230                })
 4231                .collect();
 4232
 4233            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4234                s.select(new_selections)
 4235            });
 4236            this.refresh_inline_completion(true, false, window, cx);
 4237        });
 4238    }
 4239
 4240    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4241        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4242
 4243        let buffer = self.buffer.read(cx);
 4244        let snapshot = buffer.snapshot(cx);
 4245
 4246        let mut edits = Vec::new();
 4247        let mut rows = Vec::new();
 4248
 4249        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4250            let cursor = selection.head();
 4251            let row = cursor.row;
 4252
 4253            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4254
 4255            let newline = "\n".to_string();
 4256            edits.push((start_of_line..start_of_line, newline));
 4257
 4258            rows.push(row + rows_inserted as u32);
 4259        }
 4260
 4261        self.transact(window, cx, |editor, window, cx| {
 4262            editor.edit(edits, cx);
 4263
 4264            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4265                let mut index = 0;
 4266                s.move_cursors_with(|map, _, _| {
 4267                    let row = rows[index];
 4268                    index += 1;
 4269
 4270                    let point = Point::new(row, 0);
 4271                    let boundary = map.next_line_boundary(point).1;
 4272                    let clipped = map.clip_point(boundary, Bias::Left);
 4273
 4274                    (clipped, SelectionGoal::None)
 4275                });
 4276            });
 4277
 4278            let mut indent_edits = Vec::new();
 4279            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4280            for row in rows {
 4281                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4282                for (row, indent) in indents {
 4283                    if indent.len == 0 {
 4284                        continue;
 4285                    }
 4286
 4287                    let text = match indent.kind {
 4288                        IndentKind::Space => " ".repeat(indent.len as usize),
 4289                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4290                    };
 4291                    let point = Point::new(row.0, 0);
 4292                    indent_edits.push((point..point, text));
 4293                }
 4294            }
 4295            editor.edit(indent_edits, cx);
 4296        });
 4297    }
 4298
 4299    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4300        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4301
 4302        let buffer = self.buffer.read(cx);
 4303        let snapshot = buffer.snapshot(cx);
 4304
 4305        let mut edits = Vec::new();
 4306        let mut rows = Vec::new();
 4307        let mut rows_inserted = 0;
 4308
 4309        for selection in self.selections.all_adjusted(cx) {
 4310            let cursor = selection.head();
 4311            let row = cursor.row;
 4312
 4313            let point = Point::new(row + 1, 0);
 4314            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4315
 4316            let newline = "\n".to_string();
 4317            edits.push((start_of_line..start_of_line, newline));
 4318
 4319            rows_inserted += 1;
 4320            rows.push(row + rows_inserted);
 4321        }
 4322
 4323        self.transact(window, cx, |editor, window, cx| {
 4324            editor.edit(edits, cx);
 4325
 4326            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4327                let mut index = 0;
 4328                s.move_cursors_with(|map, _, _| {
 4329                    let row = rows[index];
 4330                    index += 1;
 4331
 4332                    let point = Point::new(row, 0);
 4333                    let boundary = map.next_line_boundary(point).1;
 4334                    let clipped = map.clip_point(boundary, Bias::Left);
 4335
 4336                    (clipped, SelectionGoal::None)
 4337                });
 4338            });
 4339
 4340            let mut indent_edits = Vec::new();
 4341            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4342            for row in rows {
 4343                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4344                for (row, indent) in indents {
 4345                    if indent.len == 0 {
 4346                        continue;
 4347                    }
 4348
 4349                    let text = match indent.kind {
 4350                        IndentKind::Space => " ".repeat(indent.len as usize),
 4351                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4352                    };
 4353                    let point = Point::new(row.0, 0);
 4354                    indent_edits.push((point..point, text));
 4355                }
 4356            }
 4357            editor.edit(indent_edits, cx);
 4358        });
 4359    }
 4360
 4361    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4362        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4363            original_indent_columns: Vec::new(),
 4364        });
 4365        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4366    }
 4367
 4368    fn insert_with_autoindent_mode(
 4369        &mut self,
 4370        text: &str,
 4371        autoindent_mode: Option<AutoindentMode>,
 4372        window: &mut Window,
 4373        cx: &mut Context<Self>,
 4374    ) {
 4375        if self.read_only(cx) {
 4376            return;
 4377        }
 4378
 4379        let text: Arc<str> = text.into();
 4380        self.transact(window, cx, |this, window, cx| {
 4381            let old_selections = this.selections.all_adjusted(cx);
 4382            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4383                let anchors = {
 4384                    let snapshot = buffer.read(cx);
 4385                    old_selections
 4386                        .iter()
 4387                        .map(|s| {
 4388                            let anchor = snapshot.anchor_after(s.head());
 4389                            s.map(|_| anchor)
 4390                        })
 4391                        .collect::<Vec<_>>()
 4392                };
 4393                buffer.edit(
 4394                    old_selections
 4395                        .iter()
 4396                        .map(|s| (s.start..s.end, text.clone())),
 4397                    autoindent_mode,
 4398                    cx,
 4399                );
 4400                anchors
 4401            });
 4402
 4403            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4404                s.select_anchors(selection_anchors);
 4405            });
 4406
 4407            cx.notify();
 4408        });
 4409    }
 4410
 4411    fn trigger_completion_on_input(
 4412        &mut self,
 4413        text: &str,
 4414        trigger_in_words: bool,
 4415        window: &mut Window,
 4416        cx: &mut Context<Self>,
 4417    ) {
 4418        let ignore_completion_provider = self
 4419            .context_menu
 4420            .borrow()
 4421            .as_ref()
 4422            .map(|menu| match menu {
 4423                CodeContextMenu::Completions(completions_menu) => {
 4424                    completions_menu.ignore_completion_provider
 4425                }
 4426                CodeContextMenu::CodeActions(_) => false,
 4427            })
 4428            .unwrap_or(false);
 4429
 4430        if ignore_completion_provider {
 4431            self.show_word_completions(&ShowWordCompletions, window, cx);
 4432        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4433            self.show_completions(
 4434                &ShowCompletions {
 4435                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4436                },
 4437                window,
 4438                cx,
 4439            );
 4440        } else {
 4441            self.hide_context_menu(window, cx);
 4442        }
 4443    }
 4444
 4445    fn is_completion_trigger(
 4446        &self,
 4447        text: &str,
 4448        trigger_in_words: bool,
 4449        cx: &mut Context<Self>,
 4450    ) -> bool {
 4451        let position = self.selections.newest_anchor().head();
 4452        let multibuffer = self.buffer.read(cx);
 4453        let Some(buffer) = position
 4454            .buffer_id
 4455            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4456        else {
 4457            return false;
 4458        };
 4459
 4460        if let Some(completion_provider) = &self.completion_provider {
 4461            completion_provider.is_completion_trigger(
 4462                &buffer,
 4463                position.text_anchor,
 4464                text,
 4465                trigger_in_words,
 4466                cx,
 4467            )
 4468        } else {
 4469            false
 4470        }
 4471    }
 4472
 4473    /// If any empty selections is touching the start of its innermost containing autoclose
 4474    /// region, expand it to select the brackets.
 4475    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4476        let selections = self.selections.all::<usize>(cx);
 4477        let buffer = self.buffer.read(cx).read(cx);
 4478        let new_selections = self
 4479            .selections_with_autoclose_regions(selections, &buffer)
 4480            .map(|(mut selection, region)| {
 4481                if !selection.is_empty() {
 4482                    return selection;
 4483                }
 4484
 4485                if let Some(region) = region {
 4486                    let mut range = region.range.to_offset(&buffer);
 4487                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4488                        range.start -= region.pair.start.len();
 4489                        if buffer.contains_str_at(range.start, &region.pair.start)
 4490                            && buffer.contains_str_at(range.end, &region.pair.end)
 4491                        {
 4492                            range.end += region.pair.end.len();
 4493                            selection.start = range.start;
 4494                            selection.end = range.end;
 4495
 4496                            return selection;
 4497                        }
 4498                    }
 4499                }
 4500
 4501                let always_treat_brackets_as_autoclosed = buffer
 4502                    .language_settings_at(selection.start, cx)
 4503                    .always_treat_brackets_as_autoclosed;
 4504
 4505                if !always_treat_brackets_as_autoclosed {
 4506                    return selection;
 4507                }
 4508
 4509                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4510                    for (pair, enabled) in scope.brackets() {
 4511                        if !enabled || !pair.close {
 4512                            continue;
 4513                        }
 4514
 4515                        if buffer.contains_str_at(selection.start, &pair.end) {
 4516                            let pair_start_len = pair.start.len();
 4517                            if buffer.contains_str_at(
 4518                                selection.start.saturating_sub(pair_start_len),
 4519                                &pair.start,
 4520                            ) {
 4521                                selection.start -= pair_start_len;
 4522                                selection.end += pair.end.len();
 4523
 4524                                return selection;
 4525                            }
 4526                        }
 4527                    }
 4528                }
 4529
 4530                selection
 4531            })
 4532            .collect();
 4533
 4534        drop(buffer);
 4535        self.change_selections(None, window, cx, |selections| {
 4536            selections.select(new_selections)
 4537        });
 4538    }
 4539
 4540    /// Iterate the given selections, and for each one, find the smallest surrounding
 4541    /// autoclose region. This uses the ordering of the selections and the autoclose
 4542    /// regions to avoid repeated comparisons.
 4543    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4544        &'a self,
 4545        selections: impl IntoIterator<Item = Selection<D>>,
 4546        buffer: &'a MultiBufferSnapshot,
 4547    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4548        let mut i = 0;
 4549        let mut regions = self.autoclose_regions.as_slice();
 4550        selections.into_iter().map(move |selection| {
 4551            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4552
 4553            let mut enclosing = None;
 4554            while let Some(pair_state) = regions.get(i) {
 4555                if pair_state.range.end.to_offset(buffer) < range.start {
 4556                    regions = &regions[i + 1..];
 4557                    i = 0;
 4558                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4559                    break;
 4560                } else {
 4561                    if pair_state.selection_id == selection.id {
 4562                        enclosing = Some(pair_state);
 4563                    }
 4564                    i += 1;
 4565                }
 4566            }
 4567
 4568            (selection, enclosing)
 4569        })
 4570    }
 4571
 4572    /// Remove any autoclose regions that no longer contain their selection.
 4573    fn invalidate_autoclose_regions(
 4574        &mut self,
 4575        mut selections: &[Selection<Anchor>],
 4576        buffer: &MultiBufferSnapshot,
 4577    ) {
 4578        self.autoclose_regions.retain(|state| {
 4579            let mut i = 0;
 4580            while let Some(selection) = selections.get(i) {
 4581                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4582                    selections = &selections[1..];
 4583                    continue;
 4584                }
 4585                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4586                    break;
 4587                }
 4588                if selection.id == state.selection_id {
 4589                    return true;
 4590                } else {
 4591                    i += 1;
 4592                }
 4593            }
 4594            false
 4595        });
 4596    }
 4597
 4598    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4599        let offset = position.to_offset(buffer);
 4600        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4601        if offset > word_range.start && kind == Some(CharKind::Word) {
 4602            Some(
 4603                buffer
 4604                    .text_for_range(word_range.start..offset)
 4605                    .collect::<String>(),
 4606            )
 4607        } else {
 4608            None
 4609        }
 4610    }
 4611
 4612    pub fn toggle_inline_values(
 4613        &mut self,
 4614        _: &ToggleInlineValues,
 4615        _: &mut Window,
 4616        cx: &mut Context<Self>,
 4617    ) {
 4618        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4619
 4620        self.refresh_inline_values(cx);
 4621    }
 4622
 4623    pub fn toggle_inlay_hints(
 4624        &mut self,
 4625        _: &ToggleInlayHints,
 4626        _: &mut Window,
 4627        cx: &mut Context<Self>,
 4628    ) {
 4629        self.refresh_inlay_hints(
 4630            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4631            cx,
 4632        );
 4633    }
 4634
 4635    pub fn inlay_hints_enabled(&self) -> bool {
 4636        self.inlay_hint_cache.enabled
 4637    }
 4638
 4639    pub fn inline_values_enabled(&self) -> bool {
 4640        self.inline_value_cache.enabled
 4641    }
 4642
 4643    #[cfg(any(test, feature = "test-support"))]
 4644    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4645        self.display_map
 4646            .read(cx)
 4647            .current_inlays()
 4648            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4649            .cloned()
 4650            .collect()
 4651    }
 4652
 4653    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4654        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4655            return;
 4656        }
 4657
 4658        let reason_description = reason.description();
 4659        let ignore_debounce = matches!(
 4660            reason,
 4661            InlayHintRefreshReason::SettingsChange(_)
 4662                | InlayHintRefreshReason::Toggle(_)
 4663                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4664                | InlayHintRefreshReason::ModifiersChanged(_)
 4665        );
 4666        let (invalidate_cache, required_languages) = match reason {
 4667            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4668                match self.inlay_hint_cache.modifiers_override(enabled) {
 4669                    Some(enabled) => {
 4670                        if enabled {
 4671                            (InvalidationStrategy::RefreshRequested, None)
 4672                        } else {
 4673                            self.splice_inlays(
 4674                                &self
 4675                                    .visible_inlay_hints(cx)
 4676                                    .iter()
 4677                                    .map(|inlay| inlay.id)
 4678                                    .collect::<Vec<InlayId>>(),
 4679                                Vec::new(),
 4680                                cx,
 4681                            );
 4682                            return;
 4683                        }
 4684                    }
 4685                    None => return,
 4686                }
 4687            }
 4688            InlayHintRefreshReason::Toggle(enabled) => {
 4689                if self.inlay_hint_cache.toggle(enabled) {
 4690                    if enabled {
 4691                        (InvalidationStrategy::RefreshRequested, None)
 4692                    } else {
 4693                        self.splice_inlays(
 4694                            &self
 4695                                .visible_inlay_hints(cx)
 4696                                .iter()
 4697                                .map(|inlay| inlay.id)
 4698                                .collect::<Vec<InlayId>>(),
 4699                            Vec::new(),
 4700                            cx,
 4701                        );
 4702                        return;
 4703                    }
 4704                } else {
 4705                    return;
 4706                }
 4707            }
 4708            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4709                match self.inlay_hint_cache.update_settings(
 4710                    &self.buffer,
 4711                    new_settings,
 4712                    self.visible_inlay_hints(cx),
 4713                    cx,
 4714                ) {
 4715                    ControlFlow::Break(Some(InlaySplice {
 4716                        to_remove,
 4717                        to_insert,
 4718                    })) => {
 4719                        self.splice_inlays(&to_remove, to_insert, cx);
 4720                        return;
 4721                    }
 4722                    ControlFlow::Break(None) => return,
 4723                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4724                }
 4725            }
 4726            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4727                if let Some(InlaySplice {
 4728                    to_remove,
 4729                    to_insert,
 4730                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4731                {
 4732                    self.splice_inlays(&to_remove, to_insert, cx);
 4733                }
 4734                self.display_map.update(cx, |display_map, _| {
 4735                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4736                });
 4737                return;
 4738            }
 4739            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4740            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4741                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4742            }
 4743            InlayHintRefreshReason::RefreshRequested => {
 4744                (InvalidationStrategy::RefreshRequested, None)
 4745            }
 4746        };
 4747
 4748        if let Some(InlaySplice {
 4749            to_remove,
 4750            to_insert,
 4751        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4752            reason_description,
 4753            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4754            invalidate_cache,
 4755            ignore_debounce,
 4756            cx,
 4757        ) {
 4758            self.splice_inlays(&to_remove, to_insert, cx);
 4759        }
 4760    }
 4761
 4762    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4763        self.display_map
 4764            .read(cx)
 4765            .current_inlays()
 4766            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4767            .cloned()
 4768            .collect()
 4769    }
 4770
 4771    pub fn excerpts_for_inlay_hints_query(
 4772        &self,
 4773        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4774        cx: &mut Context<Editor>,
 4775    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4776        let Some(project) = self.project.as_ref() else {
 4777            return HashMap::default();
 4778        };
 4779        let project = project.read(cx);
 4780        let multi_buffer = self.buffer().read(cx);
 4781        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4782        let multi_buffer_visible_start = self
 4783            .scroll_manager
 4784            .anchor()
 4785            .anchor
 4786            .to_point(&multi_buffer_snapshot);
 4787        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4788            multi_buffer_visible_start
 4789                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4790            Bias::Left,
 4791        );
 4792        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4793        multi_buffer_snapshot
 4794            .range_to_buffer_ranges(multi_buffer_visible_range)
 4795            .into_iter()
 4796            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4797            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4798                let buffer_file = project::File::from_dyn(buffer.file())?;
 4799                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4800                let worktree_entry = buffer_worktree
 4801                    .read(cx)
 4802                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4803                if worktree_entry.is_ignored {
 4804                    return None;
 4805                }
 4806
 4807                let language = buffer.language()?;
 4808                if let Some(restrict_to_languages) = restrict_to_languages {
 4809                    if !restrict_to_languages.contains(language) {
 4810                        return None;
 4811                    }
 4812                }
 4813                Some((
 4814                    excerpt_id,
 4815                    (
 4816                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4817                        buffer.version().clone(),
 4818                        excerpt_visible_range,
 4819                    ),
 4820                ))
 4821            })
 4822            .collect()
 4823    }
 4824
 4825    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4826        TextLayoutDetails {
 4827            text_system: window.text_system().clone(),
 4828            editor_style: self.style.clone().unwrap(),
 4829            rem_size: window.rem_size(),
 4830            scroll_anchor: self.scroll_manager.anchor(),
 4831            visible_rows: self.visible_line_count(),
 4832            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4833        }
 4834    }
 4835
 4836    pub fn splice_inlays(
 4837        &self,
 4838        to_remove: &[InlayId],
 4839        to_insert: Vec<Inlay>,
 4840        cx: &mut Context<Self>,
 4841    ) {
 4842        self.display_map.update(cx, |display_map, cx| {
 4843            display_map.splice_inlays(to_remove, to_insert, cx)
 4844        });
 4845        cx.notify();
 4846    }
 4847
 4848    fn trigger_on_type_formatting(
 4849        &self,
 4850        input: String,
 4851        window: &mut Window,
 4852        cx: &mut Context<Self>,
 4853    ) -> Option<Task<Result<()>>> {
 4854        if input.len() != 1 {
 4855            return None;
 4856        }
 4857
 4858        let project = self.project.as_ref()?;
 4859        let position = self.selections.newest_anchor().head();
 4860        let (buffer, buffer_position) = self
 4861            .buffer
 4862            .read(cx)
 4863            .text_anchor_for_position(position, cx)?;
 4864
 4865        let settings = language_settings::language_settings(
 4866            buffer
 4867                .read(cx)
 4868                .language_at(buffer_position)
 4869                .map(|l| l.name()),
 4870            buffer.read(cx).file(),
 4871            cx,
 4872        );
 4873        if !settings.use_on_type_format {
 4874            return None;
 4875        }
 4876
 4877        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4878        // hence we do LSP request & edit on host side only — add formats to host's history.
 4879        let push_to_lsp_host_history = true;
 4880        // If this is not the host, append its history with new edits.
 4881        let push_to_client_history = project.read(cx).is_via_collab();
 4882
 4883        let on_type_formatting = project.update(cx, |project, cx| {
 4884            project.on_type_format(
 4885                buffer.clone(),
 4886                buffer_position,
 4887                input,
 4888                push_to_lsp_host_history,
 4889                cx,
 4890            )
 4891        });
 4892        Some(cx.spawn_in(window, async move |editor, cx| {
 4893            if let Some(transaction) = on_type_formatting.await? {
 4894                if push_to_client_history {
 4895                    buffer
 4896                        .update(cx, |buffer, _| {
 4897                            buffer.push_transaction(transaction, Instant::now());
 4898                            buffer.finalize_last_transaction();
 4899                        })
 4900                        .ok();
 4901                }
 4902                editor.update(cx, |editor, cx| {
 4903                    editor.refresh_document_highlights(cx);
 4904                })?;
 4905            }
 4906            Ok(())
 4907        }))
 4908    }
 4909
 4910    pub fn show_word_completions(
 4911        &mut self,
 4912        _: &ShowWordCompletions,
 4913        window: &mut Window,
 4914        cx: &mut Context<Self>,
 4915    ) {
 4916        self.open_completions_menu(true, None, window, cx);
 4917    }
 4918
 4919    pub fn show_completions(
 4920        &mut self,
 4921        options: &ShowCompletions,
 4922        window: &mut Window,
 4923        cx: &mut Context<Self>,
 4924    ) {
 4925        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4926    }
 4927
 4928    fn open_completions_menu(
 4929        &mut self,
 4930        ignore_completion_provider: bool,
 4931        trigger: Option<&str>,
 4932        window: &mut Window,
 4933        cx: &mut Context<Self>,
 4934    ) {
 4935        if self.pending_rename.is_some() {
 4936            return;
 4937        }
 4938        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4939            return;
 4940        }
 4941
 4942        let position = self.selections.newest_anchor().head();
 4943        if position.diff_base_anchor.is_some() {
 4944            return;
 4945        }
 4946        let (buffer, buffer_position) =
 4947            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4948                output
 4949            } else {
 4950                return;
 4951            };
 4952        let buffer_snapshot = buffer.read(cx).snapshot();
 4953        let show_completion_documentation = buffer_snapshot
 4954            .settings_at(buffer_position, cx)
 4955            .show_completion_documentation;
 4956
 4957        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4958
 4959        let trigger_kind = match trigger {
 4960            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4961                CompletionTriggerKind::TRIGGER_CHARACTER
 4962            }
 4963            _ => CompletionTriggerKind::INVOKED,
 4964        };
 4965        let completion_context = CompletionContext {
 4966            trigger_character: trigger.and_then(|trigger| {
 4967                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4968                    Some(String::from(trigger))
 4969                } else {
 4970                    None
 4971                }
 4972            }),
 4973            trigger_kind,
 4974        };
 4975
 4976        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4977        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4978            let word_to_exclude = buffer_snapshot
 4979                .text_for_range(old_range.clone())
 4980                .collect::<String>();
 4981            (
 4982                buffer_snapshot.anchor_before(old_range.start)
 4983                    ..buffer_snapshot.anchor_after(old_range.end),
 4984                Some(word_to_exclude),
 4985            )
 4986        } else {
 4987            (buffer_position..buffer_position, None)
 4988        };
 4989
 4990        let completion_settings = language_settings(
 4991            buffer_snapshot
 4992                .language_at(buffer_position)
 4993                .map(|language| language.name()),
 4994            buffer_snapshot.file(),
 4995            cx,
 4996        )
 4997        .completions;
 4998
 4999        // The document can be large, so stay in reasonable bounds when searching for words,
 5000        // otherwise completion pop-up might be slow to appear.
 5001        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5002        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5003        let min_word_search = buffer_snapshot.clip_point(
 5004            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5005            Bias::Left,
 5006        );
 5007        let max_word_search = buffer_snapshot.clip_point(
 5008            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5009            Bias::Right,
 5010        );
 5011        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5012            ..buffer_snapshot.point_to_offset(max_word_search);
 5013
 5014        let provider = if ignore_completion_provider {
 5015            None
 5016        } else {
 5017            self.completion_provider.clone()
 5018        };
 5019        let skip_digits = query
 5020            .as_ref()
 5021            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5022
 5023        let (mut words, provided_completions) = match &provider {
 5024            Some(provider) => {
 5025                let completions = provider.completions(
 5026                    position.excerpt_id,
 5027                    &buffer,
 5028                    buffer_position,
 5029                    completion_context,
 5030                    window,
 5031                    cx,
 5032                );
 5033
 5034                let words = match completion_settings.words {
 5035                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5036                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5037                        .background_spawn(async move {
 5038                            buffer_snapshot.words_in_range(WordsQuery {
 5039                                fuzzy_contents: None,
 5040                                range: word_search_range,
 5041                                skip_digits,
 5042                            })
 5043                        }),
 5044                };
 5045
 5046                (words, completions)
 5047            }
 5048            None => (
 5049                cx.background_spawn(async move {
 5050                    buffer_snapshot.words_in_range(WordsQuery {
 5051                        fuzzy_contents: None,
 5052                        range: word_search_range,
 5053                        skip_digits,
 5054                    })
 5055                }),
 5056                Task::ready(Ok(None)),
 5057            ),
 5058        };
 5059
 5060        let sort_completions = provider
 5061            .as_ref()
 5062            .map_or(false, |provider| provider.sort_completions());
 5063
 5064        let filter_completions = provider
 5065            .as_ref()
 5066            .map_or(true, |provider| provider.filter_completions());
 5067
 5068        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5069
 5070        let id = post_inc(&mut self.next_completion_id);
 5071        let task = cx.spawn_in(window, async move |editor, cx| {
 5072            async move {
 5073                editor.update(cx, |this, _| {
 5074                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5075                })?;
 5076
 5077                let mut completions = Vec::new();
 5078                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5079                    completions.extend(provided_completions);
 5080                    if completion_settings.words == WordsCompletionMode::Fallback {
 5081                        words = Task::ready(BTreeMap::default());
 5082                    }
 5083                }
 5084
 5085                let mut words = words.await;
 5086                if let Some(word_to_exclude) = &word_to_exclude {
 5087                    words.remove(word_to_exclude);
 5088                }
 5089                for lsp_completion in &completions {
 5090                    words.remove(&lsp_completion.new_text);
 5091                }
 5092                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5093                    replace_range: old_range.clone(),
 5094                    new_text: word.clone(),
 5095                    label: CodeLabel::plain(word, None),
 5096                    icon_path: None,
 5097                    documentation: None,
 5098                    source: CompletionSource::BufferWord {
 5099                        word_range,
 5100                        resolved: false,
 5101                    },
 5102                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5103                    confirm: None,
 5104                }));
 5105
 5106                let menu = if completions.is_empty() {
 5107                    None
 5108                } else {
 5109                    let mut menu = CompletionsMenu::new(
 5110                        id,
 5111                        sort_completions,
 5112                        show_completion_documentation,
 5113                        ignore_completion_provider,
 5114                        position,
 5115                        buffer.clone(),
 5116                        completions.into(),
 5117                        snippet_sort_order,
 5118                    );
 5119
 5120                    menu.filter(
 5121                        if filter_completions {
 5122                            query.as_deref()
 5123                        } else {
 5124                            None
 5125                        },
 5126                        provider,
 5127                        editor.clone(),
 5128                        cx,
 5129                    )
 5130                    .await;
 5131
 5132                    menu.visible().then_some(menu)
 5133                };
 5134
 5135                editor.update_in(cx, |editor, window, cx| {
 5136                    match editor.context_menu.borrow().as_ref() {
 5137                        None => {}
 5138                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5139                            if prev_menu.id > id {
 5140                                return;
 5141                            }
 5142                        }
 5143                        _ => return,
 5144                    }
 5145
 5146                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5147                        let mut menu = menu.unwrap();
 5148                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5149                        crate::hover_popover::hide_hover(editor, cx);
 5150                        *editor.context_menu.borrow_mut() =
 5151                            Some(CodeContextMenu::Completions(menu));
 5152
 5153                        if editor.show_edit_predictions_in_menu() {
 5154                            editor.update_visible_inline_completion(window, cx);
 5155                        } else {
 5156                            editor.discard_inline_completion(false, cx);
 5157                        }
 5158
 5159                        cx.notify();
 5160                    } else if editor.completion_tasks.len() <= 1 {
 5161                        // If there are no more completion tasks and the last menu was
 5162                        // empty, we should hide it.
 5163                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5164                        // If it was already hidden and we don't show inline
 5165                        // completions in the menu, we should also show the
 5166                        // inline-completion when available.
 5167                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5168                            editor.update_visible_inline_completion(window, cx);
 5169                        }
 5170                    }
 5171                })?;
 5172
 5173                anyhow::Ok(())
 5174            }
 5175            .log_err()
 5176            .await
 5177        });
 5178
 5179        self.completion_tasks.push((id, task));
 5180    }
 5181
 5182    #[cfg(feature = "test-support")]
 5183    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5184        let menu = self.context_menu.borrow();
 5185        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5186            let completions = menu.completions.borrow();
 5187            Some(completions.to_vec())
 5188        } else {
 5189            None
 5190        }
 5191    }
 5192
 5193    pub fn confirm_completion(
 5194        &mut self,
 5195        action: &ConfirmCompletion,
 5196        window: &mut Window,
 5197        cx: &mut Context<Self>,
 5198    ) -> Option<Task<Result<()>>> {
 5199        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5200        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5201    }
 5202
 5203    pub fn confirm_completion_insert(
 5204        &mut self,
 5205        _: &ConfirmCompletionInsert,
 5206        window: &mut Window,
 5207        cx: &mut Context<Self>,
 5208    ) -> Option<Task<Result<()>>> {
 5209        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5210        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5211    }
 5212
 5213    pub fn confirm_completion_replace(
 5214        &mut self,
 5215        _: &ConfirmCompletionReplace,
 5216        window: &mut Window,
 5217        cx: &mut Context<Self>,
 5218    ) -> Option<Task<Result<()>>> {
 5219        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5220        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5221    }
 5222
 5223    pub fn compose_completion(
 5224        &mut self,
 5225        action: &ComposeCompletion,
 5226        window: &mut Window,
 5227        cx: &mut Context<Self>,
 5228    ) -> Option<Task<Result<()>>> {
 5229        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5230        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5231    }
 5232
 5233    fn do_completion(
 5234        &mut self,
 5235        item_ix: Option<usize>,
 5236        intent: CompletionIntent,
 5237        window: &mut Window,
 5238        cx: &mut Context<Editor>,
 5239    ) -> Option<Task<Result<()>>> {
 5240        use language::ToOffset as _;
 5241
 5242        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5243        else {
 5244            return None;
 5245        };
 5246
 5247        let candidate_id = {
 5248            let entries = completions_menu.entries.borrow();
 5249            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5250            if self.show_edit_predictions_in_menu() {
 5251                self.discard_inline_completion(true, cx);
 5252            }
 5253            mat.candidate_id
 5254        };
 5255
 5256        let buffer_handle = completions_menu.buffer;
 5257        let completion = completions_menu
 5258            .completions
 5259            .borrow()
 5260            .get(candidate_id)?
 5261            .clone();
 5262        cx.stop_propagation();
 5263
 5264        let snapshot = self.buffer.read(cx).snapshot(cx);
 5265        let newest_anchor = self.selections.newest_anchor();
 5266
 5267        let snippet;
 5268        let new_text;
 5269        if completion.is_snippet() {
 5270            let mut snippet_source = completion.new_text.clone();
 5271            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5272                if scope.prefers_label_for_snippet_in_completion() {
 5273                    if let Some(label) = completion.label() {
 5274                        if matches!(
 5275                            completion.kind(),
 5276                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5277                        ) {
 5278                            snippet_source = label;
 5279                        }
 5280                    }
 5281                }
 5282            }
 5283            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5284            new_text = snippet.as_ref().unwrap().text.clone();
 5285        } else {
 5286            snippet = None;
 5287            new_text = completion.new_text.clone();
 5288        };
 5289
 5290        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5291        let buffer = buffer_handle.read(cx);
 5292        let replace_range_multibuffer = {
 5293            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5294            let multibuffer_anchor = snapshot
 5295                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5296                .unwrap()
 5297                ..snapshot
 5298                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5299                    .unwrap();
 5300            multibuffer_anchor.start.to_offset(&snapshot)
 5301                ..multibuffer_anchor.end.to_offset(&snapshot)
 5302        };
 5303        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5304            return None;
 5305        }
 5306
 5307        let old_text = buffer
 5308            .text_for_range(replace_range.clone())
 5309            .collect::<String>();
 5310        let lookbehind = newest_anchor
 5311            .start
 5312            .text_anchor
 5313            .to_offset(buffer)
 5314            .saturating_sub(replace_range.start);
 5315        let lookahead = replace_range
 5316            .end
 5317            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5318        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5319        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5320
 5321        let selections = self.selections.all::<usize>(cx);
 5322        let mut ranges = Vec::new();
 5323        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5324
 5325        for selection in &selections {
 5326            let range = if selection.id == newest_anchor.id {
 5327                replace_range_multibuffer.clone()
 5328            } else {
 5329                let mut range = selection.range();
 5330
 5331                // if prefix is present, don't duplicate it
 5332                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5333                    range.start = range.start.saturating_sub(lookbehind);
 5334
 5335                    // if suffix is also present, mimic the newest cursor and replace it
 5336                    if selection.id != newest_anchor.id
 5337                        && snapshot.contains_str_at(range.end, suffix)
 5338                    {
 5339                        range.end += lookahead;
 5340                    }
 5341                }
 5342                range
 5343            };
 5344
 5345            ranges.push(range.clone());
 5346
 5347            if !self.linked_edit_ranges.is_empty() {
 5348                let start_anchor = snapshot.anchor_before(range.start);
 5349                let end_anchor = snapshot.anchor_after(range.end);
 5350                if let Some(ranges) = self
 5351                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5352                {
 5353                    for (buffer, edits) in ranges {
 5354                        linked_edits
 5355                            .entry(buffer.clone())
 5356                            .or_default()
 5357                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5358                    }
 5359                }
 5360            }
 5361        }
 5362
 5363        cx.emit(EditorEvent::InputHandled {
 5364            utf16_range_to_replace: None,
 5365            text: new_text.clone().into(),
 5366        });
 5367
 5368        self.transact(window, cx, |this, window, cx| {
 5369            if let Some(mut snippet) = snippet {
 5370                snippet.text = new_text.to_string();
 5371                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5372            } else {
 5373                this.buffer.update(cx, |buffer, cx| {
 5374                    let auto_indent = match completion.insert_text_mode {
 5375                        Some(InsertTextMode::AS_IS) => None,
 5376                        _ => this.autoindent_mode.clone(),
 5377                    };
 5378                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5379                    buffer.edit(edits, auto_indent, cx);
 5380                });
 5381            }
 5382            for (buffer, edits) in linked_edits {
 5383                buffer.update(cx, |buffer, cx| {
 5384                    let snapshot = buffer.snapshot();
 5385                    let edits = edits
 5386                        .into_iter()
 5387                        .map(|(range, text)| {
 5388                            use text::ToPoint as TP;
 5389                            let end_point = TP::to_point(&range.end, &snapshot);
 5390                            let start_point = TP::to_point(&range.start, &snapshot);
 5391                            (start_point..end_point, text)
 5392                        })
 5393                        .sorted_by_key(|(range, _)| range.start);
 5394                    buffer.edit(edits, None, cx);
 5395                })
 5396            }
 5397
 5398            this.refresh_inline_completion(true, false, window, cx);
 5399        });
 5400
 5401        let show_new_completions_on_confirm = completion
 5402            .confirm
 5403            .as_ref()
 5404            .map_or(false, |confirm| confirm(intent, window, cx));
 5405        if show_new_completions_on_confirm {
 5406            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5407        }
 5408
 5409        let provider = self.completion_provider.as_ref()?;
 5410        drop(completion);
 5411        let apply_edits = provider.apply_additional_edits_for_completion(
 5412            buffer_handle,
 5413            completions_menu.completions.clone(),
 5414            candidate_id,
 5415            true,
 5416            cx,
 5417        );
 5418
 5419        let editor_settings = EditorSettings::get_global(cx);
 5420        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5421            // After the code completion is finished, users often want to know what signatures are needed.
 5422            // so we should automatically call signature_help
 5423            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5424        }
 5425
 5426        Some(cx.foreground_executor().spawn(async move {
 5427            apply_edits.await?;
 5428            Ok(())
 5429        }))
 5430    }
 5431
 5432    pub fn toggle_code_actions(
 5433        &mut self,
 5434        action: &ToggleCodeActions,
 5435        window: &mut Window,
 5436        cx: &mut Context<Self>,
 5437    ) {
 5438        let quick_launch = action.quick_launch;
 5439        let mut context_menu = self.context_menu.borrow_mut();
 5440        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5441            if code_actions.deployed_from == action.deployed_from {
 5442                // Toggle if we're selecting the same one
 5443                *context_menu = None;
 5444                cx.notify();
 5445                return;
 5446            } else {
 5447                // Otherwise, clear it and start a new one
 5448                *context_menu = None;
 5449                cx.notify();
 5450            }
 5451        }
 5452        drop(context_menu);
 5453        let snapshot = self.snapshot(window, cx);
 5454        let deployed_from = action.deployed_from.clone();
 5455        let mut task = self.code_actions_task.take();
 5456        let action = action.clone();
 5457        cx.spawn_in(window, async move |editor, cx| {
 5458            while let Some(prev_task) = task {
 5459                prev_task.await.log_err();
 5460                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5461            }
 5462
 5463            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5464                if editor.focus_handle.is_focused(window) {
 5465                    let multibuffer_point = match &action.deployed_from {
 5466                        Some(CodeActionSource::Indicator(row)) => {
 5467                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5468                        }
 5469                        _ => editor.selections.newest::<Point>(cx).head(),
 5470                    };
 5471                    let (buffer, buffer_row) = snapshot
 5472                        .buffer_snapshot
 5473                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5474                        .and_then(|(buffer_snapshot, range)| {
 5475                            editor
 5476                                .buffer
 5477                                .read(cx)
 5478                                .buffer(buffer_snapshot.remote_id())
 5479                                .map(|buffer| (buffer, range.start.row))
 5480                        })?;
 5481                    let (_, code_actions) = editor
 5482                        .available_code_actions
 5483                        .clone()
 5484                        .and_then(|(location, code_actions)| {
 5485                            let snapshot = location.buffer.read(cx).snapshot();
 5486                            let point_range = location.range.to_point(&snapshot);
 5487                            let point_range = point_range.start.row..=point_range.end.row;
 5488                            if point_range.contains(&buffer_row) {
 5489                                Some((location, code_actions))
 5490                            } else {
 5491                                None
 5492                            }
 5493                        })
 5494                        .unzip();
 5495                    let buffer_id = buffer.read(cx).remote_id();
 5496                    let tasks = editor
 5497                        .tasks
 5498                        .get(&(buffer_id, buffer_row))
 5499                        .map(|t| Arc::new(t.to_owned()));
 5500                    if tasks.is_none() && code_actions.is_none() {
 5501                        return None;
 5502                    }
 5503
 5504                    editor.completion_tasks.clear();
 5505                    editor.discard_inline_completion(false, cx);
 5506                    let task_context =
 5507                        tasks
 5508                            .as_ref()
 5509                            .zip(editor.project.clone())
 5510                            .map(|(tasks, project)| {
 5511                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5512                            });
 5513
 5514                    Some(cx.spawn_in(window, async move |editor, cx| {
 5515                        let task_context = match task_context {
 5516                            Some(task_context) => task_context.await,
 5517                            None => None,
 5518                        };
 5519                        let resolved_tasks =
 5520                            tasks
 5521                                .zip(task_context.clone())
 5522                                .map(|(tasks, task_context)| ResolvedTasks {
 5523                                    templates: tasks.resolve(&task_context).collect(),
 5524                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5525                                        multibuffer_point.row,
 5526                                        tasks.column,
 5527                                    )),
 5528                                });
 5529                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5530                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5531                                maybe!({
 5532                                    let project = editor.project.as_ref()?;
 5533                                    let dap_store = project.read(cx).dap_store();
 5534                                    let mut scenarios = vec![];
 5535                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5536                                    let buffer = buffer.read(cx);
 5537                                    let language = buffer.language()?;
 5538                                    let file = buffer.file();
 5539                                    let debug_adapter =
 5540                                        language_settings(language.name().into(), file, cx)
 5541                                            .debuggers
 5542                                            .first()
 5543                                            .map(SharedString::from)
 5544                                            .or_else(|| {
 5545                                                language
 5546                                                    .config()
 5547                                                    .debuggers
 5548                                                    .first()
 5549                                                    .map(SharedString::from)
 5550                                            })?;
 5551
 5552                                    dap_store.update(cx, |dap_store, cx| {
 5553                                        for (_, task) in &resolved_tasks.templates {
 5554                                            if let Some(scenario) = dap_store
 5555                                                .debug_scenario_for_build_task(
 5556                                                    task.original_task().clone(),
 5557                                                    debug_adapter.clone().into(),
 5558                                                    task.display_label().to_owned().into(),
 5559                                                    cx,
 5560                                                )
 5561                                            {
 5562                                                scenarios.push(scenario);
 5563                                            }
 5564                                        }
 5565                                    });
 5566                                    Some(scenarios)
 5567                                })
 5568                                .unwrap_or_default()
 5569                            } else {
 5570                                vec![]
 5571                            }
 5572                        })?;
 5573                        let spawn_straight_away = quick_launch
 5574                            && resolved_tasks
 5575                                .as_ref()
 5576                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5577                            && code_actions
 5578                                .as_ref()
 5579                                .map_or(true, |actions| actions.is_empty())
 5580                            && debug_scenarios.is_empty();
 5581                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5582                            crate::hover_popover::hide_hover(editor, cx);
 5583                            *editor.context_menu.borrow_mut() =
 5584                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5585                                    buffer,
 5586                                    actions: CodeActionContents::new(
 5587                                        resolved_tasks,
 5588                                        code_actions,
 5589                                        debug_scenarios,
 5590                                        task_context.unwrap_or_default(),
 5591                                    ),
 5592                                    selected_item: Default::default(),
 5593                                    scroll_handle: UniformListScrollHandle::default(),
 5594                                    deployed_from,
 5595                                }));
 5596                            if spawn_straight_away {
 5597                                if let Some(task) = editor.confirm_code_action(
 5598                                    &ConfirmCodeAction { item_ix: Some(0) },
 5599                                    window,
 5600                                    cx,
 5601                                ) {
 5602                                    cx.notify();
 5603                                    return task;
 5604                                }
 5605                            }
 5606                            cx.notify();
 5607                            Task::ready(Ok(()))
 5608                        }) {
 5609                            task.await
 5610                        } else {
 5611                            Ok(())
 5612                        }
 5613                    }))
 5614                } else {
 5615                    Some(Task::ready(Ok(())))
 5616                }
 5617            })?;
 5618            if let Some(task) = spawned_test_task {
 5619                task.await?;
 5620            }
 5621
 5622            anyhow::Ok(())
 5623        })
 5624        .detach_and_log_err(cx);
 5625    }
 5626
 5627    pub fn confirm_code_action(
 5628        &mut self,
 5629        action: &ConfirmCodeAction,
 5630        window: &mut Window,
 5631        cx: &mut Context<Self>,
 5632    ) -> Option<Task<Result<()>>> {
 5633        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5634
 5635        let actions_menu =
 5636            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5637                menu
 5638            } else {
 5639                return None;
 5640            };
 5641
 5642        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5643        let action = actions_menu.actions.get(action_ix)?;
 5644        let title = action.label();
 5645        let buffer = actions_menu.buffer;
 5646        let workspace = self.workspace()?;
 5647
 5648        match action {
 5649            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5650                workspace.update(cx, |workspace, cx| {
 5651                    workspace.schedule_resolved_task(
 5652                        task_source_kind,
 5653                        resolved_task,
 5654                        false,
 5655                        window,
 5656                        cx,
 5657                    );
 5658
 5659                    Some(Task::ready(Ok(())))
 5660                })
 5661            }
 5662            CodeActionsItem::CodeAction {
 5663                excerpt_id,
 5664                action,
 5665                provider,
 5666            } => {
 5667                let apply_code_action =
 5668                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5669                let workspace = workspace.downgrade();
 5670                Some(cx.spawn_in(window, async move |editor, cx| {
 5671                    let project_transaction = apply_code_action.await?;
 5672                    Self::open_project_transaction(
 5673                        &editor,
 5674                        workspace,
 5675                        project_transaction,
 5676                        title,
 5677                        cx,
 5678                    )
 5679                    .await
 5680                }))
 5681            }
 5682            CodeActionsItem::DebugScenario(scenario) => {
 5683                let context = actions_menu.actions.context.clone();
 5684
 5685                workspace.update(cx, |workspace, cx| {
 5686                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5687                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5688                });
 5689                Some(Task::ready(Ok(())))
 5690            }
 5691        }
 5692    }
 5693
 5694    pub async fn open_project_transaction(
 5695        this: &WeakEntity<Editor>,
 5696        workspace: WeakEntity<Workspace>,
 5697        transaction: ProjectTransaction,
 5698        title: String,
 5699        cx: &mut AsyncWindowContext,
 5700    ) -> Result<()> {
 5701        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5702        cx.update(|_, cx| {
 5703            entries.sort_unstable_by_key(|(buffer, _)| {
 5704                buffer.read(cx).file().map(|f| f.path().clone())
 5705            });
 5706        })?;
 5707
 5708        // If the project transaction's edits are all contained within this editor, then
 5709        // avoid opening a new editor to display them.
 5710
 5711        if let Some((buffer, transaction)) = entries.first() {
 5712            if entries.len() == 1 {
 5713                let excerpt = this.update(cx, |editor, cx| {
 5714                    editor
 5715                        .buffer()
 5716                        .read(cx)
 5717                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5718                })?;
 5719                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5720                    if excerpted_buffer == *buffer {
 5721                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5722                            let excerpt_range = excerpt_range.to_offset(buffer);
 5723                            buffer
 5724                                .edited_ranges_for_transaction::<usize>(transaction)
 5725                                .all(|range| {
 5726                                    excerpt_range.start <= range.start
 5727                                        && excerpt_range.end >= range.end
 5728                                })
 5729                        })?;
 5730
 5731                        if all_edits_within_excerpt {
 5732                            return Ok(());
 5733                        }
 5734                    }
 5735                }
 5736            }
 5737        } else {
 5738            return Ok(());
 5739        }
 5740
 5741        let mut ranges_to_highlight = Vec::new();
 5742        let excerpt_buffer = cx.new(|cx| {
 5743            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5744            for (buffer_handle, transaction) in &entries {
 5745                let edited_ranges = buffer_handle
 5746                    .read(cx)
 5747                    .edited_ranges_for_transaction::<Point>(transaction)
 5748                    .collect::<Vec<_>>();
 5749                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5750                    PathKey::for_buffer(buffer_handle, cx),
 5751                    buffer_handle.clone(),
 5752                    edited_ranges,
 5753                    DEFAULT_MULTIBUFFER_CONTEXT,
 5754                    cx,
 5755                );
 5756
 5757                ranges_to_highlight.extend(ranges);
 5758            }
 5759            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5760            multibuffer
 5761        })?;
 5762
 5763        workspace.update_in(cx, |workspace, window, cx| {
 5764            let project = workspace.project().clone();
 5765            let editor =
 5766                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5767            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5768            editor.update(cx, |editor, cx| {
 5769                editor.highlight_background::<Self>(
 5770                    &ranges_to_highlight,
 5771                    |theme| theme.editor_highlighted_line_background,
 5772                    cx,
 5773                );
 5774            });
 5775        })?;
 5776
 5777        Ok(())
 5778    }
 5779
 5780    pub fn clear_code_action_providers(&mut self) {
 5781        self.code_action_providers.clear();
 5782        self.available_code_actions.take();
 5783    }
 5784
 5785    pub fn add_code_action_provider(
 5786        &mut self,
 5787        provider: Rc<dyn CodeActionProvider>,
 5788        window: &mut Window,
 5789        cx: &mut Context<Self>,
 5790    ) {
 5791        if self
 5792            .code_action_providers
 5793            .iter()
 5794            .any(|existing_provider| existing_provider.id() == provider.id())
 5795        {
 5796            return;
 5797        }
 5798
 5799        self.code_action_providers.push(provider);
 5800        self.refresh_code_actions(window, cx);
 5801    }
 5802
 5803    pub fn remove_code_action_provider(
 5804        &mut self,
 5805        id: Arc<str>,
 5806        window: &mut Window,
 5807        cx: &mut Context<Self>,
 5808    ) {
 5809        self.code_action_providers
 5810            .retain(|provider| provider.id() != id);
 5811        self.refresh_code_actions(window, cx);
 5812    }
 5813
 5814    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 5815        !self.code_action_providers.is_empty()
 5816            && EditorSettings::get_global(cx).toolbar.code_actions
 5817    }
 5818
 5819    pub fn has_available_code_actions(&self) -> bool {
 5820        self.available_code_actions
 5821            .as_ref()
 5822            .is_some_and(|(_, actions)| !actions.is_empty())
 5823    }
 5824
 5825    fn render_inline_code_actions(
 5826        &self,
 5827        icon_size: ui::IconSize,
 5828        display_row: DisplayRow,
 5829        is_active: bool,
 5830        cx: &mut Context<Self>,
 5831    ) -> AnyElement {
 5832        let show_tooltip = !self.context_menu_visible();
 5833        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 5834            .icon_size(icon_size)
 5835            .shape(ui::IconButtonShape::Square)
 5836            .style(ButtonStyle::Transparent)
 5837            .icon_color(ui::Color::Hidden)
 5838            .toggle_state(is_active)
 5839            .when(show_tooltip, |this| {
 5840                this.tooltip({
 5841                    let focus_handle = self.focus_handle.clone();
 5842                    move |window, cx| {
 5843                        Tooltip::for_action_in(
 5844                            "Toggle Code Actions",
 5845                            &ToggleCodeActions {
 5846                                deployed_from: None,
 5847                                quick_launch: false,
 5848                            },
 5849                            &focus_handle,
 5850                            window,
 5851                            cx,
 5852                        )
 5853                    }
 5854                })
 5855            })
 5856            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 5857                window.focus(&editor.focus_handle(cx));
 5858                editor.toggle_code_actions(
 5859                    &crate::actions::ToggleCodeActions {
 5860                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 5861                            display_row,
 5862                        )),
 5863                        quick_launch: false,
 5864                    },
 5865                    window,
 5866                    cx,
 5867                );
 5868            }))
 5869            .into_any_element()
 5870    }
 5871
 5872    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 5873        &self.context_menu
 5874    }
 5875
 5876    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5877        let newest_selection = self.selections.newest_anchor().clone();
 5878        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5879        let buffer = self.buffer.read(cx);
 5880        if newest_selection.head().diff_base_anchor.is_some() {
 5881            return None;
 5882        }
 5883        let (start_buffer, start) =
 5884            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5885        let (end_buffer, end) =
 5886            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5887        if start_buffer != end_buffer {
 5888            return None;
 5889        }
 5890
 5891        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5892            cx.background_executor()
 5893                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5894                .await;
 5895
 5896            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5897                let providers = this.code_action_providers.clone();
 5898                let tasks = this
 5899                    .code_action_providers
 5900                    .iter()
 5901                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5902                    .collect::<Vec<_>>();
 5903                (providers, tasks)
 5904            })?;
 5905
 5906            let mut actions = Vec::new();
 5907            for (provider, provider_actions) in
 5908                providers.into_iter().zip(future::join_all(tasks).await)
 5909            {
 5910                if let Some(provider_actions) = provider_actions.log_err() {
 5911                    actions.extend(provider_actions.into_iter().map(|action| {
 5912                        AvailableCodeAction {
 5913                            excerpt_id: newest_selection.start.excerpt_id,
 5914                            action,
 5915                            provider: provider.clone(),
 5916                        }
 5917                    }));
 5918                }
 5919            }
 5920
 5921            this.update(cx, |this, cx| {
 5922                this.available_code_actions = if actions.is_empty() {
 5923                    None
 5924                } else {
 5925                    Some((
 5926                        Location {
 5927                            buffer: start_buffer,
 5928                            range: start..end,
 5929                        },
 5930                        actions.into(),
 5931                    ))
 5932                };
 5933                cx.notify();
 5934            })
 5935        }));
 5936        None
 5937    }
 5938
 5939    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5940        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5941            self.show_git_blame_inline = false;
 5942
 5943            self.show_git_blame_inline_delay_task =
 5944                Some(cx.spawn_in(window, async move |this, cx| {
 5945                    cx.background_executor().timer(delay).await;
 5946
 5947                    this.update(cx, |this, cx| {
 5948                        this.show_git_blame_inline = true;
 5949                        cx.notify();
 5950                    })
 5951                    .log_err();
 5952                }));
 5953        }
 5954    }
 5955
 5956    fn show_blame_popover(
 5957        &mut self,
 5958        blame_entry: &BlameEntry,
 5959        position: gpui::Point<Pixels>,
 5960        cx: &mut Context<Self>,
 5961    ) {
 5962        if let Some(state) = &mut self.inline_blame_popover {
 5963            state.hide_task.take();
 5964            cx.notify();
 5965        } else {
 5966            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5967            let show_task = cx.spawn(async move |editor, cx| {
 5968                cx.background_executor()
 5969                    .timer(std::time::Duration::from_millis(delay))
 5970                    .await;
 5971                editor
 5972                    .update(cx, |editor, cx| {
 5973                        if let Some(state) = &mut editor.inline_blame_popover {
 5974                            state.show_task = None;
 5975                            cx.notify();
 5976                        }
 5977                    })
 5978                    .ok();
 5979            });
 5980            let Some(blame) = self.blame.as_ref() else {
 5981                return;
 5982            };
 5983            let blame = blame.read(cx);
 5984            let details = blame.details_for_entry(&blame_entry);
 5985            let markdown = cx.new(|cx| {
 5986                Markdown::new(
 5987                    details
 5988                        .as_ref()
 5989                        .map(|message| message.message.clone())
 5990                        .unwrap_or_default(),
 5991                    None,
 5992                    None,
 5993                    cx,
 5994                )
 5995            });
 5996            self.inline_blame_popover = Some(InlineBlamePopover {
 5997                position,
 5998                show_task: Some(show_task),
 5999                hide_task: None,
 6000                popover_bounds: None,
 6001                popover_state: InlineBlamePopoverState {
 6002                    scroll_handle: ScrollHandle::new(),
 6003                    commit_message: details,
 6004                    markdown,
 6005                },
 6006            });
 6007        }
 6008    }
 6009
 6010    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6011        if let Some(state) = &mut self.inline_blame_popover {
 6012            if state.show_task.is_some() {
 6013                self.inline_blame_popover.take();
 6014                cx.notify();
 6015            } else {
 6016                let hide_task = cx.spawn(async move |editor, cx| {
 6017                    cx.background_executor()
 6018                        .timer(std::time::Duration::from_millis(100))
 6019                        .await;
 6020                    editor
 6021                        .update(cx, |editor, cx| {
 6022                            editor.inline_blame_popover.take();
 6023                            cx.notify();
 6024                        })
 6025                        .ok();
 6026                });
 6027                state.hide_task = Some(hide_task);
 6028            }
 6029        }
 6030    }
 6031
 6032    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6033        if self.pending_rename.is_some() {
 6034            return None;
 6035        }
 6036
 6037        let provider = self.semantics_provider.clone()?;
 6038        let buffer = self.buffer.read(cx);
 6039        let newest_selection = self.selections.newest_anchor().clone();
 6040        let cursor_position = newest_selection.head();
 6041        let (cursor_buffer, cursor_buffer_position) =
 6042            buffer.text_anchor_for_position(cursor_position, cx)?;
 6043        let (tail_buffer, tail_buffer_position) =
 6044            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6045        if cursor_buffer != tail_buffer {
 6046            return None;
 6047        }
 6048
 6049        let snapshot = cursor_buffer.read(cx).snapshot();
 6050        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6051        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6052        if start_word_range != end_word_range {
 6053            self.document_highlights_task.take();
 6054            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6055            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6056            return None;
 6057        }
 6058
 6059        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6060        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6061            cx.background_executor()
 6062                .timer(Duration::from_millis(debounce))
 6063                .await;
 6064
 6065            let highlights = if let Some(highlights) = cx
 6066                .update(|cx| {
 6067                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6068                })
 6069                .ok()
 6070                .flatten()
 6071            {
 6072                highlights.await.log_err()
 6073            } else {
 6074                None
 6075            };
 6076
 6077            if let Some(highlights) = highlights {
 6078                this.update(cx, |this, cx| {
 6079                    if this.pending_rename.is_some() {
 6080                        return;
 6081                    }
 6082
 6083                    let buffer_id = cursor_position.buffer_id;
 6084                    let buffer = this.buffer.read(cx);
 6085                    if !buffer
 6086                        .text_anchor_for_position(cursor_position, cx)
 6087                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6088                    {
 6089                        return;
 6090                    }
 6091
 6092                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6093                    let mut write_ranges = Vec::new();
 6094                    let mut read_ranges = Vec::new();
 6095                    for highlight in highlights {
 6096                        for (excerpt_id, excerpt_range) in
 6097                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6098                        {
 6099                            let start = highlight
 6100                                .range
 6101                                .start
 6102                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6103                            let end = highlight
 6104                                .range
 6105                                .end
 6106                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6107                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6108                                continue;
 6109                            }
 6110
 6111                            let range = Anchor {
 6112                                buffer_id,
 6113                                excerpt_id,
 6114                                text_anchor: start,
 6115                                diff_base_anchor: None,
 6116                            }..Anchor {
 6117                                buffer_id,
 6118                                excerpt_id,
 6119                                text_anchor: end,
 6120                                diff_base_anchor: None,
 6121                            };
 6122                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6123                                write_ranges.push(range);
 6124                            } else {
 6125                                read_ranges.push(range);
 6126                            }
 6127                        }
 6128                    }
 6129
 6130                    this.highlight_background::<DocumentHighlightRead>(
 6131                        &read_ranges,
 6132                        |theme| theme.editor_document_highlight_read_background,
 6133                        cx,
 6134                    );
 6135                    this.highlight_background::<DocumentHighlightWrite>(
 6136                        &write_ranges,
 6137                        |theme| theme.editor_document_highlight_write_background,
 6138                        cx,
 6139                    );
 6140                    cx.notify();
 6141                })
 6142                .log_err();
 6143            }
 6144        }));
 6145        None
 6146    }
 6147
 6148    fn prepare_highlight_query_from_selection(
 6149        &mut self,
 6150        cx: &mut Context<Editor>,
 6151    ) -> Option<(String, Range<Anchor>)> {
 6152        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6153            return None;
 6154        }
 6155        if !EditorSettings::get_global(cx).selection_highlight {
 6156            return None;
 6157        }
 6158        if self.selections.count() != 1 || self.selections.line_mode {
 6159            return None;
 6160        }
 6161        let selection = self.selections.newest::<Point>(cx);
 6162        if selection.is_empty() || selection.start.row != selection.end.row {
 6163            return None;
 6164        }
 6165        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6166        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6167        let query = multi_buffer_snapshot
 6168            .text_for_range(selection_anchor_range.clone())
 6169            .collect::<String>();
 6170        if query.trim().is_empty() {
 6171            return None;
 6172        }
 6173        Some((query, selection_anchor_range))
 6174    }
 6175
 6176    fn update_selection_occurrence_highlights(
 6177        &mut self,
 6178        query_text: String,
 6179        query_range: Range<Anchor>,
 6180        multi_buffer_range_to_query: Range<Point>,
 6181        use_debounce: bool,
 6182        window: &mut Window,
 6183        cx: &mut Context<Editor>,
 6184    ) -> Task<()> {
 6185        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6186        cx.spawn_in(window, async move |editor, cx| {
 6187            if use_debounce {
 6188                cx.background_executor()
 6189                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6190                    .await;
 6191            }
 6192            let match_task = cx.background_spawn(async move {
 6193                let buffer_ranges = multi_buffer_snapshot
 6194                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6195                    .into_iter()
 6196                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6197                let mut match_ranges = Vec::new();
 6198                let Ok(regex) = project::search::SearchQuery::text(
 6199                    query_text.clone(),
 6200                    false,
 6201                    false,
 6202                    false,
 6203                    Default::default(),
 6204                    Default::default(),
 6205                    false,
 6206                    None,
 6207                ) else {
 6208                    return Vec::default();
 6209                };
 6210                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6211                    match_ranges.extend(
 6212                        regex
 6213                            .search(&buffer_snapshot, Some(search_range.clone()))
 6214                            .await
 6215                            .into_iter()
 6216                            .filter_map(|match_range| {
 6217                                let match_start = buffer_snapshot
 6218                                    .anchor_after(search_range.start + match_range.start);
 6219                                let match_end = buffer_snapshot
 6220                                    .anchor_before(search_range.start + match_range.end);
 6221                                let match_anchor_range = Anchor::range_in_buffer(
 6222                                    excerpt_id,
 6223                                    buffer_snapshot.remote_id(),
 6224                                    match_start..match_end,
 6225                                );
 6226                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6227                            }),
 6228                    );
 6229                }
 6230                match_ranges
 6231            });
 6232            let match_ranges = match_task.await;
 6233            editor
 6234                .update_in(cx, |editor, _, cx| {
 6235                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6236                    if !match_ranges.is_empty() {
 6237                        editor.highlight_background::<SelectedTextHighlight>(
 6238                            &match_ranges,
 6239                            |theme| theme.editor_document_highlight_bracket_background,
 6240                            cx,
 6241                        )
 6242                    }
 6243                })
 6244                .log_err();
 6245        })
 6246    }
 6247
 6248    fn refresh_selected_text_highlights(
 6249        &mut self,
 6250        on_buffer_edit: bool,
 6251        window: &mut Window,
 6252        cx: &mut Context<Editor>,
 6253    ) {
 6254        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6255        else {
 6256            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6257            self.quick_selection_highlight_task.take();
 6258            self.debounced_selection_highlight_task.take();
 6259            return;
 6260        };
 6261        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6262        if on_buffer_edit
 6263            || self
 6264                .quick_selection_highlight_task
 6265                .as_ref()
 6266                .map_or(true, |(prev_anchor_range, _)| {
 6267                    prev_anchor_range != &query_range
 6268                })
 6269        {
 6270            let multi_buffer_visible_start = self
 6271                .scroll_manager
 6272                .anchor()
 6273                .anchor
 6274                .to_point(&multi_buffer_snapshot);
 6275            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6276                multi_buffer_visible_start
 6277                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6278                Bias::Left,
 6279            );
 6280            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6281            self.quick_selection_highlight_task = Some((
 6282                query_range.clone(),
 6283                self.update_selection_occurrence_highlights(
 6284                    query_text.clone(),
 6285                    query_range.clone(),
 6286                    multi_buffer_visible_range,
 6287                    false,
 6288                    window,
 6289                    cx,
 6290                ),
 6291            ));
 6292        }
 6293        if on_buffer_edit
 6294            || self
 6295                .debounced_selection_highlight_task
 6296                .as_ref()
 6297                .map_or(true, |(prev_anchor_range, _)| {
 6298                    prev_anchor_range != &query_range
 6299                })
 6300        {
 6301            let multi_buffer_start = multi_buffer_snapshot
 6302                .anchor_before(0)
 6303                .to_point(&multi_buffer_snapshot);
 6304            let multi_buffer_end = multi_buffer_snapshot
 6305                .anchor_after(multi_buffer_snapshot.len())
 6306                .to_point(&multi_buffer_snapshot);
 6307            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6308            self.debounced_selection_highlight_task = Some((
 6309                query_range.clone(),
 6310                self.update_selection_occurrence_highlights(
 6311                    query_text,
 6312                    query_range,
 6313                    multi_buffer_full_range,
 6314                    true,
 6315                    window,
 6316                    cx,
 6317                ),
 6318            ));
 6319        }
 6320    }
 6321
 6322    pub fn refresh_inline_completion(
 6323        &mut self,
 6324        debounce: bool,
 6325        user_requested: bool,
 6326        window: &mut Window,
 6327        cx: &mut Context<Self>,
 6328    ) -> Option<()> {
 6329        let provider = self.edit_prediction_provider()?;
 6330        let cursor = self.selections.newest_anchor().head();
 6331        let (buffer, cursor_buffer_position) =
 6332            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6333
 6334        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6335            self.discard_inline_completion(false, cx);
 6336            return None;
 6337        }
 6338
 6339        if !user_requested
 6340            && (!self.should_show_edit_predictions()
 6341                || !self.is_focused(window)
 6342                || buffer.read(cx).is_empty())
 6343        {
 6344            self.discard_inline_completion(false, cx);
 6345            return None;
 6346        }
 6347
 6348        self.update_visible_inline_completion(window, cx);
 6349        provider.refresh(
 6350            self.project.clone(),
 6351            buffer,
 6352            cursor_buffer_position,
 6353            debounce,
 6354            cx,
 6355        );
 6356        Some(())
 6357    }
 6358
 6359    fn show_edit_predictions_in_menu(&self) -> bool {
 6360        match self.edit_prediction_settings {
 6361            EditPredictionSettings::Disabled => false,
 6362            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6363        }
 6364    }
 6365
 6366    pub fn edit_predictions_enabled(&self) -> bool {
 6367        match self.edit_prediction_settings {
 6368            EditPredictionSettings::Disabled => false,
 6369            EditPredictionSettings::Enabled { .. } => true,
 6370        }
 6371    }
 6372
 6373    fn edit_prediction_requires_modifier(&self) -> bool {
 6374        match self.edit_prediction_settings {
 6375            EditPredictionSettings::Disabled => false,
 6376            EditPredictionSettings::Enabled {
 6377                preview_requires_modifier,
 6378                ..
 6379            } => preview_requires_modifier,
 6380        }
 6381    }
 6382
 6383    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6384        if self.edit_prediction_provider.is_none() {
 6385            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6386        } else {
 6387            let selection = self.selections.newest_anchor();
 6388            let cursor = selection.head();
 6389
 6390            if let Some((buffer, cursor_buffer_position)) =
 6391                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6392            {
 6393                self.edit_prediction_settings =
 6394                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6395            }
 6396        }
 6397    }
 6398
 6399    fn edit_prediction_settings_at_position(
 6400        &self,
 6401        buffer: &Entity<Buffer>,
 6402        buffer_position: language::Anchor,
 6403        cx: &App,
 6404    ) -> EditPredictionSettings {
 6405        if !self.mode.is_full()
 6406            || !self.show_inline_completions_override.unwrap_or(true)
 6407            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6408        {
 6409            return EditPredictionSettings::Disabled;
 6410        }
 6411
 6412        let buffer = buffer.read(cx);
 6413
 6414        let file = buffer.file();
 6415
 6416        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6417            return EditPredictionSettings::Disabled;
 6418        };
 6419
 6420        let by_provider = matches!(
 6421            self.menu_inline_completions_policy,
 6422            MenuInlineCompletionsPolicy::ByProvider
 6423        );
 6424
 6425        let show_in_menu = by_provider
 6426            && self
 6427                .edit_prediction_provider
 6428                .as_ref()
 6429                .map_or(false, |provider| {
 6430                    provider.provider.show_completions_in_menu()
 6431                });
 6432
 6433        let preview_requires_modifier =
 6434            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6435
 6436        EditPredictionSettings::Enabled {
 6437            show_in_menu,
 6438            preview_requires_modifier,
 6439        }
 6440    }
 6441
 6442    fn should_show_edit_predictions(&self) -> bool {
 6443        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6444    }
 6445
 6446    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6447        matches!(
 6448            self.edit_prediction_preview,
 6449            EditPredictionPreview::Active { .. }
 6450        )
 6451    }
 6452
 6453    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6454        let cursor = self.selections.newest_anchor().head();
 6455        if let Some((buffer, cursor_position)) =
 6456            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6457        {
 6458            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6459        } else {
 6460            false
 6461        }
 6462    }
 6463
 6464    pub fn supports_minimap(&self, cx: &App) -> bool {
 6465        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6466    }
 6467
 6468    fn edit_predictions_enabled_in_buffer(
 6469        &self,
 6470        buffer: &Entity<Buffer>,
 6471        buffer_position: language::Anchor,
 6472        cx: &App,
 6473    ) -> bool {
 6474        maybe!({
 6475            if self.read_only(cx) {
 6476                return Some(false);
 6477            }
 6478            let provider = self.edit_prediction_provider()?;
 6479            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6480                return Some(false);
 6481            }
 6482            let buffer = buffer.read(cx);
 6483            let Some(file) = buffer.file() else {
 6484                return Some(true);
 6485            };
 6486            let settings = all_language_settings(Some(file), cx);
 6487            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6488        })
 6489        .unwrap_or(false)
 6490    }
 6491
 6492    fn cycle_inline_completion(
 6493        &mut self,
 6494        direction: Direction,
 6495        window: &mut Window,
 6496        cx: &mut Context<Self>,
 6497    ) -> Option<()> {
 6498        let provider = self.edit_prediction_provider()?;
 6499        let cursor = self.selections.newest_anchor().head();
 6500        let (buffer, cursor_buffer_position) =
 6501            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6502        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6503            return None;
 6504        }
 6505
 6506        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6507        self.update_visible_inline_completion(window, cx);
 6508
 6509        Some(())
 6510    }
 6511
 6512    pub fn show_inline_completion(
 6513        &mut self,
 6514        _: &ShowEditPrediction,
 6515        window: &mut Window,
 6516        cx: &mut Context<Self>,
 6517    ) {
 6518        if !self.has_active_inline_completion() {
 6519            self.refresh_inline_completion(false, true, window, cx);
 6520            return;
 6521        }
 6522
 6523        self.update_visible_inline_completion(window, cx);
 6524    }
 6525
 6526    pub fn display_cursor_names(
 6527        &mut self,
 6528        _: &DisplayCursorNames,
 6529        window: &mut Window,
 6530        cx: &mut Context<Self>,
 6531    ) {
 6532        self.show_cursor_names(window, cx);
 6533    }
 6534
 6535    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6536        self.show_cursor_names = true;
 6537        cx.notify();
 6538        cx.spawn_in(window, async move |this, cx| {
 6539            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6540            this.update(cx, |this, cx| {
 6541                this.show_cursor_names = false;
 6542                cx.notify()
 6543            })
 6544            .ok()
 6545        })
 6546        .detach();
 6547    }
 6548
 6549    pub fn next_edit_prediction(
 6550        &mut self,
 6551        _: &NextEditPrediction,
 6552        window: &mut Window,
 6553        cx: &mut Context<Self>,
 6554    ) {
 6555        if self.has_active_inline_completion() {
 6556            self.cycle_inline_completion(Direction::Next, window, cx);
 6557        } else {
 6558            let is_copilot_disabled = self
 6559                .refresh_inline_completion(false, true, window, cx)
 6560                .is_none();
 6561            if is_copilot_disabled {
 6562                cx.propagate();
 6563            }
 6564        }
 6565    }
 6566
 6567    pub fn previous_edit_prediction(
 6568        &mut self,
 6569        _: &PreviousEditPrediction,
 6570        window: &mut Window,
 6571        cx: &mut Context<Self>,
 6572    ) {
 6573        if self.has_active_inline_completion() {
 6574            self.cycle_inline_completion(Direction::Prev, window, cx);
 6575        } else {
 6576            let is_copilot_disabled = self
 6577                .refresh_inline_completion(false, true, window, cx)
 6578                .is_none();
 6579            if is_copilot_disabled {
 6580                cx.propagate();
 6581            }
 6582        }
 6583    }
 6584
 6585    pub fn accept_edit_prediction(
 6586        &mut self,
 6587        _: &AcceptEditPrediction,
 6588        window: &mut Window,
 6589        cx: &mut Context<Self>,
 6590    ) {
 6591        if self.show_edit_predictions_in_menu() {
 6592            self.hide_context_menu(window, cx);
 6593        }
 6594
 6595        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6596            return;
 6597        };
 6598
 6599        self.report_inline_completion_event(
 6600            active_inline_completion.completion_id.clone(),
 6601            true,
 6602            cx,
 6603        );
 6604
 6605        match &active_inline_completion.completion {
 6606            InlineCompletion::Move { target, .. } => {
 6607                let target = *target;
 6608
 6609                if let Some(position_map) = &self.last_position_map {
 6610                    if position_map
 6611                        .visible_row_range
 6612                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6613                        || !self.edit_prediction_requires_modifier()
 6614                    {
 6615                        self.unfold_ranges(&[target..target], true, false, cx);
 6616                        // Note that this is also done in vim's handler of the Tab action.
 6617                        self.change_selections(
 6618                            Some(Autoscroll::newest()),
 6619                            window,
 6620                            cx,
 6621                            |selections| {
 6622                                selections.select_anchor_ranges([target..target]);
 6623                            },
 6624                        );
 6625                        self.clear_row_highlights::<EditPredictionPreview>();
 6626
 6627                        self.edit_prediction_preview
 6628                            .set_previous_scroll_position(None);
 6629                    } else {
 6630                        self.edit_prediction_preview
 6631                            .set_previous_scroll_position(Some(
 6632                                position_map.snapshot.scroll_anchor,
 6633                            ));
 6634
 6635                        self.highlight_rows::<EditPredictionPreview>(
 6636                            target..target,
 6637                            cx.theme().colors().editor_highlighted_line_background,
 6638                            RowHighlightOptions {
 6639                                autoscroll: true,
 6640                                ..Default::default()
 6641                            },
 6642                            cx,
 6643                        );
 6644                        self.request_autoscroll(Autoscroll::fit(), cx);
 6645                    }
 6646                }
 6647            }
 6648            InlineCompletion::Edit { edits, .. } => {
 6649                if let Some(provider) = self.edit_prediction_provider() {
 6650                    provider.accept(cx);
 6651                }
 6652
 6653                // Store the transaction ID and selections before applying the edit
 6654                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6655
 6656                let snapshot = self.buffer.read(cx).snapshot(cx);
 6657                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6658
 6659                self.buffer.update(cx, |buffer, cx| {
 6660                    buffer.edit(edits.iter().cloned(), None, cx)
 6661                });
 6662
 6663                self.change_selections(None, window, cx, |s| {
 6664                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6665                });
 6666
 6667                let selections = self.selections.disjoint_anchors();
 6668                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6669                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6670                    if has_new_transaction {
 6671                        self.selection_history
 6672                            .insert_transaction(transaction_id_now, selections);
 6673                    }
 6674                }
 6675
 6676                self.update_visible_inline_completion(window, cx);
 6677                if self.active_inline_completion.is_none() {
 6678                    self.refresh_inline_completion(true, true, window, cx);
 6679                }
 6680
 6681                cx.notify();
 6682            }
 6683        }
 6684
 6685        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6686    }
 6687
 6688    pub fn accept_partial_inline_completion(
 6689        &mut self,
 6690        _: &AcceptPartialEditPrediction,
 6691        window: &mut Window,
 6692        cx: &mut Context<Self>,
 6693    ) {
 6694        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6695            return;
 6696        };
 6697        if self.selections.count() != 1 {
 6698            return;
 6699        }
 6700
 6701        self.report_inline_completion_event(
 6702            active_inline_completion.completion_id.clone(),
 6703            true,
 6704            cx,
 6705        );
 6706
 6707        match &active_inline_completion.completion {
 6708            InlineCompletion::Move { target, .. } => {
 6709                let target = *target;
 6710                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6711                    selections.select_anchor_ranges([target..target]);
 6712                });
 6713            }
 6714            InlineCompletion::Edit { edits, .. } => {
 6715                // Find an insertion that starts at the cursor position.
 6716                let snapshot = self.buffer.read(cx).snapshot(cx);
 6717                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6718                let insertion = edits.iter().find_map(|(range, text)| {
 6719                    let range = range.to_offset(&snapshot);
 6720                    if range.is_empty() && range.start == cursor_offset {
 6721                        Some(text)
 6722                    } else {
 6723                        None
 6724                    }
 6725                });
 6726
 6727                if let Some(text) = insertion {
 6728                    let mut partial_completion = text
 6729                        .chars()
 6730                        .by_ref()
 6731                        .take_while(|c| c.is_alphabetic())
 6732                        .collect::<String>();
 6733                    if partial_completion.is_empty() {
 6734                        partial_completion = text
 6735                            .chars()
 6736                            .by_ref()
 6737                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6738                            .collect::<String>();
 6739                    }
 6740
 6741                    cx.emit(EditorEvent::InputHandled {
 6742                        utf16_range_to_replace: None,
 6743                        text: partial_completion.clone().into(),
 6744                    });
 6745
 6746                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6747
 6748                    self.refresh_inline_completion(true, true, window, cx);
 6749                    cx.notify();
 6750                } else {
 6751                    self.accept_edit_prediction(&Default::default(), window, cx);
 6752                }
 6753            }
 6754        }
 6755    }
 6756
 6757    fn discard_inline_completion(
 6758        &mut self,
 6759        should_report_inline_completion_event: bool,
 6760        cx: &mut Context<Self>,
 6761    ) -> bool {
 6762        if should_report_inline_completion_event {
 6763            let completion_id = self
 6764                .active_inline_completion
 6765                .as_ref()
 6766                .and_then(|active_completion| active_completion.completion_id.clone());
 6767
 6768            self.report_inline_completion_event(completion_id, false, cx);
 6769        }
 6770
 6771        if let Some(provider) = self.edit_prediction_provider() {
 6772            provider.discard(cx);
 6773        }
 6774
 6775        self.take_active_inline_completion(cx)
 6776    }
 6777
 6778    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6779        let Some(provider) = self.edit_prediction_provider() else {
 6780            return;
 6781        };
 6782
 6783        let Some((_, buffer, _)) = self
 6784            .buffer
 6785            .read(cx)
 6786            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6787        else {
 6788            return;
 6789        };
 6790
 6791        let extension = buffer
 6792            .read(cx)
 6793            .file()
 6794            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6795
 6796        let event_type = match accepted {
 6797            true => "Edit Prediction Accepted",
 6798            false => "Edit Prediction Discarded",
 6799        };
 6800        telemetry::event!(
 6801            event_type,
 6802            provider = provider.name(),
 6803            prediction_id = id,
 6804            suggestion_accepted = accepted,
 6805            file_extension = extension,
 6806        );
 6807    }
 6808
 6809    pub fn has_active_inline_completion(&self) -> bool {
 6810        self.active_inline_completion.is_some()
 6811    }
 6812
 6813    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6814        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6815            return false;
 6816        };
 6817
 6818        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6819        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6820        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6821        true
 6822    }
 6823
 6824    /// Returns true when we're displaying the edit prediction popover below the cursor
 6825    /// like we are not previewing and the LSP autocomplete menu is visible
 6826    /// or we are in `when_holding_modifier` mode.
 6827    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6828        if self.edit_prediction_preview_is_active()
 6829            || !self.show_edit_predictions_in_menu()
 6830            || !self.edit_predictions_enabled()
 6831        {
 6832            return false;
 6833        }
 6834
 6835        if self.has_visible_completions_menu() {
 6836            return true;
 6837        }
 6838
 6839        has_completion && self.edit_prediction_requires_modifier()
 6840    }
 6841
 6842    fn handle_modifiers_changed(
 6843        &mut self,
 6844        modifiers: Modifiers,
 6845        position_map: &PositionMap,
 6846        window: &mut Window,
 6847        cx: &mut Context<Self>,
 6848    ) {
 6849        if self.show_edit_predictions_in_menu() {
 6850            self.update_edit_prediction_preview(&modifiers, window, cx);
 6851        }
 6852
 6853        self.update_selection_mode(&modifiers, position_map, window, cx);
 6854
 6855        let mouse_position = window.mouse_position();
 6856        if !position_map.text_hitbox.is_hovered(window) {
 6857            return;
 6858        }
 6859
 6860        self.update_hovered_link(
 6861            position_map.point_for_position(mouse_position),
 6862            &position_map.snapshot,
 6863            modifiers,
 6864            window,
 6865            cx,
 6866        )
 6867    }
 6868
 6869    fn update_selection_mode(
 6870        &mut self,
 6871        modifiers: &Modifiers,
 6872        position_map: &PositionMap,
 6873        window: &mut Window,
 6874        cx: &mut Context<Self>,
 6875    ) {
 6876        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6877            return;
 6878        }
 6879
 6880        let mouse_position = window.mouse_position();
 6881        let point_for_position = position_map.point_for_position(mouse_position);
 6882        let position = point_for_position.previous_valid;
 6883
 6884        self.select(
 6885            SelectPhase::BeginColumnar {
 6886                position,
 6887                reset: false,
 6888                goal_column: point_for_position.exact_unclipped.column(),
 6889            },
 6890            window,
 6891            cx,
 6892        );
 6893    }
 6894
 6895    fn update_edit_prediction_preview(
 6896        &mut self,
 6897        modifiers: &Modifiers,
 6898        window: &mut Window,
 6899        cx: &mut Context<Self>,
 6900    ) {
 6901        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6902        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6903            return;
 6904        };
 6905
 6906        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6907            if matches!(
 6908                self.edit_prediction_preview,
 6909                EditPredictionPreview::Inactive { .. }
 6910            ) {
 6911                self.edit_prediction_preview = EditPredictionPreview::Active {
 6912                    previous_scroll_position: None,
 6913                    since: Instant::now(),
 6914                };
 6915
 6916                self.update_visible_inline_completion(window, cx);
 6917                cx.notify();
 6918            }
 6919        } else if let EditPredictionPreview::Active {
 6920            previous_scroll_position,
 6921            since,
 6922        } = self.edit_prediction_preview
 6923        {
 6924            if let (Some(previous_scroll_position), Some(position_map)) =
 6925                (previous_scroll_position, self.last_position_map.as_ref())
 6926            {
 6927                self.set_scroll_position(
 6928                    previous_scroll_position
 6929                        .scroll_position(&position_map.snapshot.display_snapshot),
 6930                    window,
 6931                    cx,
 6932                );
 6933            }
 6934
 6935            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6936                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6937            };
 6938            self.clear_row_highlights::<EditPredictionPreview>();
 6939            self.update_visible_inline_completion(window, cx);
 6940            cx.notify();
 6941        }
 6942    }
 6943
 6944    fn update_visible_inline_completion(
 6945        &mut self,
 6946        _window: &mut Window,
 6947        cx: &mut Context<Self>,
 6948    ) -> Option<()> {
 6949        let selection = self.selections.newest_anchor();
 6950        let cursor = selection.head();
 6951        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6952        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6953        let excerpt_id = cursor.excerpt_id;
 6954
 6955        let show_in_menu = self.show_edit_predictions_in_menu();
 6956        let completions_menu_has_precedence = !show_in_menu
 6957            && (self.context_menu.borrow().is_some()
 6958                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6959
 6960        if completions_menu_has_precedence
 6961            || !offset_selection.is_empty()
 6962            || self
 6963                .active_inline_completion
 6964                .as_ref()
 6965                .map_or(false, |completion| {
 6966                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6967                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6968                    !invalidation_range.contains(&offset_selection.head())
 6969                })
 6970        {
 6971            self.discard_inline_completion(false, cx);
 6972            return None;
 6973        }
 6974
 6975        self.take_active_inline_completion(cx);
 6976        let Some(provider) = self.edit_prediction_provider() else {
 6977            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6978            return None;
 6979        };
 6980
 6981        let (buffer, cursor_buffer_position) =
 6982            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6983
 6984        self.edit_prediction_settings =
 6985            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6986
 6987        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6988
 6989        if self.edit_prediction_indent_conflict {
 6990            let cursor_point = cursor.to_point(&multibuffer);
 6991
 6992            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6993
 6994            if let Some((_, indent)) = indents.iter().next() {
 6995                if indent.len == cursor_point.column {
 6996                    self.edit_prediction_indent_conflict = false;
 6997                }
 6998            }
 6999        }
 7000
 7001        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7002        let edits = inline_completion
 7003            .edits
 7004            .into_iter()
 7005            .flat_map(|(range, new_text)| {
 7006                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7007                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7008                Some((start..end, new_text))
 7009            })
 7010            .collect::<Vec<_>>();
 7011        if edits.is_empty() {
 7012            return None;
 7013        }
 7014
 7015        let first_edit_start = edits.first().unwrap().0.start;
 7016        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7017        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7018
 7019        let last_edit_end = edits.last().unwrap().0.end;
 7020        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7021        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7022
 7023        let cursor_row = cursor.to_point(&multibuffer).row;
 7024
 7025        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7026
 7027        let mut inlay_ids = Vec::new();
 7028        let invalidation_row_range;
 7029        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7030            Some(cursor_row..edit_end_row)
 7031        } else if cursor_row > edit_end_row {
 7032            Some(edit_start_row..cursor_row)
 7033        } else {
 7034            None
 7035        };
 7036        let is_move =
 7037            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7038        let completion = if is_move {
 7039            invalidation_row_range =
 7040                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7041            let target = first_edit_start;
 7042            InlineCompletion::Move { target, snapshot }
 7043        } else {
 7044            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7045                && !self.inline_completions_hidden_for_vim_mode;
 7046
 7047            if show_completions_in_buffer {
 7048                if edits
 7049                    .iter()
 7050                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7051                {
 7052                    let mut inlays = Vec::new();
 7053                    for (range, new_text) in &edits {
 7054                        let inlay = Inlay::inline_completion(
 7055                            post_inc(&mut self.next_inlay_id),
 7056                            range.start,
 7057                            new_text.as_str(),
 7058                        );
 7059                        inlay_ids.push(inlay.id);
 7060                        inlays.push(inlay);
 7061                    }
 7062
 7063                    self.splice_inlays(&[], inlays, cx);
 7064                } else {
 7065                    let background_color = cx.theme().status().deleted_background;
 7066                    self.highlight_text::<InlineCompletionHighlight>(
 7067                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7068                        HighlightStyle {
 7069                            background_color: Some(background_color),
 7070                            ..Default::default()
 7071                        },
 7072                        cx,
 7073                    );
 7074                }
 7075            }
 7076
 7077            invalidation_row_range = edit_start_row..edit_end_row;
 7078
 7079            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7080                if provider.show_tab_accept_marker() {
 7081                    EditDisplayMode::TabAccept
 7082                } else {
 7083                    EditDisplayMode::Inline
 7084                }
 7085            } else {
 7086                EditDisplayMode::DiffPopover
 7087            };
 7088
 7089            InlineCompletion::Edit {
 7090                edits,
 7091                edit_preview: inline_completion.edit_preview,
 7092                display_mode,
 7093                snapshot,
 7094            }
 7095        };
 7096
 7097        let invalidation_range = multibuffer
 7098            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7099            ..multibuffer.anchor_after(Point::new(
 7100                invalidation_row_range.end,
 7101                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7102            ));
 7103
 7104        self.stale_inline_completion_in_menu = None;
 7105        self.active_inline_completion = Some(InlineCompletionState {
 7106            inlay_ids,
 7107            completion,
 7108            completion_id: inline_completion.id,
 7109            invalidation_range,
 7110        });
 7111
 7112        cx.notify();
 7113
 7114        Some(())
 7115    }
 7116
 7117    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7118        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7119    }
 7120
 7121    fn clear_tasks(&mut self) {
 7122        self.tasks.clear()
 7123    }
 7124
 7125    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7126        if self.tasks.insert(key, value).is_some() {
 7127            // This case should hopefully be rare, but just in case...
 7128            log::error!(
 7129                "multiple different run targets found on a single line, only the last target will be rendered"
 7130            )
 7131        }
 7132    }
 7133
 7134    /// Get all display points of breakpoints that will be rendered within editor
 7135    ///
 7136    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7137    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7138    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7139    fn active_breakpoints(
 7140        &self,
 7141        range: Range<DisplayRow>,
 7142        window: &mut Window,
 7143        cx: &mut Context<Self>,
 7144    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7145        let mut breakpoint_display_points = HashMap::default();
 7146
 7147        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7148            return breakpoint_display_points;
 7149        };
 7150
 7151        let snapshot = self.snapshot(window, cx);
 7152
 7153        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7154        let Some(project) = self.project.as_ref() else {
 7155            return breakpoint_display_points;
 7156        };
 7157
 7158        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7159            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7160
 7161        for (buffer_snapshot, range, excerpt_id) in
 7162            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7163        {
 7164            let Some(buffer) = project
 7165                .read(cx)
 7166                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7167            else {
 7168                continue;
 7169            };
 7170            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7171                &buffer,
 7172                Some(
 7173                    buffer_snapshot.anchor_before(range.start)
 7174                        ..buffer_snapshot.anchor_after(range.end),
 7175                ),
 7176                buffer_snapshot,
 7177                cx,
 7178            );
 7179            for (breakpoint, state) in breakpoints {
 7180                let multi_buffer_anchor =
 7181                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7182                let position = multi_buffer_anchor
 7183                    .to_point(&multi_buffer_snapshot)
 7184                    .to_display_point(&snapshot);
 7185
 7186                breakpoint_display_points.insert(
 7187                    position.row(),
 7188                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7189                );
 7190            }
 7191        }
 7192
 7193        breakpoint_display_points
 7194    }
 7195
 7196    fn breakpoint_context_menu(
 7197        &self,
 7198        anchor: Anchor,
 7199        window: &mut Window,
 7200        cx: &mut Context<Self>,
 7201    ) -> Entity<ui::ContextMenu> {
 7202        let weak_editor = cx.weak_entity();
 7203        let focus_handle = self.focus_handle(cx);
 7204
 7205        let row = self
 7206            .buffer
 7207            .read(cx)
 7208            .snapshot(cx)
 7209            .summary_for_anchor::<Point>(&anchor)
 7210            .row;
 7211
 7212        let breakpoint = self
 7213            .breakpoint_at_row(row, window, cx)
 7214            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7215
 7216        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7217            "Edit Log Breakpoint"
 7218        } else {
 7219            "Set Log Breakpoint"
 7220        };
 7221
 7222        let condition_breakpoint_msg = if breakpoint
 7223            .as_ref()
 7224            .is_some_and(|bp| bp.1.condition.is_some())
 7225        {
 7226            "Edit Condition Breakpoint"
 7227        } else {
 7228            "Set Condition Breakpoint"
 7229        };
 7230
 7231        let hit_condition_breakpoint_msg = if breakpoint
 7232            .as_ref()
 7233            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7234        {
 7235            "Edit Hit Condition Breakpoint"
 7236        } else {
 7237            "Set Hit Condition Breakpoint"
 7238        };
 7239
 7240        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7241            "Unset Breakpoint"
 7242        } else {
 7243            "Set Breakpoint"
 7244        };
 7245
 7246        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7247            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7248
 7249        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7250            BreakpointState::Enabled => Some("Disable"),
 7251            BreakpointState::Disabled => Some("Enable"),
 7252        });
 7253
 7254        let (anchor, breakpoint) =
 7255            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7256
 7257        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7258            menu.on_blur_subscription(Subscription::new(|| {}))
 7259                .context(focus_handle)
 7260                .when(run_to_cursor, |this| {
 7261                    let weak_editor = weak_editor.clone();
 7262                    this.entry("Run to cursor", None, move |window, cx| {
 7263                        weak_editor
 7264                            .update(cx, |editor, cx| {
 7265                                editor.change_selections(None, window, cx, |s| {
 7266                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7267                                });
 7268                            })
 7269                            .ok();
 7270
 7271                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7272                    })
 7273                    .separator()
 7274                })
 7275                .when_some(toggle_state_msg, |this, msg| {
 7276                    this.entry(msg, None, {
 7277                        let weak_editor = weak_editor.clone();
 7278                        let breakpoint = breakpoint.clone();
 7279                        move |_window, cx| {
 7280                            weak_editor
 7281                                .update(cx, |this, cx| {
 7282                                    this.edit_breakpoint_at_anchor(
 7283                                        anchor,
 7284                                        breakpoint.as_ref().clone(),
 7285                                        BreakpointEditAction::InvertState,
 7286                                        cx,
 7287                                    );
 7288                                })
 7289                                .log_err();
 7290                        }
 7291                    })
 7292                })
 7293                .entry(set_breakpoint_msg, None, {
 7294                    let weak_editor = weak_editor.clone();
 7295                    let breakpoint = breakpoint.clone();
 7296                    move |_window, cx| {
 7297                        weak_editor
 7298                            .update(cx, |this, cx| {
 7299                                this.edit_breakpoint_at_anchor(
 7300                                    anchor,
 7301                                    breakpoint.as_ref().clone(),
 7302                                    BreakpointEditAction::Toggle,
 7303                                    cx,
 7304                                );
 7305                            })
 7306                            .log_err();
 7307                    }
 7308                })
 7309                .entry(log_breakpoint_msg, None, {
 7310                    let breakpoint = breakpoint.clone();
 7311                    let weak_editor = weak_editor.clone();
 7312                    move |window, cx| {
 7313                        weak_editor
 7314                            .update(cx, |this, cx| {
 7315                                this.add_edit_breakpoint_block(
 7316                                    anchor,
 7317                                    breakpoint.as_ref(),
 7318                                    BreakpointPromptEditAction::Log,
 7319                                    window,
 7320                                    cx,
 7321                                );
 7322                            })
 7323                            .log_err();
 7324                    }
 7325                })
 7326                .entry(condition_breakpoint_msg, None, {
 7327                    let breakpoint = breakpoint.clone();
 7328                    let weak_editor = weak_editor.clone();
 7329                    move |window, cx| {
 7330                        weak_editor
 7331                            .update(cx, |this, cx| {
 7332                                this.add_edit_breakpoint_block(
 7333                                    anchor,
 7334                                    breakpoint.as_ref(),
 7335                                    BreakpointPromptEditAction::Condition,
 7336                                    window,
 7337                                    cx,
 7338                                );
 7339                            })
 7340                            .log_err();
 7341                    }
 7342                })
 7343                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7344                    weak_editor
 7345                        .update(cx, |this, cx| {
 7346                            this.add_edit_breakpoint_block(
 7347                                anchor,
 7348                                breakpoint.as_ref(),
 7349                                BreakpointPromptEditAction::HitCondition,
 7350                                window,
 7351                                cx,
 7352                            );
 7353                        })
 7354                        .log_err();
 7355                })
 7356        })
 7357    }
 7358
 7359    fn render_breakpoint(
 7360        &self,
 7361        position: Anchor,
 7362        row: DisplayRow,
 7363        breakpoint: &Breakpoint,
 7364        state: Option<BreakpointSessionState>,
 7365        cx: &mut Context<Self>,
 7366    ) -> IconButton {
 7367        let is_rejected = state.is_some_and(|s| !s.verified);
 7368        // Is it a breakpoint that shows up when hovering over gutter?
 7369        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7370            (false, false),
 7371            |PhantomBreakpointIndicator {
 7372                 is_active,
 7373                 display_row,
 7374                 collides_with_existing_breakpoint,
 7375             }| {
 7376                (
 7377                    is_active && display_row == row,
 7378                    collides_with_existing_breakpoint,
 7379                )
 7380            },
 7381        );
 7382
 7383        let (color, icon) = {
 7384            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7385                (false, false) => ui::IconName::DebugBreakpoint,
 7386                (true, false) => ui::IconName::DebugLogBreakpoint,
 7387                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7388                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7389            };
 7390
 7391            let color = if is_phantom {
 7392                Color::Hint
 7393            } else if is_rejected {
 7394                Color::Disabled
 7395            } else {
 7396                Color::Debugger
 7397            };
 7398
 7399            (color, icon)
 7400        };
 7401
 7402        let breakpoint = Arc::from(breakpoint.clone());
 7403
 7404        let alt_as_text = gpui::Keystroke {
 7405            modifiers: Modifiers::secondary_key(),
 7406            ..Default::default()
 7407        };
 7408        let primary_action_text = if breakpoint.is_disabled() {
 7409            "Enable breakpoint"
 7410        } else if is_phantom && !collides_with_existing {
 7411            "Set breakpoint"
 7412        } else {
 7413            "Unset breakpoint"
 7414        };
 7415        let focus_handle = self.focus_handle.clone();
 7416
 7417        let meta = if is_rejected {
 7418            SharedString::from("No executable code is associated with this line.")
 7419        } else if collides_with_existing && !breakpoint.is_disabled() {
 7420            SharedString::from(format!(
 7421                "{alt_as_text}-click to disable,\nright-click for more options."
 7422            ))
 7423        } else {
 7424            SharedString::from("Right-click for more options.")
 7425        };
 7426        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7427            .icon_size(IconSize::XSmall)
 7428            .size(ui::ButtonSize::None)
 7429            .when(is_rejected, |this| {
 7430                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7431            })
 7432            .icon_color(color)
 7433            .style(ButtonStyle::Transparent)
 7434            .on_click(cx.listener({
 7435                let breakpoint = breakpoint.clone();
 7436
 7437                move |editor, event: &ClickEvent, window, cx| {
 7438                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7439                        BreakpointEditAction::InvertState
 7440                    } else {
 7441                        BreakpointEditAction::Toggle
 7442                    };
 7443
 7444                    window.focus(&editor.focus_handle(cx));
 7445                    editor.edit_breakpoint_at_anchor(
 7446                        position,
 7447                        breakpoint.as_ref().clone(),
 7448                        edit_action,
 7449                        cx,
 7450                    );
 7451                }
 7452            }))
 7453            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7454                editor.set_breakpoint_context_menu(
 7455                    row,
 7456                    Some(position),
 7457                    event.down.position,
 7458                    window,
 7459                    cx,
 7460                );
 7461            }))
 7462            .tooltip(move |window, cx| {
 7463                Tooltip::with_meta_in(
 7464                    primary_action_text,
 7465                    Some(&ToggleBreakpoint),
 7466                    meta.clone(),
 7467                    &focus_handle,
 7468                    window,
 7469                    cx,
 7470                )
 7471            })
 7472    }
 7473
 7474    fn build_tasks_context(
 7475        project: &Entity<Project>,
 7476        buffer: &Entity<Buffer>,
 7477        buffer_row: u32,
 7478        tasks: &Arc<RunnableTasks>,
 7479        cx: &mut Context<Self>,
 7480    ) -> Task<Option<task::TaskContext>> {
 7481        let position = Point::new(buffer_row, tasks.column);
 7482        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7483        let location = Location {
 7484            buffer: buffer.clone(),
 7485            range: range_start..range_start,
 7486        };
 7487        // Fill in the environmental variables from the tree-sitter captures
 7488        let mut captured_task_variables = TaskVariables::default();
 7489        for (capture_name, value) in tasks.extra_variables.clone() {
 7490            captured_task_variables.insert(
 7491                task::VariableName::Custom(capture_name.into()),
 7492                value.clone(),
 7493            );
 7494        }
 7495        project.update(cx, |project, cx| {
 7496            project.task_store().update(cx, |task_store, cx| {
 7497                task_store.task_context_for_location(captured_task_variables, location, cx)
 7498            })
 7499        })
 7500    }
 7501
 7502    pub fn spawn_nearest_task(
 7503        &mut self,
 7504        action: &SpawnNearestTask,
 7505        window: &mut Window,
 7506        cx: &mut Context<Self>,
 7507    ) {
 7508        let Some((workspace, _)) = self.workspace.clone() else {
 7509            return;
 7510        };
 7511        let Some(project) = self.project.clone() else {
 7512            return;
 7513        };
 7514
 7515        // Try to find a closest, enclosing node using tree-sitter that has a
 7516        // task
 7517        let Some((buffer, buffer_row, tasks)) = self
 7518            .find_enclosing_node_task(cx)
 7519            // Or find the task that's closest in row-distance.
 7520            .or_else(|| self.find_closest_task(cx))
 7521        else {
 7522            return;
 7523        };
 7524
 7525        let reveal_strategy = action.reveal;
 7526        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7527        cx.spawn_in(window, async move |_, cx| {
 7528            let context = task_context.await?;
 7529            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7530
 7531            let resolved = &mut resolved_task.resolved;
 7532            resolved.reveal = reveal_strategy;
 7533
 7534            workspace
 7535                .update_in(cx, |workspace, window, cx| {
 7536                    workspace.schedule_resolved_task(
 7537                        task_source_kind,
 7538                        resolved_task,
 7539                        false,
 7540                        window,
 7541                        cx,
 7542                    );
 7543                })
 7544                .ok()
 7545        })
 7546        .detach();
 7547    }
 7548
 7549    fn find_closest_task(
 7550        &mut self,
 7551        cx: &mut Context<Self>,
 7552    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7553        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7554
 7555        let ((buffer_id, row), tasks) = self
 7556            .tasks
 7557            .iter()
 7558            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7559
 7560        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7561        let tasks = Arc::new(tasks.to_owned());
 7562        Some((buffer, *row, tasks))
 7563    }
 7564
 7565    fn find_enclosing_node_task(
 7566        &mut self,
 7567        cx: &mut Context<Self>,
 7568    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7569        let snapshot = self.buffer.read(cx).snapshot(cx);
 7570        let offset = self.selections.newest::<usize>(cx).head();
 7571        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7572        let buffer_id = excerpt.buffer().remote_id();
 7573
 7574        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7575        let mut cursor = layer.node().walk();
 7576
 7577        while cursor.goto_first_child_for_byte(offset).is_some() {
 7578            if cursor.node().end_byte() == offset {
 7579                cursor.goto_next_sibling();
 7580            }
 7581        }
 7582
 7583        // Ascend to the smallest ancestor that contains the range and has a task.
 7584        loop {
 7585            let node = cursor.node();
 7586            let node_range = node.byte_range();
 7587            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7588
 7589            // Check if this node contains our offset
 7590            if node_range.start <= offset && node_range.end >= offset {
 7591                // If it contains offset, check for task
 7592                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7593                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7594                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7595                }
 7596            }
 7597
 7598            if !cursor.goto_parent() {
 7599                break;
 7600            }
 7601        }
 7602        None
 7603    }
 7604
 7605    fn render_run_indicator(
 7606        &self,
 7607        _style: &EditorStyle,
 7608        is_active: bool,
 7609        row: DisplayRow,
 7610        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7611        cx: &mut Context<Self>,
 7612    ) -> IconButton {
 7613        let color = Color::Muted;
 7614        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7615
 7616        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7617            .shape(ui::IconButtonShape::Square)
 7618            .icon_size(IconSize::XSmall)
 7619            .icon_color(color)
 7620            .toggle_state(is_active)
 7621            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7622                let quick_launch = e.down.button == MouseButton::Left;
 7623                window.focus(&editor.focus_handle(cx));
 7624                editor.toggle_code_actions(
 7625                    &ToggleCodeActions {
 7626                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7627                        quick_launch,
 7628                    },
 7629                    window,
 7630                    cx,
 7631                );
 7632            }))
 7633            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7634                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7635            }))
 7636    }
 7637
 7638    pub fn context_menu_visible(&self) -> bool {
 7639        !self.edit_prediction_preview_is_active()
 7640            && self
 7641                .context_menu
 7642                .borrow()
 7643                .as_ref()
 7644                .map_or(false, |menu| menu.visible())
 7645    }
 7646
 7647    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7648        self.context_menu
 7649            .borrow()
 7650            .as_ref()
 7651            .map(|menu| menu.origin())
 7652    }
 7653
 7654    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7655        self.context_menu_options = Some(options);
 7656    }
 7657
 7658    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7659    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7660
 7661    fn render_edit_prediction_popover(
 7662        &mut self,
 7663        text_bounds: &Bounds<Pixels>,
 7664        content_origin: gpui::Point<Pixels>,
 7665        right_margin: Pixels,
 7666        editor_snapshot: &EditorSnapshot,
 7667        visible_row_range: Range<DisplayRow>,
 7668        scroll_top: f32,
 7669        scroll_bottom: f32,
 7670        line_layouts: &[LineWithInvisibles],
 7671        line_height: Pixels,
 7672        scroll_pixel_position: gpui::Point<Pixels>,
 7673        newest_selection_head: Option<DisplayPoint>,
 7674        editor_width: Pixels,
 7675        style: &EditorStyle,
 7676        window: &mut Window,
 7677        cx: &mut App,
 7678    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7679        if self.mode().is_minimap() {
 7680            return None;
 7681        }
 7682        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7683
 7684        if self.edit_prediction_visible_in_cursor_popover(true) {
 7685            return None;
 7686        }
 7687
 7688        match &active_inline_completion.completion {
 7689            InlineCompletion::Move { target, .. } => {
 7690                let target_display_point = target.to_display_point(editor_snapshot);
 7691
 7692                if self.edit_prediction_requires_modifier() {
 7693                    if !self.edit_prediction_preview_is_active() {
 7694                        return None;
 7695                    }
 7696
 7697                    self.render_edit_prediction_modifier_jump_popover(
 7698                        text_bounds,
 7699                        content_origin,
 7700                        visible_row_range,
 7701                        line_layouts,
 7702                        line_height,
 7703                        scroll_pixel_position,
 7704                        newest_selection_head,
 7705                        target_display_point,
 7706                        window,
 7707                        cx,
 7708                    )
 7709                } else {
 7710                    self.render_edit_prediction_eager_jump_popover(
 7711                        text_bounds,
 7712                        content_origin,
 7713                        editor_snapshot,
 7714                        visible_row_range,
 7715                        scroll_top,
 7716                        scroll_bottom,
 7717                        line_height,
 7718                        scroll_pixel_position,
 7719                        target_display_point,
 7720                        editor_width,
 7721                        window,
 7722                        cx,
 7723                    )
 7724                }
 7725            }
 7726            InlineCompletion::Edit {
 7727                display_mode: EditDisplayMode::Inline,
 7728                ..
 7729            } => None,
 7730            InlineCompletion::Edit {
 7731                display_mode: EditDisplayMode::TabAccept,
 7732                edits,
 7733                ..
 7734            } => {
 7735                let range = &edits.first()?.0;
 7736                let target_display_point = range.end.to_display_point(editor_snapshot);
 7737
 7738                self.render_edit_prediction_end_of_line_popover(
 7739                    "Accept",
 7740                    editor_snapshot,
 7741                    visible_row_range,
 7742                    target_display_point,
 7743                    line_height,
 7744                    scroll_pixel_position,
 7745                    content_origin,
 7746                    editor_width,
 7747                    window,
 7748                    cx,
 7749                )
 7750            }
 7751            InlineCompletion::Edit {
 7752                edits,
 7753                edit_preview,
 7754                display_mode: EditDisplayMode::DiffPopover,
 7755                snapshot,
 7756            } => self.render_edit_prediction_diff_popover(
 7757                text_bounds,
 7758                content_origin,
 7759                right_margin,
 7760                editor_snapshot,
 7761                visible_row_range,
 7762                line_layouts,
 7763                line_height,
 7764                scroll_pixel_position,
 7765                newest_selection_head,
 7766                editor_width,
 7767                style,
 7768                edits,
 7769                edit_preview,
 7770                snapshot,
 7771                window,
 7772                cx,
 7773            ),
 7774        }
 7775    }
 7776
 7777    fn render_edit_prediction_modifier_jump_popover(
 7778        &mut self,
 7779        text_bounds: &Bounds<Pixels>,
 7780        content_origin: gpui::Point<Pixels>,
 7781        visible_row_range: Range<DisplayRow>,
 7782        line_layouts: &[LineWithInvisibles],
 7783        line_height: Pixels,
 7784        scroll_pixel_position: gpui::Point<Pixels>,
 7785        newest_selection_head: Option<DisplayPoint>,
 7786        target_display_point: DisplayPoint,
 7787        window: &mut Window,
 7788        cx: &mut App,
 7789    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7790        let scrolled_content_origin =
 7791            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7792
 7793        const SCROLL_PADDING_Y: Pixels = px(12.);
 7794
 7795        if target_display_point.row() < visible_row_range.start {
 7796            return self.render_edit_prediction_scroll_popover(
 7797                |_| SCROLL_PADDING_Y,
 7798                IconName::ArrowUp,
 7799                visible_row_range,
 7800                line_layouts,
 7801                newest_selection_head,
 7802                scrolled_content_origin,
 7803                window,
 7804                cx,
 7805            );
 7806        } else if target_display_point.row() >= visible_row_range.end {
 7807            return self.render_edit_prediction_scroll_popover(
 7808                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7809                IconName::ArrowDown,
 7810                visible_row_range,
 7811                line_layouts,
 7812                newest_selection_head,
 7813                scrolled_content_origin,
 7814                window,
 7815                cx,
 7816            );
 7817        }
 7818
 7819        const POLE_WIDTH: Pixels = px(2.);
 7820
 7821        let line_layout =
 7822            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7823        let target_column = target_display_point.column() as usize;
 7824
 7825        let target_x = line_layout.x_for_index(target_column);
 7826        let target_y =
 7827            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7828
 7829        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7830
 7831        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7832        border_color.l += 0.001;
 7833
 7834        let mut element = v_flex()
 7835            .items_end()
 7836            .when(flag_on_right, |el| el.items_start())
 7837            .child(if flag_on_right {
 7838                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7839                    .rounded_bl(px(0.))
 7840                    .rounded_tl(px(0.))
 7841                    .border_l_2()
 7842                    .border_color(border_color)
 7843            } else {
 7844                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7845                    .rounded_br(px(0.))
 7846                    .rounded_tr(px(0.))
 7847                    .border_r_2()
 7848                    .border_color(border_color)
 7849            })
 7850            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7851            .into_any();
 7852
 7853        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7854
 7855        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7856            - point(
 7857                if flag_on_right {
 7858                    POLE_WIDTH
 7859                } else {
 7860                    size.width - POLE_WIDTH
 7861                },
 7862                size.height - line_height,
 7863            );
 7864
 7865        origin.x = origin.x.max(content_origin.x);
 7866
 7867        element.prepaint_at(origin, window, cx);
 7868
 7869        Some((element, origin))
 7870    }
 7871
 7872    fn render_edit_prediction_scroll_popover(
 7873        &mut self,
 7874        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7875        scroll_icon: IconName,
 7876        visible_row_range: Range<DisplayRow>,
 7877        line_layouts: &[LineWithInvisibles],
 7878        newest_selection_head: Option<DisplayPoint>,
 7879        scrolled_content_origin: gpui::Point<Pixels>,
 7880        window: &mut Window,
 7881        cx: &mut App,
 7882    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7883        let mut element = self
 7884            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7885            .into_any();
 7886
 7887        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7888
 7889        let cursor = newest_selection_head?;
 7890        let cursor_row_layout =
 7891            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7892        let cursor_column = cursor.column() as usize;
 7893
 7894        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7895
 7896        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7897
 7898        element.prepaint_at(origin, window, cx);
 7899        Some((element, origin))
 7900    }
 7901
 7902    fn render_edit_prediction_eager_jump_popover(
 7903        &mut self,
 7904        text_bounds: &Bounds<Pixels>,
 7905        content_origin: gpui::Point<Pixels>,
 7906        editor_snapshot: &EditorSnapshot,
 7907        visible_row_range: Range<DisplayRow>,
 7908        scroll_top: f32,
 7909        scroll_bottom: f32,
 7910        line_height: Pixels,
 7911        scroll_pixel_position: gpui::Point<Pixels>,
 7912        target_display_point: DisplayPoint,
 7913        editor_width: Pixels,
 7914        window: &mut Window,
 7915        cx: &mut App,
 7916    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7917        if target_display_point.row().as_f32() < scroll_top {
 7918            let mut element = self
 7919                .render_edit_prediction_line_popover(
 7920                    "Jump to Edit",
 7921                    Some(IconName::ArrowUp),
 7922                    window,
 7923                    cx,
 7924                )?
 7925                .into_any();
 7926
 7927            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7928            let offset = point(
 7929                (text_bounds.size.width - size.width) / 2.,
 7930                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7931            );
 7932
 7933            let origin = text_bounds.origin + offset;
 7934            element.prepaint_at(origin, window, cx);
 7935            Some((element, origin))
 7936        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7937            let mut element = self
 7938                .render_edit_prediction_line_popover(
 7939                    "Jump to Edit",
 7940                    Some(IconName::ArrowDown),
 7941                    window,
 7942                    cx,
 7943                )?
 7944                .into_any();
 7945
 7946            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7947            let offset = point(
 7948                (text_bounds.size.width - size.width) / 2.,
 7949                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7950            );
 7951
 7952            let origin = text_bounds.origin + offset;
 7953            element.prepaint_at(origin, window, cx);
 7954            Some((element, origin))
 7955        } else {
 7956            self.render_edit_prediction_end_of_line_popover(
 7957                "Jump to Edit",
 7958                editor_snapshot,
 7959                visible_row_range,
 7960                target_display_point,
 7961                line_height,
 7962                scroll_pixel_position,
 7963                content_origin,
 7964                editor_width,
 7965                window,
 7966                cx,
 7967            )
 7968        }
 7969    }
 7970
 7971    fn render_edit_prediction_end_of_line_popover(
 7972        self: &mut Editor,
 7973        label: &'static str,
 7974        editor_snapshot: &EditorSnapshot,
 7975        visible_row_range: Range<DisplayRow>,
 7976        target_display_point: DisplayPoint,
 7977        line_height: Pixels,
 7978        scroll_pixel_position: gpui::Point<Pixels>,
 7979        content_origin: gpui::Point<Pixels>,
 7980        editor_width: Pixels,
 7981        window: &mut Window,
 7982        cx: &mut App,
 7983    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7984        let target_line_end = DisplayPoint::new(
 7985            target_display_point.row(),
 7986            editor_snapshot.line_len(target_display_point.row()),
 7987        );
 7988
 7989        let mut element = self
 7990            .render_edit_prediction_line_popover(label, None, window, cx)?
 7991            .into_any();
 7992
 7993        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7994
 7995        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7996
 7997        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7998        let mut origin = start_point
 7999            + line_origin
 8000            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8001        origin.x = origin.x.max(content_origin.x);
 8002
 8003        let max_x = content_origin.x + editor_width - size.width;
 8004
 8005        if origin.x > max_x {
 8006            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8007
 8008            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8009                origin.y += offset;
 8010                IconName::ArrowUp
 8011            } else {
 8012                origin.y -= offset;
 8013                IconName::ArrowDown
 8014            };
 8015
 8016            element = self
 8017                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8018                .into_any();
 8019
 8020            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8021
 8022            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8023        }
 8024
 8025        element.prepaint_at(origin, window, cx);
 8026        Some((element, origin))
 8027    }
 8028
 8029    fn render_edit_prediction_diff_popover(
 8030        self: &Editor,
 8031        text_bounds: &Bounds<Pixels>,
 8032        content_origin: gpui::Point<Pixels>,
 8033        right_margin: Pixels,
 8034        editor_snapshot: &EditorSnapshot,
 8035        visible_row_range: Range<DisplayRow>,
 8036        line_layouts: &[LineWithInvisibles],
 8037        line_height: Pixels,
 8038        scroll_pixel_position: gpui::Point<Pixels>,
 8039        newest_selection_head: Option<DisplayPoint>,
 8040        editor_width: Pixels,
 8041        style: &EditorStyle,
 8042        edits: &Vec<(Range<Anchor>, String)>,
 8043        edit_preview: &Option<language::EditPreview>,
 8044        snapshot: &language::BufferSnapshot,
 8045        window: &mut Window,
 8046        cx: &mut App,
 8047    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8048        let edit_start = edits
 8049            .first()
 8050            .unwrap()
 8051            .0
 8052            .start
 8053            .to_display_point(editor_snapshot);
 8054        let edit_end = edits
 8055            .last()
 8056            .unwrap()
 8057            .0
 8058            .end
 8059            .to_display_point(editor_snapshot);
 8060
 8061        let is_visible = visible_row_range.contains(&edit_start.row())
 8062            || visible_row_range.contains(&edit_end.row());
 8063        if !is_visible {
 8064            return None;
 8065        }
 8066
 8067        let highlighted_edits =
 8068            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8069
 8070        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8071        let line_count = highlighted_edits.text.lines().count();
 8072
 8073        const BORDER_WIDTH: Pixels = px(1.);
 8074
 8075        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8076        let has_keybind = keybind.is_some();
 8077
 8078        let mut element = h_flex()
 8079            .items_start()
 8080            .child(
 8081                h_flex()
 8082                    .bg(cx.theme().colors().editor_background)
 8083                    .border(BORDER_WIDTH)
 8084                    .shadow_sm()
 8085                    .border_color(cx.theme().colors().border)
 8086                    .rounded_l_lg()
 8087                    .when(line_count > 1, |el| el.rounded_br_lg())
 8088                    .pr_1()
 8089                    .child(styled_text),
 8090            )
 8091            .child(
 8092                h_flex()
 8093                    .h(line_height + BORDER_WIDTH * 2.)
 8094                    .px_1p5()
 8095                    .gap_1()
 8096                    // Workaround: For some reason, there's a gap if we don't do this
 8097                    .ml(-BORDER_WIDTH)
 8098                    .shadow(vec![gpui::BoxShadow {
 8099                        color: gpui::black().opacity(0.05),
 8100                        offset: point(px(1.), px(1.)),
 8101                        blur_radius: px(2.),
 8102                        spread_radius: px(0.),
 8103                    }])
 8104                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8105                    .border(BORDER_WIDTH)
 8106                    .border_color(cx.theme().colors().border)
 8107                    .rounded_r_lg()
 8108                    .id("edit_prediction_diff_popover_keybind")
 8109                    .when(!has_keybind, |el| {
 8110                        let status_colors = cx.theme().status();
 8111
 8112                        el.bg(status_colors.error_background)
 8113                            .border_color(status_colors.error.opacity(0.6))
 8114                            .child(Icon::new(IconName::Info).color(Color::Error))
 8115                            .cursor_default()
 8116                            .hoverable_tooltip(move |_window, cx| {
 8117                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8118                            })
 8119                    })
 8120                    .children(keybind),
 8121            )
 8122            .into_any();
 8123
 8124        let longest_row =
 8125            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8126        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8127            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8128        } else {
 8129            layout_line(
 8130                longest_row,
 8131                editor_snapshot,
 8132                style,
 8133                editor_width,
 8134                |_| false,
 8135                window,
 8136                cx,
 8137            )
 8138            .width
 8139        };
 8140
 8141        let viewport_bounds =
 8142            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8143                right: -right_margin,
 8144                ..Default::default()
 8145            });
 8146
 8147        let x_after_longest =
 8148            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8149                - scroll_pixel_position.x;
 8150
 8151        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8152
 8153        // Fully visible if it can be displayed within the window (allow overlapping other
 8154        // panes). However, this is only allowed if the popover starts within text_bounds.
 8155        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8156            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8157
 8158        let mut origin = if can_position_to_the_right {
 8159            point(
 8160                x_after_longest,
 8161                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8162                    - scroll_pixel_position.y,
 8163            )
 8164        } else {
 8165            let cursor_row = newest_selection_head.map(|head| head.row());
 8166            let above_edit = edit_start
 8167                .row()
 8168                .0
 8169                .checked_sub(line_count as u32)
 8170                .map(DisplayRow);
 8171            let below_edit = Some(edit_end.row() + 1);
 8172            let above_cursor =
 8173                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8174            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8175
 8176            // Place the edit popover adjacent to the edit if there is a location
 8177            // available that is onscreen and does not obscure the cursor. Otherwise,
 8178            // place it adjacent to the cursor.
 8179            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8180                .into_iter()
 8181                .flatten()
 8182                .find(|&start_row| {
 8183                    let end_row = start_row + line_count as u32;
 8184                    visible_row_range.contains(&start_row)
 8185                        && visible_row_range.contains(&end_row)
 8186                        && cursor_row.map_or(true, |cursor_row| {
 8187                            !((start_row..end_row).contains(&cursor_row))
 8188                        })
 8189                })?;
 8190
 8191            content_origin
 8192                + point(
 8193                    -scroll_pixel_position.x,
 8194                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8195                )
 8196        };
 8197
 8198        origin.x -= BORDER_WIDTH;
 8199
 8200        window.defer_draw(element, origin, 1);
 8201
 8202        // Do not return an element, since it will already be drawn due to defer_draw.
 8203        None
 8204    }
 8205
 8206    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8207        px(30.)
 8208    }
 8209
 8210    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8211        if self.read_only(cx) {
 8212            cx.theme().players().read_only()
 8213        } else {
 8214            self.style.as_ref().unwrap().local_player
 8215        }
 8216    }
 8217
 8218    fn render_edit_prediction_accept_keybind(
 8219        &self,
 8220        window: &mut Window,
 8221        cx: &App,
 8222    ) -> Option<AnyElement> {
 8223        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8224        let accept_keystroke = accept_binding.keystroke()?;
 8225
 8226        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8227
 8228        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8229            Color::Accent
 8230        } else {
 8231            Color::Muted
 8232        };
 8233
 8234        h_flex()
 8235            .px_0p5()
 8236            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8237            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8238            .text_size(TextSize::XSmall.rems(cx))
 8239            .child(h_flex().children(ui::render_modifiers(
 8240                &accept_keystroke.modifiers,
 8241                PlatformStyle::platform(),
 8242                Some(modifiers_color),
 8243                Some(IconSize::XSmall.rems().into()),
 8244                true,
 8245            )))
 8246            .when(is_platform_style_mac, |parent| {
 8247                parent.child(accept_keystroke.key.clone())
 8248            })
 8249            .when(!is_platform_style_mac, |parent| {
 8250                parent.child(
 8251                    Key::new(
 8252                        util::capitalize(&accept_keystroke.key),
 8253                        Some(Color::Default),
 8254                    )
 8255                    .size(Some(IconSize::XSmall.rems().into())),
 8256                )
 8257            })
 8258            .into_any()
 8259            .into()
 8260    }
 8261
 8262    fn render_edit_prediction_line_popover(
 8263        &self,
 8264        label: impl Into<SharedString>,
 8265        icon: Option<IconName>,
 8266        window: &mut Window,
 8267        cx: &App,
 8268    ) -> Option<Stateful<Div>> {
 8269        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8270
 8271        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8272        let has_keybind = keybind.is_some();
 8273
 8274        let result = h_flex()
 8275            .id("ep-line-popover")
 8276            .py_0p5()
 8277            .pl_1()
 8278            .pr(padding_right)
 8279            .gap_1()
 8280            .rounded_md()
 8281            .border_1()
 8282            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8283            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8284            .shadow_sm()
 8285            .when(!has_keybind, |el| {
 8286                let status_colors = cx.theme().status();
 8287
 8288                el.bg(status_colors.error_background)
 8289                    .border_color(status_colors.error.opacity(0.6))
 8290                    .pl_2()
 8291                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8292                    .cursor_default()
 8293                    .hoverable_tooltip(move |_window, cx| {
 8294                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8295                    })
 8296            })
 8297            .children(keybind)
 8298            .child(
 8299                Label::new(label)
 8300                    .size(LabelSize::Small)
 8301                    .when(!has_keybind, |el| {
 8302                        el.color(cx.theme().status().error.into()).strikethrough()
 8303                    }),
 8304            )
 8305            .when(!has_keybind, |el| {
 8306                el.child(
 8307                    h_flex().ml_1().child(
 8308                        Icon::new(IconName::Info)
 8309                            .size(IconSize::Small)
 8310                            .color(cx.theme().status().error.into()),
 8311                    ),
 8312                )
 8313            })
 8314            .when_some(icon, |element, icon| {
 8315                element.child(
 8316                    div()
 8317                        .mt(px(1.5))
 8318                        .child(Icon::new(icon).size(IconSize::Small)),
 8319                )
 8320            });
 8321
 8322        Some(result)
 8323    }
 8324
 8325    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8326        let accent_color = cx.theme().colors().text_accent;
 8327        let editor_bg_color = cx.theme().colors().editor_background;
 8328        editor_bg_color.blend(accent_color.opacity(0.1))
 8329    }
 8330
 8331    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8332        let accent_color = cx.theme().colors().text_accent;
 8333        let editor_bg_color = cx.theme().colors().editor_background;
 8334        editor_bg_color.blend(accent_color.opacity(0.6))
 8335    }
 8336
 8337    fn render_edit_prediction_cursor_popover(
 8338        &self,
 8339        min_width: Pixels,
 8340        max_width: Pixels,
 8341        cursor_point: Point,
 8342        style: &EditorStyle,
 8343        accept_keystroke: Option<&gpui::Keystroke>,
 8344        _window: &Window,
 8345        cx: &mut Context<Editor>,
 8346    ) -> Option<AnyElement> {
 8347        let provider = self.edit_prediction_provider.as_ref()?;
 8348
 8349        if provider.provider.needs_terms_acceptance(cx) {
 8350            return Some(
 8351                h_flex()
 8352                    .min_w(min_width)
 8353                    .flex_1()
 8354                    .px_2()
 8355                    .py_1()
 8356                    .gap_3()
 8357                    .elevation_2(cx)
 8358                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8359                    .id("accept-terms")
 8360                    .cursor_pointer()
 8361                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8362                    .on_click(cx.listener(|this, _event, window, cx| {
 8363                        cx.stop_propagation();
 8364                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8365                        window.dispatch_action(
 8366                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8367                            cx,
 8368                        );
 8369                    }))
 8370                    .child(
 8371                        h_flex()
 8372                            .flex_1()
 8373                            .gap_2()
 8374                            .child(Icon::new(IconName::ZedPredict))
 8375                            .child(Label::new("Accept Terms of Service"))
 8376                            .child(div().w_full())
 8377                            .child(
 8378                                Icon::new(IconName::ArrowUpRight)
 8379                                    .color(Color::Muted)
 8380                                    .size(IconSize::Small),
 8381                            )
 8382                            .into_any_element(),
 8383                    )
 8384                    .into_any(),
 8385            );
 8386        }
 8387
 8388        let is_refreshing = provider.provider.is_refreshing(cx);
 8389
 8390        fn pending_completion_container() -> Div {
 8391            h_flex()
 8392                .h_full()
 8393                .flex_1()
 8394                .gap_2()
 8395                .child(Icon::new(IconName::ZedPredict))
 8396        }
 8397
 8398        let completion = match &self.active_inline_completion {
 8399            Some(prediction) => {
 8400                if !self.has_visible_completions_menu() {
 8401                    const RADIUS: Pixels = px(6.);
 8402                    const BORDER_WIDTH: Pixels = px(1.);
 8403
 8404                    return Some(
 8405                        h_flex()
 8406                            .elevation_2(cx)
 8407                            .border(BORDER_WIDTH)
 8408                            .border_color(cx.theme().colors().border)
 8409                            .when(accept_keystroke.is_none(), |el| {
 8410                                el.border_color(cx.theme().status().error)
 8411                            })
 8412                            .rounded(RADIUS)
 8413                            .rounded_tl(px(0.))
 8414                            .overflow_hidden()
 8415                            .child(div().px_1p5().child(match &prediction.completion {
 8416                                InlineCompletion::Move { target, snapshot } => {
 8417                                    use text::ToPoint as _;
 8418                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8419                                    {
 8420                                        Icon::new(IconName::ZedPredictDown)
 8421                                    } else {
 8422                                        Icon::new(IconName::ZedPredictUp)
 8423                                    }
 8424                                }
 8425                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8426                            }))
 8427                            .child(
 8428                                h_flex()
 8429                                    .gap_1()
 8430                                    .py_1()
 8431                                    .px_2()
 8432                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8433                                    .border_l_1()
 8434                                    .border_color(cx.theme().colors().border)
 8435                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8436                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8437                                        el.child(
 8438                                            Label::new("Hold")
 8439                                                .size(LabelSize::Small)
 8440                                                .when(accept_keystroke.is_none(), |el| {
 8441                                                    el.strikethrough()
 8442                                                })
 8443                                                .line_height_style(LineHeightStyle::UiLabel),
 8444                                        )
 8445                                    })
 8446                                    .id("edit_prediction_cursor_popover_keybind")
 8447                                    .when(accept_keystroke.is_none(), |el| {
 8448                                        let status_colors = cx.theme().status();
 8449
 8450                                        el.bg(status_colors.error_background)
 8451                                            .border_color(status_colors.error.opacity(0.6))
 8452                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8453                                            .cursor_default()
 8454                                            .hoverable_tooltip(move |_window, cx| {
 8455                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8456                                                    .into()
 8457                                            })
 8458                                    })
 8459                                    .when_some(
 8460                                        accept_keystroke.as_ref(),
 8461                                        |el, accept_keystroke| {
 8462                                            el.child(h_flex().children(ui::render_modifiers(
 8463                                                &accept_keystroke.modifiers,
 8464                                                PlatformStyle::platform(),
 8465                                                Some(Color::Default),
 8466                                                Some(IconSize::XSmall.rems().into()),
 8467                                                false,
 8468                                            )))
 8469                                        },
 8470                                    ),
 8471                            )
 8472                            .into_any(),
 8473                    );
 8474                }
 8475
 8476                self.render_edit_prediction_cursor_popover_preview(
 8477                    prediction,
 8478                    cursor_point,
 8479                    style,
 8480                    cx,
 8481                )?
 8482            }
 8483
 8484            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8485                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8486                    stale_completion,
 8487                    cursor_point,
 8488                    style,
 8489                    cx,
 8490                )?,
 8491
 8492                None => {
 8493                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8494                }
 8495            },
 8496
 8497            None => pending_completion_container().child(Label::new("No Prediction")),
 8498        };
 8499
 8500        let completion = if is_refreshing {
 8501            completion
 8502                .with_animation(
 8503                    "loading-completion",
 8504                    Animation::new(Duration::from_secs(2))
 8505                        .repeat()
 8506                        .with_easing(pulsating_between(0.4, 0.8)),
 8507                    |label, delta| label.opacity(delta),
 8508                )
 8509                .into_any_element()
 8510        } else {
 8511            completion.into_any_element()
 8512        };
 8513
 8514        let has_completion = self.active_inline_completion.is_some();
 8515
 8516        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8517        Some(
 8518            h_flex()
 8519                .min_w(min_width)
 8520                .max_w(max_width)
 8521                .flex_1()
 8522                .elevation_2(cx)
 8523                .border_color(cx.theme().colors().border)
 8524                .child(
 8525                    div()
 8526                        .flex_1()
 8527                        .py_1()
 8528                        .px_2()
 8529                        .overflow_hidden()
 8530                        .child(completion),
 8531                )
 8532                .when_some(accept_keystroke, |el, accept_keystroke| {
 8533                    if !accept_keystroke.modifiers.modified() {
 8534                        return el;
 8535                    }
 8536
 8537                    el.child(
 8538                        h_flex()
 8539                            .h_full()
 8540                            .border_l_1()
 8541                            .rounded_r_lg()
 8542                            .border_color(cx.theme().colors().border)
 8543                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8544                            .gap_1()
 8545                            .py_1()
 8546                            .px_2()
 8547                            .child(
 8548                                h_flex()
 8549                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8550                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8551                                    .child(h_flex().children(ui::render_modifiers(
 8552                                        &accept_keystroke.modifiers,
 8553                                        PlatformStyle::platform(),
 8554                                        Some(if !has_completion {
 8555                                            Color::Muted
 8556                                        } else {
 8557                                            Color::Default
 8558                                        }),
 8559                                        None,
 8560                                        false,
 8561                                    ))),
 8562                            )
 8563                            .child(Label::new("Preview").into_any_element())
 8564                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8565                    )
 8566                })
 8567                .into_any(),
 8568        )
 8569    }
 8570
 8571    fn render_edit_prediction_cursor_popover_preview(
 8572        &self,
 8573        completion: &InlineCompletionState,
 8574        cursor_point: Point,
 8575        style: &EditorStyle,
 8576        cx: &mut Context<Editor>,
 8577    ) -> Option<Div> {
 8578        use text::ToPoint as _;
 8579
 8580        fn render_relative_row_jump(
 8581            prefix: impl Into<String>,
 8582            current_row: u32,
 8583            target_row: u32,
 8584        ) -> Div {
 8585            let (row_diff, arrow) = if target_row < current_row {
 8586                (current_row - target_row, IconName::ArrowUp)
 8587            } else {
 8588                (target_row - current_row, IconName::ArrowDown)
 8589            };
 8590
 8591            h_flex()
 8592                .child(
 8593                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8594                        .color(Color::Muted)
 8595                        .size(LabelSize::Small),
 8596                )
 8597                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8598        }
 8599
 8600        match &completion.completion {
 8601            InlineCompletion::Move {
 8602                target, snapshot, ..
 8603            } => Some(
 8604                h_flex()
 8605                    .px_2()
 8606                    .gap_2()
 8607                    .flex_1()
 8608                    .child(
 8609                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8610                            Icon::new(IconName::ZedPredictDown)
 8611                        } else {
 8612                            Icon::new(IconName::ZedPredictUp)
 8613                        },
 8614                    )
 8615                    .child(Label::new("Jump to Edit")),
 8616            ),
 8617
 8618            InlineCompletion::Edit {
 8619                edits,
 8620                edit_preview,
 8621                snapshot,
 8622                display_mode: _,
 8623            } => {
 8624                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8625
 8626                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8627                    &snapshot,
 8628                    &edits,
 8629                    edit_preview.as_ref()?,
 8630                    true,
 8631                    cx,
 8632                )
 8633                .first_line_preview();
 8634
 8635                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8636                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8637
 8638                let preview = h_flex()
 8639                    .gap_1()
 8640                    .min_w_16()
 8641                    .child(styled_text)
 8642                    .when(has_more_lines, |parent| parent.child(""));
 8643
 8644                let left = if first_edit_row != cursor_point.row {
 8645                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8646                        .into_any_element()
 8647                } else {
 8648                    Icon::new(IconName::ZedPredict).into_any_element()
 8649                };
 8650
 8651                Some(
 8652                    h_flex()
 8653                        .h_full()
 8654                        .flex_1()
 8655                        .gap_2()
 8656                        .pr_1()
 8657                        .overflow_x_hidden()
 8658                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8659                        .child(left)
 8660                        .child(preview),
 8661                )
 8662            }
 8663        }
 8664    }
 8665
 8666    pub fn render_context_menu(
 8667        &self,
 8668        style: &EditorStyle,
 8669        max_height_in_lines: u32,
 8670        window: &mut Window,
 8671        cx: &mut Context<Editor>,
 8672    ) -> Option<AnyElement> {
 8673        let menu = self.context_menu.borrow();
 8674        let menu = menu.as_ref()?;
 8675        if !menu.visible() {
 8676            return None;
 8677        };
 8678        Some(menu.render(style, max_height_in_lines, window, cx))
 8679    }
 8680
 8681    fn render_context_menu_aside(
 8682        &mut self,
 8683        max_size: Size<Pixels>,
 8684        window: &mut Window,
 8685        cx: &mut Context<Editor>,
 8686    ) -> Option<AnyElement> {
 8687        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8688            if menu.visible() {
 8689                menu.render_aside(self, max_size, window, cx)
 8690            } else {
 8691                None
 8692            }
 8693        })
 8694    }
 8695
 8696    fn hide_context_menu(
 8697        &mut self,
 8698        window: &mut Window,
 8699        cx: &mut Context<Self>,
 8700    ) -> Option<CodeContextMenu> {
 8701        cx.notify();
 8702        self.completion_tasks.clear();
 8703        let context_menu = self.context_menu.borrow_mut().take();
 8704        self.stale_inline_completion_in_menu.take();
 8705        self.update_visible_inline_completion(window, cx);
 8706        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8707            if let Some(completion_provider) = &self.completion_provider {
 8708                completion_provider.selection_changed(None, window, cx);
 8709            }
 8710        }
 8711        context_menu
 8712    }
 8713
 8714    fn show_snippet_choices(
 8715        &mut self,
 8716        choices: &Vec<String>,
 8717        selection: Range<Anchor>,
 8718        cx: &mut Context<Self>,
 8719    ) {
 8720        if selection.start.buffer_id.is_none() {
 8721            return;
 8722        }
 8723        let buffer_id = selection.start.buffer_id.unwrap();
 8724        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8725        let id = post_inc(&mut self.next_completion_id);
 8726        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8727
 8728        if let Some(buffer) = buffer {
 8729            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8730                CompletionsMenu::new_snippet_choices(
 8731                    id,
 8732                    true,
 8733                    choices,
 8734                    selection,
 8735                    buffer,
 8736                    snippet_sort_order,
 8737                ),
 8738            ));
 8739        }
 8740    }
 8741
 8742    pub fn insert_snippet(
 8743        &mut self,
 8744        insertion_ranges: &[Range<usize>],
 8745        snippet: Snippet,
 8746        window: &mut Window,
 8747        cx: &mut Context<Self>,
 8748    ) -> Result<()> {
 8749        struct Tabstop<T> {
 8750            is_end_tabstop: bool,
 8751            ranges: Vec<Range<T>>,
 8752            choices: Option<Vec<String>>,
 8753        }
 8754
 8755        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8756            let snippet_text: Arc<str> = snippet.text.clone().into();
 8757            let edits = insertion_ranges
 8758                .iter()
 8759                .cloned()
 8760                .map(|range| (range, snippet_text.clone()));
 8761            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8762
 8763            let snapshot = &*buffer.read(cx);
 8764            let snippet = &snippet;
 8765            snippet
 8766                .tabstops
 8767                .iter()
 8768                .map(|tabstop| {
 8769                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8770                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8771                    });
 8772                    let mut tabstop_ranges = tabstop
 8773                        .ranges
 8774                        .iter()
 8775                        .flat_map(|tabstop_range| {
 8776                            let mut delta = 0_isize;
 8777                            insertion_ranges.iter().map(move |insertion_range| {
 8778                                let insertion_start = insertion_range.start as isize + delta;
 8779                                delta +=
 8780                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8781
 8782                                let start = ((insertion_start + tabstop_range.start) as usize)
 8783                                    .min(snapshot.len());
 8784                                let end = ((insertion_start + tabstop_range.end) as usize)
 8785                                    .min(snapshot.len());
 8786                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8787                            })
 8788                        })
 8789                        .collect::<Vec<_>>();
 8790                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8791
 8792                    Tabstop {
 8793                        is_end_tabstop,
 8794                        ranges: tabstop_ranges,
 8795                        choices: tabstop.choices.clone(),
 8796                    }
 8797                })
 8798                .collect::<Vec<_>>()
 8799        });
 8800        if let Some(tabstop) = tabstops.first() {
 8801            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8802                s.select_ranges(tabstop.ranges.iter().cloned());
 8803            });
 8804
 8805            if let Some(choices) = &tabstop.choices {
 8806                if let Some(selection) = tabstop.ranges.first() {
 8807                    self.show_snippet_choices(choices, selection.clone(), cx)
 8808                }
 8809            }
 8810
 8811            // If we're already at the last tabstop and it's at the end of the snippet,
 8812            // we're done, we don't need to keep the state around.
 8813            if !tabstop.is_end_tabstop {
 8814                let choices = tabstops
 8815                    .iter()
 8816                    .map(|tabstop| tabstop.choices.clone())
 8817                    .collect();
 8818
 8819                let ranges = tabstops
 8820                    .into_iter()
 8821                    .map(|tabstop| tabstop.ranges)
 8822                    .collect::<Vec<_>>();
 8823
 8824                self.snippet_stack.push(SnippetState {
 8825                    active_index: 0,
 8826                    ranges,
 8827                    choices,
 8828                });
 8829            }
 8830
 8831            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8832            if self.autoclose_regions.is_empty() {
 8833                let snapshot = self.buffer.read(cx).snapshot(cx);
 8834                for selection in &mut self.selections.all::<Point>(cx) {
 8835                    let selection_head = selection.head();
 8836                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8837                        continue;
 8838                    };
 8839
 8840                    let mut bracket_pair = None;
 8841                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8842                    let prev_chars = snapshot
 8843                        .reversed_chars_at(selection_head)
 8844                        .collect::<String>();
 8845                    for (pair, enabled) in scope.brackets() {
 8846                        if enabled
 8847                            && pair.close
 8848                            && prev_chars.starts_with(pair.start.as_str())
 8849                            && next_chars.starts_with(pair.end.as_str())
 8850                        {
 8851                            bracket_pair = Some(pair.clone());
 8852                            break;
 8853                        }
 8854                    }
 8855                    if let Some(pair) = bracket_pair {
 8856                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8857                        let autoclose_enabled =
 8858                            self.use_autoclose && snapshot_settings.use_autoclose;
 8859                        if autoclose_enabled {
 8860                            let start = snapshot.anchor_after(selection_head);
 8861                            let end = snapshot.anchor_after(selection_head);
 8862                            self.autoclose_regions.push(AutocloseRegion {
 8863                                selection_id: selection.id,
 8864                                range: start..end,
 8865                                pair,
 8866                            });
 8867                        }
 8868                    }
 8869                }
 8870            }
 8871        }
 8872        Ok(())
 8873    }
 8874
 8875    pub fn move_to_next_snippet_tabstop(
 8876        &mut self,
 8877        window: &mut Window,
 8878        cx: &mut Context<Self>,
 8879    ) -> bool {
 8880        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8881    }
 8882
 8883    pub fn move_to_prev_snippet_tabstop(
 8884        &mut self,
 8885        window: &mut Window,
 8886        cx: &mut Context<Self>,
 8887    ) -> bool {
 8888        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8889    }
 8890
 8891    pub fn move_to_snippet_tabstop(
 8892        &mut self,
 8893        bias: Bias,
 8894        window: &mut Window,
 8895        cx: &mut Context<Self>,
 8896    ) -> bool {
 8897        if let Some(mut snippet) = self.snippet_stack.pop() {
 8898            match bias {
 8899                Bias::Left => {
 8900                    if snippet.active_index > 0 {
 8901                        snippet.active_index -= 1;
 8902                    } else {
 8903                        self.snippet_stack.push(snippet);
 8904                        return false;
 8905                    }
 8906                }
 8907                Bias::Right => {
 8908                    if snippet.active_index + 1 < snippet.ranges.len() {
 8909                        snippet.active_index += 1;
 8910                    } else {
 8911                        self.snippet_stack.push(snippet);
 8912                        return false;
 8913                    }
 8914                }
 8915            }
 8916            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8917                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8918                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8919                });
 8920
 8921                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8922                    if let Some(selection) = current_ranges.first() {
 8923                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8924                    }
 8925                }
 8926
 8927                // If snippet state is not at the last tabstop, push it back on the stack
 8928                if snippet.active_index + 1 < snippet.ranges.len() {
 8929                    self.snippet_stack.push(snippet);
 8930                }
 8931                return true;
 8932            }
 8933        }
 8934
 8935        false
 8936    }
 8937
 8938    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8939        self.transact(window, cx, |this, window, cx| {
 8940            this.select_all(&SelectAll, window, cx);
 8941            this.insert("", window, cx);
 8942        });
 8943    }
 8944
 8945    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8946        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8947        self.transact(window, cx, |this, window, cx| {
 8948            this.select_autoclose_pair(window, cx);
 8949            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8950            if !this.linked_edit_ranges.is_empty() {
 8951                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8952                let snapshot = this.buffer.read(cx).snapshot(cx);
 8953
 8954                for selection in selections.iter() {
 8955                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8956                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8957                    if selection_start.buffer_id != selection_end.buffer_id {
 8958                        continue;
 8959                    }
 8960                    if let Some(ranges) =
 8961                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8962                    {
 8963                        for (buffer, entries) in ranges {
 8964                            linked_ranges.entry(buffer).or_default().extend(entries);
 8965                        }
 8966                    }
 8967                }
 8968            }
 8969
 8970            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8971            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8972            for selection in &mut selections {
 8973                if selection.is_empty() {
 8974                    let old_head = selection.head();
 8975                    let mut new_head =
 8976                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8977                            .to_point(&display_map);
 8978                    if let Some((buffer, line_buffer_range)) = display_map
 8979                        .buffer_snapshot
 8980                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8981                    {
 8982                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8983                        let indent_len = match indent_size.kind {
 8984                            IndentKind::Space => {
 8985                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8986                            }
 8987                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8988                        };
 8989                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8990                            let indent_len = indent_len.get();
 8991                            new_head = cmp::min(
 8992                                new_head,
 8993                                MultiBufferPoint::new(
 8994                                    old_head.row,
 8995                                    ((old_head.column - 1) / indent_len) * indent_len,
 8996                                ),
 8997                            );
 8998                        }
 8999                    }
 9000
 9001                    selection.set_head(new_head, SelectionGoal::None);
 9002                }
 9003            }
 9004
 9005            this.signature_help_state.set_backspace_pressed(true);
 9006            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9007                s.select(selections)
 9008            });
 9009            this.insert("", window, cx);
 9010            let empty_str: Arc<str> = Arc::from("");
 9011            for (buffer, edits) in linked_ranges {
 9012                let snapshot = buffer.read(cx).snapshot();
 9013                use text::ToPoint as TP;
 9014
 9015                let edits = edits
 9016                    .into_iter()
 9017                    .map(|range| {
 9018                        let end_point = TP::to_point(&range.end, &snapshot);
 9019                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9020
 9021                        if end_point == start_point {
 9022                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9023                                .saturating_sub(1);
 9024                            start_point =
 9025                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9026                        };
 9027
 9028                        (start_point..end_point, empty_str.clone())
 9029                    })
 9030                    .sorted_by_key(|(range, _)| range.start)
 9031                    .collect::<Vec<_>>();
 9032                buffer.update(cx, |this, cx| {
 9033                    this.edit(edits, None, cx);
 9034                })
 9035            }
 9036            this.refresh_inline_completion(true, false, window, cx);
 9037            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9038        });
 9039    }
 9040
 9041    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9042        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9043        self.transact(window, cx, |this, window, cx| {
 9044            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9045                s.move_with(|map, selection| {
 9046                    if selection.is_empty() {
 9047                        let cursor = movement::right(map, selection.head());
 9048                        selection.end = cursor;
 9049                        selection.reversed = true;
 9050                        selection.goal = SelectionGoal::None;
 9051                    }
 9052                })
 9053            });
 9054            this.insert("", window, cx);
 9055            this.refresh_inline_completion(true, false, window, cx);
 9056        });
 9057    }
 9058
 9059    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9060        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9061        if self.move_to_prev_snippet_tabstop(window, cx) {
 9062            return;
 9063        }
 9064        self.outdent(&Outdent, window, cx);
 9065    }
 9066
 9067    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9068        if self.move_to_next_snippet_tabstop(window, cx) {
 9069            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9070            return;
 9071        }
 9072        if self.read_only(cx) {
 9073            return;
 9074        }
 9075        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9076        let mut selections = self.selections.all_adjusted(cx);
 9077        let buffer = self.buffer.read(cx);
 9078        let snapshot = buffer.snapshot(cx);
 9079        let rows_iter = selections.iter().map(|s| s.head().row);
 9080        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9081
 9082        let has_some_cursor_in_whitespace = selections
 9083            .iter()
 9084            .filter(|selection| selection.is_empty())
 9085            .any(|selection| {
 9086                let cursor = selection.head();
 9087                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9088                cursor.column < current_indent.len
 9089            });
 9090
 9091        let mut edits = Vec::new();
 9092        let mut prev_edited_row = 0;
 9093        let mut row_delta = 0;
 9094        for selection in &mut selections {
 9095            if selection.start.row != prev_edited_row {
 9096                row_delta = 0;
 9097            }
 9098            prev_edited_row = selection.end.row;
 9099
 9100            // If the selection is non-empty, then increase the indentation of the selected lines.
 9101            if !selection.is_empty() {
 9102                row_delta =
 9103                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9104                continue;
 9105            }
 9106
 9107            let cursor = selection.head();
 9108            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9109            if let Some(suggested_indent) =
 9110                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9111            {
 9112                // Don't do anything if already at suggested indent
 9113                // and there is any other cursor which is not
 9114                if has_some_cursor_in_whitespace
 9115                    && cursor.column == current_indent.len
 9116                    && current_indent.len == suggested_indent.len
 9117                {
 9118                    continue;
 9119                }
 9120
 9121                // Adjust line and move cursor to suggested indent
 9122                // if cursor is not at suggested indent
 9123                if cursor.column < suggested_indent.len
 9124                    && cursor.column <= current_indent.len
 9125                    && current_indent.len <= suggested_indent.len
 9126                {
 9127                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9128                    selection.end = selection.start;
 9129                    if row_delta == 0 {
 9130                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9131                            cursor.row,
 9132                            current_indent,
 9133                            suggested_indent,
 9134                        ));
 9135                        row_delta = suggested_indent.len - current_indent.len;
 9136                    }
 9137                    continue;
 9138                }
 9139
 9140                // If current indent is more than suggested indent
 9141                // only move cursor to current indent and skip indent
 9142                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9143                    selection.start = Point::new(cursor.row, current_indent.len);
 9144                    selection.end = selection.start;
 9145                    continue;
 9146                }
 9147            }
 9148
 9149            // Otherwise, insert a hard or soft tab.
 9150            let settings = buffer.language_settings_at(cursor, cx);
 9151            let tab_size = if settings.hard_tabs {
 9152                IndentSize::tab()
 9153            } else {
 9154                let tab_size = settings.tab_size.get();
 9155                let indent_remainder = snapshot
 9156                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9157                    .flat_map(str::chars)
 9158                    .fold(row_delta % tab_size, |counter: u32, c| {
 9159                        if c == '\t' {
 9160                            0
 9161                        } else {
 9162                            (counter + 1) % tab_size
 9163                        }
 9164                    });
 9165
 9166                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9167                IndentSize::spaces(chars_to_next_tab_stop)
 9168            };
 9169            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9170            selection.end = selection.start;
 9171            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9172            row_delta += tab_size.len;
 9173        }
 9174
 9175        self.transact(window, cx, |this, window, cx| {
 9176            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9177            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9178                s.select(selections)
 9179            });
 9180            this.refresh_inline_completion(true, false, window, cx);
 9181        });
 9182    }
 9183
 9184    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9185        if self.read_only(cx) {
 9186            return;
 9187        }
 9188        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9189        let mut selections = self.selections.all::<Point>(cx);
 9190        let mut prev_edited_row = 0;
 9191        let mut row_delta = 0;
 9192        let mut edits = Vec::new();
 9193        let buffer = self.buffer.read(cx);
 9194        let snapshot = buffer.snapshot(cx);
 9195        for selection in &mut selections {
 9196            if selection.start.row != prev_edited_row {
 9197                row_delta = 0;
 9198            }
 9199            prev_edited_row = selection.end.row;
 9200
 9201            row_delta =
 9202                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9203        }
 9204
 9205        self.transact(window, cx, |this, window, cx| {
 9206            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9207            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9208                s.select(selections)
 9209            });
 9210        });
 9211    }
 9212
 9213    fn indent_selection(
 9214        buffer: &MultiBuffer,
 9215        snapshot: &MultiBufferSnapshot,
 9216        selection: &mut Selection<Point>,
 9217        edits: &mut Vec<(Range<Point>, String)>,
 9218        delta_for_start_row: u32,
 9219        cx: &App,
 9220    ) -> u32 {
 9221        let settings = buffer.language_settings_at(selection.start, cx);
 9222        let tab_size = settings.tab_size.get();
 9223        let indent_kind = if settings.hard_tabs {
 9224            IndentKind::Tab
 9225        } else {
 9226            IndentKind::Space
 9227        };
 9228        let mut start_row = selection.start.row;
 9229        let mut end_row = selection.end.row + 1;
 9230
 9231        // If a selection ends at the beginning of a line, don't indent
 9232        // that last line.
 9233        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9234            end_row -= 1;
 9235        }
 9236
 9237        // Avoid re-indenting a row that has already been indented by a
 9238        // previous selection, but still update this selection's column
 9239        // to reflect that indentation.
 9240        if delta_for_start_row > 0 {
 9241            start_row += 1;
 9242            selection.start.column += delta_for_start_row;
 9243            if selection.end.row == selection.start.row {
 9244                selection.end.column += delta_for_start_row;
 9245            }
 9246        }
 9247
 9248        let mut delta_for_end_row = 0;
 9249        let has_multiple_rows = start_row + 1 != end_row;
 9250        for row in start_row..end_row {
 9251            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9252            let indent_delta = match (current_indent.kind, indent_kind) {
 9253                (IndentKind::Space, IndentKind::Space) => {
 9254                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9255                    IndentSize::spaces(columns_to_next_tab_stop)
 9256                }
 9257                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9258                (_, IndentKind::Tab) => IndentSize::tab(),
 9259            };
 9260
 9261            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9262                0
 9263            } else {
 9264                selection.start.column
 9265            };
 9266            let row_start = Point::new(row, start);
 9267            edits.push((
 9268                row_start..row_start,
 9269                indent_delta.chars().collect::<String>(),
 9270            ));
 9271
 9272            // Update this selection's endpoints to reflect the indentation.
 9273            if row == selection.start.row {
 9274                selection.start.column += indent_delta.len;
 9275            }
 9276            if row == selection.end.row {
 9277                selection.end.column += indent_delta.len;
 9278                delta_for_end_row = indent_delta.len;
 9279            }
 9280        }
 9281
 9282        if selection.start.row == selection.end.row {
 9283            delta_for_start_row + delta_for_end_row
 9284        } else {
 9285            delta_for_end_row
 9286        }
 9287    }
 9288
 9289    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9290        if self.read_only(cx) {
 9291            return;
 9292        }
 9293        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9294        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9295        let selections = self.selections.all::<Point>(cx);
 9296        let mut deletion_ranges = Vec::new();
 9297        let mut last_outdent = None;
 9298        {
 9299            let buffer = self.buffer.read(cx);
 9300            let snapshot = buffer.snapshot(cx);
 9301            for selection in &selections {
 9302                let settings = buffer.language_settings_at(selection.start, cx);
 9303                let tab_size = settings.tab_size.get();
 9304                let mut rows = selection.spanned_rows(false, &display_map);
 9305
 9306                // Avoid re-outdenting a row that has already been outdented by a
 9307                // previous selection.
 9308                if let Some(last_row) = last_outdent {
 9309                    if last_row == rows.start {
 9310                        rows.start = rows.start.next_row();
 9311                    }
 9312                }
 9313                let has_multiple_rows = rows.len() > 1;
 9314                for row in rows.iter_rows() {
 9315                    let indent_size = snapshot.indent_size_for_line(row);
 9316                    if indent_size.len > 0 {
 9317                        let deletion_len = match indent_size.kind {
 9318                            IndentKind::Space => {
 9319                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9320                                if columns_to_prev_tab_stop == 0 {
 9321                                    tab_size
 9322                                } else {
 9323                                    columns_to_prev_tab_stop
 9324                                }
 9325                            }
 9326                            IndentKind::Tab => 1,
 9327                        };
 9328                        let start = if has_multiple_rows
 9329                            || deletion_len > selection.start.column
 9330                            || indent_size.len < selection.start.column
 9331                        {
 9332                            0
 9333                        } else {
 9334                            selection.start.column - deletion_len
 9335                        };
 9336                        deletion_ranges.push(
 9337                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9338                        );
 9339                        last_outdent = Some(row);
 9340                    }
 9341                }
 9342            }
 9343        }
 9344
 9345        self.transact(window, cx, |this, window, cx| {
 9346            this.buffer.update(cx, |buffer, cx| {
 9347                let empty_str: Arc<str> = Arc::default();
 9348                buffer.edit(
 9349                    deletion_ranges
 9350                        .into_iter()
 9351                        .map(|range| (range, empty_str.clone())),
 9352                    None,
 9353                    cx,
 9354                );
 9355            });
 9356            let selections = this.selections.all::<usize>(cx);
 9357            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9358                s.select(selections)
 9359            });
 9360        });
 9361    }
 9362
 9363    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9364        if self.read_only(cx) {
 9365            return;
 9366        }
 9367        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9368        let selections = self
 9369            .selections
 9370            .all::<usize>(cx)
 9371            .into_iter()
 9372            .map(|s| s.range());
 9373
 9374        self.transact(window, cx, |this, window, cx| {
 9375            this.buffer.update(cx, |buffer, cx| {
 9376                buffer.autoindent_ranges(selections, cx);
 9377            });
 9378            let selections = this.selections.all::<usize>(cx);
 9379            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9380                s.select(selections)
 9381            });
 9382        });
 9383    }
 9384
 9385    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9386        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9387        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9388        let selections = self.selections.all::<Point>(cx);
 9389
 9390        let mut new_cursors = Vec::new();
 9391        let mut edit_ranges = Vec::new();
 9392        let mut selections = selections.iter().peekable();
 9393        while let Some(selection) = selections.next() {
 9394            let mut rows = selection.spanned_rows(false, &display_map);
 9395            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9396
 9397            // Accumulate contiguous regions of rows that we want to delete.
 9398            while let Some(next_selection) = selections.peek() {
 9399                let next_rows = next_selection.spanned_rows(false, &display_map);
 9400                if next_rows.start <= rows.end {
 9401                    rows.end = next_rows.end;
 9402                    selections.next().unwrap();
 9403                } else {
 9404                    break;
 9405                }
 9406            }
 9407
 9408            let buffer = &display_map.buffer_snapshot;
 9409            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9410            let edit_end;
 9411            let cursor_buffer_row;
 9412            if buffer.max_point().row >= rows.end.0 {
 9413                // If there's a line after the range, delete the \n from the end of the row range
 9414                // and position the cursor on the next line.
 9415                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9416                cursor_buffer_row = rows.end;
 9417            } else {
 9418                // If there isn't a line after the range, delete the \n from the line before the
 9419                // start of the row range and position the cursor there.
 9420                edit_start = edit_start.saturating_sub(1);
 9421                edit_end = buffer.len();
 9422                cursor_buffer_row = rows.start.previous_row();
 9423            }
 9424
 9425            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9426            *cursor.column_mut() =
 9427                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9428
 9429            new_cursors.push((
 9430                selection.id,
 9431                buffer.anchor_after(cursor.to_point(&display_map)),
 9432            ));
 9433            edit_ranges.push(edit_start..edit_end);
 9434        }
 9435
 9436        self.transact(window, cx, |this, window, cx| {
 9437            let buffer = this.buffer.update(cx, |buffer, cx| {
 9438                let empty_str: Arc<str> = Arc::default();
 9439                buffer.edit(
 9440                    edit_ranges
 9441                        .into_iter()
 9442                        .map(|range| (range, empty_str.clone())),
 9443                    None,
 9444                    cx,
 9445                );
 9446                buffer.snapshot(cx)
 9447            });
 9448            let new_selections = new_cursors
 9449                .into_iter()
 9450                .map(|(id, cursor)| {
 9451                    let cursor = cursor.to_point(&buffer);
 9452                    Selection {
 9453                        id,
 9454                        start: cursor,
 9455                        end: cursor,
 9456                        reversed: false,
 9457                        goal: SelectionGoal::None,
 9458                    }
 9459                })
 9460                .collect();
 9461
 9462            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9463                s.select(new_selections);
 9464            });
 9465        });
 9466    }
 9467
 9468    pub fn join_lines_impl(
 9469        &mut self,
 9470        insert_whitespace: bool,
 9471        window: &mut Window,
 9472        cx: &mut Context<Self>,
 9473    ) {
 9474        if self.read_only(cx) {
 9475            return;
 9476        }
 9477        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9478        for selection in self.selections.all::<Point>(cx) {
 9479            let start = MultiBufferRow(selection.start.row);
 9480            // Treat single line selections as if they include the next line. Otherwise this action
 9481            // would do nothing for single line selections individual cursors.
 9482            let end = if selection.start.row == selection.end.row {
 9483                MultiBufferRow(selection.start.row + 1)
 9484            } else {
 9485                MultiBufferRow(selection.end.row)
 9486            };
 9487
 9488            if let Some(last_row_range) = row_ranges.last_mut() {
 9489                if start <= last_row_range.end {
 9490                    last_row_range.end = end;
 9491                    continue;
 9492                }
 9493            }
 9494            row_ranges.push(start..end);
 9495        }
 9496
 9497        let snapshot = self.buffer.read(cx).snapshot(cx);
 9498        let mut cursor_positions = Vec::new();
 9499        for row_range in &row_ranges {
 9500            let anchor = snapshot.anchor_before(Point::new(
 9501                row_range.end.previous_row().0,
 9502                snapshot.line_len(row_range.end.previous_row()),
 9503            ));
 9504            cursor_positions.push(anchor..anchor);
 9505        }
 9506
 9507        self.transact(window, cx, |this, window, cx| {
 9508            for row_range in row_ranges.into_iter().rev() {
 9509                for row in row_range.iter_rows().rev() {
 9510                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9511                    let next_line_row = row.next_row();
 9512                    let indent = snapshot.indent_size_for_line(next_line_row);
 9513                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9514
 9515                    let replace =
 9516                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9517                            " "
 9518                        } else {
 9519                            ""
 9520                        };
 9521
 9522                    this.buffer.update(cx, |buffer, cx| {
 9523                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9524                    });
 9525                }
 9526            }
 9527
 9528            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9529                s.select_anchor_ranges(cursor_positions)
 9530            });
 9531        });
 9532    }
 9533
 9534    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9535        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9536        self.join_lines_impl(true, window, cx);
 9537    }
 9538
 9539    pub fn sort_lines_case_sensitive(
 9540        &mut self,
 9541        _: &SortLinesCaseSensitive,
 9542        window: &mut Window,
 9543        cx: &mut Context<Self>,
 9544    ) {
 9545        self.manipulate_lines(window, cx, |lines| lines.sort())
 9546    }
 9547
 9548    pub fn sort_lines_case_insensitive(
 9549        &mut self,
 9550        _: &SortLinesCaseInsensitive,
 9551        window: &mut Window,
 9552        cx: &mut Context<Self>,
 9553    ) {
 9554        self.manipulate_lines(window, cx, |lines| {
 9555            lines.sort_by_key(|line| line.to_lowercase())
 9556        })
 9557    }
 9558
 9559    pub fn unique_lines_case_insensitive(
 9560        &mut self,
 9561        _: &UniqueLinesCaseInsensitive,
 9562        window: &mut Window,
 9563        cx: &mut Context<Self>,
 9564    ) {
 9565        self.manipulate_lines(window, cx, |lines| {
 9566            let mut seen = HashSet::default();
 9567            lines.retain(|line| seen.insert(line.to_lowercase()));
 9568        })
 9569    }
 9570
 9571    pub fn unique_lines_case_sensitive(
 9572        &mut self,
 9573        _: &UniqueLinesCaseSensitive,
 9574        window: &mut Window,
 9575        cx: &mut Context<Self>,
 9576    ) {
 9577        self.manipulate_lines(window, cx, |lines| {
 9578            let mut seen = HashSet::default();
 9579            lines.retain(|line| seen.insert(*line));
 9580        })
 9581    }
 9582
 9583    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9584        let Some(project) = self.project.clone() else {
 9585            return;
 9586        };
 9587        self.reload(project, window, cx)
 9588            .detach_and_notify_err(window, cx);
 9589    }
 9590
 9591    pub fn restore_file(
 9592        &mut self,
 9593        _: &::git::RestoreFile,
 9594        window: &mut Window,
 9595        cx: &mut Context<Self>,
 9596    ) {
 9597        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9598        let mut buffer_ids = HashSet::default();
 9599        let snapshot = self.buffer().read(cx).snapshot(cx);
 9600        for selection in self.selections.all::<usize>(cx) {
 9601            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9602        }
 9603
 9604        let buffer = self.buffer().read(cx);
 9605        let ranges = buffer_ids
 9606            .into_iter()
 9607            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9608            .collect::<Vec<_>>();
 9609
 9610        self.restore_hunks_in_ranges(ranges, window, cx);
 9611    }
 9612
 9613    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9614        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9615        let selections = self
 9616            .selections
 9617            .all(cx)
 9618            .into_iter()
 9619            .map(|s| s.range())
 9620            .collect();
 9621        self.restore_hunks_in_ranges(selections, window, cx);
 9622    }
 9623
 9624    pub fn restore_hunks_in_ranges(
 9625        &mut self,
 9626        ranges: Vec<Range<Point>>,
 9627        window: &mut Window,
 9628        cx: &mut Context<Editor>,
 9629    ) {
 9630        let mut revert_changes = HashMap::default();
 9631        let chunk_by = self
 9632            .snapshot(window, cx)
 9633            .hunks_for_ranges(ranges)
 9634            .into_iter()
 9635            .chunk_by(|hunk| hunk.buffer_id);
 9636        for (buffer_id, hunks) in &chunk_by {
 9637            let hunks = hunks.collect::<Vec<_>>();
 9638            for hunk in &hunks {
 9639                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9640            }
 9641            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9642        }
 9643        drop(chunk_by);
 9644        if !revert_changes.is_empty() {
 9645            self.transact(window, cx, |editor, window, cx| {
 9646                editor.restore(revert_changes, window, cx);
 9647            });
 9648        }
 9649    }
 9650
 9651    pub fn open_active_item_in_terminal(
 9652        &mut self,
 9653        _: &OpenInTerminal,
 9654        window: &mut Window,
 9655        cx: &mut Context<Self>,
 9656    ) {
 9657        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9658            let project_path = buffer.read(cx).project_path(cx)?;
 9659            let project = self.project.as_ref()?.read(cx);
 9660            let entry = project.entry_for_path(&project_path, cx)?;
 9661            let parent = match &entry.canonical_path {
 9662                Some(canonical_path) => canonical_path.to_path_buf(),
 9663                None => project.absolute_path(&project_path, cx)?,
 9664            }
 9665            .parent()?
 9666            .to_path_buf();
 9667            Some(parent)
 9668        }) {
 9669            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9670        }
 9671    }
 9672
 9673    fn set_breakpoint_context_menu(
 9674        &mut self,
 9675        display_row: DisplayRow,
 9676        position: Option<Anchor>,
 9677        clicked_point: gpui::Point<Pixels>,
 9678        window: &mut Window,
 9679        cx: &mut Context<Self>,
 9680    ) {
 9681        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9682            return;
 9683        }
 9684        let source = self
 9685            .buffer
 9686            .read(cx)
 9687            .snapshot(cx)
 9688            .anchor_before(Point::new(display_row.0, 0u32));
 9689
 9690        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9691
 9692        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9693            self,
 9694            source,
 9695            clicked_point,
 9696            context_menu,
 9697            window,
 9698            cx,
 9699        );
 9700    }
 9701
 9702    fn add_edit_breakpoint_block(
 9703        &mut self,
 9704        anchor: Anchor,
 9705        breakpoint: &Breakpoint,
 9706        edit_action: BreakpointPromptEditAction,
 9707        window: &mut Window,
 9708        cx: &mut Context<Self>,
 9709    ) {
 9710        let weak_editor = cx.weak_entity();
 9711        let bp_prompt = cx.new(|cx| {
 9712            BreakpointPromptEditor::new(
 9713                weak_editor,
 9714                anchor,
 9715                breakpoint.clone(),
 9716                edit_action,
 9717                window,
 9718                cx,
 9719            )
 9720        });
 9721
 9722        let height = bp_prompt.update(cx, |this, cx| {
 9723            this.prompt
 9724                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9725        });
 9726        let cloned_prompt = bp_prompt.clone();
 9727        let blocks = vec![BlockProperties {
 9728            style: BlockStyle::Sticky,
 9729            placement: BlockPlacement::Above(anchor),
 9730            height: Some(height),
 9731            render: Arc::new(move |cx| {
 9732                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9733                cloned_prompt.clone().into_any_element()
 9734            }),
 9735            priority: 0,
 9736            render_in_minimap: true,
 9737        }];
 9738
 9739        let focus_handle = bp_prompt.focus_handle(cx);
 9740        window.focus(&focus_handle);
 9741
 9742        let block_ids = self.insert_blocks(blocks, None, cx);
 9743        bp_prompt.update(cx, |prompt, _| {
 9744            prompt.add_block_ids(block_ids);
 9745        });
 9746    }
 9747
 9748    pub(crate) fn breakpoint_at_row(
 9749        &self,
 9750        row: u32,
 9751        window: &mut Window,
 9752        cx: &mut Context<Self>,
 9753    ) -> Option<(Anchor, Breakpoint)> {
 9754        let snapshot = self.snapshot(window, cx);
 9755        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9756
 9757        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9758    }
 9759
 9760    pub(crate) fn breakpoint_at_anchor(
 9761        &self,
 9762        breakpoint_position: Anchor,
 9763        snapshot: &EditorSnapshot,
 9764        cx: &mut Context<Self>,
 9765    ) -> Option<(Anchor, Breakpoint)> {
 9766        let project = self.project.clone()?;
 9767
 9768        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9769            snapshot
 9770                .buffer_snapshot
 9771                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9772        })?;
 9773
 9774        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9775        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
 9776        let buffer_snapshot = buffer.read(cx).snapshot();
 9777
 9778        let row = buffer_snapshot
 9779            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9780            .row;
 9781
 9782        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9783        let anchor_end = snapshot
 9784            .buffer_snapshot
 9785            .anchor_after(Point::new(row, line_len));
 9786
 9787        let bp = self
 9788            .breakpoint_store
 9789            .as_ref()?
 9790            .read_with(cx, |breakpoint_store, cx| {
 9791                breakpoint_store
 9792                    .breakpoints(
 9793                        &buffer,
 9794                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9795                        &buffer_snapshot,
 9796                        cx,
 9797                    )
 9798                    .next()
 9799                    .and_then(|(bp, _)| {
 9800                        let breakpoint_row = buffer_snapshot
 9801                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9802                            .row;
 9803
 9804                        if breakpoint_row == row {
 9805                            snapshot
 9806                                .buffer_snapshot
 9807                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9808                                .map(|position| (position, bp.bp.clone()))
 9809                        } else {
 9810                            None
 9811                        }
 9812                    })
 9813            });
 9814        bp
 9815    }
 9816
 9817    pub fn edit_log_breakpoint(
 9818        &mut self,
 9819        _: &EditLogBreakpoint,
 9820        window: &mut Window,
 9821        cx: &mut Context<Self>,
 9822    ) {
 9823        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9824            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9825                message: None,
 9826                state: BreakpointState::Enabled,
 9827                condition: None,
 9828                hit_condition: None,
 9829            });
 9830
 9831            self.add_edit_breakpoint_block(
 9832                anchor,
 9833                &breakpoint,
 9834                BreakpointPromptEditAction::Log,
 9835                window,
 9836                cx,
 9837            );
 9838        }
 9839    }
 9840
 9841    fn breakpoints_at_cursors(
 9842        &self,
 9843        window: &mut Window,
 9844        cx: &mut Context<Self>,
 9845    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9846        let snapshot = self.snapshot(window, cx);
 9847        let cursors = self
 9848            .selections
 9849            .disjoint_anchors()
 9850            .into_iter()
 9851            .map(|selection| {
 9852                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9853
 9854                let breakpoint_position = self
 9855                    .breakpoint_at_row(cursor_position.row, window, cx)
 9856                    .map(|bp| bp.0)
 9857                    .unwrap_or_else(|| {
 9858                        snapshot
 9859                            .display_snapshot
 9860                            .buffer_snapshot
 9861                            .anchor_after(Point::new(cursor_position.row, 0))
 9862                    });
 9863
 9864                let breakpoint = self
 9865                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9866                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9867
 9868                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9869            })
 9870            // 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.
 9871            .collect::<HashMap<Anchor, _>>();
 9872
 9873        cursors.into_iter().collect()
 9874    }
 9875
 9876    pub fn enable_breakpoint(
 9877        &mut self,
 9878        _: &crate::actions::EnableBreakpoint,
 9879        window: &mut Window,
 9880        cx: &mut Context<Self>,
 9881    ) {
 9882        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9883            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9884                continue;
 9885            };
 9886            self.edit_breakpoint_at_anchor(
 9887                anchor,
 9888                breakpoint,
 9889                BreakpointEditAction::InvertState,
 9890                cx,
 9891            );
 9892        }
 9893    }
 9894
 9895    pub fn disable_breakpoint(
 9896        &mut self,
 9897        _: &crate::actions::DisableBreakpoint,
 9898        window: &mut Window,
 9899        cx: &mut Context<Self>,
 9900    ) {
 9901        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9902            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9903                continue;
 9904            };
 9905            self.edit_breakpoint_at_anchor(
 9906                anchor,
 9907                breakpoint,
 9908                BreakpointEditAction::InvertState,
 9909                cx,
 9910            );
 9911        }
 9912    }
 9913
 9914    pub fn toggle_breakpoint(
 9915        &mut self,
 9916        _: &crate::actions::ToggleBreakpoint,
 9917        window: &mut Window,
 9918        cx: &mut Context<Self>,
 9919    ) {
 9920        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9921            if let Some(breakpoint) = breakpoint {
 9922                self.edit_breakpoint_at_anchor(
 9923                    anchor,
 9924                    breakpoint,
 9925                    BreakpointEditAction::Toggle,
 9926                    cx,
 9927                );
 9928            } else {
 9929                self.edit_breakpoint_at_anchor(
 9930                    anchor,
 9931                    Breakpoint::new_standard(),
 9932                    BreakpointEditAction::Toggle,
 9933                    cx,
 9934                );
 9935            }
 9936        }
 9937    }
 9938
 9939    pub fn edit_breakpoint_at_anchor(
 9940        &mut self,
 9941        breakpoint_position: Anchor,
 9942        breakpoint: Breakpoint,
 9943        edit_action: BreakpointEditAction,
 9944        cx: &mut Context<Self>,
 9945    ) {
 9946        let Some(breakpoint_store) = &self.breakpoint_store else {
 9947            return;
 9948        };
 9949
 9950        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9951            if breakpoint_position == Anchor::min() {
 9952                self.buffer()
 9953                    .read(cx)
 9954                    .excerpt_buffer_ids()
 9955                    .into_iter()
 9956                    .next()
 9957            } else {
 9958                None
 9959            }
 9960        }) else {
 9961            return;
 9962        };
 9963
 9964        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9965            return;
 9966        };
 9967
 9968        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9969            breakpoint_store.toggle_breakpoint(
 9970                buffer,
 9971                BreakpointWithPosition {
 9972                    position: breakpoint_position.text_anchor,
 9973                    bp: breakpoint,
 9974                },
 9975                edit_action,
 9976                cx,
 9977            );
 9978        });
 9979
 9980        cx.notify();
 9981    }
 9982
 9983    #[cfg(any(test, feature = "test-support"))]
 9984    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9985        self.breakpoint_store.clone()
 9986    }
 9987
 9988    pub fn prepare_restore_change(
 9989        &self,
 9990        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9991        hunk: &MultiBufferDiffHunk,
 9992        cx: &mut App,
 9993    ) -> Option<()> {
 9994        if hunk.is_created_file() {
 9995            return None;
 9996        }
 9997        let buffer = self.buffer.read(cx);
 9998        let diff = buffer.diff_for(hunk.buffer_id)?;
 9999        let buffer = buffer.buffer(hunk.buffer_id)?;
10000        let buffer = buffer.read(cx);
10001        let original_text = diff
10002            .read(cx)
10003            .base_text()
10004            .as_rope()
10005            .slice(hunk.diff_base_byte_range.clone());
10006        let buffer_snapshot = buffer.snapshot();
10007        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10008        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10009            probe
10010                .0
10011                .start
10012                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10013                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10014        }) {
10015            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10016            Some(())
10017        } else {
10018            None
10019        }
10020    }
10021
10022    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10023        self.manipulate_lines(window, cx, |lines| lines.reverse())
10024    }
10025
10026    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10027        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10028    }
10029
10030    fn manipulate_lines<Fn>(
10031        &mut self,
10032        window: &mut Window,
10033        cx: &mut Context<Self>,
10034        mut callback: Fn,
10035    ) where
10036        Fn: FnMut(&mut Vec<&str>),
10037    {
10038        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10039
10040        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10041        let buffer = self.buffer.read(cx).snapshot(cx);
10042
10043        let mut edits = Vec::new();
10044
10045        let selections = self.selections.all::<Point>(cx);
10046        let mut selections = selections.iter().peekable();
10047        let mut contiguous_row_selections = Vec::new();
10048        let mut new_selections = Vec::new();
10049        let mut added_lines = 0;
10050        let mut removed_lines = 0;
10051
10052        while let Some(selection) = selections.next() {
10053            let (start_row, end_row) = consume_contiguous_rows(
10054                &mut contiguous_row_selections,
10055                selection,
10056                &display_map,
10057                &mut selections,
10058            );
10059
10060            let start_point = Point::new(start_row.0, 0);
10061            let end_point = Point::new(
10062                end_row.previous_row().0,
10063                buffer.line_len(end_row.previous_row()),
10064            );
10065            let text = buffer
10066                .text_for_range(start_point..end_point)
10067                .collect::<String>();
10068
10069            let mut lines = text.split('\n').collect_vec();
10070
10071            let lines_before = lines.len();
10072            callback(&mut lines);
10073            let lines_after = lines.len();
10074
10075            edits.push((start_point..end_point, lines.join("\n")));
10076
10077            // Selections must change based on added and removed line count
10078            let start_row =
10079                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10080            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10081            new_selections.push(Selection {
10082                id: selection.id,
10083                start: start_row,
10084                end: end_row,
10085                goal: SelectionGoal::None,
10086                reversed: selection.reversed,
10087            });
10088
10089            if lines_after > lines_before {
10090                added_lines += lines_after - lines_before;
10091            } else if lines_before > lines_after {
10092                removed_lines += lines_before - lines_after;
10093            }
10094        }
10095
10096        self.transact(window, cx, |this, window, cx| {
10097            let buffer = this.buffer.update(cx, |buffer, cx| {
10098                buffer.edit(edits, None, cx);
10099                buffer.snapshot(cx)
10100            });
10101
10102            // Recalculate offsets on newly edited buffer
10103            let new_selections = new_selections
10104                .iter()
10105                .map(|s| {
10106                    let start_point = Point::new(s.start.0, 0);
10107                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10108                    Selection {
10109                        id: s.id,
10110                        start: buffer.point_to_offset(start_point),
10111                        end: buffer.point_to_offset(end_point),
10112                        goal: s.goal,
10113                        reversed: s.reversed,
10114                    }
10115                })
10116                .collect();
10117
10118            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10119                s.select(new_selections);
10120            });
10121
10122            this.request_autoscroll(Autoscroll::fit(), cx);
10123        });
10124    }
10125
10126    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10127        self.manipulate_text(window, cx, |text| {
10128            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10129            if has_upper_case_characters {
10130                text.to_lowercase()
10131            } else {
10132                text.to_uppercase()
10133            }
10134        })
10135    }
10136
10137    pub fn convert_to_upper_case(
10138        &mut self,
10139        _: &ConvertToUpperCase,
10140        window: &mut Window,
10141        cx: &mut Context<Self>,
10142    ) {
10143        self.manipulate_text(window, cx, |text| text.to_uppercase())
10144    }
10145
10146    pub fn convert_to_lower_case(
10147        &mut self,
10148        _: &ConvertToLowerCase,
10149        window: &mut Window,
10150        cx: &mut Context<Self>,
10151    ) {
10152        self.manipulate_text(window, cx, |text| text.to_lowercase())
10153    }
10154
10155    pub fn convert_to_title_case(
10156        &mut self,
10157        _: &ConvertToTitleCase,
10158        window: &mut Window,
10159        cx: &mut Context<Self>,
10160    ) {
10161        self.manipulate_text(window, cx, |text| {
10162            text.split('\n')
10163                .map(|line| line.to_case(Case::Title))
10164                .join("\n")
10165        })
10166    }
10167
10168    pub fn convert_to_snake_case(
10169        &mut self,
10170        _: &ConvertToSnakeCase,
10171        window: &mut Window,
10172        cx: &mut Context<Self>,
10173    ) {
10174        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10175    }
10176
10177    pub fn convert_to_kebab_case(
10178        &mut self,
10179        _: &ConvertToKebabCase,
10180        window: &mut Window,
10181        cx: &mut Context<Self>,
10182    ) {
10183        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10184    }
10185
10186    pub fn convert_to_upper_camel_case(
10187        &mut self,
10188        _: &ConvertToUpperCamelCase,
10189        window: &mut Window,
10190        cx: &mut Context<Self>,
10191    ) {
10192        self.manipulate_text(window, cx, |text| {
10193            text.split('\n')
10194                .map(|line| line.to_case(Case::UpperCamel))
10195                .join("\n")
10196        })
10197    }
10198
10199    pub fn convert_to_lower_camel_case(
10200        &mut self,
10201        _: &ConvertToLowerCamelCase,
10202        window: &mut Window,
10203        cx: &mut Context<Self>,
10204    ) {
10205        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10206    }
10207
10208    pub fn convert_to_opposite_case(
10209        &mut self,
10210        _: &ConvertToOppositeCase,
10211        window: &mut Window,
10212        cx: &mut Context<Self>,
10213    ) {
10214        self.manipulate_text(window, cx, |text| {
10215            text.chars()
10216                .fold(String::with_capacity(text.len()), |mut t, c| {
10217                    if c.is_uppercase() {
10218                        t.extend(c.to_lowercase());
10219                    } else {
10220                        t.extend(c.to_uppercase());
10221                    }
10222                    t
10223                })
10224        })
10225    }
10226
10227    pub fn convert_to_rot13(
10228        &mut self,
10229        _: &ConvertToRot13,
10230        window: &mut Window,
10231        cx: &mut Context<Self>,
10232    ) {
10233        self.manipulate_text(window, cx, |text| {
10234            text.chars()
10235                .map(|c| match c {
10236                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10237                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10238                    _ => c,
10239                })
10240                .collect()
10241        })
10242    }
10243
10244    pub fn convert_to_rot47(
10245        &mut self,
10246        _: &ConvertToRot47,
10247        window: &mut Window,
10248        cx: &mut Context<Self>,
10249    ) {
10250        self.manipulate_text(window, cx, |text| {
10251            text.chars()
10252                .map(|c| {
10253                    let code_point = c as u32;
10254                    if code_point >= 33 && code_point <= 126 {
10255                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10256                    }
10257                    c
10258                })
10259                .collect()
10260        })
10261    }
10262
10263    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10264    where
10265        Fn: FnMut(&str) -> String,
10266    {
10267        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10268        let buffer = self.buffer.read(cx).snapshot(cx);
10269
10270        let mut new_selections = Vec::new();
10271        let mut edits = Vec::new();
10272        let mut selection_adjustment = 0i32;
10273
10274        for selection in self.selections.all::<usize>(cx) {
10275            let selection_is_empty = selection.is_empty();
10276
10277            let (start, end) = if selection_is_empty {
10278                let word_range = movement::surrounding_word(
10279                    &display_map,
10280                    selection.start.to_display_point(&display_map),
10281                );
10282                let start = word_range.start.to_offset(&display_map, Bias::Left);
10283                let end = word_range.end.to_offset(&display_map, Bias::Left);
10284                (start, end)
10285            } else {
10286                (selection.start, selection.end)
10287            };
10288
10289            let text = buffer.text_for_range(start..end).collect::<String>();
10290            let old_length = text.len() as i32;
10291            let text = callback(&text);
10292
10293            new_selections.push(Selection {
10294                start: (start as i32 - selection_adjustment) as usize,
10295                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10296                goal: SelectionGoal::None,
10297                ..selection
10298            });
10299
10300            selection_adjustment += old_length - text.len() as i32;
10301
10302            edits.push((start..end, text));
10303        }
10304
10305        self.transact(window, cx, |this, window, cx| {
10306            this.buffer.update(cx, |buffer, cx| {
10307                buffer.edit(edits, None, cx);
10308            });
10309
10310            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10311                s.select(new_selections);
10312            });
10313
10314            this.request_autoscroll(Autoscroll::fit(), cx);
10315        });
10316    }
10317
10318    pub fn duplicate(
10319        &mut self,
10320        upwards: bool,
10321        whole_lines: bool,
10322        window: &mut Window,
10323        cx: &mut Context<Self>,
10324    ) {
10325        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10326
10327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10328        let buffer = &display_map.buffer_snapshot;
10329        let selections = self.selections.all::<Point>(cx);
10330
10331        let mut edits = Vec::new();
10332        let mut selections_iter = selections.iter().peekable();
10333        while let Some(selection) = selections_iter.next() {
10334            let mut rows = selection.spanned_rows(false, &display_map);
10335            // duplicate line-wise
10336            if whole_lines || selection.start == selection.end {
10337                // Avoid duplicating the same lines twice.
10338                while let Some(next_selection) = selections_iter.peek() {
10339                    let next_rows = next_selection.spanned_rows(false, &display_map);
10340                    if next_rows.start < rows.end {
10341                        rows.end = next_rows.end;
10342                        selections_iter.next().unwrap();
10343                    } else {
10344                        break;
10345                    }
10346                }
10347
10348                // Copy the text from the selected row region and splice it either at the start
10349                // or end of the region.
10350                let start = Point::new(rows.start.0, 0);
10351                let end = Point::new(
10352                    rows.end.previous_row().0,
10353                    buffer.line_len(rows.end.previous_row()),
10354                );
10355                let text = buffer
10356                    .text_for_range(start..end)
10357                    .chain(Some("\n"))
10358                    .collect::<String>();
10359                let insert_location = if upwards {
10360                    Point::new(rows.end.0, 0)
10361                } else {
10362                    start
10363                };
10364                edits.push((insert_location..insert_location, text));
10365            } else {
10366                // duplicate character-wise
10367                let start = selection.start;
10368                let end = selection.end;
10369                let text = buffer.text_for_range(start..end).collect::<String>();
10370                edits.push((selection.end..selection.end, text));
10371            }
10372        }
10373
10374        self.transact(window, cx, |this, _, cx| {
10375            this.buffer.update(cx, |buffer, cx| {
10376                buffer.edit(edits, None, cx);
10377            });
10378
10379            this.request_autoscroll(Autoscroll::fit(), cx);
10380        });
10381    }
10382
10383    pub fn duplicate_line_up(
10384        &mut self,
10385        _: &DuplicateLineUp,
10386        window: &mut Window,
10387        cx: &mut Context<Self>,
10388    ) {
10389        self.duplicate(true, true, window, cx);
10390    }
10391
10392    pub fn duplicate_line_down(
10393        &mut self,
10394        _: &DuplicateLineDown,
10395        window: &mut Window,
10396        cx: &mut Context<Self>,
10397    ) {
10398        self.duplicate(false, true, window, cx);
10399    }
10400
10401    pub fn duplicate_selection(
10402        &mut self,
10403        _: &DuplicateSelection,
10404        window: &mut Window,
10405        cx: &mut Context<Self>,
10406    ) {
10407        self.duplicate(false, false, window, cx);
10408    }
10409
10410    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10411        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10412
10413        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10414        let buffer = self.buffer.read(cx).snapshot(cx);
10415
10416        let mut edits = Vec::new();
10417        let mut unfold_ranges = Vec::new();
10418        let mut refold_creases = Vec::new();
10419
10420        let selections = self.selections.all::<Point>(cx);
10421        let mut selections = selections.iter().peekable();
10422        let mut contiguous_row_selections = Vec::new();
10423        let mut new_selections = Vec::new();
10424
10425        while let Some(selection) = selections.next() {
10426            // Find all the selections that span a contiguous row range
10427            let (start_row, end_row) = consume_contiguous_rows(
10428                &mut contiguous_row_selections,
10429                selection,
10430                &display_map,
10431                &mut selections,
10432            );
10433
10434            // Move the text spanned by the row range to be before the line preceding the row range
10435            if start_row.0 > 0 {
10436                let range_to_move = Point::new(
10437                    start_row.previous_row().0,
10438                    buffer.line_len(start_row.previous_row()),
10439                )
10440                    ..Point::new(
10441                        end_row.previous_row().0,
10442                        buffer.line_len(end_row.previous_row()),
10443                    );
10444                let insertion_point = display_map
10445                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10446                    .0;
10447
10448                // Don't move lines across excerpts
10449                if buffer
10450                    .excerpt_containing(insertion_point..range_to_move.end)
10451                    .is_some()
10452                {
10453                    let text = buffer
10454                        .text_for_range(range_to_move.clone())
10455                        .flat_map(|s| s.chars())
10456                        .skip(1)
10457                        .chain(['\n'])
10458                        .collect::<String>();
10459
10460                    edits.push((
10461                        buffer.anchor_after(range_to_move.start)
10462                            ..buffer.anchor_before(range_to_move.end),
10463                        String::new(),
10464                    ));
10465                    let insertion_anchor = buffer.anchor_after(insertion_point);
10466                    edits.push((insertion_anchor..insertion_anchor, text));
10467
10468                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10469
10470                    // Move selections up
10471                    new_selections.extend(contiguous_row_selections.drain(..).map(
10472                        |mut selection| {
10473                            selection.start.row -= row_delta;
10474                            selection.end.row -= row_delta;
10475                            selection
10476                        },
10477                    ));
10478
10479                    // Move folds up
10480                    unfold_ranges.push(range_to_move.clone());
10481                    for fold in display_map.folds_in_range(
10482                        buffer.anchor_before(range_to_move.start)
10483                            ..buffer.anchor_after(range_to_move.end),
10484                    ) {
10485                        let mut start = fold.range.start.to_point(&buffer);
10486                        let mut end = fold.range.end.to_point(&buffer);
10487                        start.row -= row_delta;
10488                        end.row -= row_delta;
10489                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10490                    }
10491                }
10492            }
10493
10494            // If we didn't move line(s), preserve the existing selections
10495            new_selections.append(&mut contiguous_row_selections);
10496        }
10497
10498        self.transact(window, cx, |this, window, cx| {
10499            this.unfold_ranges(&unfold_ranges, true, true, cx);
10500            this.buffer.update(cx, |buffer, cx| {
10501                for (range, text) in edits {
10502                    buffer.edit([(range, text)], None, cx);
10503                }
10504            });
10505            this.fold_creases(refold_creases, true, window, cx);
10506            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10507                s.select(new_selections);
10508            })
10509        });
10510    }
10511
10512    pub fn move_line_down(
10513        &mut self,
10514        _: &MoveLineDown,
10515        window: &mut Window,
10516        cx: &mut Context<Self>,
10517    ) {
10518        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10519
10520        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10521        let buffer = self.buffer.read(cx).snapshot(cx);
10522
10523        let mut edits = Vec::new();
10524        let mut unfold_ranges = Vec::new();
10525        let mut refold_creases = Vec::new();
10526
10527        let selections = self.selections.all::<Point>(cx);
10528        let mut selections = selections.iter().peekable();
10529        let mut contiguous_row_selections = Vec::new();
10530        let mut new_selections = Vec::new();
10531
10532        while let Some(selection) = selections.next() {
10533            // Find all the selections that span a contiguous row range
10534            let (start_row, end_row) = consume_contiguous_rows(
10535                &mut contiguous_row_selections,
10536                selection,
10537                &display_map,
10538                &mut selections,
10539            );
10540
10541            // Move the text spanned by the row range to be after the last line of the row range
10542            if end_row.0 <= buffer.max_point().row {
10543                let range_to_move =
10544                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10545                let insertion_point = display_map
10546                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10547                    .0;
10548
10549                // Don't move lines across excerpt boundaries
10550                if buffer
10551                    .excerpt_containing(range_to_move.start..insertion_point)
10552                    .is_some()
10553                {
10554                    let mut text = String::from("\n");
10555                    text.extend(buffer.text_for_range(range_to_move.clone()));
10556                    text.pop(); // Drop trailing newline
10557                    edits.push((
10558                        buffer.anchor_after(range_to_move.start)
10559                            ..buffer.anchor_before(range_to_move.end),
10560                        String::new(),
10561                    ));
10562                    let insertion_anchor = buffer.anchor_after(insertion_point);
10563                    edits.push((insertion_anchor..insertion_anchor, text));
10564
10565                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10566
10567                    // Move selections down
10568                    new_selections.extend(contiguous_row_selections.drain(..).map(
10569                        |mut selection| {
10570                            selection.start.row += row_delta;
10571                            selection.end.row += row_delta;
10572                            selection
10573                        },
10574                    ));
10575
10576                    // Move folds down
10577                    unfold_ranges.push(range_to_move.clone());
10578                    for fold in display_map.folds_in_range(
10579                        buffer.anchor_before(range_to_move.start)
10580                            ..buffer.anchor_after(range_to_move.end),
10581                    ) {
10582                        let mut start = fold.range.start.to_point(&buffer);
10583                        let mut end = fold.range.end.to_point(&buffer);
10584                        start.row += row_delta;
10585                        end.row += row_delta;
10586                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10587                    }
10588                }
10589            }
10590
10591            // If we didn't move line(s), preserve the existing selections
10592            new_selections.append(&mut contiguous_row_selections);
10593        }
10594
10595        self.transact(window, cx, |this, window, cx| {
10596            this.unfold_ranges(&unfold_ranges, true, true, cx);
10597            this.buffer.update(cx, |buffer, cx| {
10598                for (range, text) in edits {
10599                    buffer.edit([(range, text)], None, cx);
10600                }
10601            });
10602            this.fold_creases(refold_creases, true, window, cx);
10603            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10604                s.select(new_selections)
10605            });
10606        });
10607    }
10608
10609    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10610        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10611        let text_layout_details = &self.text_layout_details(window);
10612        self.transact(window, cx, |this, window, cx| {
10613            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10614                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10615                s.move_with(|display_map, selection| {
10616                    if !selection.is_empty() {
10617                        return;
10618                    }
10619
10620                    let mut head = selection.head();
10621                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10622                    if head.column() == display_map.line_len(head.row()) {
10623                        transpose_offset = display_map
10624                            .buffer_snapshot
10625                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10626                    }
10627
10628                    if transpose_offset == 0 {
10629                        return;
10630                    }
10631
10632                    *head.column_mut() += 1;
10633                    head = display_map.clip_point(head, Bias::Right);
10634                    let goal = SelectionGoal::HorizontalPosition(
10635                        display_map
10636                            .x_for_display_point(head, text_layout_details)
10637                            .into(),
10638                    );
10639                    selection.collapse_to(head, goal);
10640
10641                    let transpose_start = display_map
10642                        .buffer_snapshot
10643                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10644                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10645                        let transpose_end = display_map
10646                            .buffer_snapshot
10647                            .clip_offset(transpose_offset + 1, Bias::Right);
10648                        if let Some(ch) =
10649                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10650                        {
10651                            edits.push((transpose_start..transpose_offset, String::new()));
10652                            edits.push((transpose_end..transpose_end, ch.to_string()));
10653                        }
10654                    }
10655                });
10656                edits
10657            });
10658            this.buffer
10659                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10660            let selections = this.selections.all::<usize>(cx);
10661            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10662                s.select(selections);
10663            });
10664        });
10665    }
10666
10667    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10668        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10669        self.rewrap_impl(RewrapOptions::default(), cx)
10670    }
10671
10672    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10673        let buffer = self.buffer.read(cx).snapshot(cx);
10674        let selections = self.selections.all::<Point>(cx);
10675        let mut selections = selections.iter().peekable();
10676
10677        let mut edits = Vec::new();
10678        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10679
10680        while let Some(selection) = selections.next() {
10681            let mut start_row = selection.start.row;
10682            let mut end_row = selection.end.row;
10683
10684            // Skip selections that overlap with a range that has already been rewrapped.
10685            let selection_range = start_row..end_row;
10686            if rewrapped_row_ranges
10687                .iter()
10688                .any(|range| range.overlaps(&selection_range))
10689            {
10690                continue;
10691            }
10692
10693            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10694
10695            // Since not all lines in the selection may be at the same indent
10696            // level, choose the indent size that is the most common between all
10697            // of the lines.
10698            //
10699            // If there is a tie, we use the deepest indent.
10700            let (indent_size, indent_end) = {
10701                let mut indent_size_occurrences = HashMap::default();
10702                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10703
10704                for row in start_row..=end_row {
10705                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10706                    rows_by_indent_size.entry(indent).or_default().push(row);
10707                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10708                }
10709
10710                let indent_size = indent_size_occurrences
10711                    .into_iter()
10712                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10713                    .map(|(indent, _)| indent)
10714                    .unwrap_or_default();
10715                let row = rows_by_indent_size[&indent_size][0];
10716                let indent_end = Point::new(row, indent_size.len);
10717
10718                (indent_size, indent_end)
10719            };
10720
10721            let mut line_prefix = indent_size.chars().collect::<String>();
10722
10723            let mut inside_comment = false;
10724            if let Some(comment_prefix) =
10725                buffer
10726                    .language_scope_at(selection.head())
10727                    .and_then(|language| {
10728                        language
10729                            .line_comment_prefixes()
10730                            .iter()
10731                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10732                            .cloned()
10733                    })
10734            {
10735                line_prefix.push_str(&comment_prefix);
10736                inside_comment = true;
10737            }
10738
10739            let language_settings = buffer.language_settings_at(selection.head(), cx);
10740            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10741                RewrapBehavior::InComments => inside_comment,
10742                RewrapBehavior::InSelections => !selection.is_empty(),
10743                RewrapBehavior::Anywhere => true,
10744            };
10745
10746            let should_rewrap = options.override_language_settings
10747                || allow_rewrap_based_on_language
10748                || self.hard_wrap.is_some();
10749            if !should_rewrap {
10750                continue;
10751            }
10752
10753            if selection.is_empty() {
10754                'expand_upwards: while start_row > 0 {
10755                    let prev_row = start_row - 1;
10756                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10757                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10758                    {
10759                        start_row = prev_row;
10760                    } else {
10761                        break 'expand_upwards;
10762                    }
10763                }
10764
10765                'expand_downwards: while end_row < buffer.max_point().row {
10766                    let next_row = end_row + 1;
10767                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10768                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10769                    {
10770                        end_row = next_row;
10771                    } else {
10772                        break 'expand_downwards;
10773                    }
10774                }
10775            }
10776
10777            let start = Point::new(start_row, 0);
10778            let start_offset = start.to_offset(&buffer);
10779            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10780            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10781            let Some(lines_without_prefixes) = selection_text
10782                .lines()
10783                .map(|line| {
10784                    line.strip_prefix(&line_prefix)
10785                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10786                        .with_context(|| {
10787                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10788                        })
10789                })
10790                .collect::<Result<Vec<_>, _>>()
10791                .log_err()
10792            else {
10793                continue;
10794            };
10795
10796            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10797                buffer
10798                    .language_settings_at(Point::new(start_row, 0), cx)
10799                    .preferred_line_length as usize
10800            });
10801            let wrapped_text = wrap_with_prefix(
10802                line_prefix,
10803                lines_without_prefixes.join("\n"),
10804                wrap_column,
10805                tab_size,
10806                options.preserve_existing_whitespace,
10807            );
10808
10809            // TODO: should always use char-based diff while still supporting cursor behavior that
10810            // matches vim.
10811            let mut diff_options = DiffOptions::default();
10812            if options.override_language_settings {
10813                diff_options.max_word_diff_len = 0;
10814                diff_options.max_word_diff_line_count = 0;
10815            } else {
10816                diff_options.max_word_diff_len = usize::MAX;
10817                diff_options.max_word_diff_line_count = usize::MAX;
10818            }
10819
10820            for (old_range, new_text) in
10821                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10822            {
10823                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10824                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10825                edits.push((edit_start..edit_end, new_text));
10826            }
10827
10828            rewrapped_row_ranges.push(start_row..=end_row);
10829        }
10830
10831        self.buffer
10832            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10833    }
10834
10835    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10836        let mut text = String::new();
10837        let buffer = self.buffer.read(cx).snapshot(cx);
10838        let mut selections = self.selections.all::<Point>(cx);
10839        let mut clipboard_selections = Vec::with_capacity(selections.len());
10840        {
10841            let max_point = buffer.max_point();
10842            let mut is_first = true;
10843            for selection in &mut selections {
10844                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10845                if is_entire_line {
10846                    selection.start = Point::new(selection.start.row, 0);
10847                    if !selection.is_empty() && selection.end.column == 0 {
10848                        selection.end = cmp::min(max_point, selection.end);
10849                    } else {
10850                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10851                    }
10852                    selection.goal = SelectionGoal::None;
10853                }
10854                if is_first {
10855                    is_first = false;
10856                } else {
10857                    text += "\n";
10858                }
10859                let mut len = 0;
10860                for chunk in buffer.text_for_range(selection.start..selection.end) {
10861                    text.push_str(chunk);
10862                    len += chunk.len();
10863                }
10864                clipboard_selections.push(ClipboardSelection {
10865                    len,
10866                    is_entire_line,
10867                    first_line_indent: buffer
10868                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10869                        .len,
10870                });
10871            }
10872        }
10873
10874        self.transact(window, cx, |this, window, cx| {
10875            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10876                s.select(selections);
10877            });
10878            this.insert("", window, cx);
10879        });
10880        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10881    }
10882
10883    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10884        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10885        let item = self.cut_common(window, cx);
10886        cx.write_to_clipboard(item);
10887    }
10888
10889    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10890        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10891        self.change_selections(None, window, cx, |s| {
10892            s.move_with(|snapshot, sel| {
10893                if sel.is_empty() {
10894                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10895                }
10896            });
10897        });
10898        let item = self.cut_common(window, cx);
10899        cx.set_global(KillRing(item))
10900    }
10901
10902    pub fn kill_ring_yank(
10903        &mut self,
10904        _: &KillRingYank,
10905        window: &mut Window,
10906        cx: &mut Context<Self>,
10907    ) {
10908        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10909        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10910            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10911                (kill_ring.text().to_string(), kill_ring.metadata_json())
10912            } else {
10913                return;
10914            }
10915        } else {
10916            return;
10917        };
10918        self.do_paste(&text, metadata, false, window, cx);
10919    }
10920
10921    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10922        self.do_copy(true, cx);
10923    }
10924
10925    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10926        self.do_copy(false, cx);
10927    }
10928
10929    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10930        let selections = self.selections.all::<Point>(cx);
10931        let buffer = self.buffer.read(cx).read(cx);
10932        let mut text = String::new();
10933
10934        let mut clipboard_selections = Vec::with_capacity(selections.len());
10935        {
10936            let max_point = buffer.max_point();
10937            let mut is_first = true;
10938            for selection in &selections {
10939                let mut start = selection.start;
10940                let mut end = selection.end;
10941                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10942                if is_entire_line {
10943                    start = Point::new(start.row, 0);
10944                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10945                }
10946
10947                let mut trimmed_selections = Vec::new();
10948                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10949                    let row = MultiBufferRow(start.row);
10950                    let first_indent = buffer.indent_size_for_line(row);
10951                    if first_indent.len == 0 || start.column > first_indent.len {
10952                        trimmed_selections.push(start..end);
10953                    } else {
10954                        trimmed_selections.push(
10955                            Point::new(row.0, first_indent.len)
10956                                ..Point::new(row.0, buffer.line_len(row)),
10957                        );
10958                        for row in start.row + 1..=end.row {
10959                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10960                            if row == end.row {
10961                                line_len = end.column;
10962                            }
10963                            if line_len == 0 {
10964                                trimmed_selections
10965                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10966                                continue;
10967                            }
10968                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10969                            if row_indent_size.len >= first_indent.len {
10970                                trimmed_selections.push(
10971                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10972                                );
10973                            } else {
10974                                trimmed_selections.clear();
10975                                trimmed_selections.push(start..end);
10976                                break;
10977                            }
10978                        }
10979                    }
10980                } else {
10981                    trimmed_selections.push(start..end);
10982                }
10983
10984                for trimmed_range in trimmed_selections {
10985                    if is_first {
10986                        is_first = false;
10987                    } else {
10988                        text += "\n";
10989                    }
10990                    let mut len = 0;
10991                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10992                        text.push_str(chunk);
10993                        len += chunk.len();
10994                    }
10995                    clipboard_selections.push(ClipboardSelection {
10996                        len,
10997                        is_entire_line,
10998                        first_line_indent: buffer
10999                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11000                            .len,
11001                    });
11002                }
11003            }
11004        }
11005
11006        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11007            text,
11008            clipboard_selections,
11009        ));
11010    }
11011
11012    pub fn do_paste(
11013        &mut self,
11014        text: &String,
11015        clipboard_selections: Option<Vec<ClipboardSelection>>,
11016        handle_entire_lines: bool,
11017        window: &mut Window,
11018        cx: &mut Context<Self>,
11019    ) {
11020        if self.read_only(cx) {
11021            return;
11022        }
11023
11024        let clipboard_text = Cow::Borrowed(text);
11025
11026        self.transact(window, cx, |this, window, cx| {
11027            if let Some(mut clipboard_selections) = clipboard_selections {
11028                let old_selections = this.selections.all::<usize>(cx);
11029                let all_selections_were_entire_line =
11030                    clipboard_selections.iter().all(|s| s.is_entire_line);
11031                let first_selection_indent_column =
11032                    clipboard_selections.first().map(|s| s.first_line_indent);
11033                if clipboard_selections.len() != old_selections.len() {
11034                    clipboard_selections.drain(..);
11035                }
11036                let cursor_offset = this.selections.last::<usize>(cx).head();
11037                let mut auto_indent_on_paste = true;
11038
11039                this.buffer.update(cx, |buffer, cx| {
11040                    let snapshot = buffer.read(cx);
11041                    auto_indent_on_paste = snapshot
11042                        .language_settings_at(cursor_offset, cx)
11043                        .auto_indent_on_paste;
11044
11045                    let mut start_offset = 0;
11046                    let mut edits = Vec::new();
11047                    let mut original_indent_columns = Vec::new();
11048                    for (ix, selection) in old_selections.iter().enumerate() {
11049                        let to_insert;
11050                        let entire_line;
11051                        let original_indent_column;
11052                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11053                            let end_offset = start_offset + clipboard_selection.len;
11054                            to_insert = &clipboard_text[start_offset..end_offset];
11055                            entire_line = clipboard_selection.is_entire_line;
11056                            start_offset = end_offset + 1;
11057                            original_indent_column = Some(clipboard_selection.first_line_indent);
11058                        } else {
11059                            to_insert = clipboard_text.as_str();
11060                            entire_line = all_selections_were_entire_line;
11061                            original_indent_column = first_selection_indent_column
11062                        }
11063
11064                        // If the corresponding selection was empty when this slice of the
11065                        // clipboard text was written, then the entire line containing the
11066                        // selection was copied. If this selection is also currently empty,
11067                        // then paste the line before the current line of the buffer.
11068                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11069                            let column = selection.start.to_point(&snapshot).column as usize;
11070                            let line_start = selection.start - column;
11071                            line_start..line_start
11072                        } else {
11073                            selection.range()
11074                        };
11075
11076                        edits.push((range, to_insert));
11077                        original_indent_columns.push(original_indent_column);
11078                    }
11079                    drop(snapshot);
11080
11081                    buffer.edit(
11082                        edits,
11083                        if auto_indent_on_paste {
11084                            Some(AutoindentMode::Block {
11085                                original_indent_columns,
11086                            })
11087                        } else {
11088                            None
11089                        },
11090                        cx,
11091                    );
11092                });
11093
11094                let selections = this.selections.all::<usize>(cx);
11095                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11096                    s.select(selections)
11097                });
11098            } else {
11099                this.insert(&clipboard_text, window, cx);
11100            }
11101        });
11102    }
11103
11104    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11105        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11106        if let Some(item) = cx.read_from_clipboard() {
11107            let entries = item.entries();
11108
11109            match entries.first() {
11110                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11111                // of all the pasted entries.
11112                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11113                    .do_paste(
11114                        clipboard_string.text(),
11115                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11116                        true,
11117                        window,
11118                        cx,
11119                    ),
11120                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11121            }
11122        }
11123    }
11124
11125    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11126        if self.read_only(cx) {
11127            return;
11128        }
11129
11130        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11131
11132        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11133            if let Some((selections, _)) =
11134                self.selection_history.transaction(transaction_id).cloned()
11135            {
11136                self.change_selections(None, window, cx, |s| {
11137                    s.select_anchors(selections.to_vec());
11138                });
11139            } else {
11140                log::error!(
11141                    "No entry in selection_history found for undo. \
11142                     This may correspond to a bug where undo does not update the selection. \
11143                     If this is occurring, please add details to \
11144                     https://github.com/zed-industries/zed/issues/22692"
11145                );
11146            }
11147            self.request_autoscroll(Autoscroll::fit(), cx);
11148            self.unmark_text(window, cx);
11149            self.refresh_inline_completion(true, false, window, cx);
11150            cx.emit(EditorEvent::Edited { transaction_id });
11151            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11152        }
11153    }
11154
11155    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11156        if self.read_only(cx) {
11157            return;
11158        }
11159
11160        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11161
11162        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11163            if let Some((_, Some(selections))) =
11164                self.selection_history.transaction(transaction_id).cloned()
11165            {
11166                self.change_selections(None, window, cx, |s| {
11167                    s.select_anchors(selections.to_vec());
11168                });
11169            } else {
11170                log::error!(
11171                    "No entry in selection_history found for redo. \
11172                     This may correspond to a bug where undo does not update the selection. \
11173                     If this is occurring, please add details to \
11174                     https://github.com/zed-industries/zed/issues/22692"
11175                );
11176            }
11177            self.request_autoscroll(Autoscroll::fit(), cx);
11178            self.unmark_text(window, cx);
11179            self.refresh_inline_completion(true, false, window, cx);
11180            cx.emit(EditorEvent::Edited { transaction_id });
11181        }
11182    }
11183
11184    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11185        self.buffer
11186            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11187    }
11188
11189    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11190        self.buffer
11191            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11192    }
11193
11194    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11195        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11196        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11197            s.move_with(|map, selection| {
11198                let cursor = if selection.is_empty() {
11199                    movement::left(map, selection.start)
11200                } else {
11201                    selection.start
11202                };
11203                selection.collapse_to(cursor, SelectionGoal::None);
11204            });
11205        })
11206    }
11207
11208    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11209        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11210        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11211            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11212        })
11213    }
11214
11215    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11216        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11217        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11218            s.move_with(|map, selection| {
11219                let cursor = if selection.is_empty() {
11220                    movement::right(map, selection.end)
11221                } else {
11222                    selection.end
11223                };
11224                selection.collapse_to(cursor, SelectionGoal::None)
11225            });
11226        })
11227    }
11228
11229    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11230        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11231        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11232            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11233        })
11234    }
11235
11236    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11237        if self.take_rename(true, window, cx).is_some() {
11238            return;
11239        }
11240
11241        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11242            cx.propagate();
11243            return;
11244        }
11245
11246        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11247
11248        let text_layout_details = &self.text_layout_details(window);
11249        let selection_count = self.selections.count();
11250        let first_selection = self.selections.first_anchor();
11251
11252        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11253            s.move_with(|map, selection| {
11254                if !selection.is_empty() {
11255                    selection.goal = SelectionGoal::None;
11256                }
11257                let (cursor, goal) = movement::up(
11258                    map,
11259                    selection.start,
11260                    selection.goal,
11261                    false,
11262                    text_layout_details,
11263                );
11264                selection.collapse_to(cursor, goal);
11265            });
11266        });
11267
11268        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11269        {
11270            cx.propagate();
11271        }
11272    }
11273
11274    pub fn move_up_by_lines(
11275        &mut self,
11276        action: &MoveUpByLines,
11277        window: &mut Window,
11278        cx: &mut Context<Self>,
11279    ) {
11280        if self.take_rename(true, window, cx).is_some() {
11281            return;
11282        }
11283
11284        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11285            cx.propagate();
11286            return;
11287        }
11288
11289        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11290
11291        let text_layout_details = &self.text_layout_details(window);
11292
11293        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11294            s.move_with(|map, selection| {
11295                if !selection.is_empty() {
11296                    selection.goal = SelectionGoal::None;
11297                }
11298                let (cursor, goal) = movement::up_by_rows(
11299                    map,
11300                    selection.start,
11301                    action.lines,
11302                    selection.goal,
11303                    false,
11304                    text_layout_details,
11305                );
11306                selection.collapse_to(cursor, goal);
11307            });
11308        })
11309    }
11310
11311    pub fn move_down_by_lines(
11312        &mut self,
11313        action: &MoveDownByLines,
11314        window: &mut Window,
11315        cx: &mut Context<Self>,
11316    ) {
11317        if self.take_rename(true, window, cx).is_some() {
11318            return;
11319        }
11320
11321        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11322            cx.propagate();
11323            return;
11324        }
11325
11326        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11327
11328        let text_layout_details = &self.text_layout_details(window);
11329
11330        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11331            s.move_with(|map, selection| {
11332                if !selection.is_empty() {
11333                    selection.goal = SelectionGoal::None;
11334                }
11335                let (cursor, goal) = movement::down_by_rows(
11336                    map,
11337                    selection.start,
11338                    action.lines,
11339                    selection.goal,
11340                    false,
11341                    text_layout_details,
11342                );
11343                selection.collapse_to(cursor, goal);
11344            });
11345        })
11346    }
11347
11348    pub fn select_down_by_lines(
11349        &mut self,
11350        action: &SelectDownByLines,
11351        window: &mut Window,
11352        cx: &mut Context<Self>,
11353    ) {
11354        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11355        let text_layout_details = &self.text_layout_details(window);
11356        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11357            s.move_heads_with(|map, head, goal| {
11358                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11359            })
11360        })
11361    }
11362
11363    pub fn select_up_by_lines(
11364        &mut self,
11365        action: &SelectUpByLines,
11366        window: &mut Window,
11367        cx: &mut Context<Self>,
11368    ) {
11369        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11370        let text_layout_details = &self.text_layout_details(window);
11371        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11372            s.move_heads_with(|map, head, goal| {
11373                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11374            })
11375        })
11376    }
11377
11378    pub fn select_page_up(
11379        &mut self,
11380        _: &SelectPageUp,
11381        window: &mut Window,
11382        cx: &mut Context<Self>,
11383    ) {
11384        let Some(row_count) = self.visible_row_count() else {
11385            return;
11386        };
11387
11388        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11389
11390        let text_layout_details = &self.text_layout_details(window);
11391
11392        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11393            s.move_heads_with(|map, head, goal| {
11394                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11395            })
11396        })
11397    }
11398
11399    pub fn move_page_up(
11400        &mut self,
11401        action: &MovePageUp,
11402        window: &mut Window,
11403        cx: &mut Context<Self>,
11404    ) {
11405        if self.take_rename(true, window, cx).is_some() {
11406            return;
11407        }
11408
11409        if self
11410            .context_menu
11411            .borrow_mut()
11412            .as_mut()
11413            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11414            .unwrap_or(false)
11415        {
11416            return;
11417        }
11418
11419        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11420            cx.propagate();
11421            return;
11422        }
11423
11424        let Some(row_count) = self.visible_row_count() else {
11425            return;
11426        };
11427
11428        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11429
11430        let autoscroll = if action.center_cursor {
11431            Autoscroll::center()
11432        } else {
11433            Autoscroll::fit()
11434        };
11435
11436        let text_layout_details = &self.text_layout_details(window);
11437
11438        self.change_selections(Some(autoscroll), window, cx, |s| {
11439            s.move_with(|map, selection| {
11440                if !selection.is_empty() {
11441                    selection.goal = SelectionGoal::None;
11442                }
11443                let (cursor, goal) = movement::up_by_rows(
11444                    map,
11445                    selection.end,
11446                    row_count,
11447                    selection.goal,
11448                    false,
11449                    text_layout_details,
11450                );
11451                selection.collapse_to(cursor, goal);
11452            });
11453        });
11454    }
11455
11456    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11457        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11458        let text_layout_details = &self.text_layout_details(window);
11459        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11460            s.move_heads_with(|map, head, goal| {
11461                movement::up(map, head, goal, false, text_layout_details)
11462            })
11463        })
11464    }
11465
11466    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11467        self.take_rename(true, window, cx);
11468
11469        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11470            cx.propagate();
11471            return;
11472        }
11473
11474        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11475
11476        let text_layout_details = &self.text_layout_details(window);
11477        let selection_count = self.selections.count();
11478        let first_selection = self.selections.first_anchor();
11479
11480        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11481            s.move_with(|map, selection| {
11482                if !selection.is_empty() {
11483                    selection.goal = SelectionGoal::None;
11484                }
11485                let (cursor, goal) = movement::down(
11486                    map,
11487                    selection.end,
11488                    selection.goal,
11489                    false,
11490                    text_layout_details,
11491                );
11492                selection.collapse_to(cursor, goal);
11493            });
11494        });
11495
11496        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11497        {
11498            cx.propagate();
11499        }
11500    }
11501
11502    pub fn select_page_down(
11503        &mut self,
11504        _: &SelectPageDown,
11505        window: &mut Window,
11506        cx: &mut Context<Self>,
11507    ) {
11508        let Some(row_count) = self.visible_row_count() else {
11509            return;
11510        };
11511
11512        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11513
11514        let text_layout_details = &self.text_layout_details(window);
11515
11516        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11517            s.move_heads_with(|map, head, goal| {
11518                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11519            })
11520        })
11521    }
11522
11523    pub fn move_page_down(
11524        &mut self,
11525        action: &MovePageDown,
11526        window: &mut Window,
11527        cx: &mut Context<Self>,
11528    ) {
11529        if self.take_rename(true, window, cx).is_some() {
11530            return;
11531        }
11532
11533        if self
11534            .context_menu
11535            .borrow_mut()
11536            .as_mut()
11537            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11538            .unwrap_or(false)
11539        {
11540            return;
11541        }
11542
11543        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11544            cx.propagate();
11545            return;
11546        }
11547
11548        let Some(row_count) = self.visible_row_count() else {
11549            return;
11550        };
11551
11552        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11553
11554        let autoscroll = if action.center_cursor {
11555            Autoscroll::center()
11556        } else {
11557            Autoscroll::fit()
11558        };
11559
11560        let text_layout_details = &self.text_layout_details(window);
11561        self.change_selections(Some(autoscroll), window, cx, |s| {
11562            s.move_with(|map, selection| {
11563                if !selection.is_empty() {
11564                    selection.goal = SelectionGoal::None;
11565                }
11566                let (cursor, goal) = movement::down_by_rows(
11567                    map,
11568                    selection.end,
11569                    row_count,
11570                    selection.goal,
11571                    false,
11572                    text_layout_details,
11573                );
11574                selection.collapse_to(cursor, goal);
11575            });
11576        });
11577    }
11578
11579    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11580        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11581        let text_layout_details = &self.text_layout_details(window);
11582        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11583            s.move_heads_with(|map, head, goal| {
11584                movement::down(map, head, goal, false, text_layout_details)
11585            })
11586        });
11587    }
11588
11589    pub fn context_menu_first(
11590        &mut self,
11591        _: &ContextMenuFirst,
11592        window: &mut Window,
11593        cx: &mut Context<Self>,
11594    ) {
11595        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11596            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11597        }
11598    }
11599
11600    pub fn context_menu_prev(
11601        &mut self,
11602        _: &ContextMenuPrevious,
11603        window: &mut Window,
11604        cx: &mut Context<Self>,
11605    ) {
11606        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11607            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11608        }
11609    }
11610
11611    pub fn context_menu_next(
11612        &mut self,
11613        _: &ContextMenuNext,
11614        window: &mut Window,
11615        cx: &mut Context<Self>,
11616    ) {
11617        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11618            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11619        }
11620    }
11621
11622    pub fn context_menu_last(
11623        &mut self,
11624        _: &ContextMenuLast,
11625        window: &mut Window,
11626        cx: &mut Context<Self>,
11627    ) {
11628        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11629            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11630        }
11631    }
11632
11633    pub fn move_to_previous_word_start(
11634        &mut self,
11635        _: &MoveToPreviousWordStart,
11636        window: &mut Window,
11637        cx: &mut Context<Self>,
11638    ) {
11639        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11640        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11641            s.move_cursors_with(|map, head, _| {
11642                (
11643                    movement::previous_word_start(map, head),
11644                    SelectionGoal::None,
11645                )
11646            });
11647        })
11648    }
11649
11650    pub fn move_to_previous_subword_start(
11651        &mut self,
11652        _: &MoveToPreviousSubwordStart,
11653        window: &mut Window,
11654        cx: &mut Context<Self>,
11655    ) {
11656        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11657        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11658            s.move_cursors_with(|map, head, _| {
11659                (
11660                    movement::previous_subword_start(map, head),
11661                    SelectionGoal::None,
11662                )
11663            });
11664        })
11665    }
11666
11667    pub fn select_to_previous_word_start(
11668        &mut self,
11669        _: &SelectToPreviousWordStart,
11670        window: &mut Window,
11671        cx: &mut Context<Self>,
11672    ) {
11673        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11674        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11675            s.move_heads_with(|map, head, _| {
11676                (
11677                    movement::previous_word_start(map, head),
11678                    SelectionGoal::None,
11679                )
11680            });
11681        })
11682    }
11683
11684    pub fn select_to_previous_subword_start(
11685        &mut self,
11686        _: &SelectToPreviousSubwordStart,
11687        window: &mut Window,
11688        cx: &mut Context<Self>,
11689    ) {
11690        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11691        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11692            s.move_heads_with(|map, head, _| {
11693                (
11694                    movement::previous_subword_start(map, head),
11695                    SelectionGoal::None,
11696                )
11697            });
11698        })
11699    }
11700
11701    pub fn delete_to_previous_word_start(
11702        &mut self,
11703        action: &DeleteToPreviousWordStart,
11704        window: &mut Window,
11705        cx: &mut Context<Self>,
11706    ) {
11707        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11708        self.transact(window, cx, |this, window, cx| {
11709            this.select_autoclose_pair(window, cx);
11710            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11711                s.move_with(|map, selection| {
11712                    if selection.is_empty() {
11713                        let cursor = if action.ignore_newlines {
11714                            movement::previous_word_start(map, selection.head())
11715                        } else {
11716                            movement::previous_word_start_or_newline(map, selection.head())
11717                        };
11718                        selection.set_head(cursor, SelectionGoal::None);
11719                    }
11720                });
11721            });
11722            this.insert("", window, cx);
11723        });
11724    }
11725
11726    pub fn delete_to_previous_subword_start(
11727        &mut self,
11728        _: &DeleteToPreviousSubwordStart,
11729        window: &mut Window,
11730        cx: &mut Context<Self>,
11731    ) {
11732        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11733        self.transact(window, cx, |this, window, cx| {
11734            this.select_autoclose_pair(window, cx);
11735            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11736                s.move_with(|map, selection| {
11737                    if selection.is_empty() {
11738                        let cursor = movement::previous_subword_start(map, selection.head());
11739                        selection.set_head(cursor, SelectionGoal::None);
11740                    }
11741                });
11742            });
11743            this.insert("", window, cx);
11744        });
11745    }
11746
11747    pub fn move_to_next_word_end(
11748        &mut self,
11749        _: &MoveToNextWordEnd,
11750        window: &mut Window,
11751        cx: &mut Context<Self>,
11752    ) {
11753        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11754        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11755            s.move_cursors_with(|map, head, _| {
11756                (movement::next_word_end(map, head), SelectionGoal::None)
11757            });
11758        })
11759    }
11760
11761    pub fn move_to_next_subword_end(
11762        &mut self,
11763        _: &MoveToNextSubwordEnd,
11764        window: &mut Window,
11765        cx: &mut Context<Self>,
11766    ) {
11767        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11768        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11769            s.move_cursors_with(|map, head, _| {
11770                (movement::next_subword_end(map, head), SelectionGoal::None)
11771            });
11772        })
11773    }
11774
11775    pub fn select_to_next_word_end(
11776        &mut self,
11777        _: &SelectToNextWordEnd,
11778        window: &mut Window,
11779        cx: &mut Context<Self>,
11780    ) {
11781        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11782        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11783            s.move_heads_with(|map, head, _| {
11784                (movement::next_word_end(map, head), SelectionGoal::None)
11785            });
11786        })
11787    }
11788
11789    pub fn select_to_next_subword_end(
11790        &mut self,
11791        _: &SelectToNextSubwordEnd,
11792        window: &mut Window,
11793        cx: &mut Context<Self>,
11794    ) {
11795        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11796        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11797            s.move_heads_with(|map, head, _| {
11798                (movement::next_subword_end(map, head), SelectionGoal::None)
11799            });
11800        })
11801    }
11802
11803    pub fn delete_to_next_word_end(
11804        &mut self,
11805        action: &DeleteToNextWordEnd,
11806        window: &mut Window,
11807        cx: &mut Context<Self>,
11808    ) {
11809        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11810        self.transact(window, cx, |this, window, cx| {
11811            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11812                s.move_with(|map, selection| {
11813                    if selection.is_empty() {
11814                        let cursor = if action.ignore_newlines {
11815                            movement::next_word_end(map, selection.head())
11816                        } else {
11817                            movement::next_word_end_or_newline(map, selection.head())
11818                        };
11819                        selection.set_head(cursor, SelectionGoal::None);
11820                    }
11821                });
11822            });
11823            this.insert("", window, cx);
11824        });
11825    }
11826
11827    pub fn delete_to_next_subword_end(
11828        &mut self,
11829        _: &DeleteToNextSubwordEnd,
11830        window: &mut Window,
11831        cx: &mut Context<Self>,
11832    ) {
11833        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11834        self.transact(window, cx, |this, window, cx| {
11835            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11836                s.move_with(|map, selection| {
11837                    if selection.is_empty() {
11838                        let cursor = movement::next_subword_end(map, selection.head());
11839                        selection.set_head(cursor, SelectionGoal::None);
11840                    }
11841                });
11842            });
11843            this.insert("", window, cx);
11844        });
11845    }
11846
11847    pub fn move_to_beginning_of_line(
11848        &mut self,
11849        action: &MoveToBeginningOfLine,
11850        window: &mut Window,
11851        cx: &mut Context<Self>,
11852    ) {
11853        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11854        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11855            s.move_cursors_with(|map, head, _| {
11856                (
11857                    movement::indented_line_beginning(
11858                        map,
11859                        head,
11860                        action.stop_at_soft_wraps,
11861                        action.stop_at_indent,
11862                    ),
11863                    SelectionGoal::None,
11864                )
11865            });
11866        })
11867    }
11868
11869    pub fn select_to_beginning_of_line(
11870        &mut self,
11871        action: &SelectToBeginningOfLine,
11872        window: &mut Window,
11873        cx: &mut Context<Self>,
11874    ) {
11875        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11876        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11877            s.move_heads_with(|map, head, _| {
11878                (
11879                    movement::indented_line_beginning(
11880                        map,
11881                        head,
11882                        action.stop_at_soft_wraps,
11883                        action.stop_at_indent,
11884                    ),
11885                    SelectionGoal::None,
11886                )
11887            });
11888        });
11889    }
11890
11891    pub fn delete_to_beginning_of_line(
11892        &mut self,
11893        action: &DeleteToBeginningOfLine,
11894        window: &mut Window,
11895        cx: &mut Context<Self>,
11896    ) {
11897        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11898        self.transact(window, cx, |this, window, cx| {
11899            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11900                s.move_with(|_, selection| {
11901                    selection.reversed = true;
11902                });
11903            });
11904
11905            this.select_to_beginning_of_line(
11906                &SelectToBeginningOfLine {
11907                    stop_at_soft_wraps: false,
11908                    stop_at_indent: action.stop_at_indent,
11909                },
11910                window,
11911                cx,
11912            );
11913            this.backspace(&Backspace, window, cx);
11914        });
11915    }
11916
11917    pub fn move_to_end_of_line(
11918        &mut self,
11919        action: &MoveToEndOfLine,
11920        window: &mut Window,
11921        cx: &mut Context<Self>,
11922    ) {
11923        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11924        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11925            s.move_cursors_with(|map, head, _| {
11926                (
11927                    movement::line_end(map, head, action.stop_at_soft_wraps),
11928                    SelectionGoal::None,
11929                )
11930            });
11931        })
11932    }
11933
11934    pub fn select_to_end_of_line(
11935        &mut self,
11936        action: &SelectToEndOfLine,
11937        window: &mut Window,
11938        cx: &mut Context<Self>,
11939    ) {
11940        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11941        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11942            s.move_heads_with(|map, head, _| {
11943                (
11944                    movement::line_end(map, head, action.stop_at_soft_wraps),
11945                    SelectionGoal::None,
11946                )
11947            });
11948        })
11949    }
11950
11951    pub fn delete_to_end_of_line(
11952        &mut self,
11953        _: &DeleteToEndOfLine,
11954        window: &mut Window,
11955        cx: &mut Context<Self>,
11956    ) {
11957        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11958        self.transact(window, cx, |this, window, cx| {
11959            this.select_to_end_of_line(
11960                &SelectToEndOfLine {
11961                    stop_at_soft_wraps: false,
11962                },
11963                window,
11964                cx,
11965            );
11966            this.delete(&Delete, window, cx);
11967        });
11968    }
11969
11970    pub fn cut_to_end_of_line(
11971        &mut self,
11972        _: &CutToEndOfLine,
11973        window: &mut Window,
11974        cx: &mut Context<Self>,
11975    ) {
11976        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11977        self.transact(window, cx, |this, window, cx| {
11978            this.select_to_end_of_line(
11979                &SelectToEndOfLine {
11980                    stop_at_soft_wraps: false,
11981                },
11982                window,
11983                cx,
11984            );
11985            this.cut(&Cut, window, cx);
11986        });
11987    }
11988
11989    pub fn move_to_start_of_paragraph(
11990        &mut self,
11991        _: &MoveToStartOfParagraph,
11992        window: &mut Window,
11993        cx: &mut Context<Self>,
11994    ) {
11995        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11996            cx.propagate();
11997            return;
11998        }
11999        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12000        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12001            s.move_with(|map, selection| {
12002                selection.collapse_to(
12003                    movement::start_of_paragraph(map, selection.head(), 1),
12004                    SelectionGoal::None,
12005                )
12006            });
12007        })
12008    }
12009
12010    pub fn move_to_end_of_paragraph(
12011        &mut self,
12012        _: &MoveToEndOfParagraph,
12013        window: &mut Window,
12014        cx: &mut Context<Self>,
12015    ) {
12016        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12017            cx.propagate();
12018            return;
12019        }
12020        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12021        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12022            s.move_with(|map, selection| {
12023                selection.collapse_to(
12024                    movement::end_of_paragraph(map, selection.head(), 1),
12025                    SelectionGoal::None,
12026                )
12027            });
12028        })
12029    }
12030
12031    pub fn select_to_start_of_paragraph(
12032        &mut self,
12033        _: &SelectToStartOfParagraph,
12034        window: &mut Window,
12035        cx: &mut Context<Self>,
12036    ) {
12037        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12038            cx.propagate();
12039            return;
12040        }
12041        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12042        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12043            s.move_heads_with(|map, head, _| {
12044                (
12045                    movement::start_of_paragraph(map, head, 1),
12046                    SelectionGoal::None,
12047                )
12048            });
12049        })
12050    }
12051
12052    pub fn select_to_end_of_paragraph(
12053        &mut self,
12054        _: &SelectToEndOfParagraph,
12055        window: &mut Window,
12056        cx: &mut Context<Self>,
12057    ) {
12058        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12059            cx.propagate();
12060            return;
12061        }
12062        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12063        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12064            s.move_heads_with(|map, head, _| {
12065                (
12066                    movement::end_of_paragraph(map, head, 1),
12067                    SelectionGoal::None,
12068                )
12069            });
12070        })
12071    }
12072
12073    pub fn move_to_start_of_excerpt(
12074        &mut self,
12075        _: &MoveToStartOfExcerpt,
12076        window: &mut Window,
12077        cx: &mut Context<Self>,
12078    ) {
12079        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12080            cx.propagate();
12081            return;
12082        }
12083        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12084        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12085            s.move_with(|map, selection| {
12086                selection.collapse_to(
12087                    movement::start_of_excerpt(
12088                        map,
12089                        selection.head(),
12090                        workspace::searchable::Direction::Prev,
12091                    ),
12092                    SelectionGoal::None,
12093                )
12094            });
12095        })
12096    }
12097
12098    pub fn move_to_start_of_next_excerpt(
12099        &mut self,
12100        _: &MoveToStartOfNextExcerpt,
12101        window: &mut Window,
12102        cx: &mut Context<Self>,
12103    ) {
12104        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12105            cx.propagate();
12106            return;
12107        }
12108
12109        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12110            s.move_with(|map, selection| {
12111                selection.collapse_to(
12112                    movement::start_of_excerpt(
12113                        map,
12114                        selection.head(),
12115                        workspace::searchable::Direction::Next,
12116                    ),
12117                    SelectionGoal::None,
12118                )
12119            });
12120        })
12121    }
12122
12123    pub fn move_to_end_of_excerpt(
12124        &mut self,
12125        _: &MoveToEndOfExcerpt,
12126        window: &mut Window,
12127        cx: &mut Context<Self>,
12128    ) {
12129        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12130            cx.propagate();
12131            return;
12132        }
12133        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12134        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12135            s.move_with(|map, selection| {
12136                selection.collapse_to(
12137                    movement::end_of_excerpt(
12138                        map,
12139                        selection.head(),
12140                        workspace::searchable::Direction::Next,
12141                    ),
12142                    SelectionGoal::None,
12143                )
12144            });
12145        })
12146    }
12147
12148    pub fn move_to_end_of_previous_excerpt(
12149        &mut self,
12150        _: &MoveToEndOfPreviousExcerpt,
12151        window: &mut Window,
12152        cx: &mut Context<Self>,
12153    ) {
12154        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12155            cx.propagate();
12156            return;
12157        }
12158        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12159        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12160            s.move_with(|map, selection| {
12161                selection.collapse_to(
12162                    movement::end_of_excerpt(
12163                        map,
12164                        selection.head(),
12165                        workspace::searchable::Direction::Prev,
12166                    ),
12167                    SelectionGoal::None,
12168                )
12169            });
12170        })
12171    }
12172
12173    pub fn select_to_start_of_excerpt(
12174        &mut self,
12175        _: &SelectToStartOfExcerpt,
12176        window: &mut Window,
12177        cx: &mut Context<Self>,
12178    ) {
12179        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12180            cx.propagate();
12181            return;
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::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12188                    SelectionGoal::None,
12189                )
12190            });
12191        })
12192    }
12193
12194    pub fn select_to_start_of_next_excerpt(
12195        &mut self,
12196        _: &SelectToStartOfNextExcerpt,
12197        window: &mut Window,
12198        cx: &mut Context<Self>,
12199    ) {
12200        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12201            cx.propagate();
12202            return;
12203        }
12204        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12205        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12206            s.move_heads_with(|map, head, _| {
12207                (
12208                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12209                    SelectionGoal::None,
12210                )
12211            });
12212        })
12213    }
12214
12215    pub fn select_to_end_of_excerpt(
12216        &mut self,
12217        _: &SelectToEndOfExcerpt,
12218        window: &mut Window,
12219        cx: &mut Context<Self>,
12220    ) {
12221        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12222            cx.propagate();
12223            return;
12224        }
12225        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12226        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12227            s.move_heads_with(|map, head, _| {
12228                (
12229                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12230                    SelectionGoal::None,
12231                )
12232            });
12233        })
12234    }
12235
12236    pub fn select_to_end_of_previous_excerpt(
12237        &mut self,
12238        _: &SelectToEndOfPreviousExcerpt,
12239        window: &mut Window,
12240        cx: &mut Context<Self>,
12241    ) {
12242        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12243            cx.propagate();
12244            return;
12245        }
12246        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12247        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12248            s.move_heads_with(|map, head, _| {
12249                (
12250                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12251                    SelectionGoal::None,
12252                )
12253            });
12254        })
12255    }
12256
12257    pub fn move_to_beginning(
12258        &mut self,
12259        _: &MoveToBeginning,
12260        window: &mut Window,
12261        cx: &mut Context<Self>,
12262    ) {
12263        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12264            cx.propagate();
12265            return;
12266        }
12267        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12268        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12269            s.select_ranges(vec![0..0]);
12270        });
12271    }
12272
12273    pub fn select_to_beginning(
12274        &mut self,
12275        _: &SelectToBeginning,
12276        window: &mut Window,
12277        cx: &mut Context<Self>,
12278    ) {
12279        let mut selection = self.selections.last::<Point>(cx);
12280        selection.set_head(Point::zero(), SelectionGoal::None);
12281        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12282        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12283            s.select(vec![selection]);
12284        });
12285    }
12286
12287    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12288        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12289            cx.propagate();
12290            return;
12291        }
12292        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12293        let cursor = self.buffer.read(cx).read(cx).len();
12294        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12295            s.select_ranges(vec![cursor..cursor])
12296        });
12297    }
12298
12299    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12300        self.nav_history = nav_history;
12301    }
12302
12303    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12304        self.nav_history.as_ref()
12305    }
12306
12307    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12308        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12309    }
12310
12311    fn push_to_nav_history(
12312        &mut self,
12313        cursor_anchor: Anchor,
12314        new_position: Option<Point>,
12315        is_deactivate: bool,
12316        cx: &mut Context<Self>,
12317    ) {
12318        if let Some(nav_history) = self.nav_history.as_mut() {
12319            let buffer = self.buffer.read(cx).read(cx);
12320            let cursor_position = cursor_anchor.to_point(&buffer);
12321            let scroll_state = self.scroll_manager.anchor();
12322            let scroll_top_row = scroll_state.top_row(&buffer);
12323            drop(buffer);
12324
12325            if let Some(new_position) = new_position {
12326                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12327                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12328                    return;
12329                }
12330            }
12331
12332            nav_history.push(
12333                Some(NavigationData {
12334                    cursor_anchor,
12335                    cursor_position,
12336                    scroll_anchor: scroll_state,
12337                    scroll_top_row,
12338                }),
12339                cx,
12340            );
12341            cx.emit(EditorEvent::PushedToNavHistory {
12342                anchor: cursor_anchor,
12343                is_deactivate,
12344            })
12345        }
12346    }
12347
12348    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12349        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12350        let buffer = self.buffer.read(cx).snapshot(cx);
12351        let mut selection = self.selections.first::<usize>(cx);
12352        selection.set_head(buffer.len(), SelectionGoal::None);
12353        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12354            s.select(vec![selection]);
12355        });
12356    }
12357
12358    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12359        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12360        let end = self.buffer.read(cx).read(cx).len();
12361        self.change_selections(None, window, cx, |s| {
12362            s.select_ranges(vec![0..end]);
12363        });
12364    }
12365
12366    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12367        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12368        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12369        let mut selections = self.selections.all::<Point>(cx);
12370        let max_point = display_map.buffer_snapshot.max_point();
12371        for selection in &mut selections {
12372            let rows = selection.spanned_rows(true, &display_map);
12373            selection.start = Point::new(rows.start.0, 0);
12374            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12375            selection.reversed = false;
12376        }
12377        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12378            s.select(selections);
12379        });
12380    }
12381
12382    pub fn split_selection_into_lines(
12383        &mut self,
12384        _: &SplitSelectionIntoLines,
12385        window: &mut Window,
12386        cx: &mut Context<Self>,
12387    ) {
12388        let selections = self
12389            .selections
12390            .all::<Point>(cx)
12391            .into_iter()
12392            .map(|selection| selection.start..selection.end)
12393            .collect::<Vec<_>>();
12394        self.unfold_ranges(&selections, true, true, cx);
12395
12396        let mut new_selection_ranges = Vec::new();
12397        {
12398            let buffer = self.buffer.read(cx).read(cx);
12399            for selection in selections {
12400                for row in selection.start.row..selection.end.row {
12401                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12402                    new_selection_ranges.push(cursor..cursor);
12403                }
12404
12405                let is_multiline_selection = selection.start.row != selection.end.row;
12406                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12407                // so this action feels more ergonomic when paired with other selection operations
12408                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12409                if !should_skip_last {
12410                    new_selection_ranges.push(selection.end..selection.end);
12411                }
12412            }
12413        }
12414        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12415            s.select_ranges(new_selection_ranges);
12416        });
12417    }
12418
12419    pub fn add_selection_above(
12420        &mut self,
12421        _: &AddSelectionAbove,
12422        window: &mut Window,
12423        cx: &mut Context<Self>,
12424    ) {
12425        self.add_selection(true, window, cx);
12426    }
12427
12428    pub fn add_selection_below(
12429        &mut self,
12430        _: &AddSelectionBelow,
12431        window: &mut Window,
12432        cx: &mut Context<Self>,
12433    ) {
12434        self.add_selection(false, window, cx);
12435    }
12436
12437    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12438        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12439
12440        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12441        let mut selections = self.selections.all::<Point>(cx);
12442        let text_layout_details = self.text_layout_details(window);
12443        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12444            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12445            let range = oldest_selection.display_range(&display_map).sorted();
12446
12447            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12448            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12449            let positions = start_x.min(end_x)..start_x.max(end_x);
12450
12451            selections.clear();
12452            let mut stack = Vec::new();
12453            for row in range.start.row().0..=range.end.row().0 {
12454                if let Some(selection) = self.selections.build_columnar_selection(
12455                    &display_map,
12456                    DisplayRow(row),
12457                    &positions,
12458                    oldest_selection.reversed,
12459                    &text_layout_details,
12460                ) {
12461                    stack.push(selection.id);
12462                    selections.push(selection);
12463                }
12464            }
12465
12466            if above {
12467                stack.reverse();
12468            }
12469
12470            AddSelectionsState { above, stack }
12471        });
12472
12473        let last_added_selection = *state.stack.last().unwrap();
12474        let mut new_selections = Vec::new();
12475        if above == state.above {
12476            let end_row = if above {
12477                DisplayRow(0)
12478            } else {
12479                display_map.max_point().row()
12480            };
12481
12482            'outer: for selection in selections {
12483                if selection.id == last_added_selection {
12484                    let range = selection.display_range(&display_map).sorted();
12485                    debug_assert_eq!(range.start.row(), range.end.row());
12486                    let mut row = range.start.row();
12487                    let positions =
12488                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12489                            px(start)..px(end)
12490                        } else {
12491                            let start_x =
12492                                display_map.x_for_display_point(range.start, &text_layout_details);
12493                            let end_x =
12494                                display_map.x_for_display_point(range.end, &text_layout_details);
12495                            start_x.min(end_x)..start_x.max(end_x)
12496                        };
12497
12498                    while row != end_row {
12499                        if above {
12500                            row.0 -= 1;
12501                        } else {
12502                            row.0 += 1;
12503                        }
12504
12505                        if let Some(new_selection) = self.selections.build_columnar_selection(
12506                            &display_map,
12507                            row,
12508                            &positions,
12509                            selection.reversed,
12510                            &text_layout_details,
12511                        ) {
12512                            state.stack.push(new_selection.id);
12513                            if above {
12514                                new_selections.push(new_selection);
12515                                new_selections.push(selection);
12516                            } else {
12517                                new_selections.push(selection);
12518                                new_selections.push(new_selection);
12519                            }
12520
12521                            continue 'outer;
12522                        }
12523                    }
12524                }
12525
12526                new_selections.push(selection);
12527            }
12528        } else {
12529            new_selections = selections;
12530            new_selections.retain(|s| s.id != last_added_selection);
12531            state.stack.pop();
12532        }
12533
12534        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12535            s.select(new_selections);
12536        });
12537        if state.stack.len() > 1 {
12538            self.add_selections_state = Some(state);
12539        }
12540    }
12541
12542    fn select_match_ranges(
12543        &mut self,
12544        range: Range<usize>,
12545        reversed: bool,
12546        replace_newest: bool,
12547        auto_scroll: Option<Autoscroll>,
12548        window: &mut Window,
12549        cx: &mut Context<Editor>,
12550    ) {
12551        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12552        self.change_selections(auto_scroll, window, cx, |s| {
12553            if replace_newest {
12554                s.delete(s.newest_anchor().id);
12555            }
12556            if reversed {
12557                s.insert_range(range.end..range.start);
12558            } else {
12559                s.insert_range(range);
12560            }
12561        });
12562    }
12563
12564    pub fn select_next_match_internal(
12565        &mut self,
12566        display_map: &DisplaySnapshot,
12567        replace_newest: bool,
12568        autoscroll: Option<Autoscroll>,
12569        window: &mut Window,
12570        cx: &mut Context<Self>,
12571    ) -> Result<()> {
12572        let buffer = &display_map.buffer_snapshot;
12573        let mut selections = self.selections.all::<usize>(cx);
12574        if let Some(mut select_next_state) = self.select_next_state.take() {
12575            let query = &select_next_state.query;
12576            if !select_next_state.done {
12577                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12578                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12579                let mut next_selected_range = None;
12580
12581                let bytes_after_last_selection =
12582                    buffer.bytes_in_range(last_selection.end..buffer.len());
12583                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12584                let query_matches = query
12585                    .stream_find_iter(bytes_after_last_selection)
12586                    .map(|result| (last_selection.end, result))
12587                    .chain(
12588                        query
12589                            .stream_find_iter(bytes_before_first_selection)
12590                            .map(|result| (0, result)),
12591                    );
12592
12593                for (start_offset, query_match) in query_matches {
12594                    let query_match = query_match.unwrap(); // can only fail due to I/O
12595                    let offset_range =
12596                        start_offset + query_match.start()..start_offset + query_match.end();
12597                    let display_range = offset_range.start.to_display_point(display_map)
12598                        ..offset_range.end.to_display_point(display_map);
12599
12600                    if !select_next_state.wordwise
12601                        || (!movement::is_inside_word(display_map, display_range.start)
12602                            && !movement::is_inside_word(display_map, display_range.end))
12603                    {
12604                        // TODO: This is n^2, because we might check all the selections
12605                        if !selections
12606                            .iter()
12607                            .any(|selection| selection.range().overlaps(&offset_range))
12608                        {
12609                            next_selected_range = Some(offset_range);
12610                            break;
12611                        }
12612                    }
12613                }
12614
12615                if let Some(next_selected_range) = next_selected_range {
12616                    self.select_match_ranges(
12617                        next_selected_range,
12618                        last_selection.reversed,
12619                        replace_newest,
12620                        autoscroll,
12621                        window,
12622                        cx,
12623                    );
12624                } else {
12625                    select_next_state.done = true;
12626                }
12627            }
12628
12629            self.select_next_state = Some(select_next_state);
12630        } else {
12631            let mut only_carets = true;
12632            let mut same_text_selected = true;
12633            let mut selected_text = None;
12634
12635            let mut selections_iter = selections.iter().peekable();
12636            while let Some(selection) = selections_iter.next() {
12637                if selection.start != selection.end {
12638                    only_carets = false;
12639                }
12640
12641                if same_text_selected {
12642                    if selected_text.is_none() {
12643                        selected_text =
12644                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12645                    }
12646
12647                    if let Some(next_selection) = selections_iter.peek() {
12648                        if next_selection.range().len() == selection.range().len() {
12649                            let next_selected_text = buffer
12650                                .text_for_range(next_selection.range())
12651                                .collect::<String>();
12652                            if Some(next_selected_text) != selected_text {
12653                                same_text_selected = false;
12654                                selected_text = None;
12655                            }
12656                        } else {
12657                            same_text_selected = false;
12658                            selected_text = None;
12659                        }
12660                    }
12661                }
12662            }
12663
12664            if only_carets {
12665                for selection in &mut selections {
12666                    let word_range = movement::surrounding_word(
12667                        display_map,
12668                        selection.start.to_display_point(display_map),
12669                    );
12670                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12671                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12672                    selection.goal = SelectionGoal::None;
12673                    selection.reversed = false;
12674                    self.select_match_ranges(
12675                        selection.start..selection.end,
12676                        selection.reversed,
12677                        replace_newest,
12678                        autoscroll,
12679                        window,
12680                        cx,
12681                    );
12682                }
12683
12684                if selections.len() == 1 {
12685                    let selection = selections
12686                        .last()
12687                        .expect("ensured that there's only one selection");
12688                    let query = buffer
12689                        .text_for_range(selection.start..selection.end)
12690                        .collect::<String>();
12691                    let is_empty = query.is_empty();
12692                    let select_state = SelectNextState {
12693                        query: AhoCorasick::new(&[query])?,
12694                        wordwise: true,
12695                        done: is_empty,
12696                    };
12697                    self.select_next_state = Some(select_state);
12698                } else {
12699                    self.select_next_state = None;
12700                }
12701            } else if let Some(selected_text) = selected_text {
12702                self.select_next_state = Some(SelectNextState {
12703                    query: AhoCorasick::new(&[selected_text])?,
12704                    wordwise: false,
12705                    done: false,
12706                });
12707                self.select_next_match_internal(
12708                    display_map,
12709                    replace_newest,
12710                    autoscroll,
12711                    window,
12712                    cx,
12713                )?;
12714            }
12715        }
12716        Ok(())
12717    }
12718
12719    pub fn select_all_matches(
12720        &mut self,
12721        _action: &SelectAllMatches,
12722        window: &mut Window,
12723        cx: &mut Context<Self>,
12724    ) -> Result<()> {
12725        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12726
12727        self.push_to_selection_history();
12728        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12729
12730        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12731        let Some(select_next_state) = self.select_next_state.as_mut() else {
12732            return Ok(());
12733        };
12734        if select_next_state.done {
12735            return Ok(());
12736        }
12737
12738        let mut new_selections = Vec::new();
12739
12740        let reversed = self.selections.oldest::<usize>(cx).reversed;
12741        let buffer = &display_map.buffer_snapshot;
12742        let query_matches = select_next_state
12743            .query
12744            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12745
12746        for query_match in query_matches.into_iter() {
12747            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12748            let offset_range = if reversed {
12749                query_match.end()..query_match.start()
12750            } else {
12751                query_match.start()..query_match.end()
12752            };
12753            let display_range = offset_range.start.to_display_point(&display_map)
12754                ..offset_range.end.to_display_point(&display_map);
12755
12756            if !select_next_state.wordwise
12757                || (!movement::is_inside_word(&display_map, display_range.start)
12758                    && !movement::is_inside_word(&display_map, display_range.end))
12759            {
12760                new_selections.push(offset_range.start..offset_range.end);
12761            }
12762        }
12763
12764        select_next_state.done = true;
12765        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12766        self.change_selections(None, window, cx, |selections| {
12767            selections.select_ranges(new_selections)
12768        });
12769
12770        Ok(())
12771    }
12772
12773    pub fn select_next(
12774        &mut self,
12775        action: &SelectNext,
12776        window: &mut Window,
12777        cx: &mut Context<Self>,
12778    ) -> Result<()> {
12779        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12780        self.push_to_selection_history();
12781        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12782        self.select_next_match_internal(
12783            &display_map,
12784            action.replace_newest,
12785            Some(Autoscroll::newest()),
12786            window,
12787            cx,
12788        )?;
12789        Ok(())
12790    }
12791
12792    pub fn select_previous(
12793        &mut self,
12794        action: &SelectPrevious,
12795        window: &mut Window,
12796        cx: &mut Context<Self>,
12797    ) -> Result<()> {
12798        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12799        self.push_to_selection_history();
12800        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12801        let buffer = &display_map.buffer_snapshot;
12802        let mut selections = self.selections.all::<usize>(cx);
12803        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12804            let query = &select_prev_state.query;
12805            if !select_prev_state.done {
12806                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12807                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12808                let mut next_selected_range = None;
12809                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12810                let bytes_before_last_selection =
12811                    buffer.reversed_bytes_in_range(0..last_selection.start);
12812                let bytes_after_first_selection =
12813                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12814                let query_matches = query
12815                    .stream_find_iter(bytes_before_last_selection)
12816                    .map(|result| (last_selection.start, result))
12817                    .chain(
12818                        query
12819                            .stream_find_iter(bytes_after_first_selection)
12820                            .map(|result| (buffer.len(), result)),
12821                    );
12822                for (end_offset, query_match) in query_matches {
12823                    let query_match = query_match.unwrap(); // can only fail due to I/O
12824                    let offset_range =
12825                        end_offset - query_match.end()..end_offset - query_match.start();
12826                    let display_range = offset_range.start.to_display_point(&display_map)
12827                        ..offset_range.end.to_display_point(&display_map);
12828
12829                    if !select_prev_state.wordwise
12830                        || (!movement::is_inside_word(&display_map, display_range.start)
12831                            && !movement::is_inside_word(&display_map, display_range.end))
12832                    {
12833                        next_selected_range = Some(offset_range);
12834                        break;
12835                    }
12836                }
12837
12838                if let Some(next_selected_range) = next_selected_range {
12839                    self.select_match_ranges(
12840                        next_selected_range,
12841                        last_selection.reversed,
12842                        action.replace_newest,
12843                        Some(Autoscroll::newest()),
12844                        window,
12845                        cx,
12846                    );
12847                } else {
12848                    select_prev_state.done = true;
12849                }
12850            }
12851
12852            self.select_prev_state = Some(select_prev_state);
12853        } else {
12854            let mut only_carets = true;
12855            let mut same_text_selected = true;
12856            let mut selected_text = None;
12857
12858            let mut selections_iter = selections.iter().peekable();
12859            while let Some(selection) = selections_iter.next() {
12860                if selection.start != selection.end {
12861                    only_carets = false;
12862                }
12863
12864                if same_text_selected {
12865                    if selected_text.is_none() {
12866                        selected_text =
12867                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12868                    }
12869
12870                    if let Some(next_selection) = selections_iter.peek() {
12871                        if next_selection.range().len() == selection.range().len() {
12872                            let next_selected_text = buffer
12873                                .text_for_range(next_selection.range())
12874                                .collect::<String>();
12875                            if Some(next_selected_text) != selected_text {
12876                                same_text_selected = false;
12877                                selected_text = None;
12878                            }
12879                        } else {
12880                            same_text_selected = false;
12881                            selected_text = None;
12882                        }
12883                    }
12884                }
12885            }
12886
12887            if only_carets {
12888                for selection in &mut selections {
12889                    let word_range = movement::surrounding_word(
12890                        &display_map,
12891                        selection.start.to_display_point(&display_map),
12892                    );
12893                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12894                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12895                    selection.goal = SelectionGoal::None;
12896                    selection.reversed = false;
12897                    self.select_match_ranges(
12898                        selection.start..selection.end,
12899                        selection.reversed,
12900                        action.replace_newest,
12901                        Some(Autoscroll::newest()),
12902                        window,
12903                        cx,
12904                    );
12905                }
12906                if selections.len() == 1 {
12907                    let selection = selections
12908                        .last()
12909                        .expect("ensured that there's only one selection");
12910                    let query = buffer
12911                        .text_for_range(selection.start..selection.end)
12912                        .collect::<String>();
12913                    let is_empty = query.is_empty();
12914                    let select_state = SelectNextState {
12915                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12916                        wordwise: true,
12917                        done: is_empty,
12918                    };
12919                    self.select_prev_state = Some(select_state);
12920                } else {
12921                    self.select_prev_state = None;
12922                }
12923            } else if let Some(selected_text) = selected_text {
12924                self.select_prev_state = Some(SelectNextState {
12925                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12926                    wordwise: false,
12927                    done: false,
12928                });
12929                self.select_previous(action, window, cx)?;
12930            }
12931        }
12932        Ok(())
12933    }
12934
12935    pub fn find_next_match(
12936        &mut self,
12937        _: &FindNextMatch,
12938        window: &mut Window,
12939        cx: &mut Context<Self>,
12940    ) -> Result<()> {
12941        let selections = self.selections.disjoint_anchors();
12942        match selections.first() {
12943            Some(first) if selections.len() >= 2 => {
12944                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12945                    s.select_ranges([first.range()]);
12946                });
12947            }
12948            _ => self.select_next(
12949                &SelectNext {
12950                    replace_newest: true,
12951                },
12952                window,
12953                cx,
12954            )?,
12955        }
12956        Ok(())
12957    }
12958
12959    pub fn find_previous_match(
12960        &mut self,
12961        _: &FindPreviousMatch,
12962        window: &mut Window,
12963        cx: &mut Context<Self>,
12964    ) -> Result<()> {
12965        let selections = self.selections.disjoint_anchors();
12966        match selections.last() {
12967            Some(last) if selections.len() >= 2 => {
12968                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12969                    s.select_ranges([last.range()]);
12970                });
12971            }
12972            _ => self.select_previous(
12973                &SelectPrevious {
12974                    replace_newest: true,
12975                },
12976                window,
12977                cx,
12978            )?,
12979        }
12980        Ok(())
12981    }
12982
12983    pub fn toggle_comments(
12984        &mut self,
12985        action: &ToggleComments,
12986        window: &mut Window,
12987        cx: &mut Context<Self>,
12988    ) {
12989        if self.read_only(cx) {
12990            return;
12991        }
12992        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12993        let text_layout_details = &self.text_layout_details(window);
12994        self.transact(window, cx, |this, window, cx| {
12995            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12996            let mut edits = Vec::new();
12997            let mut selection_edit_ranges = Vec::new();
12998            let mut last_toggled_row = None;
12999            let snapshot = this.buffer.read(cx).read(cx);
13000            let empty_str: Arc<str> = Arc::default();
13001            let mut suffixes_inserted = Vec::new();
13002            let ignore_indent = action.ignore_indent;
13003
13004            fn comment_prefix_range(
13005                snapshot: &MultiBufferSnapshot,
13006                row: MultiBufferRow,
13007                comment_prefix: &str,
13008                comment_prefix_whitespace: &str,
13009                ignore_indent: bool,
13010            ) -> Range<Point> {
13011                let indent_size = if ignore_indent {
13012                    0
13013                } else {
13014                    snapshot.indent_size_for_line(row).len
13015                };
13016
13017                let start = Point::new(row.0, indent_size);
13018
13019                let mut line_bytes = snapshot
13020                    .bytes_in_range(start..snapshot.max_point())
13021                    .flatten()
13022                    .copied();
13023
13024                // If this line currently begins with the line comment prefix, then record
13025                // the range containing the prefix.
13026                if line_bytes
13027                    .by_ref()
13028                    .take(comment_prefix.len())
13029                    .eq(comment_prefix.bytes())
13030                {
13031                    // Include any whitespace that matches the comment prefix.
13032                    let matching_whitespace_len = line_bytes
13033                        .zip(comment_prefix_whitespace.bytes())
13034                        .take_while(|(a, b)| a == b)
13035                        .count() as u32;
13036                    let end = Point::new(
13037                        start.row,
13038                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13039                    );
13040                    start..end
13041                } else {
13042                    start..start
13043                }
13044            }
13045
13046            fn comment_suffix_range(
13047                snapshot: &MultiBufferSnapshot,
13048                row: MultiBufferRow,
13049                comment_suffix: &str,
13050                comment_suffix_has_leading_space: bool,
13051            ) -> Range<Point> {
13052                let end = Point::new(row.0, snapshot.line_len(row));
13053                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13054
13055                let mut line_end_bytes = snapshot
13056                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13057                    .flatten()
13058                    .copied();
13059
13060                let leading_space_len = if suffix_start_column > 0
13061                    && line_end_bytes.next() == Some(b' ')
13062                    && comment_suffix_has_leading_space
13063                {
13064                    1
13065                } else {
13066                    0
13067                };
13068
13069                // If this line currently begins with the line comment prefix, then record
13070                // the range containing the prefix.
13071                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13072                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13073                    start..end
13074                } else {
13075                    end..end
13076                }
13077            }
13078
13079            // TODO: Handle selections that cross excerpts
13080            for selection in &mut selections {
13081                let start_column = snapshot
13082                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13083                    .len;
13084                let language = if let Some(language) =
13085                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13086                {
13087                    language
13088                } else {
13089                    continue;
13090                };
13091
13092                selection_edit_ranges.clear();
13093
13094                // If multiple selections contain a given row, avoid processing that
13095                // row more than once.
13096                let mut start_row = MultiBufferRow(selection.start.row);
13097                if last_toggled_row == Some(start_row) {
13098                    start_row = start_row.next_row();
13099                }
13100                let end_row =
13101                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13102                        MultiBufferRow(selection.end.row - 1)
13103                    } else {
13104                        MultiBufferRow(selection.end.row)
13105                    };
13106                last_toggled_row = Some(end_row);
13107
13108                if start_row > end_row {
13109                    continue;
13110                }
13111
13112                // If the language has line comments, toggle those.
13113                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13114
13115                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13116                if ignore_indent {
13117                    full_comment_prefixes = full_comment_prefixes
13118                        .into_iter()
13119                        .map(|s| Arc::from(s.trim_end()))
13120                        .collect();
13121                }
13122
13123                if !full_comment_prefixes.is_empty() {
13124                    let first_prefix = full_comment_prefixes
13125                        .first()
13126                        .expect("prefixes is non-empty");
13127                    let prefix_trimmed_lengths = full_comment_prefixes
13128                        .iter()
13129                        .map(|p| p.trim_end_matches(' ').len())
13130                        .collect::<SmallVec<[usize; 4]>>();
13131
13132                    let mut all_selection_lines_are_comments = true;
13133
13134                    for row in start_row.0..=end_row.0 {
13135                        let row = MultiBufferRow(row);
13136                        if start_row < end_row && snapshot.is_line_blank(row) {
13137                            continue;
13138                        }
13139
13140                        let prefix_range = full_comment_prefixes
13141                            .iter()
13142                            .zip(prefix_trimmed_lengths.iter().copied())
13143                            .map(|(prefix, trimmed_prefix_len)| {
13144                                comment_prefix_range(
13145                                    snapshot.deref(),
13146                                    row,
13147                                    &prefix[..trimmed_prefix_len],
13148                                    &prefix[trimmed_prefix_len..],
13149                                    ignore_indent,
13150                                )
13151                            })
13152                            .max_by_key(|range| range.end.column - range.start.column)
13153                            .expect("prefixes is non-empty");
13154
13155                        if prefix_range.is_empty() {
13156                            all_selection_lines_are_comments = false;
13157                        }
13158
13159                        selection_edit_ranges.push(prefix_range);
13160                    }
13161
13162                    if all_selection_lines_are_comments {
13163                        edits.extend(
13164                            selection_edit_ranges
13165                                .iter()
13166                                .cloned()
13167                                .map(|range| (range, empty_str.clone())),
13168                        );
13169                    } else {
13170                        let min_column = selection_edit_ranges
13171                            .iter()
13172                            .map(|range| range.start.column)
13173                            .min()
13174                            .unwrap_or(0);
13175                        edits.extend(selection_edit_ranges.iter().map(|range| {
13176                            let position = Point::new(range.start.row, min_column);
13177                            (position..position, first_prefix.clone())
13178                        }));
13179                    }
13180                } else if let Some((full_comment_prefix, comment_suffix)) =
13181                    language.block_comment_delimiters()
13182                {
13183                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13184                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13185                    let prefix_range = comment_prefix_range(
13186                        snapshot.deref(),
13187                        start_row,
13188                        comment_prefix,
13189                        comment_prefix_whitespace,
13190                        ignore_indent,
13191                    );
13192                    let suffix_range = comment_suffix_range(
13193                        snapshot.deref(),
13194                        end_row,
13195                        comment_suffix.trim_start_matches(' '),
13196                        comment_suffix.starts_with(' '),
13197                    );
13198
13199                    if prefix_range.is_empty() || suffix_range.is_empty() {
13200                        edits.push((
13201                            prefix_range.start..prefix_range.start,
13202                            full_comment_prefix.clone(),
13203                        ));
13204                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13205                        suffixes_inserted.push((end_row, comment_suffix.len()));
13206                    } else {
13207                        edits.push((prefix_range, empty_str.clone()));
13208                        edits.push((suffix_range, empty_str.clone()));
13209                    }
13210                } else {
13211                    continue;
13212                }
13213            }
13214
13215            drop(snapshot);
13216            this.buffer.update(cx, |buffer, cx| {
13217                buffer.edit(edits, None, cx);
13218            });
13219
13220            // Adjust selections so that they end before any comment suffixes that
13221            // were inserted.
13222            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13223            let mut selections = this.selections.all::<Point>(cx);
13224            let snapshot = this.buffer.read(cx).read(cx);
13225            for selection in &mut selections {
13226                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13227                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13228                        Ordering::Less => {
13229                            suffixes_inserted.next();
13230                            continue;
13231                        }
13232                        Ordering::Greater => break,
13233                        Ordering::Equal => {
13234                            if selection.end.column == snapshot.line_len(row) {
13235                                if selection.is_empty() {
13236                                    selection.start.column -= suffix_len as u32;
13237                                }
13238                                selection.end.column -= suffix_len as u32;
13239                            }
13240                            break;
13241                        }
13242                    }
13243                }
13244            }
13245
13246            drop(snapshot);
13247            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13248                s.select(selections)
13249            });
13250
13251            let selections = this.selections.all::<Point>(cx);
13252            let selections_on_single_row = selections.windows(2).all(|selections| {
13253                selections[0].start.row == selections[1].start.row
13254                    && selections[0].end.row == selections[1].end.row
13255                    && selections[0].start.row == selections[0].end.row
13256            });
13257            let selections_selecting = selections
13258                .iter()
13259                .any(|selection| selection.start != selection.end);
13260            let advance_downwards = action.advance_downwards
13261                && selections_on_single_row
13262                && !selections_selecting
13263                && !matches!(this.mode, EditorMode::SingleLine { .. });
13264
13265            if advance_downwards {
13266                let snapshot = this.buffer.read(cx).snapshot(cx);
13267
13268                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13269                    s.move_cursors_with(|display_snapshot, display_point, _| {
13270                        let mut point = display_point.to_point(display_snapshot);
13271                        point.row += 1;
13272                        point = snapshot.clip_point(point, Bias::Left);
13273                        let display_point = point.to_display_point(display_snapshot);
13274                        let goal = SelectionGoal::HorizontalPosition(
13275                            display_snapshot
13276                                .x_for_display_point(display_point, text_layout_details)
13277                                .into(),
13278                        );
13279                        (display_point, goal)
13280                    })
13281                });
13282            }
13283        });
13284    }
13285
13286    pub fn select_enclosing_symbol(
13287        &mut self,
13288        _: &SelectEnclosingSymbol,
13289        window: &mut Window,
13290        cx: &mut Context<Self>,
13291    ) {
13292        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13293
13294        let buffer = self.buffer.read(cx).snapshot(cx);
13295        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13296
13297        fn update_selection(
13298            selection: &Selection<usize>,
13299            buffer_snap: &MultiBufferSnapshot,
13300        ) -> Option<Selection<usize>> {
13301            let cursor = selection.head();
13302            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13303            for symbol in symbols.iter().rev() {
13304                let start = symbol.range.start.to_offset(buffer_snap);
13305                let end = symbol.range.end.to_offset(buffer_snap);
13306                let new_range = start..end;
13307                if start < selection.start || end > selection.end {
13308                    return Some(Selection {
13309                        id: selection.id,
13310                        start: new_range.start,
13311                        end: new_range.end,
13312                        goal: SelectionGoal::None,
13313                        reversed: selection.reversed,
13314                    });
13315                }
13316            }
13317            None
13318        }
13319
13320        let mut selected_larger_symbol = false;
13321        let new_selections = old_selections
13322            .iter()
13323            .map(|selection| match update_selection(selection, &buffer) {
13324                Some(new_selection) => {
13325                    if new_selection.range() != selection.range() {
13326                        selected_larger_symbol = true;
13327                    }
13328                    new_selection
13329                }
13330                None => selection.clone(),
13331            })
13332            .collect::<Vec<_>>();
13333
13334        if selected_larger_symbol {
13335            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13336                s.select(new_selections);
13337            });
13338        }
13339    }
13340
13341    pub fn select_larger_syntax_node(
13342        &mut self,
13343        _: &SelectLargerSyntaxNode,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) {
13347        let Some(visible_row_count) = self.visible_row_count() else {
13348            return;
13349        };
13350        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13351        if old_selections.is_empty() {
13352            return;
13353        }
13354
13355        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13356
13357        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13358        let buffer = self.buffer.read(cx).snapshot(cx);
13359
13360        let mut selected_larger_node = false;
13361        let mut new_selections = old_selections
13362            .iter()
13363            .map(|selection| {
13364                let old_range = selection.start..selection.end;
13365
13366                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13367                    // manually select word at selection
13368                    if ["string_content", "inline"].contains(&node.kind()) {
13369                        let word_range = {
13370                            let display_point = buffer
13371                                .offset_to_point(old_range.start)
13372                                .to_display_point(&display_map);
13373                            let Range { start, end } =
13374                                movement::surrounding_word(&display_map, display_point);
13375                            start.to_point(&display_map).to_offset(&buffer)
13376                                ..end.to_point(&display_map).to_offset(&buffer)
13377                        };
13378                        // ignore if word is already selected
13379                        if !word_range.is_empty() && old_range != word_range {
13380                            let last_word_range = {
13381                                let display_point = buffer
13382                                    .offset_to_point(old_range.end)
13383                                    .to_display_point(&display_map);
13384                                let Range { start, end } =
13385                                    movement::surrounding_word(&display_map, display_point);
13386                                start.to_point(&display_map).to_offset(&buffer)
13387                                    ..end.to_point(&display_map).to_offset(&buffer)
13388                            };
13389                            // only select word if start and end point belongs to same word
13390                            if word_range == last_word_range {
13391                                selected_larger_node = true;
13392                                return Selection {
13393                                    id: selection.id,
13394                                    start: word_range.start,
13395                                    end: word_range.end,
13396                                    goal: SelectionGoal::None,
13397                                    reversed: selection.reversed,
13398                                };
13399                            }
13400                        }
13401                    }
13402                }
13403
13404                let mut new_range = old_range.clone();
13405                while let Some((_node, containing_range)) =
13406                    buffer.syntax_ancestor(new_range.clone())
13407                {
13408                    new_range = match containing_range {
13409                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13410                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13411                    };
13412                    if !display_map.intersects_fold(new_range.start)
13413                        && !display_map.intersects_fold(new_range.end)
13414                    {
13415                        break;
13416                    }
13417                }
13418
13419                selected_larger_node |= new_range != old_range;
13420                Selection {
13421                    id: selection.id,
13422                    start: new_range.start,
13423                    end: new_range.end,
13424                    goal: SelectionGoal::None,
13425                    reversed: selection.reversed,
13426                }
13427            })
13428            .collect::<Vec<_>>();
13429
13430        if !selected_larger_node {
13431            return; // don't put this call in the history
13432        }
13433
13434        // scroll based on transformation done to the last selection created by the user
13435        let (last_old, last_new) = old_selections
13436            .last()
13437            .zip(new_selections.last().cloned())
13438            .expect("old_selections isn't empty");
13439
13440        // revert selection
13441        let is_selection_reversed = {
13442            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13443            new_selections.last_mut().expect("checked above").reversed =
13444                should_newest_selection_be_reversed;
13445            should_newest_selection_be_reversed
13446        };
13447
13448        if selected_larger_node {
13449            self.select_syntax_node_history.disable_clearing = true;
13450            self.change_selections(None, window, cx, |s| {
13451                s.select(new_selections.clone());
13452            });
13453            self.select_syntax_node_history.disable_clearing = false;
13454        }
13455
13456        let start_row = last_new.start.to_display_point(&display_map).row().0;
13457        let end_row = last_new.end.to_display_point(&display_map).row().0;
13458        let selection_height = end_row - start_row + 1;
13459        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13460
13461        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13462        let scroll_behavior = if fits_on_the_screen {
13463            self.request_autoscroll(Autoscroll::fit(), cx);
13464            SelectSyntaxNodeScrollBehavior::FitSelection
13465        } else if is_selection_reversed {
13466            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13467            SelectSyntaxNodeScrollBehavior::CursorTop
13468        } else {
13469            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13470            SelectSyntaxNodeScrollBehavior::CursorBottom
13471        };
13472
13473        self.select_syntax_node_history.push((
13474            old_selections,
13475            scroll_behavior,
13476            is_selection_reversed,
13477        ));
13478    }
13479
13480    pub fn select_smaller_syntax_node(
13481        &mut self,
13482        _: &SelectSmallerSyntaxNode,
13483        window: &mut Window,
13484        cx: &mut Context<Self>,
13485    ) {
13486        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13487
13488        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13489            self.select_syntax_node_history.pop()
13490        {
13491            if let Some(selection) = selections.last_mut() {
13492                selection.reversed = is_selection_reversed;
13493            }
13494
13495            self.select_syntax_node_history.disable_clearing = true;
13496            self.change_selections(None, window, cx, |s| {
13497                s.select(selections.to_vec());
13498            });
13499            self.select_syntax_node_history.disable_clearing = false;
13500
13501            match scroll_behavior {
13502                SelectSyntaxNodeScrollBehavior::CursorTop => {
13503                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13504                }
13505                SelectSyntaxNodeScrollBehavior::FitSelection => {
13506                    self.request_autoscroll(Autoscroll::fit(), cx);
13507                }
13508                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13509                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13510                }
13511            }
13512        }
13513    }
13514
13515    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13516        if !EditorSettings::get_global(cx).gutter.runnables {
13517            self.clear_tasks();
13518            return Task::ready(());
13519        }
13520        let project = self.project.as_ref().map(Entity::downgrade);
13521        let task_sources = self.lsp_task_sources(cx);
13522        cx.spawn_in(window, async move |editor, cx| {
13523            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13524            let Some(project) = project.and_then(|p| p.upgrade()) else {
13525                return;
13526            };
13527            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13528                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13529            }) else {
13530                return;
13531            };
13532
13533            let hide_runnables = project
13534                .update(cx, |project, cx| {
13535                    // Do not display any test indicators in non-dev server remote projects.
13536                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13537                })
13538                .unwrap_or(true);
13539            if hide_runnables {
13540                return;
13541            }
13542            let new_rows =
13543                cx.background_spawn({
13544                    let snapshot = display_snapshot.clone();
13545                    async move {
13546                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13547                    }
13548                })
13549                    .await;
13550            let Ok(lsp_tasks) =
13551                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13552            else {
13553                return;
13554            };
13555            let lsp_tasks = lsp_tasks.await;
13556
13557            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13558                lsp_tasks
13559                    .into_iter()
13560                    .flat_map(|(kind, tasks)| {
13561                        tasks.into_iter().filter_map(move |(location, task)| {
13562                            Some((kind.clone(), location?, task))
13563                        })
13564                    })
13565                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13566                        let buffer = location.target.buffer;
13567                        let buffer_snapshot = buffer.read(cx).snapshot();
13568                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13569                            |(excerpt_id, snapshot, _)| {
13570                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13571                                    display_snapshot
13572                                        .buffer_snapshot
13573                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13574                                } else {
13575                                    None
13576                                }
13577                            },
13578                        );
13579                        if let Some(offset) = offset {
13580                            let task_buffer_range =
13581                                location.target.range.to_point(&buffer_snapshot);
13582                            let context_buffer_range =
13583                                task_buffer_range.to_offset(&buffer_snapshot);
13584                            let context_range = BufferOffset(context_buffer_range.start)
13585                                ..BufferOffset(context_buffer_range.end);
13586
13587                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13588                                .or_insert_with(|| RunnableTasks {
13589                                    templates: Vec::new(),
13590                                    offset,
13591                                    column: task_buffer_range.start.column,
13592                                    extra_variables: HashMap::default(),
13593                                    context_range,
13594                                })
13595                                .templates
13596                                .push((kind, task.original_task().clone()));
13597                        }
13598
13599                        acc
13600                    })
13601            }) else {
13602                return;
13603            };
13604
13605            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13606            editor
13607                .update(cx, |editor, _| {
13608                    editor.clear_tasks();
13609                    for (key, mut value) in rows {
13610                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13611                            value.templates.extend(lsp_tasks.templates);
13612                        }
13613
13614                        editor.insert_tasks(key, value);
13615                    }
13616                    for (key, value) in lsp_tasks_by_rows {
13617                        editor.insert_tasks(key, value);
13618                    }
13619                })
13620                .ok();
13621        })
13622    }
13623    fn fetch_runnable_ranges(
13624        snapshot: &DisplaySnapshot,
13625        range: Range<Anchor>,
13626    ) -> Vec<language::RunnableRange> {
13627        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13628    }
13629
13630    fn runnable_rows(
13631        project: Entity<Project>,
13632        snapshot: DisplaySnapshot,
13633        runnable_ranges: Vec<RunnableRange>,
13634        mut cx: AsyncWindowContext,
13635    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13636        runnable_ranges
13637            .into_iter()
13638            .filter_map(|mut runnable| {
13639                let tasks = cx
13640                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13641                    .ok()?;
13642                if tasks.is_empty() {
13643                    return None;
13644                }
13645
13646                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13647
13648                let row = snapshot
13649                    .buffer_snapshot
13650                    .buffer_line_for_row(MultiBufferRow(point.row))?
13651                    .1
13652                    .start
13653                    .row;
13654
13655                let context_range =
13656                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13657                Some((
13658                    (runnable.buffer_id, row),
13659                    RunnableTasks {
13660                        templates: tasks,
13661                        offset: snapshot
13662                            .buffer_snapshot
13663                            .anchor_before(runnable.run_range.start),
13664                        context_range,
13665                        column: point.column,
13666                        extra_variables: runnable.extra_captures,
13667                    },
13668                ))
13669            })
13670            .collect()
13671    }
13672
13673    fn templates_with_tags(
13674        project: &Entity<Project>,
13675        runnable: &mut Runnable,
13676        cx: &mut App,
13677    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13678        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13679            let (worktree_id, file) = project
13680                .buffer_for_id(runnable.buffer, cx)
13681                .and_then(|buffer| buffer.read(cx).file())
13682                .map(|file| (file.worktree_id(cx), file.clone()))
13683                .unzip();
13684
13685            (
13686                project.task_store().read(cx).task_inventory().cloned(),
13687                worktree_id,
13688                file,
13689            )
13690        });
13691
13692        let mut templates_with_tags = mem::take(&mut runnable.tags)
13693            .into_iter()
13694            .flat_map(|RunnableTag(tag)| {
13695                inventory
13696                    .as_ref()
13697                    .into_iter()
13698                    .flat_map(|inventory| {
13699                        inventory.read(cx).list_tasks(
13700                            file.clone(),
13701                            Some(runnable.language.clone()),
13702                            worktree_id,
13703                            cx,
13704                        )
13705                    })
13706                    .filter(move |(_, template)| {
13707                        template.tags.iter().any(|source_tag| source_tag == &tag)
13708                    })
13709            })
13710            .sorted_by_key(|(kind, _)| kind.to_owned())
13711            .collect::<Vec<_>>();
13712        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13713            // Strongest source wins; if we have worktree tag binding, prefer that to
13714            // global and language bindings;
13715            // if we have a global binding, prefer that to language binding.
13716            let first_mismatch = templates_with_tags
13717                .iter()
13718                .position(|(tag_source, _)| tag_source != leading_tag_source);
13719            if let Some(index) = first_mismatch {
13720                templates_with_tags.truncate(index);
13721            }
13722        }
13723
13724        templates_with_tags
13725    }
13726
13727    pub fn move_to_enclosing_bracket(
13728        &mut self,
13729        _: &MoveToEnclosingBracket,
13730        window: &mut Window,
13731        cx: &mut Context<Self>,
13732    ) {
13733        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13734        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13735            s.move_offsets_with(|snapshot, selection| {
13736                let Some(enclosing_bracket_ranges) =
13737                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13738                else {
13739                    return;
13740                };
13741
13742                let mut best_length = usize::MAX;
13743                let mut best_inside = false;
13744                let mut best_in_bracket_range = false;
13745                let mut best_destination = None;
13746                for (open, close) in enclosing_bracket_ranges {
13747                    let close = close.to_inclusive();
13748                    let length = close.end() - open.start;
13749                    let inside = selection.start >= open.end && selection.end <= *close.start();
13750                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13751                        || close.contains(&selection.head());
13752
13753                    // If best is next to a bracket and current isn't, skip
13754                    if !in_bracket_range && best_in_bracket_range {
13755                        continue;
13756                    }
13757
13758                    // Prefer smaller lengths unless best is inside and current isn't
13759                    if length > best_length && (best_inside || !inside) {
13760                        continue;
13761                    }
13762
13763                    best_length = length;
13764                    best_inside = inside;
13765                    best_in_bracket_range = in_bracket_range;
13766                    best_destination = Some(
13767                        if close.contains(&selection.start) && close.contains(&selection.end) {
13768                            if inside { open.end } else { open.start }
13769                        } else if inside {
13770                            *close.start()
13771                        } else {
13772                            *close.end()
13773                        },
13774                    );
13775                }
13776
13777                if let Some(destination) = best_destination {
13778                    selection.collapse_to(destination, SelectionGoal::None);
13779                }
13780            })
13781        });
13782    }
13783
13784    pub fn undo_selection(
13785        &mut self,
13786        _: &UndoSelection,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) {
13790        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13791        self.end_selection(window, cx);
13792        self.selection_history.mode = SelectionHistoryMode::Undoing;
13793        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13794            self.change_selections(None, window, cx, |s| {
13795                s.select_anchors(entry.selections.to_vec())
13796            });
13797            self.select_next_state = entry.select_next_state;
13798            self.select_prev_state = entry.select_prev_state;
13799            self.add_selections_state = entry.add_selections_state;
13800            self.request_autoscroll(Autoscroll::newest(), cx);
13801        }
13802        self.selection_history.mode = SelectionHistoryMode::Normal;
13803    }
13804
13805    pub fn redo_selection(
13806        &mut self,
13807        _: &RedoSelection,
13808        window: &mut Window,
13809        cx: &mut Context<Self>,
13810    ) {
13811        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13812        self.end_selection(window, cx);
13813        self.selection_history.mode = SelectionHistoryMode::Redoing;
13814        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13815            self.change_selections(None, window, cx, |s| {
13816                s.select_anchors(entry.selections.to_vec())
13817            });
13818            self.select_next_state = entry.select_next_state;
13819            self.select_prev_state = entry.select_prev_state;
13820            self.add_selections_state = entry.add_selections_state;
13821            self.request_autoscroll(Autoscroll::newest(), cx);
13822        }
13823        self.selection_history.mode = SelectionHistoryMode::Normal;
13824    }
13825
13826    pub fn expand_excerpts(
13827        &mut self,
13828        action: &ExpandExcerpts,
13829        _: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13833    }
13834
13835    pub fn expand_excerpts_down(
13836        &mut self,
13837        action: &ExpandExcerptsDown,
13838        _: &mut Window,
13839        cx: &mut Context<Self>,
13840    ) {
13841        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13842    }
13843
13844    pub fn expand_excerpts_up(
13845        &mut self,
13846        action: &ExpandExcerptsUp,
13847        _: &mut Window,
13848        cx: &mut Context<Self>,
13849    ) {
13850        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13851    }
13852
13853    pub fn expand_excerpts_for_direction(
13854        &mut self,
13855        lines: u32,
13856        direction: ExpandExcerptDirection,
13857
13858        cx: &mut Context<Self>,
13859    ) {
13860        let selections = self.selections.disjoint_anchors();
13861
13862        let lines = if lines == 0 {
13863            EditorSettings::get_global(cx).expand_excerpt_lines
13864        } else {
13865            lines
13866        };
13867
13868        self.buffer.update(cx, |buffer, cx| {
13869            let snapshot = buffer.snapshot(cx);
13870            let mut excerpt_ids = selections
13871                .iter()
13872                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13873                .collect::<Vec<_>>();
13874            excerpt_ids.sort();
13875            excerpt_ids.dedup();
13876            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13877        })
13878    }
13879
13880    pub fn expand_excerpt(
13881        &mut self,
13882        excerpt: ExcerptId,
13883        direction: ExpandExcerptDirection,
13884        window: &mut Window,
13885        cx: &mut Context<Self>,
13886    ) {
13887        let current_scroll_position = self.scroll_position(cx);
13888        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13889        let mut should_scroll_up = false;
13890
13891        if direction == ExpandExcerptDirection::Down {
13892            let multi_buffer = self.buffer.read(cx);
13893            let snapshot = multi_buffer.snapshot(cx);
13894            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13895                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13896                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13897                        let buffer_snapshot = buffer.read(cx).snapshot();
13898                        let excerpt_end_row =
13899                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13900                        let last_row = buffer_snapshot.max_point().row;
13901                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13902                        should_scroll_up = lines_below >= lines_to_expand;
13903                    }
13904                }
13905            }
13906        }
13907
13908        self.buffer.update(cx, |buffer, cx| {
13909            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13910        });
13911
13912        if should_scroll_up {
13913            let new_scroll_position =
13914                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13915            self.set_scroll_position(new_scroll_position, window, cx);
13916        }
13917    }
13918
13919    pub fn go_to_singleton_buffer_point(
13920        &mut self,
13921        point: Point,
13922        window: &mut Window,
13923        cx: &mut Context<Self>,
13924    ) {
13925        self.go_to_singleton_buffer_range(point..point, window, cx);
13926    }
13927
13928    pub fn go_to_singleton_buffer_range(
13929        &mut self,
13930        range: Range<Point>,
13931        window: &mut Window,
13932        cx: &mut Context<Self>,
13933    ) {
13934        let multibuffer = self.buffer().read(cx);
13935        let Some(buffer) = multibuffer.as_singleton() else {
13936            return;
13937        };
13938        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13939            return;
13940        };
13941        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13942            return;
13943        };
13944        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13945            s.select_anchor_ranges([start..end])
13946        });
13947    }
13948
13949    pub fn go_to_diagnostic(
13950        &mut self,
13951        _: &GoToDiagnostic,
13952        window: &mut Window,
13953        cx: &mut Context<Self>,
13954    ) {
13955        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13956        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13957    }
13958
13959    pub fn go_to_prev_diagnostic(
13960        &mut self,
13961        _: &GoToPreviousDiagnostic,
13962        window: &mut Window,
13963        cx: &mut Context<Self>,
13964    ) {
13965        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13966        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13967    }
13968
13969    pub fn go_to_diagnostic_impl(
13970        &mut self,
13971        direction: Direction,
13972        window: &mut Window,
13973        cx: &mut Context<Self>,
13974    ) {
13975        let buffer = self.buffer.read(cx).snapshot(cx);
13976        let selection = self.selections.newest::<usize>(cx);
13977
13978        let mut active_group_id = None;
13979        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13980            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13981                active_group_id = Some(active_group.group_id);
13982            }
13983        }
13984
13985        fn filtered(
13986            snapshot: EditorSnapshot,
13987            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13988        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13989            diagnostics
13990                .filter(|entry| entry.range.start != entry.range.end)
13991                .filter(|entry| !entry.diagnostic.is_unnecessary)
13992                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13993        }
13994
13995        let snapshot = self.snapshot(window, cx);
13996        let before = filtered(
13997            snapshot.clone(),
13998            buffer
13999                .diagnostics_in_range(0..selection.start)
14000                .filter(|entry| entry.range.start <= selection.start),
14001        );
14002        let after = filtered(
14003            snapshot,
14004            buffer
14005                .diagnostics_in_range(selection.start..buffer.len())
14006                .filter(|entry| entry.range.start >= selection.start),
14007        );
14008
14009        let mut found: Option<DiagnosticEntry<usize>> = None;
14010        if direction == Direction::Prev {
14011            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14012            {
14013                for diagnostic in prev_diagnostics.into_iter().rev() {
14014                    if diagnostic.range.start != selection.start
14015                        || active_group_id
14016                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14017                    {
14018                        found = Some(diagnostic);
14019                        break 'outer;
14020                    }
14021                }
14022            }
14023        } else {
14024            for diagnostic in after.chain(before) {
14025                if diagnostic.range.start != selection.start
14026                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14027                {
14028                    found = Some(diagnostic);
14029                    break;
14030                }
14031            }
14032        }
14033        let Some(next_diagnostic) = found else {
14034            return;
14035        };
14036
14037        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14038            return;
14039        };
14040        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14041            s.select_ranges(vec![
14042                next_diagnostic.range.start..next_diagnostic.range.start,
14043            ])
14044        });
14045        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14046        self.refresh_inline_completion(false, true, window, cx);
14047    }
14048
14049    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14050        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14051        let snapshot = self.snapshot(window, cx);
14052        let selection = self.selections.newest::<Point>(cx);
14053        self.go_to_hunk_before_or_after_position(
14054            &snapshot,
14055            selection.head(),
14056            Direction::Next,
14057            window,
14058            cx,
14059        );
14060    }
14061
14062    pub fn go_to_hunk_before_or_after_position(
14063        &mut self,
14064        snapshot: &EditorSnapshot,
14065        position: Point,
14066        direction: Direction,
14067        window: &mut Window,
14068        cx: &mut Context<Editor>,
14069    ) {
14070        let row = if direction == Direction::Next {
14071            self.hunk_after_position(snapshot, position)
14072                .map(|hunk| hunk.row_range.start)
14073        } else {
14074            self.hunk_before_position(snapshot, position)
14075        };
14076
14077        if let Some(row) = row {
14078            let destination = Point::new(row.0, 0);
14079            let autoscroll = Autoscroll::center();
14080
14081            self.unfold_ranges(&[destination..destination], false, false, cx);
14082            self.change_selections(Some(autoscroll), window, cx, |s| {
14083                s.select_ranges([destination..destination]);
14084            });
14085        }
14086    }
14087
14088    fn hunk_after_position(
14089        &mut self,
14090        snapshot: &EditorSnapshot,
14091        position: Point,
14092    ) -> Option<MultiBufferDiffHunk> {
14093        snapshot
14094            .buffer_snapshot
14095            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14096            .find(|hunk| hunk.row_range.start.0 > position.row)
14097            .or_else(|| {
14098                snapshot
14099                    .buffer_snapshot
14100                    .diff_hunks_in_range(Point::zero()..position)
14101                    .find(|hunk| hunk.row_range.end.0 < position.row)
14102            })
14103    }
14104
14105    fn go_to_prev_hunk(
14106        &mut self,
14107        _: &GoToPreviousHunk,
14108        window: &mut Window,
14109        cx: &mut Context<Self>,
14110    ) {
14111        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14112        let snapshot = self.snapshot(window, cx);
14113        let selection = self.selections.newest::<Point>(cx);
14114        self.go_to_hunk_before_or_after_position(
14115            &snapshot,
14116            selection.head(),
14117            Direction::Prev,
14118            window,
14119            cx,
14120        );
14121    }
14122
14123    fn hunk_before_position(
14124        &mut self,
14125        snapshot: &EditorSnapshot,
14126        position: Point,
14127    ) -> Option<MultiBufferRow> {
14128        snapshot
14129            .buffer_snapshot
14130            .diff_hunk_before(position)
14131            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14132    }
14133
14134    fn go_to_next_change(
14135        &mut self,
14136        _: &GoToNextChange,
14137        window: &mut Window,
14138        cx: &mut Context<Self>,
14139    ) {
14140        if let Some(selections) = self
14141            .change_list
14142            .next_change(1, Direction::Next)
14143            .map(|s| s.to_vec())
14144        {
14145            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14146                let map = s.display_map();
14147                s.select_display_ranges(selections.iter().map(|a| {
14148                    let point = a.to_display_point(&map);
14149                    point..point
14150                }))
14151            })
14152        }
14153    }
14154
14155    fn go_to_previous_change(
14156        &mut self,
14157        _: &GoToPreviousChange,
14158        window: &mut Window,
14159        cx: &mut Context<Self>,
14160    ) {
14161        if let Some(selections) = self
14162            .change_list
14163            .next_change(1, Direction::Prev)
14164            .map(|s| s.to_vec())
14165        {
14166            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14167                let map = s.display_map();
14168                s.select_display_ranges(selections.iter().map(|a| {
14169                    let point = a.to_display_point(&map);
14170                    point..point
14171                }))
14172            })
14173        }
14174    }
14175
14176    fn go_to_line<T: 'static>(
14177        &mut self,
14178        position: Anchor,
14179        highlight_color: Option<Hsla>,
14180        window: &mut Window,
14181        cx: &mut Context<Self>,
14182    ) {
14183        let snapshot = self.snapshot(window, cx).display_snapshot;
14184        let position = position.to_point(&snapshot.buffer_snapshot);
14185        let start = snapshot
14186            .buffer_snapshot
14187            .clip_point(Point::new(position.row, 0), Bias::Left);
14188        let end = start + Point::new(1, 0);
14189        let start = snapshot.buffer_snapshot.anchor_before(start);
14190        let end = snapshot.buffer_snapshot.anchor_before(end);
14191
14192        self.highlight_rows::<T>(
14193            start..end,
14194            highlight_color
14195                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14196            Default::default(),
14197            cx,
14198        );
14199
14200        if self.buffer.read(cx).is_singleton() {
14201            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14202        }
14203    }
14204
14205    pub fn go_to_definition(
14206        &mut self,
14207        _: &GoToDefinition,
14208        window: &mut Window,
14209        cx: &mut Context<Self>,
14210    ) -> Task<Result<Navigated>> {
14211        let definition =
14212            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14213        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14214        cx.spawn_in(window, async move |editor, cx| {
14215            if definition.await? == Navigated::Yes {
14216                return Ok(Navigated::Yes);
14217            }
14218            match fallback_strategy {
14219                GoToDefinitionFallback::None => Ok(Navigated::No),
14220                GoToDefinitionFallback::FindAllReferences => {
14221                    match editor.update_in(cx, |editor, window, cx| {
14222                        editor.find_all_references(&FindAllReferences, window, cx)
14223                    })? {
14224                        Some(references) => references.await,
14225                        None => Ok(Navigated::No),
14226                    }
14227                }
14228            }
14229        })
14230    }
14231
14232    pub fn go_to_declaration(
14233        &mut self,
14234        _: &GoToDeclaration,
14235        window: &mut Window,
14236        cx: &mut Context<Self>,
14237    ) -> Task<Result<Navigated>> {
14238        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14239    }
14240
14241    pub fn go_to_declaration_split(
14242        &mut self,
14243        _: &GoToDeclaration,
14244        window: &mut Window,
14245        cx: &mut Context<Self>,
14246    ) -> Task<Result<Navigated>> {
14247        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14248    }
14249
14250    pub fn go_to_implementation(
14251        &mut self,
14252        _: &GoToImplementation,
14253        window: &mut Window,
14254        cx: &mut Context<Self>,
14255    ) -> Task<Result<Navigated>> {
14256        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14257    }
14258
14259    pub fn go_to_implementation_split(
14260        &mut self,
14261        _: &GoToImplementationSplit,
14262        window: &mut Window,
14263        cx: &mut Context<Self>,
14264    ) -> Task<Result<Navigated>> {
14265        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14266    }
14267
14268    pub fn go_to_type_definition(
14269        &mut self,
14270        _: &GoToTypeDefinition,
14271        window: &mut Window,
14272        cx: &mut Context<Self>,
14273    ) -> Task<Result<Navigated>> {
14274        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14275    }
14276
14277    pub fn go_to_definition_split(
14278        &mut self,
14279        _: &GoToDefinitionSplit,
14280        window: &mut Window,
14281        cx: &mut Context<Self>,
14282    ) -> Task<Result<Navigated>> {
14283        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14284    }
14285
14286    pub fn go_to_type_definition_split(
14287        &mut self,
14288        _: &GoToTypeDefinitionSplit,
14289        window: &mut Window,
14290        cx: &mut Context<Self>,
14291    ) -> Task<Result<Navigated>> {
14292        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14293    }
14294
14295    fn go_to_definition_of_kind(
14296        &mut self,
14297        kind: GotoDefinitionKind,
14298        split: bool,
14299        window: &mut Window,
14300        cx: &mut Context<Self>,
14301    ) -> Task<Result<Navigated>> {
14302        let Some(provider) = self.semantics_provider.clone() else {
14303            return Task::ready(Ok(Navigated::No));
14304        };
14305        let head = self.selections.newest::<usize>(cx).head();
14306        let buffer = self.buffer.read(cx);
14307        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14308            text_anchor
14309        } else {
14310            return Task::ready(Ok(Navigated::No));
14311        };
14312
14313        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14314            return Task::ready(Ok(Navigated::No));
14315        };
14316
14317        cx.spawn_in(window, async move |editor, cx| {
14318            let definitions = definitions.await?;
14319            let navigated = editor
14320                .update_in(cx, |editor, window, cx| {
14321                    editor.navigate_to_hover_links(
14322                        Some(kind),
14323                        definitions
14324                            .into_iter()
14325                            .filter(|location| {
14326                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14327                            })
14328                            .map(HoverLink::Text)
14329                            .collect::<Vec<_>>(),
14330                        split,
14331                        window,
14332                        cx,
14333                    )
14334                })?
14335                .await?;
14336            anyhow::Ok(navigated)
14337        })
14338    }
14339
14340    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14341        let selection = self.selections.newest_anchor();
14342        let head = selection.head();
14343        let tail = selection.tail();
14344
14345        let Some((buffer, start_position)) =
14346            self.buffer.read(cx).text_anchor_for_position(head, cx)
14347        else {
14348            return;
14349        };
14350
14351        let end_position = if head != tail {
14352            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14353                return;
14354            };
14355            Some(pos)
14356        } else {
14357            None
14358        };
14359
14360        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14361            let url = if let Some(end_pos) = end_position {
14362                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14363            } else {
14364                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14365            };
14366
14367            if let Some(url) = url {
14368                editor.update(cx, |_, cx| {
14369                    cx.open_url(&url);
14370                })
14371            } else {
14372                Ok(())
14373            }
14374        });
14375
14376        url_finder.detach();
14377    }
14378
14379    pub fn open_selected_filename(
14380        &mut self,
14381        _: &OpenSelectedFilename,
14382        window: &mut Window,
14383        cx: &mut Context<Self>,
14384    ) {
14385        let Some(workspace) = self.workspace() else {
14386            return;
14387        };
14388
14389        let position = self.selections.newest_anchor().head();
14390
14391        let Some((buffer, buffer_position)) =
14392            self.buffer.read(cx).text_anchor_for_position(position, cx)
14393        else {
14394            return;
14395        };
14396
14397        let project = self.project.clone();
14398
14399        cx.spawn_in(window, async move |_, cx| {
14400            let result = find_file(&buffer, project, buffer_position, cx).await;
14401
14402            if let Some((_, path)) = result {
14403                workspace
14404                    .update_in(cx, |workspace, window, cx| {
14405                        workspace.open_resolved_path(path, window, cx)
14406                    })?
14407                    .await?;
14408            }
14409            anyhow::Ok(())
14410        })
14411        .detach();
14412    }
14413
14414    pub(crate) fn navigate_to_hover_links(
14415        &mut self,
14416        kind: Option<GotoDefinitionKind>,
14417        mut definitions: Vec<HoverLink>,
14418        split: bool,
14419        window: &mut Window,
14420        cx: &mut Context<Editor>,
14421    ) -> Task<Result<Navigated>> {
14422        // If there is one definition, just open it directly
14423        if definitions.len() == 1 {
14424            let definition = definitions.pop().unwrap();
14425
14426            enum TargetTaskResult {
14427                Location(Option<Location>),
14428                AlreadyNavigated,
14429            }
14430
14431            let target_task = match definition {
14432                HoverLink::Text(link) => {
14433                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14434                }
14435                HoverLink::InlayHint(lsp_location, server_id) => {
14436                    let computation =
14437                        self.compute_target_location(lsp_location, server_id, window, cx);
14438                    cx.background_spawn(async move {
14439                        let location = computation.await?;
14440                        Ok(TargetTaskResult::Location(location))
14441                    })
14442                }
14443                HoverLink::Url(url) => {
14444                    cx.open_url(&url);
14445                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14446                }
14447                HoverLink::File(path) => {
14448                    if let Some(workspace) = self.workspace() {
14449                        cx.spawn_in(window, async move |_, cx| {
14450                            workspace
14451                                .update_in(cx, |workspace, window, cx| {
14452                                    workspace.open_resolved_path(path, window, cx)
14453                                })?
14454                                .await
14455                                .map(|_| TargetTaskResult::AlreadyNavigated)
14456                        })
14457                    } else {
14458                        Task::ready(Ok(TargetTaskResult::Location(None)))
14459                    }
14460                }
14461            };
14462            cx.spawn_in(window, async move |editor, cx| {
14463                let target = match target_task.await.context("target resolution task")? {
14464                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14465                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14466                    TargetTaskResult::Location(Some(target)) => target,
14467                };
14468
14469                editor.update_in(cx, |editor, window, cx| {
14470                    let Some(workspace) = editor.workspace() else {
14471                        return Navigated::No;
14472                    };
14473                    let pane = workspace.read(cx).active_pane().clone();
14474
14475                    let range = target.range.to_point(target.buffer.read(cx));
14476                    let range = editor.range_for_match(&range);
14477                    let range = collapse_multiline_range(range);
14478
14479                    if !split
14480                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14481                    {
14482                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14483                    } else {
14484                        window.defer(cx, move |window, cx| {
14485                            let target_editor: Entity<Self> =
14486                                workspace.update(cx, |workspace, cx| {
14487                                    let pane = if split {
14488                                        workspace.adjacent_pane(window, cx)
14489                                    } else {
14490                                        workspace.active_pane().clone()
14491                                    };
14492
14493                                    workspace.open_project_item(
14494                                        pane,
14495                                        target.buffer.clone(),
14496                                        true,
14497                                        true,
14498                                        window,
14499                                        cx,
14500                                    )
14501                                });
14502                            target_editor.update(cx, |target_editor, cx| {
14503                                // When selecting a definition in a different buffer, disable the nav history
14504                                // to avoid creating a history entry at the previous cursor location.
14505                                pane.update(cx, |pane, _| pane.disable_history());
14506                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14507                                pane.update(cx, |pane, _| pane.enable_history());
14508                            });
14509                        });
14510                    }
14511                    Navigated::Yes
14512                })
14513            })
14514        } else if !definitions.is_empty() {
14515            cx.spawn_in(window, async move |editor, cx| {
14516                let (title, location_tasks, workspace) = editor
14517                    .update_in(cx, |editor, window, cx| {
14518                        let tab_kind = match kind {
14519                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14520                            _ => "Definitions",
14521                        };
14522                        let title = definitions
14523                            .iter()
14524                            .find_map(|definition| match definition {
14525                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14526                                    let buffer = origin.buffer.read(cx);
14527                                    format!(
14528                                        "{} for {}",
14529                                        tab_kind,
14530                                        buffer
14531                                            .text_for_range(origin.range.clone())
14532                                            .collect::<String>()
14533                                    )
14534                                }),
14535                                HoverLink::InlayHint(_, _) => None,
14536                                HoverLink::Url(_) => None,
14537                                HoverLink::File(_) => None,
14538                            })
14539                            .unwrap_or(tab_kind.to_string());
14540                        let location_tasks = definitions
14541                            .into_iter()
14542                            .map(|definition| match definition {
14543                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14544                                HoverLink::InlayHint(lsp_location, server_id) => editor
14545                                    .compute_target_location(lsp_location, server_id, window, cx),
14546                                HoverLink::Url(_) => Task::ready(Ok(None)),
14547                                HoverLink::File(_) => Task::ready(Ok(None)),
14548                            })
14549                            .collect::<Vec<_>>();
14550                        (title, location_tasks, editor.workspace().clone())
14551                    })
14552                    .context("location tasks preparation")?;
14553
14554                let locations = future::join_all(location_tasks)
14555                    .await
14556                    .into_iter()
14557                    .filter_map(|location| location.transpose())
14558                    .collect::<Result<_>>()
14559                    .context("location tasks")?;
14560
14561                let Some(workspace) = workspace else {
14562                    return Ok(Navigated::No);
14563                };
14564                let opened = workspace
14565                    .update_in(cx, |workspace, window, cx| {
14566                        Self::open_locations_in_multibuffer(
14567                            workspace,
14568                            locations,
14569                            title,
14570                            split,
14571                            MultibufferSelectionMode::First,
14572                            window,
14573                            cx,
14574                        )
14575                    })
14576                    .ok();
14577
14578                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14579            })
14580        } else {
14581            Task::ready(Ok(Navigated::No))
14582        }
14583    }
14584
14585    fn compute_target_location(
14586        &self,
14587        lsp_location: lsp::Location,
14588        server_id: LanguageServerId,
14589        window: &mut Window,
14590        cx: &mut Context<Self>,
14591    ) -> Task<anyhow::Result<Option<Location>>> {
14592        let Some(project) = self.project.clone() else {
14593            return Task::ready(Ok(None));
14594        };
14595
14596        cx.spawn_in(window, async move |editor, cx| {
14597            let location_task = editor.update(cx, |_, cx| {
14598                project.update(cx, |project, cx| {
14599                    let language_server_name = project
14600                        .language_server_statuses(cx)
14601                        .find(|(id, _)| server_id == *id)
14602                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14603                    language_server_name.map(|language_server_name| {
14604                        project.open_local_buffer_via_lsp(
14605                            lsp_location.uri.clone(),
14606                            server_id,
14607                            language_server_name,
14608                            cx,
14609                        )
14610                    })
14611                })
14612            })?;
14613            let location = match location_task {
14614                Some(task) => Some({
14615                    let target_buffer_handle = task.await.context("open local buffer")?;
14616                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
14617                        let target_start = target_buffer
14618                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14619                        let target_end = target_buffer
14620                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14621                        target_buffer.anchor_after(target_start)
14622                            ..target_buffer.anchor_before(target_end)
14623                    })?;
14624                    Location {
14625                        buffer: target_buffer_handle,
14626                        range,
14627                    }
14628                }),
14629                None => None,
14630            };
14631            Ok(location)
14632        })
14633    }
14634
14635    pub fn find_all_references(
14636        &mut self,
14637        _: &FindAllReferences,
14638        window: &mut Window,
14639        cx: &mut Context<Self>,
14640    ) -> Option<Task<Result<Navigated>>> {
14641        let selection = self.selections.newest::<usize>(cx);
14642        let multi_buffer = self.buffer.read(cx);
14643        let head = selection.head();
14644
14645        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14646        let head_anchor = multi_buffer_snapshot.anchor_at(
14647            head,
14648            if head < selection.tail() {
14649                Bias::Right
14650            } else {
14651                Bias::Left
14652            },
14653        );
14654
14655        match self
14656            .find_all_references_task_sources
14657            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14658        {
14659            Ok(_) => {
14660                log::info!(
14661                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14662                );
14663                return None;
14664            }
14665            Err(i) => {
14666                self.find_all_references_task_sources.insert(i, head_anchor);
14667            }
14668        }
14669
14670        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14671        let workspace = self.workspace()?;
14672        let project = workspace.read(cx).project().clone();
14673        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14674        Some(cx.spawn_in(window, async move |editor, cx| {
14675            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14676                if let Ok(i) = editor
14677                    .find_all_references_task_sources
14678                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14679                {
14680                    editor.find_all_references_task_sources.remove(i);
14681                }
14682            });
14683
14684            let locations = references.await?;
14685            if locations.is_empty() {
14686                return anyhow::Ok(Navigated::No);
14687            }
14688
14689            workspace.update_in(cx, |workspace, window, cx| {
14690                let title = locations
14691                    .first()
14692                    .as_ref()
14693                    .map(|location| {
14694                        let buffer = location.buffer.read(cx);
14695                        format!(
14696                            "References to `{}`",
14697                            buffer
14698                                .text_for_range(location.range.clone())
14699                                .collect::<String>()
14700                        )
14701                    })
14702                    .unwrap();
14703                Self::open_locations_in_multibuffer(
14704                    workspace,
14705                    locations,
14706                    title,
14707                    false,
14708                    MultibufferSelectionMode::First,
14709                    window,
14710                    cx,
14711                );
14712                Navigated::Yes
14713            })
14714        }))
14715    }
14716
14717    /// Opens a multibuffer with the given project locations in it
14718    pub fn open_locations_in_multibuffer(
14719        workspace: &mut Workspace,
14720        mut locations: Vec<Location>,
14721        title: String,
14722        split: bool,
14723        multibuffer_selection_mode: MultibufferSelectionMode,
14724        window: &mut Window,
14725        cx: &mut Context<Workspace>,
14726    ) {
14727        // If there are multiple definitions, open them in a multibuffer
14728        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14729        let mut locations = locations.into_iter().peekable();
14730        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14731        let capability = workspace.project().read(cx).capability();
14732
14733        let excerpt_buffer = cx.new(|cx| {
14734            let mut multibuffer = MultiBuffer::new(capability);
14735            while let Some(location) = locations.next() {
14736                let buffer = location.buffer.read(cx);
14737                let mut ranges_for_buffer = Vec::new();
14738                let range = location.range.to_point(buffer);
14739                ranges_for_buffer.push(range.clone());
14740
14741                while let Some(next_location) = locations.peek() {
14742                    if next_location.buffer == location.buffer {
14743                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14744                        locations.next();
14745                    } else {
14746                        break;
14747                    }
14748                }
14749
14750                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14751                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14752                    PathKey::for_buffer(&location.buffer, cx),
14753                    location.buffer.clone(),
14754                    ranges_for_buffer,
14755                    DEFAULT_MULTIBUFFER_CONTEXT,
14756                    cx,
14757                );
14758                ranges.extend(new_ranges)
14759            }
14760
14761            multibuffer.with_title(title)
14762        });
14763
14764        let editor = cx.new(|cx| {
14765            Editor::for_multibuffer(
14766                excerpt_buffer,
14767                Some(workspace.project().clone()),
14768                window,
14769                cx,
14770            )
14771        });
14772        editor.update(cx, |editor, cx| {
14773            match multibuffer_selection_mode {
14774                MultibufferSelectionMode::First => {
14775                    if let Some(first_range) = ranges.first() {
14776                        editor.change_selections(None, window, cx, |selections| {
14777                            selections.clear_disjoint();
14778                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14779                        });
14780                    }
14781                    editor.highlight_background::<Self>(
14782                        &ranges,
14783                        |theme| theme.editor_highlighted_line_background,
14784                        cx,
14785                    );
14786                }
14787                MultibufferSelectionMode::All => {
14788                    editor.change_selections(None, window, cx, |selections| {
14789                        selections.clear_disjoint();
14790                        selections.select_anchor_ranges(ranges);
14791                    });
14792                }
14793            }
14794            editor.register_buffers_with_language_servers(cx);
14795        });
14796
14797        let item = Box::new(editor);
14798        let item_id = item.item_id();
14799
14800        if split {
14801            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14802        } else {
14803            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14804                let (preview_item_id, preview_item_idx) =
14805                    workspace.active_pane().read_with(cx, |pane, _| {
14806                        (pane.preview_item_id(), pane.preview_item_idx())
14807                    });
14808
14809                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14810
14811                if let Some(preview_item_id) = preview_item_id {
14812                    workspace.active_pane().update(cx, |pane, cx| {
14813                        pane.remove_item(preview_item_id, false, false, window, cx);
14814                    });
14815                }
14816            } else {
14817                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14818            }
14819        }
14820        workspace.active_pane().update(cx, |pane, cx| {
14821            pane.set_preview_item_id(Some(item_id), cx);
14822        });
14823    }
14824
14825    pub fn rename(
14826        &mut self,
14827        _: &Rename,
14828        window: &mut Window,
14829        cx: &mut Context<Self>,
14830    ) -> Option<Task<Result<()>>> {
14831        use language::ToOffset as _;
14832
14833        let provider = self.semantics_provider.clone()?;
14834        let selection = self.selections.newest_anchor().clone();
14835        let (cursor_buffer, cursor_buffer_position) = self
14836            .buffer
14837            .read(cx)
14838            .text_anchor_for_position(selection.head(), cx)?;
14839        let (tail_buffer, cursor_buffer_position_end) = self
14840            .buffer
14841            .read(cx)
14842            .text_anchor_for_position(selection.tail(), cx)?;
14843        if tail_buffer != cursor_buffer {
14844            return None;
14845        }
14846
14847        let snapshot = cursor_buffer.read(cx).snapshot();
14848        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14849        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14850        let prepare_rename = provider
14851            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14852            .unwrap_or_else(|| Task::ready(Ok(None)));
14853        drop(snapshot);
14854
14855        Some(cx.spawn_in(window, async move |this, cx| {
14856            let rename_range = if let Some(range) = prepare_rename.await? {
14857                Some(range)
14858            } else {
14859                this.update(cx, |this, cx| {
14860                    let buffer = this.buffer.read(cx).snapshot(cx);
14861                    let mut buffer_highlights = this
14862                        .document_highlights_for_position(selection.head(), &buffer)
14863                        .filter(|highlight| {
14864                            highlight.start.excerpt_id == selection.head().excerpt_id
14865                                && highlight.end.excerpt_id == selection.head().excerpt_id
14866                        });
14867                    buffer_highlights
14868                        .next()
14869                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14870                })?
14871            };
14872            if let Some(rename_range) = rename_range {
14873                this.update_in(cx, |this, window, cx| {
14874                    let snapshot = cursor_buffer.read(cx).snapshot();
14875                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14876                    let cursor_offset_in_rename_range =
14877                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14878                    let cursor_offset_in_rename_range_end =
14879                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14880
14881                    this.take_rename(false, window, cx);
14882                    let buffer = this.buffer.read(cx).read(cx);
14883                    let cursor_offset = selection.head().to_offset(&buffer);
14884                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14885                    let rename_end = rename_start + rename_buffer_range.len();
14886                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14887                    let mut old_highlight_id = None;
14888                    let old_name: Arc<str> = buffer
14889                        .chunks(rename_start..rename_end, true)
14890                        .map(|chunk| {
14891                            if old_highlight_id.is_none() {
14892                                old_highlight_id = chunk.syntax_highlight_id;
14893                            }
14894                            chunk.text
14895                        })
14896                        .collect::<String>()
14897                        .into();
14898
14899                    drop(buffer);
14900
14901                    // Position the selection in the rename editor so that it matches the current selection.
14902                    this.show_local_selections = false;
14903                    let rename_editor = cx.new(|cx| {
14904                        let mut editor = Editor::single_line(window, cx);
14905                        editor.buffer.update(cx, |buffer, cx| {
14906                            buffer.edit([(0..0, old_name.clone())], None, cx)
14907                        });
14908                        let rename_selection_range = match cursor_offset_in_rename_range
14909                            .cmp(&cursor_offset_in_rename_range_end)
14910                        {
14911                            Ordering::Equal => {
14912                                editor.select_all(&SelectAll, window, cx);
14913                                return editor;
14914                            }
14915                            Ordering::Less => {
14916                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14917                            }
14918                            Ordering::Greater => {
14919                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14920                            }
14921                        };
14922                        if rename_selection_range.end > old_name.len() {
14923                            editor.select_all(&SelectAll, window, cx);
14924                        } else {
14925                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14926                                s.select_ranges([rename_selection_range]);
14927                            });
14928                        }
14929                        editor
14930                    });
14931                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14932                        if e == &EditorEvent::Focused {
14933                            cx.emit(EditorEvent::FocusedIn)
14934                        }
14935                    })
14936                    .detach();
14937
14938                    let write_highlights =
14939                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14940                    let read_highlights =
14941                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14942                    let ranges = write_highlights
14943                        .iter()
14944                        .flat_map(|(_, ranges)| ranges.iter())
14945                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14946                        .cloned()
14947                        .collect();
14948
14949                    this.highlight_text::<Rename>(
14950                        ranges,
14951                        HighlightStyle {
14952                            fade_out: Some(0.6),
14953                            ..Default::default()
14954                        },
14955                        cx,
14956                    );
14957                    let rename_focus_handle = rename_editor.focus_handle(cx);
14958                    window.focus(&rename_focus_handle);
14959                    let block_id = this.insert_blocks(
14960                        [BlockProperties {
14961                            style: BlockStyle::Flex,
14962                            placement: BlockPlacement::Below(range.start),
14963                            height: Some(1),
14964                            render: Arc::new({
14965                                let rename_editor = rename_editor.clone();
14966                                move |cx: &mut BlockContext| {
14967                                    let mut text_style = cx.editor_style.text.clone();
14968                                    if let Some(highlight_style) = old_highlight_id
14969                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14970                                    {
14971                                        text_style = text_style.highlight(highlight_style);
14972                                    }
14973                                    div()
14974                                        .block_mouse_down()
14975                                        .pl(cx.anchor_x)
14976                                        .child(EditorElement::new(
14977                                            &rename_editor,
14978                                            EditorStyle {
14979                                                background: cx.theme().system().transparent,
14980                                                local_player: cx.editor_style.local_player,
14981                                                text: text_style,
14982                                                scrollbar_width: cx.editor_style.scrollbar_width,
14983                                                syntax: cx.editor_style.syntax.clone(),
14984                                                status: cx.editor_style.status.clone(),
14985                                                inlay_hints_style: HighlightStyle {
14986                                                    font_weight: Some(FontWeight::BOLD),
14987                                                    ..make_inlay_hints_style(cx.app)
14988                                                },
14989                                                inline_completion_styles: make_suggestion_styles(
14990                                                    cx.app,
14991                                                ),
14992                                                ..EditorStyle::default()
14993                                            },
14994                                        ))
14995                                        .into_any_element()
14996                                }
14997                            }),
14998                            priority: 0,
14999                            render_in_minimap: true,
15000                        }],
15001                        Some(Autoscroll::fit()),
15002                        cx,
15003                    )[0];
15004                    this.pending_rename = Some(RenameState {
15005                        range,
15006                        old_name,
15007                        editor: rename_editor,
15008                        block_id,
15009                    });
15010                })?;
15011            }
15012
15013            Ok(())
15014        }))
15015    }
15016
15017    pub fn confirm_rename(
15018        &mut self,
15019        _: &ConfirmRename,
15020        window: &mut Window,
15021        cx: &mut Context<Self>,
15022    ) -> Option<Task<Result<()>>> {
15023        let rename = self.take_rename(false, window, cx)?;
15024        let workspace = self.workspace()?.downgrade();
15025        let (buffer, start) = self
15026            .buffer
15027            .read(cx)
15028            .text_anchor_for_position(rename.range.start, cx)?;
15029        let (end_buffer, _) = self
15030            .buffer
15031            .read(cx)
15032            .text_anchor_for_position(rename.range.end, cx)?;
15033        if buffer != end_buffer {
15034            return None;
15035        }
15036
15037        let old_name = rename.old_name;
15038        let new_name = rename.editor.read(cx).text(cx);
15039
15040        let rename = self.semantics_provider.as_ref()?.perform_rename(
15041            &buffer,
15042            start,
15043            new_name.clone(),
15044            cx,
15045        )?;
15046
15047        Some(cx.spawn_in(window, async move |editor, cx| {
15048            let project_transaction = rename.await?;
15049            Self::open_project_transaction(
15050                &editor,
15051                workspace,
15052                project_transaction,
15053                format!("Rename: {}{}", old_name, new_name),
15054                cx,
15055            )
15056            .await?;
15057
15058            editor.update(cx, |editor, cx| {
15059                editor.refresh_document_highlights(cx);
15060            })?;
15061            Ok(())
15062        }))
15063    }
15064
15065    fn take_rename(
15066        &mut self,
15067        moving_cursor: bool,
15068        window: &mut Window,
15069        cx: &mut Context<Self>,
15070    ) -> Option<RenameState> {
15071        let rename = self.pending_rename.take()?;
15072        if rename.editor.focus_handle(cx).is_focused(window) {
15073            window.focus(&self.focus_handle);
15074        }
15075
15076        self.remove_blocks(
15077            [rename.block_id].into_iter().collect(),
15078            Some(Autoscroll::fit()),
15079            cx,
15080        );
15081        self.clear_highlights::<Rename>(cx);
15082        self.show_local_selections = true;
15083
15084        if moving_cursor {
15085            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15086                editor.selections.newest::<usize>(cx).head()
15087            });
15088
15089            // Update the selection to match the position of the selection inside
15090            // the rename editor.
15091            let snapshot = self.buffer.read(cx).read(cx);
15092            let rename_range = rename.range.to_offset(&snapshot);
15093            let cursor_in_editor = snapshot
15094                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15095                .min(rename_range.end);
15096            drop(snapshot);
15097
15098            self.change_selections(None, window, cx, |s| {
15099                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15100            });
15101        } else {
15102            self.refresh_document_highlights(cx);
15103        }
15104
15105        Some(rename)
15106    }
15107
15108    pub fn pending_rename(&self) -> Option<&RenameState> {
15109        self.pending_rename.as_ref()
15110    }
15111
15112    fn format(
15113        &mut self,
15114        _: &Format,
15115        window: &mut Window,
15116        cx: &mut Context<Self>,
15117    ) -> Option<Task<Result<()>>> {
15118        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15119
15120        let project = match &self.project {
15121            Some(project) => project.clone(),
15122            None => return None,
15123        };
15124
15125        Some(self.perform_format(
15126            project,
15127            FormatTrigger::Manual,
15128            FormatTarget::Buffers,
15129            window,
15130            cx,
15131        ))
15132    }
15133
15134    fn format_selections(
15135        &mut self,
15136        _: &FormatSelections,
15137        window: &mut Window,
15138        cx: &mut Context<Self>,
15139    ) -> Option<Task<Result<()>>> {
15140        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15141
15142        let project = match &self.project {
15143            Some(project) => project.clone(),
15144            None => return None,
15145        };
15146
15147        let ranges = self
15148            .selections
15149            .all_adjusted(cx)
15150            .into_iter()
15151            .map(|selection| selection.range())
15152            .collect_vec();
15153
15154        Some(self.perform_format(
15155            project,
15156            FormatTrigger::Manual,
15157            FormatTarget::Ranges(ranges),
15158            window,
15159            cx,
15160        ))
15161    }
15162
15163    fn perform_format(
15164        &mut self,
15165        project: Entity<Project>,
15166        trigger: FormatTrigger,
15167        target: FormatTarget,
15168        window: &mut Window,
15169        cx: &mut Context<Self>,
15170    ) -> Task<Result<()>> {
15171        let buffer = self.buffer.clone();
15172        let (buffers, target) = match target {
15173            FormatTarget::Buffers => {
15174                let mut buffers = buffer.read(cx).all_buffers();
15175                if trigger == FormatTrigger::Save {
15176                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15177                }
15178                (buffers, LspFormatTarget::Buffers)
15179            }
15180            FormatTarget::Ranges(selection_ranges) => {
15181                let multi_buffer = buffer.read(cx);
15182                let snapshot = multi_buffer.read(cx);
15183                let mut buffers = HashSet::default();
15184                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15185                    BTreeMap::new();
15186                for selection_range in selection_ranges {
15187                    for (buffer, buffer_range, _) in
15188                        snapshot.range_to_buffer_ranges(selection_range)
15189                    {
15190                        let buffer_id = buffer.remote_id();
15191                        let start = buffer.anchor_before(buffer_range.start);
15192                        let end = buffer.anchor_after(buffer_range.end);
15193                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15194                        buffer_id_to_ranges
15195                            .entry(buffer_id)
15196                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15197                            .or_insert_with(|| vec![start..end]);
15198                    }
15199                }
15200                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15201            }
15202        };
15203
15204        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15205        let selections_prev = transaction_id_prev
15206            .and_then(|transaction_id_prev| {
15207                // default to selections as they were after the last edit, if we have them,
15208                // instead of how they are now.
15209                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15210                // will take you back to where you made the last edit, instead of staying where you scrolled
15211                self.selection_history
15212                    .transaction(transaction_id_prev)
15213                    .map(|t| t.0.clone())
15214            })
15215            .unwrap_or_else(|| {
15216                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15217                self.selections.disjoint_anchors()
15218            });
15219
15220        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15221        let format = project.update(cx, |project, cx| {
15222            project.format(buffers, target, true, trigger, cx)
15223        });
15224
15225        cx.spawn_in(window, async move |editor, cx| {
15226            let transaction = futures::select_biased! {
15227                transaction = format.log_err().fuse() => transaction,
15228                () = timeout => {
15229                    log::warn!("timed out waiting for formatting");
15230                    None
15231                }
15232            };
15233
15234            buffer
15235                .update(cx, |buffer, cx| {
15236                    if let Some(transaction) = transaction {
15237                        if !buffer.is_singleton() {
15238                            buffer.push_transaction(&transaction.0, cx);
15239                        }
15240                    }
15241                    cx.notify();
15242                })
15243                .ok();
15244
15245            if let Some(transaction_id_now) =
15246                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15247            {
15248                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15249                if has_new_transaction {
15250                    _ = editor.update(cx, |editor, _| {
15251                        editor
15252                            .selection_history
15253                            .insert_transaction(transaction_id_now, selections_prev);
15254                    });
15255                }
15256            }
15257
15258            Ok(())
15259        })
15260    }
15261
15262    fn organize_imports(
15263        &mut self,
15264        _: &OrganizeImports,
15265        window: &mut Window,
15266        cx: &mut Context<Self>,
15267    ) -> Option<Task<Result<()>>> {
15268        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15269        let project = match &self.project {
15270            Some(project) => project.clone(),
15271            None => return None,
15272        };
15273        Some(self.perform_code_action_kind(
15274            project,
15275            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15276            window,
15277            cx,
15278        ))
15279    }
15280
15281    fn perform_code_action_kind(
15282        &mut self,
15283        project: Entity<Project>,
15284        kind: CodeActionKind,
15285        window: &mut Window,
15286        cx: &mut Context<Self>,
15287    ) -> Task<Result<()>> {
15288        let buffer = self.buffer.clone();
15289        let buffers = buffer.read(cx).all_buffers();
15290        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15291        let apply_action = project.update(cx, |project, cx| {
15292            project.apply_code_action_kind(buffers, kind, true, cx)
15293        });
15294        cx.spawn_in(window, async move |_, cx| {
15295            let transaction = futures::select_biased! {
15296                () = timeout => {
15297                    log::warn!("timed out waiting for executing code action");
15298                    None
15299                }
15300                transaction = apply_action.log_err().fuse() => transaction,
15301            };
15302            buffer
15303                .update(cx, |buffer, cx| {
15304                    // check if we need this
15305                    if let Some(transaction) = transaction {
15306                        if !buffer.is_singleton() {
15307                            buffer.push_transaction(&transaction.0, cx);
15308                        }
15309                    }
15310                    cx.notify();
15311                })
15312                .ok();
15313            Ok(())
15314        })
15315    }
15316
15317    fn restart_language_server(
15318        &mut self,
15319        _: &RestartLanguageServer,
15320        _: &mut Window,
15321        cx: &mut Context<Self>,
15322    ) {
15323        if let Some(project) = self.project.clone() {
15324            self.buffer.update(cx, |multi_buffer, cx| {
15325                project.update(cx, |project, cx| {
15326                    project.restart_language_servers_for_buffers(
15327                        multi_buffer.all_buffers().into_iter().collect(),
15328                        cx,
15329                    );
15330                });
15331            })
15332        }
15333    }
15334
15335    fn stop_language_server(
15336        &mut self,
15337        _: &StopLanguageServer,
15338        _: &mut Window,
15339        cx: &mut Context<Self>,
15340    ) {
15341        if let Some(project) = self.project.clone() {
15342            self.buffer.update(cx, |multi_buffer, cx| {
15343                project.update(cx, |project, cx| {
15344                    project.stop_language_servers_for_buffers(
15345                        multi_buffer.all_buffers().into_iter().collect(),
15346                        cx,
15347                    );
15348                    cx.emit(project::Event::RefreshInlayHints);
15349                });
15350            });
15351        }
15352    }
15353
15354    fn cancel_language_server_work(
15355        workspace: &mut Workspace,
15356        _: &actions::CancelLanguageServerWork,
15357        _: &mut Window,
15358        cx: &mut Context<Workspace>,
15359    ) {
15360        let project = workspace.project();
15361        let buffers = workspace
15362            .active_item(cx)
15363            .and_then(|item| item.act_as::<Editor>(cx))
15364            .map_or(HashSet::default(), |editor| {
15365                editor.read(cx).buffer.read(cx).all_buffers()
15366            });
15367        project.update(cx, |project, cx| {
15368            project.cancel_language_server_work_for_buffers(buffers, cx);
15369        });
15370    }
15371
15372    fn show_character_palette(
15373        &mut self,
15374        _: &ShowCharacterPalette,
15375        window: &mut Window,
15376        _: &mut Context<Self>,
15377    ) {
15378        window.show_character_palette();
15379    }
15380
15381    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15382        if self.mode.is_minimap() {
15383            return;
15384        }
15385
15386        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15387            let buffer = self.buffer.read(cx).snapshot(cx);
15388            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15389            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15390            let is_valid = buffer
15391                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15392                .any(|entry| {
15393                    entry.diagnostic.is_primary
15394                        && !entry.range.is_empty()
15395                        && entry.range.start == primary_range_start
15396                        && entry.diagnostic.message == active_diagnostics.active_message
15397                });
15398
15399            if !is_valid {
15400                self.dismiss_diagnostics(cx);
15401            }
15402        }
15403    }
15404
15405    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15406        match &self.active_diagnostics {
15407            ActiveDiagnostic::Group(group) => Some(group),
15408            _ => None,
15409        }
15410    }
15411
15412    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15413        self.dismiss_diagnostics(cx);
15414        self.active_diagnostics = ActiveDiagnostic::All;
15415    }
15416
15417    fn activate_diagnostics(
15418        &mut self,
15419        buffer_id: BufferId,
15420        diagnostic: DiagnosticEntry<usize>,
15421        window: &mut Window,
15422        cx: &mut Context<Self>,
15423    ) {
15424        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15425            return;
15426        }
15427        self.dismiss_diagnostics(cx);
15428        let snapshot = self.snapshot(window, cx);
15429        let buffer = self.buffer.read(cx).snapshot(cx);
15430        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15431            return;
15432        };
15433
15434        let diagnostic_group = buffer
15435            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15436            .collect::<Vec<_>>();
15437
15438        let blocks =
15439            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15440
15441        let blocks = self.display_map.update(cx, |display_map, cx| {
15442            display_map.insert_blocks(blocks, cx).into_iter().collect()
15443        });
15444        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15445            active_range: buffer.anchor_before(diagnostic.range.start)
15446                ..buffer.anchor_after(diagnostic.range.end),
15447            active_message: diagnostic.diagnostic.message.clone(),
15448            group_id: diagnostic.diagnostic.group_id,
15449            blocks,
15450        });
15451        cx.notify();
15452    }
15453
15454    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15455        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15456            return;
15457        };
15458
15459        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15460        if let ActiveDiagnostic::Group(group) = prev {
15461            self.display_map.update(cx, |display_map, cx| {
15462                display_map.remove_blocks(group.blocks, cx);
15463            });
15464            cx.notify();
15465        }
15466    }
15467
15468    /// Disable inline diagnostics rendering for this editor.
15469    pub fn disable_inline_diagnostics(&mut self) {
15470        self.inline_diagnostics_enabled = false;
15471        self.inline_diagnostics_update = Task::ready(());
15472        self.inline_diagnostics.clear();
15473    }
15474
15475    pub fn diagnostics_enabled(&self) -> bool {
15476        self.mode.is_full()
15477    }
15478
15479    pub fn inline_diagnostics_enabled(&self) -> bool {
15480        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15481    }
15482
15483    pub fn show_inline_diagnostics(&self) -> bool {
15484        self.show_inline_diagnostics
15485    }
15486
15487    pub fn toggle_inline_diagnostics(
15488        &mut self,
15489        _: &ToggleInlineDiagnostics,
15490        window: &mut Window,
15491        cx: &mut Context<Editor>,
15492    ) {
15493        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15494        self.refresh_inline_diagnostics(false, window, cx);
15495    }
15496
15497    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15498        self.diagnostics_max_severity = severity;
15499        self.display_map.update(cx, |display_map, _| {
15500            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15501        });
15502    }
15503
15504    pub fn toggle_diagnostics(
15505        &mut self,
15506        _: &ToggleDiagnostics,
15507        window: &mut Window,
15508        cx: &mut Context<Editor>,
15509    ) {
15510        if !self.diagnostics_enabled() {
15511            return;
15512        }
15513
15514        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15515            EditorSettings::get_global(cx)
15516                .diagnostics_max_severity
15517                .filter(|severity| severity != &DiagnosticSeverity::Off)
15518                .unwrap_or(DiagnosticSeverity::Hint)
15519        } else {
15520            DiagnosticSeverity::Off
15521        };
15522        self.set_max_diagnostics_severity(new_severity, cx);
15523        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15524            self.active_diagnostics = ActiveDiagnostic::None;
15525            self.inline_diagnostics_update = Task::ready(());
15526            self.inline_diagnostics.clear();
15527        } else {
15528            self.refresh_inline_diagnostics(false, window, cx);
15529        }
15530
15531        cx.notify();
15532    }
15533
15534    pub fn toggle_minimap(
15535        &mut self,
15536        _: &ToggleMinimap,
15537        window: &mut Window,
15538        cx: &mut Context<Editor>,
15539    ) {
15540        if self.supports_minimap(cx) {
15541            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15542        }
15543    }
15544
15545    fn refresh_inline_diagnostics(
15546        &mut self,
15547        debounce: bool,
15548        window: &mut Window,
15549        cx: &mut Context<Self>,
15550    ) {
15551        let max_severity = ProjectSettings::get_global(cx)
15552            .diagnostics
15553            .inline
15554            .max_severity
15555            .unwrap_or(self.diagnostics_max_severity);
15556
15557        if !self.inline_diagnostics_enabled()
15558            || !self.show_inline_diagnostics
15559            || max_severity == DiagnosticSeverity::Off
15560        {
15561            self.inline_diagnostics_update = Task::ready(());
15562            self.inline_diagnostics.clear();
15563            return;
15564        }
15565
15566        let debounce_ms = ProjectSettings::get_global(cx)
15567            .diagnostics
15568            .inline
15569            .update_debounce_ms;
15570        let debounce = if debounce && debounce_ms > 0 {
15571            Some(Duration::from_millis(debounce_ms))
15572        } else {
15573            None
15574        };
15575        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15576            let editor = editor.upgrade().unwrap();
15577
15578            if let Some(debounce) = debounce {
15579                cx.background_executor().timer(debounce).await;
15580            }
15581            let Some(snapshot) = editor
15582                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15583                .ok()
15584            else {
15585                return;
15586            };
15587
15588            let new_inline_diagnostics = cx
15589                .background_spawn(async move {
15590                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15591                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15592                        let message = diagnostic_entry
15593                            .diagnostic
15594                            .message
15595                            .split_once('\n')
15596                            .map(|(line, _)| line)
15597                            .map(SharedString::new)
15598                            .unwrap_or_else(|| {
15599                                SharedString::from(diagnostic_entry.diagnostic.message)
15600                            });
15601                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15602                        let (Ok(i) | Err(i)) = inline_diagnostics
15603                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15604                        inline_diagnostics.insert(
15605                            i,
15606                            (
15607                                start_anchor,
15608                                InlineDiagnostic {
15609                                    message,
15610                                    group_id: diagnostic_entry.diagnostic.group_id,
15611                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15612                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15613                                    severity: diagnostic_entry.diagnostic.severity,
15614                                },
15615                            ),
15616                        );
15617                    }
15618                    inline_diagnostics
15619                })
15620                .await;
15621
15622            editor
15623                .update(cx, |editor, cx| {
15624                    editor.inline_diagnostics = new_inline_diagnostics;
15625                    cx.notify();
15626                })
15627                .ok();
15628        });
15629    }
15630
15631    pub fn set_selections_from_remote(
15632        &mut self,
15633        selections: Vec<Selection<Anchor>>,
15634        pending_selection: Option<Selection<Anchor>>,
15635        window: &mut Window,
15636        cx: &mut Context<Self>,
15637    ) {
15638        let old_cursor_position = self.selections.newest_anchor().head();
15639        self.selections.change_with(cx, |s| {
15640            s.select_anchors(selections);
15641            if let Some(pending_selection) = pending_selection {
15642                s.set_pending(pending_selection, SelectMode::Character);
15643            } else {
15644                s.clear_pending();
15645            }
15646        });
15647        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15648    }
15649
15650    fn push_to_selection_history(&mut self) {
15651        self.selection_history.push(SelectionHistoryEntry {
15652            selections: self.selections.disjoint_anchors(),
15653            select_next_state: self.select_next_state.clone(),
15654            select_prev_state: self.select_prev_state.clone(),
15655            add_selections_state: self.add_selections_state.clone(),
15656        });
15657    }
15658
15659    pub fn transact(
15660        &mut self,
15661        window: &mut Window,
15662        cx: &mut Context<Self>,
15663        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15664    ) -> Option<TransactionId> {
15665        self.start_transaction_at(Instant::now(), window, cx);
15666        update(self, window, cx);
15667        self.end_transaction_at(Instant::now(), cx)
15668    }
15669
15670    pub fn start_transaction_at(
15671        &mut self,
15672        now: Instant,
15673        window: &mut Window,
15674        cx: &mut Context<Self>,
15675    ) {
15676        self.end_selection(window, cx);
15677        if let Some(tx_id) = self
15678            .buffer
15679            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15680        {
15681            self.selection_history
15682                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15683            cx.emit(EditorEvent::TransactionBegun {
15684                transaction_id: tx_id,
15685            })
15686        }
15687    }
15688
15689    pub fn end_transaction_at(
15690        &mut self,
15691        now: Instant,
15692        cx: &mut Context<Self>,
15693    ) -> Option<TransactionId> {
15694        if let Some(transaction_id) = self
15695            .buffer
15696            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15697        {
15698            if let Some((_, end_selections)) =
15699                self.selection_history.transaction_mut(transaction_id)
15700            {
15701                *end_selections = Some(self.selections.disjoint_anchors());
15702            } else {
15703                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15704            }
15705
15706            cx.emit(EditorEvent::Edited { transaction_id });
15707            Some(transaction_id)
15708        } else {
15709            None
15710        }
15711    }
15712
15713    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15714        if self.selection_mark_mode {
15715            self.change_selections(None, window, cx, |s| {
15716                s.move_with(|_, sel| {
15717                    sel.collapse_to(sel.head(), SelectionGoal::None);
15718                });
15719            })
15720        }
15721        self.selection_mark_mode = true;
15722        cx.notify();
15723    }
15724
15725    pub fn swap_selection_ends(
15726        &mut self,
15727        _: &actions::SwapSelectionEnds,
15728        window: &mut Window,
15729        cx: &mut Context<Self>,
15730    ) {
15731        self.change_selections(None, window, cx, |s| {
15732            s.move_with(|_, sel| {
15733                if sel.start != sel.end {
15734                    sel.reversed = !sel.reversed
15735                }
15736            });
15737        });
15738        self.request_autoscroll(Autoscroll::newest(), cx);
15739        cx.notify();
15740    }
15741
15742    pub fn toggle_fold(
15743        &mut self,
15744        _: &actions::ToggleFold,
15745        window: &mut Window,
15746        cx: &mut Context<Self>,
15747    ) {
15748        if self.is_singleton(cx) {
15749            let selection = self.selections.newest::<Point>(cx);
15750
15751            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15752            let range = if selection.is_empty() {
15753                let point = selection.head().to_display_point(&display_map);
15754                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15755                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15756                    .to_point(&display_map);
15757                start..end
15758            } else {
15759                selection.range()
15760            };
15761            if display_map.folds_in_range(range).next().is_some() {
15762                self.unfold_lines(&Default::default(), window, cx)
15763            } else {
15764                self.fold(&Default::default(), window, cx)
15765            }
15766        } else {
15767            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15768            let buffer_ids: HashSet<_> = self
15769                .selections
15770                .disjoint_anchor_ranges()
15771                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15772                .collect();
15773
15774            let should_unfold = buffer_ids
15775                .iter()
15776                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15777
15778            for buffer_id in buffer_ids {
15779                if should_unfold {
15780                    self.unfold_buffer(buffer_id, cx);
15781                } else {
15782                    self.fold_buffer(buffer_id, cx);
15783                }
15784            }
15785        }
15786    }
15787
15788    pub fn toggle_fold_recursive(
15789        &mut self,
15790        _: &actions::ToggleFoldRecursive,
15791        window: &mut Window,
15792        cx: &mut Context<Self>,
15793    ) {
15794        let selection = self.selections.newest::<Point>(cx);
15795
15796        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15797        let range = if selection.is_empty() {
15798            let point = selection.head().to_display_point(&display_map);
15799            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15800            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15801                .to_point(&display_map);
15802            start..end
15803        } else {
15804            selection.range()
15805        };
15806        if display_map.folds_in_range(range).next().is_some() {
15807            self.unfold_recursive(&Default::default(), window, cx)
15808        } else {
15809            self.fold_recursive(&Default::default(), window, cx)
15810        }
15811    }
15812
15813    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15814        if self.is_singleton(cx) {
15815            let mut to_fold = Vec::new();
15816            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15817            let selections = self.selections.all_adjusted(cx);
15818
15819            for selection in selections {
15820                let range = selection.range().sorted();
15821                let buffer_start_row = range.start.row;
15822
15823                if range.start.row != range.end.row {
15824                    let mut found = false;
15825                    let mut row = range.start.row;
15826                    while row <= range.end.row {
15827                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15828                        {
15829                            found = true;
15830                            row = crease.range().end.row + 1;
15831                            to_fold.push(crease);
15832                        } else {
15833                            row += 1
15834                        }
15835                    }
15836                    if found {
15837                        continue;
15838                    }
15839                }
15840
15841                for row in (0..=range.start.row).rev() {
15842                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15843                        if crease.range().end.row >= buffer_start_row {
15844                            to_fold.push(crease);
15845                            if row <= range.start.row {
15846                                break;
15847                            }
15848                        }
15849                    }
15850                }
15851            }
15852
15853            self.fold_creases(to_fold, true, window, cx);
15854        } else {
15855            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15856            let buffer_ids = self
15857                .selections
15858                .disjoint_anchor_ranges()
15859                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15860                .collect::<HashSet<_>>();
15861            for buffer_id in buffer_ids {
15862                self.fold_buffer(buffer_id, cx);
15863            }
15864        }
15865    }
15866
15867    fn fold_at_level(
15868        &mut self,
15869        fold_at: &FoldAtLevel,
15870        window: &mut Window,
15871        cx: &mut Context<Self>,
15872    ) {
15873        if !self.buffer.read(cx).is_singleton() {
15874            return;
15875        }
15876
15877        let fold_at_level = fold_at.0;
15878        let snapshot = self.buffer.read(cx).snapshot(cx);
15879        let mut to_fold = Vec::new();
15880        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15881
15882        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15883            while start_row < end_row {
15884                match self
15885                    .snapshot(window, cx)
15886                    .crease_for_buffer_row(MultiBufferRow(start_row))
15887                {
15888                    Some(crease) => {
15889                        let nested_start_row = crease.range().start.row + 1;
15890                        let nested_end_row = crease.range().end.row;
15891
15892                        if current_level < fold_at_level {
15893                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15894                        } else if current_level == fold_at_level {
15895                            to_fold.push(crease);
15896                        }
15897
15898                        start_row = nested_end_row + 1;
15899                    }
15900                    None => start_row += 1,
15901                }
15902            }
15903        }
15904
15905        self.fold_creases(to_fold, true, window, cx);
15906    }
15907
15908    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15909        if self.buffer.read(cx).is_singleton() {
15910            let mut fold_ranges = Vec::new();
15911            let snapshot = self.buffer.read(cx).snapshot(cx);
15912
15913            for row in 0..snapshot.max_row().0 {
15914                if let Some(foldable_range) = self
15915                    .snapshot(window, cx)
15916                    .crease_for_buffer_row(MultiBufferRow(row))
15917                {
15918                    fold_ranges.push(foldable_range);
15919                }
15920            }
15921
15922            self.fold_creases(fold_ranges, true, window, cx);
15923        } else {
15924            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15925                editor
15926                    .update_in(cx, |editor, _, cx| {
15927                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15928                            editor.fold_buffer(buffer_id, cx);
15929                        }
15930                    })
15931                    .ok();
15932            });
15933        }
15934    }
15935
15936    pub fn fold_function_bodies(
15937        &mut self,
15938        _: &actions::FoldFunctionBodies,
15939        window: &mut Window,
15940        cx: &mut Context<Self>,
15941    ) {
15942        let snapshot = self.buffer.read(cx).snapshot(cx);
15943
15944        let ranges = snapshot
15945            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15946            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15947            .collect::<Vec<_>>();
15948
15949        let creases = ranges
15950            .into_iter()
15951            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15952            .collect();
15953
15954        self.fold_creases(creases, true, window, cx);
15955    }
15956
15957    pub fn fold_recursive(
15958        &mut self,
15959        _: &actions::FoldRecursive,
15960        window: &mut Window,
15961        cx: &mut Context<Self>,
15962    ) {
15963        let mut to_fold = Vec::new();
15964        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15965        let selections = self.selections.all_adjusted(cx);
15966
15967        for selection in selections {
15968            let range = selection.range().sorted();
15969            let buffer_start_row = range.start.row;
15970
15971            if range.start.row != range.end.row {
15972                let mut found = false;
15973                for row in range.start.row..=range.end.row {
15974                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15975                        found = true;
15976                        to_fold.push(crease);
15977                    }
15978                }
15979                if found {
15980                    continue;
15981                }
15982            }
15983
15984            for row in (0..=range.start.row).rev() {
15985                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15986                    if crease.range().end.row >= buffer_start_row {
15987                        to_fold.push(crease);
15988                    } else {
15989                        break;
15990                    }
15991                }
15992            }
15993        }
15994
15995        self.fold_creases(to_fold, true, window, cx);
15996    }
15997
15998    pub fn fold_at(
15999        &mut self,
16000        buffer_row: MultiBufferRow,
16001        window: &mut Window,
16002        cx: &mut Context<Self>,
16003    ) {
16004        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16005
16006        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16007            let autoscroll = self
16008                .selections
16009                .all::<Point>(cx)
16010                .iter()
16011                .any(|selection| crease.range().overlaps(&selection.range()));
16012
16013            self.fold_creases(vec![crease], autoscroll, window, cx);
16014        }
16015    }
16016
16017    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16018        if self.is_singleton(cx) {
16019            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16020            let buffer = &display_map.buffer_snapshot;
16021            let selections = self.selections.all::<Point>(cx);
16022            let ranges = selections
16023                .iter()
16024                .map(|s| {
16025                    let range = s.display_range(&display_map).sorted();
16026                    let mut start = range.start.to_point(&display_map);
16027                    let mut end = range.end.to_point(&display_map);
16028                    start.column = 0;
16029                    end.column = buffer.line_len(MultiBufferRow(end.row));
16030                    start..end
16031                })
16032                .collect::<Vec<_>>();
16033
16034            self.unfold_ranges(&ranges, true, true, cx);
16035        } else {
16036            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16037            let buffer_ids = self
16038                .selections
16039                .disjoint_anchor_ranges()
16040                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16041                .collect::<HashSet<_>>();
16042            for buffer_id in buffer_ids {
16043                self.unfold_buffer(buffer_id, cx);
16044            }
16045        }
16046    }
16047
16048    pub fn unfold_recursive(
16049        &mut self,
16050        _: &UnfoldRecursive,
16051        _window: &mut Window,
16052        cx: &mut Context<Self>,
16053    ) {
16054        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16055        let selections = self.selections.all::<Point>(cx);
16056        let ranges = selections
16057            .iter()
16058            .map(|s| {
16059                let mut range = s.display_range(&display_map).sorted();
16060                *range.start.column_mut() = 0;
16061                *range.end.column_mut() = display_map.line_len(range.end.row());
16062                let start = range.start.to_point(&display_map);
16063                let end = range.end.to_point(&display_map);
16064                start..end
16065            })
16066            .collect::<Vec<_>>();
16067
16068        self.unfold_ranges(&ranges, true, true, cx);
16069    }
16070
16071    pub fn unfold_at(
16072        &mut self,
16073        buffer_row: MultiBufferRow,
16074        _window: &mut Window,
16075        cx: &mut Context<Self>,
16076    ) {
16077        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16078
16079        let intersection_range = Point::new(buffer_row.0, 0)
16080            ..Point::new(
16081                buffer_row.0,
16082                display_map.buffer_snapshot.line_len(buffer_row),
16083            );
16084
16085        let autoscroll = self
16086            .selections
16087            .all::<Point>(cx)
16088            .iter()
16089            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16090
16091        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16092    }
16093
16094    pub fn unfold_all(
16095        &mut self,
16096        _: &actions::UnfoldAll,
16097        _window: &mut Window,
16098        cx: &mut Context<Self>,
16099    ) {
16100        if self.buffer.read(cx).is_singleton() {
16101            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16102            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16103        } else {
16104            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16105                editor
16106                    .update(cx, |editor, cx| {
16107                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16108                            editor.unfold_buffer(buffer_id, cx);
16109                        }
16110                    })
16111                    .ok();
16112            });
16113        }
16114    }
16115
16116    pub fn fold_selected_ranges(
16117        &mut self,
16118        _: &FoldSelectedRanges,
16119        window: &mut Window,
16120        cx: &mut Context<Self>,
16121    ) {
16122        let selections = self.selections.all_adjusted(cx);
16123        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16124        let ranges = selections
16125            .into_iter()
16126            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16127            .collect::<Vec<_>>();
16128        self.fold_creases(ranges, true, window, cx);
16129    }
16130
16131    pub fn fold_ranges<T: ToOffset + Clone>(
16132        &mut self,
16133        ranges: Vec<Range<T>>,
16134        auto_scroll: bool,
16135        window: &mut Window,
16136        cx: &mut Context<Self>,
16137    ) {
16138        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16139        let ranges = ranges
16140            .into_iter()
16141            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16142            .collect::<Vec<_>>();
16143        self.fold_creases(ranges, auto_scroll, window, cx);
16144    }
16145
16146    pub fn fold_creases<T: ToOffset + Clone>(
16147        &mut self,
16148        creases: Vec<Crease<T>>,
16149        auto_scroll: bool,
16150        _window: &mut Window,
16151        cx: &mut Context<Self>,
16152    ) {
16153        if creases.is_empty() {
16154            return;
16155        }
16156
16157        let mut buffers_affected = HashSet::default();
16158        let multi_buffer = self.buffer().read(cx);
16159        for crease in &creases {
16160            if let Some((_, buffer, _)) =
16161                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16162            {
16163                buffers_affected.insert(buffer.read(cx).remote_id());
16164            };
16165        }
16166
16167        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16168
16169        if auto_scroll {
16170            self.request_autoscroll(Autoscroll::fit(), cx);
16171        }
16172
16173        cx.notify();
16174
16175        self.scrollbar_marker_state.dirty = true;
16176        self.folds_did_change(cx);
16177    }
16178
16179    /// Removes any folds whose ranges intersect any of the given ranges.
16180    pub fn unfold_ranges<T: ToOffset + Clone>(
16181        &mut self,
16182        ranges: &[Range<T>],
16183        inclusive: bool,
16184        auto_scroll: bool,
16185        cx: &mut Context<Self>,
16186    ) {
16187        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16188            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16189        });
16190        self.folds_did_change(cx);
16191    }
16192
16193    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16194        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16195            return;
16196        }
16197        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16198        self.display_map.update(cx, |display_map, cx| {
16199            display_map.fold_buffers([buffer_id], cx)
16200        });
16201        cx.emit(EditorEvent::BufferFoldToggled {
16202            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16203            folded: true,
16204        });
16205        cx.notify();
16206    }
16207
16208    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16209        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16210            return;
16211        }
16212        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16213        self.display_map.update(cx, |display_map, cx| {
16214            display_map.unfold_buffers([buffer_id], cx);
16215        });
16216        cx.emit(EditorEvent::BufferFoldToggled {
16217            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16218            folded: false,
16219        });
16220        cx.notify();
16221    }
16222
16223    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16224        self.display_map.read(cx).is_buffer_folded(buffer)
16225    }
16226
16227    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16228        self.display_map.read(cx).folded_buffers()
16229    }
16230
16231    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16232        self.display_map.update(cx, |display_map, cx| {
16233            display_map.disable_header_for_buffer(buffer_id, cx);
16234        });
16235        cx.notify();
16236    }
16237
16238    /// Removes any folds with the given ranges.
16239    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16240        &mut self,
16241        ranges: &[Range<T>],
16242        type_id: TypeId,
16243        auto_scroll: bool,
16244        cx: &mut Context<Self>,
16245    ) {
16246        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16247            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16248        });
16249        self.folds_did_change(cx);
16250    }
16251
16252    fn remove_folds_with<T: ToOffset + Clone>(
16253        &mut self,
16254        ranges: &[Range<T>],
16255        auto_scroll: bool,
16256        cx: &mut Context<Self>,
16257        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16258    ) {
16259        if ranges.is_empty() {
16260            return;
16261        }
16262
16263        let mut buffers_affected = HashSet::default();
16264        let multi_buffer = self.buffer().read(cx);
16265        for range in ranges {
16266            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16267                buffers_affected.insert(buffer.read(cx).remote_id());
16268            };
16269        }
16270
16271        self.display_map.update(cx, update);
16272
16273        if auto_scroll {
16274            self.request_autoscroll(Autoscroll::fit(), cx);
16275        }
16276
16277        cx.notify();
16278        self.scrollbar_marker_state.dirty = true;
16279        self.active_indent_guides_state.dirty = true;
16280    }
16281
16282    pub fn update_fold_widths(
16283        &mut self,
16284        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16285        cx: &mut Context<Self>,
16286    ) -> bool {
16287        self.display_map
16288            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16289    }
16290
16291    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16292        self.display_map.read(cx).fold_placeholder.clone()
16293    }
16294
16295    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16296        self.buffer.update(cx, |buffer, cx| {
16297            buffer.set_all_diff_hunks_expanded(cx);
16298        });
16299    }
16300
16301    pub fn expand_all_diff_hunks(
16302        &mut self,
16303        _: &ExpandAllDiffHunks,
16304        _window: &mut Window,
16305        cx: &mut Context<Self>,
16306    ) {
16307        self.buffer.update(cx, |buffer, cx| {
16308            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16309        });
16310    }
16311
16312    pub fn toggle_selected_diff_hunks(
16313        &mut self,
16314        _: &ToggleSelectedDiffHunks,
16315        _window: &mut Window,
16316        cx: &mut Context<Self>,
16317    ) {
16318        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16319        self.toggle_diff_hunks_in_ranges(ranges, cx);
16320    }
16321
16322    pub fn diff_hunks_in_ranges<'a>(
16323        &'a self,
16324        ranges: &'a [Range<Anchor>],
16325        buffer: &'a MultiBufferSnapshot,
16326    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16327        ranges.iter().flat_map(move |range| {
16328            let end_excerpt_id = range.end.excerpt_id;
16329            let range = range.to_point(buffer);
16330            let mut peek_end = range.end;
16331            if range.end.row < buffer.max_row().0 {
16332                peek_end = Point::new(range.end.row + 1, 0);
16333            }
16334            buffer
16335                .diff_hunks_in_range(range.start..peek_end)
16336                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16337        })
16338    }
16339
16340    pub fn has_stageable_diff_hunks_in_ranges(
16341        &self,
16342        ranges: &[Range<Anchor>],
16343        snapshot: &MultiBufferSnapshot,
16344    ) -> bool {
16345        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16346        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16347    }
16348
16349    pub fn toggle_staged_selected_diff_hunks(
16350        &mut self,
16351        _: &::git::ToggleStaged,
16352        _: &mut Window,
16353        cx: &mut Context<Self>,
16354    ) {
16355        let snapshot = self.buffer.read(cx).snapshot(cx);
16356        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16357        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16358        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16359    }
16360
16361    pub fn set_render_diff_hunk_controls(
16362        &mut self,
16363        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16364        cx: &mut Context<Self>,
16365    ) {
16366        self.render_diff_hunk_controls = render_diff_hunk_controls;
16367        cx.notify();
16368    }
16369
16370    pub fn stage_and_next(
16371        &mut self,
16372        _: &::git::StageAndNext,
16373        window: &mut Window,
16374        cx: &mut Context<Self>,
16375    ) {
16376        self.do_stage_or_unstage_and_next(true, window, cx);
16377    }
16378
16379    pub fn unstage_and_next(
16380        &mut self,
16381        _: &::git::UnstageAndNext,
16382        window: &mut Window,
16383        cx: &mut Context<Self>,
16384    ) {
16385        self.do_stage_or_unstage_and_next(false, window, cx);
16386    }
16387
16388    pub fn stage_or_unstage_diff_hunks(
16389        &mut self,
16390        stage: bool,
16391        ranges: Vec<Range<Anchor>>,
16392        cx: &mut Context<Self>,
16393    ) {
16394        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16395        cx.spawn(async move |this, cx| {
16396            task.await?;
16397            this.update(cx, |this, cx| {
16398                let snapshot = this.buffer.read(cx).snapshot(cx);
16399                let chunk_by = this
16400                    .diff_hunks_in_ranges(&ranges, &snapshot)
16401                    .chunk_by(|hunk| hunk.buffer_id);
16402                for (buffer_id, hunks) in &chunk_by {
16403                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16404                }
16405            })
16406        })
16407        .detach_and_log_err(cx);
16408    }
16409
16410    fn save_buffers_for_ranges_if_needed(
16411        &mut self,
16412        ranges: &[Range<Anchor>],
16413        cx: &mut Context<Editor>,
16414    ) -> Task<Result<()>> {
16415        let multibuffer = self.buffer.read(cx);
16416        let snapshot = multibuffer.read(cx);
16417        let buffer_ids: HashSet<_> = ranges
16418            .iter()
16419            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16420            .collect();
16421        drop(snapshot);
16422
16423        let mut buffers = HashSet::default();
16424        for buffer_id in buffer_ids {
16425            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16426                let buffer = buffer_entity.read(cx);
16427                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16428                {
16429                    buffers.insert(buffer_entity);
16430                }
16431            }
16432        }
16433
16434        if let Some(project) = &self.project {
16435            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16436        } else {
16437            Task::ready(Ok(()))
16438        }
16439    }
16440
16441    fn do_stage_or_unstage_and_next(
16442        &mut self,
16443        stage: bool,
16444        window: &mut Window,
16445        cx: &mut Context<Self>,
16446    ) {
16447        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16448
16449        if ranges.iter().any(|range| range.start != range.end) {
16450            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16451            return;
16452        }
16453
16454        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16455        let snapshot = self.snapshot(window, cx);
16456        let position = self.selections.newest::<Point>(cx).head();
16457        let mut row = snapshot
16458            .buffer_snapshot
16459            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16460            .find(|hunk| hunk.row_range.start.0 > position.row)
16461            .map(|hunk| hunk.row_range.start);
16462
16463        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16464        // Outside of the project diff editor, wrap around to the beginning.
16465        if !all_diff_hunks_expanded {
16466            row = row.or_else(|| {
16467                snapshot
16468                    .buffer_snapshot
16469                    .diff_hunks_in_range(Point::zero()..position)
16470                    .find(|hunk| hunk.row_range.end.0 < position.row)
16471                    .map(|hunk| hunk.row_range.start)
16472            });
16473        }
16474
16475        if let Some(row) = row {
16476            let destination = Point::new(row.0, 0);
16477            let autoscroll = Autoscroll::center();
16478
16479            self.unfold_ranges(&[destination..destination], false, false, cx);
16480            self.change_selections(Some(autoscroll), window, cx, |s| {
16481                s.select_ranges([destination..destination]);
16482            });
16483        }
16484    }
16485
16486    fn do_stage_or_unstage(
16487        &self,
16488        stage: bool,
16489        buffer_id: BufferId,
16490        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16491        cx: &mut App,
16492    ) -> Option<()> {
16493        let project = self.project.as_ref()?;
16494        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16495        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16496        let buffer_snapshot = buffer.read(cx).snapshot();
16497        let file_exists = buffer_snapshot
16498            .file()
16499            .is_some_and(|file| file.disk_state().exists());
16500        diff.update(cx, |diff, cx| {
16501            diff.stage_or_unstage_hunks(
16502                stage,
16503                &hunks
16504                    .map(|hunk| buffer_diff::DiffHunk {
16505                        buffer_range: hunk.buffer_range,
16506                        diff_base_byte_range: hunk.diff_base_byte_range,
16507                        secondary_status: hunk.secondary_status,
16508                        range: Point::zero()..Point::zero(), // unused
16509                    })
16510                    .collect::<Vec<_>>(),
16511                &buffer_snapshot,
16512                file_exists,
16513                cx,
16514            )
16515        });
16516        None
16517    }
16518
16519    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16520        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16521        self.buffer
16522            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16523    }
16524
16525    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16526        self.buffer.update(cx, |buffer, cx| {
16527            let ranges = vec![Anchor::min()..Anchor::max()];
16528            if !buffer.all_diff_hunks_expanded()
16529                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16530            {
16531                buffer.collapse_diff_hunks(ranges, cx);
16532                true
16533            } else {
16534                false
16535            }
16536        })
16537    }
16538
16539    fn toggle_diff_hunks_in_ranges(
16540        &mut self,
16541        ranges: Vec<Range<Anchor>>,
16542        cx: &mut Context<Editor>,
16543    ) {
16544        self.buffer.update(cx, |buffer, cx| {
16545            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16546            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16547        })
16548    }
16549
16550    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16551        self.buffer.update(cx, |buffer, cx| {
16552            let snapshot = buffer.snapshot(cx);
16553            let excerpt_id = range.end.excerpt_id;
16554            let point_range = range.to_point(&snapshot);
16555            let expand = !buffer.single_hunk_is_expanded(range, cx);
16556            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16557        })
16558    }
16559
16560    pub(crate) fn apply_all_diff_hunks(
16561        &mut self,
16562        _: &ApplyAllDiffHunks,
16563        window: &mut Window,
16564        cx: &mut Context<Self>,
16565    ) {
16566        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16567
16568        let buffers = self.buffer.read(cx).all_buffers();
16569        for branch_buffer in buffers {
16570            branch_buffer.update(cx, |branch_buffer, cx| {
16571                branch_buffer.merge_into_base(Vec::new(), cx);
16572            });
16573        }
16574
16575        if let Some(project) = self.project.clone() {
16576            self.save(true, project, window, cx).detach_and_log_err(cx);
16577        }
16578    }
16579
16580    pub(crate) fn apply_selected_diff_hunks(
16581        &mut self,
16582        _: &ApplyDiffHunk,
16583        window: &mut Window,
16584        cx: &mut Context<Self>,
16585    ) {
16586        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16587        let snapshot = self.snapshot(window, cx);
16588        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16589        let mut ranges_by_buffer = HashMap::default();
16590        self.transact(window, cx, |editor, _window, cx| {
16591            for hunk in hunks {
16592                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16593                    ranges_by_buffer
16594                        .entry(buffer.clone())
16595                        .or_insert_with(Vec::new)
16596                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16597                }
16598            }
16599
16600            for (buffer, ranges) in ranges_by_buffer {
16601                buffer.update(cx, |buffer, cx| {
16602                    buffer.merge_into_base(ranges, cx);
16603                });
16604            }
16605        });
16606
16607        if let Some(project) = self.project.clone() {
16608            self.save(true, project, window, cx).detach_and_log_err(cx);
16609        }
16610    }
16611
16612    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16613        if hovered != self.gutter_hovered {
16614            self.gutter_hovered = hovered;
16615            cx.notify();
16616        }
16617    }
16618
16619    pub fn insert_blocks(
16620        &mut self,
16621        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16622        autoscroll: Option<Autoscroll>,
16623        cx: &mut Context<Self>,
16624    ) -> Vec<CustomBlockId> {
16625        let blocks = self
16626            .display_map
16627            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16628        if let Some(autoscroll) = autoscroll {
16629            self.request_autoscroll(autoscroll, cx);
16630        }
16631        cx.notify();
16632        blocks
16633    }
16634
16635    pub fn resize_blocks(
16636        &mut self,
16637        heights: HashMap<CustomBlockId, u32>,
16638        autoscroll: Option<Autoscroll>,
16639        cx: &mut Context<Self>,
16640    ) {
16641        self.display_map
16642            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16643        if let Some(autoscroll) = autoscroll {
16644            self.request_autoscroll(autoscroll, cx);
16645        }
16646        cx.notify();
16647    }
16648
16649    pub fn replace_blocks(
16650        &mut self,
16651        renderers: HashMap<CustomBlockId, RenderBlock>,
16652        autoscroll: Option<Autoscroll>,
16653        cx: &mut Context<Self>,
16654    ) {
16655        self.display_map
16656            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16657        if let Some(autoscroll) = autoscroll {
16658            self.request_autoscroll(autoscroll, cx);
16659        }
16660        cx.notify();
16661    }
16662
16663    pub fn remove_blocks(
16664        &mut self,
16665        block_ids: HashSet<CustomBlockId>,
16666        autoscroll: Option<Autoscroll>,
16667        cx: &mut Context<Self>,
16668    ) {
16669        self.display_map.update(cx, |display_map, cx| {
16670            display_map.remove_blocks(block_ids, cx)
16671        });
16672        if let Some(autoscroll) = autoscroll {
16673            self.request_autoscroll(autoscroll, cx);
16674        }
16675        cx.notify();
16676    }
16677
16678    pub fn row_for_block(
16679        &self,
16680        block_id: CustomBlockId,
16681        cx: &mut Context<Self>,
16682    ) -> Option<DisplayRow> {
16683        self.display_map
16684            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16685    }
16686
16687    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16688        self.focused_block = Some(focused_block);
16689    }
16690
16691    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16692        self.focused_block.take()
16693    }
16694
16695    pub fn insert_creases(
16696        &mut self,
16697        creases: impl IntoIterator<Item = Crease<Anchor>>,
16698        cx: &mut Context<Self>,
16699    ) -> Vec<CreaseId> {
16700        self.display_map
16701            .update(cx, |map, cx| map.insert_creases(creases, cx))
16702    }
16703
16704    pub fn remove_creases(
16705        &mut self,
16706        ids: impl IntoIterator<Item = CreaseId>,
16707        cx: &mut Context<Self>,
16708    ) -> Vec<(CreaseId, Range<Anchor>)> {
16709        self.display_map
16710            .update(cx, |map, cx| map.remove_creases(ids, cx))
16711    }
16712
16713    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16714        self.display_map
16715            .update(cx, |map, cx| map.snapshot(cx))
16716            .longest_row()
16717    }
16718
16719    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16720        self.display_map
16721            .update(cx, |map, cx| map.snapshot(cx))
16722            .max_point()
16723    }
16724
16725    pub fn text(&self, cx: &App) -> String {
16726        self.buffer.read(cx).read(cx).text()
16727    }
16728
16729    pub fn is_empty(&self, cx: &App) -> bool {
16730        self.buffer.read(cx).read(cx).is_empty()
16731    }
16732
16733    pub fn text_option(&self, cx: &App) -> Option<String> {
16734        let text = self.text(cx);
16735        let text = text.trim();
16736
16737        if text.is_empty() {
16738            return None;
16739        }
16740
16741        Some(text.to_string())
16742    }
16743
16744    pub fn set_text(
16745        &mut self,
16746        text: impl Into<Arc<str>>,
16747        window: &mut Window,
16748        cx: &mut Context<Self>,
16749    ) {
16750        self.transact(window, cx, |this, _, cx| {
16751            this.buffer
16752                .read(cx)
16753                .as_singleton()
16754                .expect("you can only call set_text on editors for singleton buffers")
16755                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16756        });
16757    }
16758
16759    pub fn display_text(&self, cx: &mut App) -> String {
16760        self.display_map
16761            .update(cx, |map, cx| map.snapshot(cx))
16762            .text()
16763    }
16764
16765    fn create_minimap(
16766        &self,
16767        minimap_settings: MinimapSettings,
16768        window: &mut Window,
16769        cx: &mut Context<Self>,
16770    ) -> Option<Entity<Self>> {
16771        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16772            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16773    }
16774
16775    fn initialize_new_minimap(
16776        &self,
16777        minimap_settings: MinimapSettings,
16778        window: &mut Window,
16779        cx: &mut Context<Self>,
16780    ) -> Entity<Self> {
16781        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16782
16783        let mut minimap = Editor::new_internal(
16784            EditorMode::Minimap {
16785                parent: cx.weak_entity(),
16786            },
16787            self.buffer.clone(),
16788            self.project.clone(),
16789            Some(self.display_map.clone()),
16790            window,
16791            cx,
16792        );
16793        minimap.scroll_manager.clone_state(&self.scroll_manager);
16794        minimap.set_text_style_refinement(TextStyleRefinement {
16795            font_size: Some(MINIMAP_FONT_SIZE),
16796            font_weight: Some(MINIMAP_FONT_WEIGHT),
16797            ..Default::default()
16798        });
16799        minimap.update_minimap_configuration(minimap_settings, cx);
16800        cx.new(|_| minimap)
16801    }
16802
16803    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16804        let current_line_highlight = minimap_settings
16805            .current_line_highlight
16806            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16807        self.set_current_line_highlight(Some(current_line_highlight));
16808    }
16809
16810    pub fn minimap(&self) -> Option<&Entity<Self>> {
16811        self.minimap
16812            .as_ref()
16813            .filter(|_| self.minimap_visibility.visible())
16814    }
16815
16816    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16817        let mut wrap_guides = smallvec![];
16818
16819        if self.show_wrap_guides == Some(false) {
16820            return wrap_guides;
16821        }
16822
16823        let settings = self.buffer.read(cx).language_settings(cx);
16824        if settings.show_wrap_guides {
16825            match self.soft_wrap_mode(cx) {
16826                SoftWrap::Column(soft_wrap) => {
16827                    wrap_guides.push((soft_wrap as usize, true));
16828                }
16829                SoftWrap::Bounded(soft_wrap) => {
16830                    wrap_guides.push((soft_wrap as usize, true));
16831                }
16832                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16833            }
16834            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16835        }
16836
16837        wrap_guides
16838    }
16839
16840    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16841        let settings = self.buffer.read(cx).language_settings(cx);
16842        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16843        match mode {
16844            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16845                SoftWrap::None
16846            }
16847            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16848            language_settings::SoftWrap::PreferredLineLength => {
16849                SoftWrap::Column(settings.preferred_line_length)
16850            }
16851            language_settings::SoftWrap::Bounded => {
16852                SoftWrap::Bounded(settings.preferred_line_length)
16853            }
16854        }
16855    }
16856
16857    pub fn set_soft_wrap_mode(
16858        &mut self,
16859        mode: language_settings::SoftWrap,
16860
16861        cx: &mut Context<Self>,
16862    ) {
16863        self.soft_wrap_mode_override = Some(mode);
16864        cx.notify();
16865    }
16866
16867    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16868        self.hard_wrap = hard_wrap;
16869        cx.notify();
16870    }
16871
16872    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16873        self.text_style_refinement = Some(style);
16874    }
16875
16876    /// called by the Element so we know what style we were most recently rendered with.
16877    pub(crate) fn set_style(
16878        &mut self,
16879        style: EditorStyle,
16880        window: &mut Window,
16881        cx: &mut Context<Self>,
16882    ) {
16883        // We intentionally do not inform the display map about the minimap style
16884        // so that wrapping is not recalculated and stays consistent for the editor
16885        // and its linked minimap.
16886        if !self.mode.is_minimap() {
16887            let rem_size = window.rem_size();
16888            self.display_map.update(cx, |map, cx| {
16889                map.set_font(
16890                    style.text.font(),
16891                    style.text.font_size.to_pixels(rem_size),
16892                    cx,
16893                )
16894            });
16895        }
16896        self.style = Some(style);
16897    }
16898
16899    pub fn style(&self) -> Option<&EditorStyle> {
16900        self.style.as_ref()
16901    }
16902
16903    // Called by the element. This method is not designed to be called outside of the editor
16904    // element's layout code because it does not notify when rewrapping is computed synchronously.
16905    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16906        self.display_map
16907            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16908    }
16909
16910    pub fn set_soft_wrap(&mut self) {
16911        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16912    }
16913
16914    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16915        if self.soft_wrap_mode_override.is_some() {
16916            self.soft_wrap_mode_override.take();
16917        } else {
16918            let soft_wrap = match self.soft_wrap_mode(cx) {
16919                SoftWrap::GitDiff => return,
16920                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16921                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16922                    language_settings::SoftWrap::None
16923                }
16924            };
16925            self.soft_wrap_mode_override = Some(soft_wrap);
16926        }
16927        cx.notify();
16928    }
16929
16930    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16931        let Some(workspace) = self.workspace() else {
16932            return;
16933        };
16934        let fs = workspace.read(cx).app_state().fs.clone();
16935        let current_show = TabBarSettings::get_global(cx).show;
16936        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16937            setting.show = Some(!current_show);
16938        });
16939    }
16940
16941    pub fn toggle_indent_guides(
16942        &mut self,
16943        _: &ToggleIndentGuides,
16944        _: &mut Window,
16945        cx: &mut Context<Self>,
16946    ) {
16947        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16948            self.buffer
16949                .read(cx)
16950                .language_settings(cx)
16951                .indent_guides
16952                .enabled
16953        });
16954        self.show_indent_guides = Some(!currently_enabled);
16955        cx.notify();
16956    }
16957
16958    fn should_show_indent_guides(&self) -> Option<bool> {
16959        self.show_indent_guides
16960    }
16961
16962    pub fn toggle_line_numbers(
16963        &mut self,
16964        _: &ToggleLineNumbers,
16965        _: &mut Window,
16966        cx: &mut Context<Self>,
16967    ) {
16968        let mut editor_settings = EditorSettings::get_global(cx).clone();
16969        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16970        EditorSettings::override_global(editor_settings, cx);
16971    }
16972
16973    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16974        if let Some(show_line_numbers) = self.show_line_numbers {
16975            return show_line_numbers;
16976        }
16977        EditorSettings::get_global(cx).gutter.line_numbers
16978    }
16979
16980    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16981        self.use_relative_line_numbers
16982            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16983    }
16984
16985    pub fn toggle_relative_line_numbers(
16986        &mut self,
16987        _: &ToggleRelativeLineNumbers,
16988        _: &mut Window,
16989        cx: &mut Context<Self>,
16990    ) {
16991        let is_relative = self.should_use_relative_line_numbers(cx);
16992        self.set_relative_line_number(Some(!is_relative), cx)
16993    }
16994
16995    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16996        self.use_relative_line_numbers = is_relative;
16997        cx.notify();
16998    }
16999
17000    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17001        self.show_gutter = show_gutter;
17002        cx.notify();
17003    }
17004
17005    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17006        self.show_scrollbars = ScrollbarAxes {
17007            horizontal: show,
17008            vertical: show,
17009        };
17010        cx.notify();
17011    }
17012
17013    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17014        self.show_scrollbars.vertical = show;
17015        cx.notify();
17016    }
17017
17018    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17019        self.show_scrollbars.horizontal = show;
17020        cx.notify();
17021    }
17022
17023    pub fn set_minimap_visibility(
17024        &mut self,
17025        minimap_visibility: MinimapVisibility,
17026        window: &mut Window,
17027        cx: &mut Context<Self>,
17028    ) {
17029        if self.minimap_visibility != minimap_visibility {
17030            if minimap_visibility.visible() && self.minimap.is_none() {
17031                let minimap_settings = EditorSettings::get_global(cx).minimap;
17032                self.minimap =
17033                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17034            }
17035            self.minimap_visibility = minimap_visibility;
17036            cx.notify();
17037        }
17038    }
17039
17040    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17041        self.set_show_scrollbars(false, cx);
17042        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17043    }
17044
17045    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17046        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17047    }
17048
17049    /// Normally the text in full mode and auto height editors is padded on the
17050    /// left side by roughly half a character width for improved hit testing.
17051    ///
17052    /// Use this method to disable this for cases where this is not wanted (e.g.
17053    /// if you want to align the editor text with some other text above or below)
17054    /// or if you want to add this padding to single-line editors.
17055    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17056        self.offset_content = offset_content;
17057        cx.notify();
17058    }
17059
17060    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17061        self.show_line_numbers = Some(show_line_numbers);
17062        cx.notify();
17063    }
17064
17065    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17066        self.disable_expand_excerpt_buttons = true;
17067        cx.notify();
17068    }
17069
17070    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17071        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17072        cx.notify();
17073    }
17074
17075    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17076        self.show_code_actions = Some(show_code_actions);
17077        cx.notify();
17078    }
17079
17080    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17081        self.show_runnables = Some(show_runnables);
17082        cx.notify();
17083    }
17084
17085    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17086        self.show_breakpoints = Some(show_breakpoints);
17087        cx.notify();
17088    }
17089
17090    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17091        if self.display_map.read(cx).masked != masked {
17092            self.display_map.update(cx, |map, _| map.masked = masked);
17093        }
17094        cx.notify()
17095    }
17096
17097    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17098        self.show_wrap_guides = Some(show_wrap_guides);
17099        cx.notify();
17100    }
17101
17102    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17103        self.show_indent_guides = Some(show_indent_guides);
17104        cx.notify();
17105    }
17106
17107    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17108        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17109            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17110                if let Some(dir) = file.abs_path(cx).parent() {
17111                    return Some(dir.to_owned());
17112                }
17113            }
17114
17115            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17116                return Some(project_path.path.to_path_buf());
17117            }
17118        }
17119
17120        None
17121    }
17122
17123    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17124        self.active_excerpt(cx)?
17125            .1
17126            .read(cx)
17127            .file()
17128            .and_then(|f| f.as_local())
17129    }
17130
17131    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17132        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17133            let buffer = buffer.read(cx);
17134            if let Some(project_path) = buffer.project_path(cx) {
17135                let project = self.project.as_ref()?.read(cx);
17136                project.absolute_path(&project_path, cx)
17137            } else {
17138                buffer
17139                    .file()
17140                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17141            }
17142        })
17143    }
17144
17145    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17146        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17147            let project_path = buffer.read(cx).project_path(cx)?;
17148            let project = self.project.as_ref()?.read(cx);
17149            let entry = project.entry_for_path(&project_path, cx)?;
17150            let path = entry.path.to_path_buf();
17151            Some(path)
17152        })
17153    }
17154
17155    pub fn reveal_in_finder(
17156        &mut self,
17157        _: &RevealInFileManager,
17158        _window: &mut Window,
17159        cx: &mut Context<Self>,
17160    ) {
17161        if let Some(target) = self.target_file(cx) {
17162            cx.reveal_path(&target.abs_path(cx));
17163        }
17164    }
17165
17166    pub fn copy_path(
17167        &mut self,
17168        _: &zed_actions::workspace::CopyPath,
17169        _window: &mut Window,
17170        cx: &mut Context<Self>,
17171    ) {
17172        if let Some(path) = self.target_file_abs_path(cx) {
17173            if let Some(path) = path.to_str() {
17174                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17175            }
17176        }
17177    }
17178
17179    pub fn copy_relative_path(
17180        &mut self,
17181        _: &zed_actions::workspace::CopyRelativePath,
17182        _window: &mut Window,
17183        cx: &mut Context<Self>,
17184    ) {
17185        if let Some(path) = self.target_file_path(cx) {
17186            if let Some(path) = path.to_str() {
17187                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17188            }
17189        }
17190    }
17191
17192    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17193        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17194            buffer.read(cx).project_path(cx)
17195        } else {
17196            None
17197        }
17198    }
17199
17200    // Returns true if the editor handled a go-to-line request
17201    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17202        maybe!({
17203            let breakpoint_store = self.breakpoint_store.as_ref()?;
17204
17205            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17206            else {
17207                self.clear_row_highlights::<ActiveDebugLine>();
17208                return None;
17209            };
17210
17211            let position = active_stack_frame.position;
17212            let buffer_id = position.buffer_id?;
17213            let snapshot = self
17214                .project
17215                .as_ref()?
17216                .read(cx)
17217                .buffer_for_id(buffer_id, cx)?
17218                .read(cx)
17219                .snapshot();
17220
17221            let mut handled = false;
17222            for (id, ExcerptRange { context, .. }) in
17223                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17224            {
17225                if context.start.cmp(&position, &snapshot).is_ge()
17226                    || context.end.cmp(&position, &snapshot).is_lt()
17227                {
17228                    continue;
17229                }
17230                let snapshot = self.buffer.read(cx).snapshot(cx);
17231                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17232
17233                handled = true;
17234                self.clear_row_highlights::<ActiveDebugLine>();
17235
17236                self.go_to_line::<ActiveDebugLine>(
17237                    multibuffer_anchor,
17238                    Some(cx.theme().colors().editor_debugger_active_line_background),
17239                    window,
17240                    cx,
17241                );
17242
17243                cx.notify();
17244            }
17245
17246            handled.then_some(())
17247        })
17248        .is_some()
17249    }
17250
17251    pub fn copy_file_name_without_extension(
17252        &mut self,
17253        _: &CopyFileNameWithoutExtension,
17254        _: &mut Window,
17255        cx: &mut Context<Self>,
17256    ) {
17257        if let Some(file) = self.target_file(cx) {
17258            if let Some(file_stem) = file.path().file_stem() {
17259                if let Some(name) = file_stem.to_str() {
17260                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17261                }
17262            }
17263        }
17264    }
17265
17266    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17267        if let Some(file) = self.target_file(cx) {
17268            if let Some(file_name) = file.path().file_name() {
17269                if let Some(name) = file_name.to_str() {
17270                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17271                }
17272            }
17273        }
17274    }
17275
17276    pub fn toggle_git_blame(
17277        &mut self,
17278        _: &::git::Blame,
17279        window: &mut Window,
17280        cx: &mut Context<Self>,
17281    ) {
17282        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17283
17284        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17285            self.start_git_blame(true, window, cx);
17286        }
17287
17288        cx.notify();
17289    }
17290
17291    pub fn toggle_git_blame_inline(
17292        &mut self,
17293        _: &ToggleGitBlameInline,
17294        window: &mut Window,
17295        cx: &mut Context<Self>,
17296    ) {
17297        self.toggle_git_blame_inline_internal(true, window, cx);
17298        cx.notify();
17299    }
17300
17301    pub fn open_git_blame_commit(
17302        &mut self,
17303        _: &OpenGitBlameCommit,
17304        window: &mut Window,
17305        cx: &mut Context<Self>,
17306    ) {
17307        self.open_git_blame_commit_internal(window, cx);
17308    }
17309
17310    fn open_git_blame_commit_internal(
17311        &mut self,
17312        window: &mut Window,
17313        cx: &mut Context<Self>,
17314    ) -> Option<()> {
17315        let blame = self.blame.as_ref()?;
17316        let snapshot = self.snapshot(window, cx);
17317        let cursor = self.selections.newest::<Point>(cx).head();
17318        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17319        let blame_entry = blame
17320            .update(cx, |blame, cx| {
17321                blame
17322                    .blame_for_rows(
17323                        &[RowInfo {
17324                            buffer_id: Some(buffer.remote_id()),
17325                            buffer_row: Some(point.row),
17326                            ..Default::default()
17327                        }],
17328                        cx,
17329                    )
17330                    .next()
17331            })
17332            .flatten()?;
17333        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17334        let repo = blame.read(cx).repository(cx)?;
17335        let workspace = self.workspace()?.downgrade();
17336        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17337        None
17338    }
17339
17340    pub fn git_blame_inline_enabled(&self) -> bool {
17341        self.git_blame_inline_enabled
17342    }
17343
17344    pub fn toggle_selection_menu(
17345        &mut self,
17346        _: &ToggleSelectionMenu,
17347        _: &mut Window,
17348        cx: &mut Context<Self>,
17349    ) {
17350        self.show_selection_menu = self
17351            .show_selection_menu
17352            .map(|show_selections_menu| !show_selections_menu)
17353            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17354
17355        cx.notify();
17356    }
17357
17358    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17359        self.show_selection_menu
17360            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17361    }
17362
17363    fn start_git_blame(
17364        &mut self,
17365        user_triggered: bool,
17366        window: &mut Window,
17367        cx: &mut Context<Self>,
17368    ) {
17369        if let Some(project) = self.project.as_ref() {
17370            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17371                return;
17372            };
17373
17374            if buffer.read(cx).file().is_none() {
17375                return;
17376            }
17377
17378            let focused = self.focus_handle(cx).contains_focused(window, cx);
17379
17380            let project = project.clone();
17381            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17382            self.blame_subscription =
17383                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17384            self.blame = Some(blame);
17385        }
17386    }
17387
17388    fn toggle_git_blame_inline_internal(
17389        &mut self,
17390        user_triggered: bool,
17391        window: &mut Window,
17392        cx: &mut Context<Self>,
17393    ) {
17394        if self.git_blame_inline_enabled {
17395            self.git_blame_inline_enabled = false;
17396            self.show_git_blame_inline = false;
17397            self.show_git_blame_inline_delay_task.take();
17398        } else {
17399            self.git_blame_inline_enabled = true;
17400            self.start_git_blame_inline(user_triggered, window, cx);
17401        }
17402
17403        cx.notify();
17404    }
17405
17406    fn start_git_blame_inline(
17407        &mut self,
17408        user_triggered: bool,
17409        window: &mut Window,
17410        cx: &mut Context<Self>,
17411    ) {
17412        self.start_git_blame(user_triggered, window, cx);
17413
17414        if ProjectSettings::get_global(cx)
17415            .git
17416            .inline_blame_delay()
17417            .is_some()
17418        {
17419            self.start_inline_blame_timer(window, cx);
17420        } else {
17421            self.show_git_blame_inline = true
17422        }
17423    }
17424
17425    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17426        self.blame.as_ref()
17427    }
17428
17429    pub fn show_git_blame_gutter(&self) -> bool {
17430        self.show_git_blame_gutter
17431    }
17432
17433    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17434        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17435    }
17436
17437    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17438        self.show_git_blame_inline
17439            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17440            && !self.newest_selection_head_on_empty_line(cx)
17441            && self.has_blame_entries(cx)
17442    }
17443
17444    fn has_blame_entries(&self, cx: &App) -> bool {
17445        self.blame()
17446            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17447    }
17448
17449    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17450        let cursor_anchor = self.selections.newest_anchor().head();
17451
17452        let snapshot = self.buffer.read(cx).snapshot(cx);
17453        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17454
17455        snapshot.line_len(buffer_row) == 0
17456    }
17457
17458    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17459        let buffer_and_selection = maybe!({
17460            let selection = self.selections.newest::<Point>(cx);
17461            let selection_range = selection.range();
17462
17463            let multi_buffer = self.buffer().read(cx);
17464            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17465            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17466
17467            let (buffer, range, _) = if selection.reversed {
17468                buffer_ranges.first()
17469            } else {
17470                buffer_ranges.last()
17471            }?;
17472
17473            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17474                ..text::ToPoint::to_point(&range.end, &buffer).row;
17475            Some((
17476                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17477                selection,
17478            ))
17479        });
17480
17481        let Some((buffer, selection)) = buffer_and_selection else {
17482            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17483        };
17484
17485        let Some(project) = self.project.as_ref() else {
17486            return Task::ready(Err(anyhow!("editor does not have project")));
17487        };
17488
17489        project.update(cx, |project, cx| {
17490            project.get_permalink_to_line(&buffer, selection, cx)
17491        })
17492    }
17493
17494    pub fn copy_permalink_to_line(
17495        &mut self,
17496        _: &CopyPermalinkToLine,
17497        window: &mut Window,
17498        cx: &mut Context<Self>,
17499    ) {
17500        let permalink_task = self.get_permalink_to_line(cx);
17501        let workspace = self.workspace();
17502
17503        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17504            Ok(permalink) => {
17505                cx.update(|_, cx| {
17506                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17507                })
17508                .ok();
17509            }
17510            Err(err) => {
17511                let message = format!("Failed to copy permalink: {err}");
17512
17513                anyhow::Result::<()>::Err(err).log_err();
17514
17515                if let Some(workspace) = workspace {
17516                    workspace
17517                        .update_in(cx, |workspace, _, cx| {
17518                            struct CopyPermalinkToLine;
17519
17520                            workspace.show_toast(
17521                                Toast::new(
17522                                    NotificationId::unique::<CopyPermalinkToLine>(),
17523                                    message,
17524                                ),
17525                                cx,
17526                            )
17527                        })
17528                        .ok();
17529                }
17530            }
17531        })
17532        .detach();
17533    }
17534
17535    pub fn copy_file_location(
17536        &mut self,
17537        _: &CopyFileLocation,
17538        _: &mut Window,
17539        cx: &mut Context<Self>,
17540    ) {
17541        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17542        if let Some(file) = self.target_file(cx) {
17543            if let Some(path) = file.path().to_str() {
17544                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17545            }
17546        }
17547    }
17548
17549    pub fn open_permalink_to_line(
17550        &mut self,
17551        _: &OpenPermalinkToLine,
17552        window: &mut Window,
17553        cx: &mut Context<Self>,
17554    ) {
17555        let permalink_task = self.get_permalink_to_line(cx);
17556        let workspace = self.workspace();
17557
17558        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17559            Ok(permalink) => {
17560                cx.update(|_, cx| {
17561                    cx.open_url(permalink.as_ref());
17562                })
17563                .ok();
17564            }
17565            Err(err) => {
17566                let message = format!("Failed to open permalink: {err}");
17567
17568                anyhow::Result::<()>::Err(err).log_err();
17569
17570                if let Some(workspace) = workspace {
17571                    workspace
17572                        .update(cx, |workspace, cx| {
17573                            struct OpenPermalinkToLine;
17574
17575                            workspace.show_toast(
17576                                Toast::new(
17577                                    NotificationId::unique::<OpenPermalinkToLine>(),
17578                                    message,
17579                                ),
17580                                cx,
17581                            )
17582                        })
17583                        .ok();
17584                }
17585            }
17586        })
17587        .detach();
17588    }
17589
17590    pub fn insert_uuid_v4(
17591        &mut self,
17592        _: &InsertUuidV4,
17593        window: &mut Window,
17594        cx: &mut Context<Self>,
17595    ) {
17596        self.insert_uuid(UuidVersion::V4, window, cx);
17597    }
17598
17599    pub fn insert_uuid_v7(
17600        &mut self,
17601        _: &InsertUuidV7,
17602        window: &mut Window,
17603        cx: &mut Context<Self>,
17604    ) {
17605        self.insert_uuid(UuidVersion::V7, window, cx);
17606    }
17607
17608    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17609        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17610        self.transact(window, cx, |this, window, cx| {
17611            let edits = this
17612                .selections
17613                .all::<Point>(cx)
17614                .into_iter()
17615                .map(|selection| {
17616                    let uuid = match version {
17617                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17618                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17619                    };
17620
17621                    (selection.range(), uuid.to_string())
17622                });
17623            this.edit(edits, cx);
17624            this.refresh_inline_completion(true, false, window, cx);
17625        });
17626    }
17627
17628    pub fn open_selections_in_multibuffer(
17629        &mut self,
17630        _: &OpenSelectionsInMultibuffer,
17631        window: &mut Window,
17632        cx: &mut Context<Self>,
17633    ) {
17634        let multibuffer = self.buffer.read(cx);
17635
17636        let Some(buffer) = multibuffer.as_singleton() else {
17637            return;
17638        };
17639
17640        let Some(workspace) = self.workspace() else {
17641            return;
17642        };
17643
17644        let locations = self
17645            .selections
17646            .disjoint_anchors()
17647            .iter()
17648            .map(|selection| {
17649                let range = if selection.reversed {
17650                    selection.end.text_anchor..selection.start.text_anchor
17651                } else {
17652                    selection.start.text_anchor..selection.end.text_anchor
17653                };
17654                Location {
17655                    buffer: buffer.clone(),
17656                    range,
17657                }
17658            })
17659            .collect::<Vec<_>>();
17660
17661        let title = multibuffer.title(cx).to_string();
17662
17663        cx.spawn_in(window, async move |_, cx| {
17664            workspace.update_in(cx, |workspace, window, cx| {
17665                Self::open_locations_in_multibuffer(
17666                    workspace,
17667                    locations,
17668                    format!("Selections for '{title}'"),
17669                    false,
17670                    MultibufferSelectionMode::All,
17671                    window,
17672                    cx,
17673                );
17674            })
17675        })
17676        .detach();
17677    }
17678
17679    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17680    /// last highlight added will be used.
17681    ///
17682    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17683    pub fn highlight_rows<T: 'static>(
17684        &mut self,
17685        range: Range<Anchor>,
17686        color: Hsla,
17687        options: RowHighlightOptions,
17688        cx: &mut Context<Self>,
17689    ) {
17690        let snapshot = self.buffer().read(cx).snapshot(cx);
17691        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17692        let ix = row_highlights.binary_search_by(|highlight| {
17693            Ordering::Equal
17694                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17695                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17696        });
17697
17698        if let Err(mut ix) = ix {
17699            let index = post_inc(&mut self.highlight_order);
17700
17701            // If this range intersects with the preceding highlight, then merge it with
17702            // the preceding highlight. Otherwise insert a new highlight.
17703            let mut merged = false;
17704            if ix > 0 {
17705                let prev_highlight = &mut row_highlights[ix - 1];
17706                if prev_highlight
17707                    .range
17708                    .end
17709                    .cmp(&range.start, &snapshot)
17710                    .is_ge()
17711                {
17712                    ix -= 1;
17713                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17714                        prev_highlight.range.end = range.end;
17715                    }
17716                    merged = true;
17717                    prev_highlight.index = index;
17718                    prev_highlight.color = color;
17719                    prev_highlight.options = options;
17720                }
17721            }
17722
17723            if !merged {
17724                row_highlights.insert(
17725                    ix,
17726                    RowHighlight {
17727                        range: range.clone(),
17728                        index,
17729                        color,
17730                        options,
17731                        type_id: TypeId::of::<T>(),
17732                    },
17733                );
17734            }
17735
17736            // If any of the following highlights intersect with this one, merge them.
17737            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17738                let highlight = &row_highlights[ix];
17739                if next_highlight
17740                    .range
17741                    .start
17742                    .cmp(&highlight.range.end, &snapshot)
17743                    .is_le()
17744                {
17745                    if next_highlight
17746                        .range
17747                        .end
17748                        .cmp(&highlight.range.end, &snapshot)
17749                        .is_gt()
17750                    {
17751                        row_highlights[ix].range.end = next_highlight.range.end;
17752                    }
17753                    row_highlights.remove(ix + 1);
17754                } else {
17755                    break;
17756                }
17757            }
17758        }
17759    }
17760
17761    /// Remove any highlighted row ranges of the given type that intersect the
17762    /// given ranges.
17763    pub fn remove_highlighted_rows<T: 'static>(
17764        &mut self,
17765        ranges_to_remove: Vec<Range<Anchor>>,
17766        cx: &mut Context<Self>,
17767    ) {
17768        let snapshot = self.buffer().read(cx).snapshot(cx);
17769        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17770        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17771        row_highlights.retain(|highlight| {
17772            while let Some(range_to_remove) = ranges_to_remove.peek() {
17773                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17774                    Ordering::Less | Ordering::Equal => {
17775                        ranges_to_remove.next();
17776                    }
17777                    Ordering::Greater => {
17778                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17779                            Ordering::Less | Ordering::Equal => {
17780                                return false;
17781                            }
17782                            Ordering::Greater => break,
17783                        }
17784                    }
17785                }
17786            }
17787
17788            true
17789        })
17790    }
17791
17792    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17793    pub fn clear_row_highlights<T: 'static>(&mut self) {
17794        self.highlighted_rows.remove(&TypeId::of::<T>());
17795    }
17796
17797    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17798    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17799        self.highlighted_rows
17800            .get(&TypeId::of::<T>())
17801            .map_or(&[] as &[_], |vec| vec.as_slice())
17802            .iter()
17803            .map(|highlight| (highlight.range.clone(), highlight.color))
17804    }
17805
17806    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17807    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17808    /// Allows to ignore certain kinds of highlights.
17809    pub fn highlighted_display_rows(
17810        &self,
17811        window: &mut Window,
17812        cx: &mut App,
17813    ) -> BTreeMap<DisplayRow, LineHighlight> {
17814        let snapshot = self.snapshot(window, cx);
17815        let mut used_highlight_orders = HashMap::default();
17816        self.highlighted_rows
17817            .iter()
17818            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17819            .fold(
17820                BTreeMap::<DisplayRow, LineHighlight>::new(),
17821                |mut unique_rows, highlight| {
17822                    let start = highlight.range.start.to_display_point(&snapshot);
17823                    let end = highlight.range.end.to_display_point(&snapshot);
17824                    let start_row = start.row().0;
17825                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17826                        && end.column() == 0
17827                    {
17828                        end.row().0.saturating_sub(1)
17829                    } else {
17830                        end.row().0
17831                    };
17832                    for row in start_row..=end_row {
17833                        let used_index =
17834                            used_highlight_orders.entry(row).or_insert(highlight.index);
17835                        if highlight.index >= *used_index {
17836                            *used_index = highlight.index;
17837                            unique_rows.insert(
17838                                DisplayRow(row),
17839                                LineHighlight {
17840                                    include_gutter: highlight.options.include_gutter,
17841                                    border: None,
17842                                    background: highlight.color.into(),
17843                                    type_id: Some(highlight.type_id),
17844                                },
17845                            );
17846                        }
17847                    }
17848                    unique_rows
17849                },
17850            )
17851    }
17852
17853    pub fn highlighted_display_row_for_autoscroll(
17854        &self,
17855        snapshot: &DisplaySnapshot,
17856    ) -> Option<DisplayRow> {
17857        self.highlighted_rows
17858            .values()
17859            .flat_map(|highlighted_rows| highlighted_rows.iter())
17860            .filter_map(|highlight| {
17861                if highlight.options.autoscroll {
17862                    Some(highlight.range.start.to_display_point(snapshot).row())
17863                } else {
17864                    None
17865                }
17866            })
17867            .min()
17868    }
17869
17870    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17871        self.highlight_background::<SearchWithinRange>(
17872            ranges,
17873            |colors| colors.editor_document_highlight_read_background,
17874            cx,
17875        )
17876    }
17877
17878    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17879        self.breadcrumb_header = Some(new_header);
17880    }
17881
17882    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17883        self.clear_background_highlights::<SearchWithinRange>(cx);
17884    }
17885
17886    pub fn highlight_background<T: 'static>(
17887        &mut self,
17888        ranges: &[Range<Anchor>],
17889        color_fetcher: fn(&ThemeColors) -> Hsla,
17890        cx: &mut Context<Self>,
17891    ) {
17892        self.background_highlights
17893            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17894        self.scrollbar_marker_state.dirty = true;
17895        cx.notify();
17896    }
17897
17898    pub fn clear_background_highlights<T: 'static>(
17899        &mut self,
17900        cx: &mut Context<Self>,
17901    ) -> Option<BackgroundHighlight> {
17902        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17903        if !text_highlights.1.is_empty() {
17904            self.scrollbar_marker_state.dirty = true;
17905            cx.notify();
17906        }
17907        Some(text_highlights)
17908    }
17909
17910    pub fn highlight_gutter<T: 'static>(
17911        &mut self,
17912        ranges: &[Range<Anchor>],
17913        color_fetcher: fn(&App) -> Hsla,
17914        cx: &mut Context<Self>,
17915    ) {
17916        self.gutter_highlights
17917            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17918        cx.notify();
17919    }
17920
17921    pub fn clear_gutter_highlights<T: 'static>(
17922        &mut self,
17923        cx: &mut Context<Self>,
17924    ) -> Option<GutterHighlight> {
17925        cx.notify();
17926        self.gutter_highlights.remove(&TypeId::of::<T>())
17927    }
17928
17929    #[cfg(feature = "test-support")]
17930    pub fn all_text_background_highlights(
17931        &self,
17932        window: &mut Window,
17933        cx: &mut Context<Self>,
17934    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17935        let snapshot = self.snapshot(window, cx);
17936        let buffer = &snapshot.buffer_snapshot;
17937        let start = buffer.anchor_before(0);
17938        let end = buffer.anchor_after(buffer.len());
17939        let theme = cx.theme().colors();
17940        self.background_highlights_in_range(start..end, &snapshot, theme)
17941    }
17942
17943    #[cfg(feature = "test-support")]
17944    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17945        let snapshot = self.buffer().read(cx).snapshot(cx);
17946
17947        let highlights = self
17948            .background_highlights
17949            .get(&TypeId::of::<items::BufferSearchHighlights>());
17950
17951        if let Some((_color, ranges)) = highlights {
17952            ranges
17953                .iter()
17954                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17955                .collect_vec()
17956        } else {
17957            vec![]
17958        }
17959    }
17960
17961    fn document_highlights_for_position<'a>(
17962        &'a self,
17963        position: Anchor,
17964        buffer: &'a MultiBufferSnapshot,
17965    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17966        let read_highlights = self
17967            .background_highlights
17968            .get(&TypeId::of::<DocumentHighlightRead>())
17969            .map(|h| &h.1);
17970        let write_highlights = self
17971            .background_highlights
17972            .get(&TypeId::of::<DocumentHighlightWrite>())
17973            .map(|h| &h.1);
17974        let left_position = position.bias_left(buffer);
17975        let right_position = position.bias_right(buffer);
17976        read_highlights
17977            .into_iter()
17978            .chain(write_highlights)
17979            .flat_map(move |ranges| {
17980                let start_ix = match ranges.binary_search_by(|probe| {
17981                    let cmp = probe.end.cmp(&left_position, buffer);
17982                    if cmp.is_ge() {
17983                        Ordering::Greater
17984                    } else {
17985                        Ordering::Less
17986                    }
17987                }) {
17988                    Ok(i) | Err(i) => i,
17989                };
17990
17991                ranges[start_ix..]
17992                    .iter()
17993                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17994            })
17995    }
17996
17997    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17998        self.background_highlights
17999            .get(&TypeId::of::<T>())
18000            .map_or(false, |(_, highlights)| !highlights.is_empty())
18001    }
18002
18003    pub fn background_highlights_in_range(
18004        &self,
18005        search_range: Range<Anchor>,
18006        display_snapshot: &DisplaySnapshot,
18007        theme: &ThemeColors,
18008    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18009        let mut results = Vec::new();
18010        for (color_fetcher, ranges) in self.background_highlights.values() {
18011            let color = color_fetcher(theme);
18012            let start_ix = match ranges.binary_search_by(|probe| {
18013                let cmp = probe
18014                    .end
18015                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18016                if cmp.is_gt() {
18017                    Ordering::Greater
18018                } else {
18019                    Ordering::Less
18020                }
18021            }) {
18022                Ok(i) | Err(i) => i,
18023            };
18024            for range in &ranges[start_ix..] {
18025                if range
18026                    .start
18027                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18028                    .is_ge()
18029                {
18030                    break;
18031                }
18032
18033                let start = range.start.to_display_point(display_snapshot);
18034                let end = range.end.to_display_point(display_snapshot);
18035                results.push((start..end, color))
18036            }
18037        }
18038        results
18039    }
18040
18041    pub fn background_highlight_row_ranges<T: 'static>(
18042        &self,
18043        search_range: Range<Anchor>,
18044        display_snapshot: &DisplaySnapshot,
18045        count: usize,
18046    ) -> Vec<RangeInclusive<DisplayPoint>> {
18047        let mut results = Vec::new();
18048        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18049            return vec![];
18050        };
18051
18052        let start_ix = match ranges.binary_search_by(|probe| {
18053            let cmp = probe
18054                .end
18055                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18056            if cmp.is_gt() {
18057                Ordering::Greater
18058            } else {
18059                Ordering::Less
18060            }
18061        }) {
18062            Ok(i) | Err(i) => i,
18063        };
18064        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18065            if let (Some(start_display), Some(end_display)) = (start, end) {
18066                results.push(
18067                    start_display.to_display_point(display_snapshot)
18068                        ..=end_display.to_display_point(display_snapshot),
18069                );
18070            }
18071        };
18072        let mut start_row: Option<Point> = None;
18073        let mut end_row: Option<Point> = None;
18074        if ranges.len() > count {
18075            return Vec::new();
18076        }
18077        for range in &ranges[start_ix..] {
18078            if range
18079                .start
18080                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18081                .is_ge()
18082            {
18083                break;
18084            }
18085            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18086            if let Some(current_row) = &end_row {
18087                if end.row == current_row.row {
18088                    continue;
18089                }
18090            }
18091            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18092            if start_row.is_none() {
18093                assert_eq!(end_row, None);
18094                start_row = Some(start);
18095                end_row = Some(end);
18096                continue;
18097            }
18098            if let Some(current_end) = end_row.as_mut() {
18099                if start.row > current_end.row + 1 {
18100                    push_region(start_row, end_row);
18101                    start_row = Some(start);
18102                    end_row = Some(end);
18103                } else {
18104                    // Merge two hunks.
18105                    *current_end = end;
18106                }
18107            } else {
18108                unreachable!();
18109            }
18110        }
18111        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18112        push_region(start_row, end_row);
18113        results
18114    }
18115
18116    pub fn gutter_highlights_in_range(
18117        &self,
18118        search_range: Range<Anchor>,
18119        display_snapshot: &DisplaySnapshot,
18120        cx: &App,
18121    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18122        let mut results = Vec::new();
18123        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18124            let color = color_fetcher(cx);
18125            let start_ix = match ranges.binary_search_by(|probe| {
18126                let cmp = probe
18127                    .end
18128                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18129                if cmp.is_gt() {
18130                    Ordering::Greater
18131                } else {
18132                    Ordering::Less
18133                }
18134            }) {
18135                Ok(i) | Err(i) => i,
18136            };
18137            for range in &ranges[start_ix..] {
18138                if range
18139                    .start
18140                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18141                    .is_ge()
18142                {
18143                    break;
18144                }
18145
18146                let start = range.start.to_display_point(display_snapshot);
18147                let end = range.end.to_display_point(display_snapshot);
18148                results.push((start..end, color))
18149            }
18150        }
18151        results
18152    }
18153
18154    /// Get the text ranges corresponding to the redaction query
18155    pub fn redacted_ranges(
18156        &self,
18157        search_range: Range<Anchor>,
18158        display_snapshot: &DisplaySnapshot,
18159        cx: &App,
18160    ) -> Vec<Range<DisplayPoint>> {
18161        display_snapshot
18162            .buffer_snapshot
18163            .redacted_ranges(search_range, |file| {
18164                if let Some(file) = file {
18165                    file.is_private()
18166                        && EditorSettings::get(
18167                            Some(SettingsLocation {
18168                                worktree_id: file.worktree_id(cx),
18169                                path: file.path().as_ref(),
18170                            }),
18171                            cx,
18172                        )
18173                        .redact_private_values
18174                } else {
18175                    false
18176                }
18177            })
18178            .map(|range| {
18179                range.start.to_display_point(display_snapshot)
18180                    ..range.end.to_display_point(display_snapshot)
18181            })
18182            .collect()
18183    }
18184
18185    pub fn highlight_text<T: 'static>(
18186        &mut self,
18187        ranges: Vec<Range<Anchor>>,
18188        style: HighlightStyle,
18189        cx: &mut Context<Self>,
18190    ) {
18191        self.display_map.update(cx, |map, _| {
18192            map.highlight_text(TypeId::of::<T>(), ranges, style)
18193        });
18194        cx.notify();
18195    }
18196
18197    pub(crate) fn highlight_inlays<T: 'static>(
18198        &mut self,
18199        highlights: Vec<InlayHighlight>,
18200        style: HighlightStyle,
18201        cx: &mut Context<Self>,
18202    ) {
18203        self.display_map.update(cx, |map, _| {
18204            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18205        });
18206        cx.notify();
18207    }
18208
18209    pub fn text_highlights<'a, T: 'static>(
18210        &'a self,
18211        cx: &'a App,
18212    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18213        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18214    }
18215
18216    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18217        let cleared = self
18218            .display_map
18219            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18220        if cleared {
18221            cx.notify();
18222        }
18223    }
18224
18225    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18226        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18227            && self.focus_handle.is_focused(window)
18228    }
18229
18230    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18231        self.show_cursor_when_unfocused = is_enabled;
18232        cx.notify();
18233    }
18234
18235    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18236        cx.notify();
18237    }
18238
18239    fn on_debug_session_event(
18240        &mut self,
18241        _session: Entity<Session>,
18242        event: &SessionEvent,
18243        cx: &mut Context<Self>,
18244    ) {
18245        match event {
18246            SessionEvent::InvalidateInlineValue => {
18247                self.refresh_inline_values(cx);
18248            }
18249            _ => {}
18250        }
18251    }
18252
18253    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18254        let Some(project) = self.project.clone() else {
18255            return;
18256        };
18257
18258        if !self.inline_value_cache.enabled {
18259            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18260            self.splice_inlays(&inlays, Vec::new(), cx);
18261            return;
18262        }
18263
18264        let current_execution_position = self
18265            .highlighted_rows
18266            .get(&TypeId::of::<ActiveDebugLine>())
18267            .and_then(|lines| lines.last().map(|line| line.range.start));
18268
18269        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18270            let inline_values = editor
18271                .update(cx, |editor, cx| {
18272                    let Some(current_execution_position) = current_execution_position else {
18273                        return Some(Task::ready(Ok(Vec::new())));
18274                    };
18275
18276                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18277                        let snapshot = buffer.snapshot(cx);
18278
18279                        let excerpt = snapshot.excerpt_containing(
18280                            current_execution_position..current_execution_position,
18281                        )?;
18282
18283                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18284                    })?;
18285
18286                    let range =
18287                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18288
18289                    project.inline_values(buffer, range, cx)
18290                })
18291                .ok()
18292                .flatten()?
18293                .await
18294                .context("refreshing debugger inlays")
18295                .log_err()?;
18296
18297            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18298
18299            for (buffer_id, inline_value) in inline_values
18300                .into_iter()
18301                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18302            {
18303                buffer_inline_values
18304                    .entry(buffer_id)
18305                    .or_default()
18306                    .push(inline_value);
18307            }
18308
18309            editor
18310                .update(cx, |editor, cx| {
18311                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18312                    let mut new_inlays = Vec::default();
18313
18314                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18315                        let buffer_id = buffer_snapshot.remote_id();
18316                        buffer_inline_values
18317                            .get(&buffer_id)
18318                            .into_iter()
18319                            .flatten()
18320                            .for_each(|hint| {
18321                                let inlay = Inlay::debugger_hint(
18322                                    post_inc(&mut editor.next_inlay_id),
18323                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18324                                    hint.text(),
18325                                );
18326
18327                                new_inlays.push(inlay);
18328                            });
18329                    }
18330
18331                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18332                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18333
18334                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18335                })
18336                .ok()?;
18337            Some(())
18338        });
18339    }
18340
18341    fn on_buffer_event(
18342        &mut self,
18343        multibuffer: &Entity<MultiBuffer>,
18344        event: &multi_buffer::Event,
18345        window: &mut Window,
18346        cx: &mut Context<Self>,
18347    ) {
18348        match event {
18349            multi_buffer::Event::Edited {
18350                singleton_buffer_edited,
18351                edited_buffer: buffer_edited,
18352            } => {
18353                self.scrollbar_marker_state.dirty = true;
18354                self.active_indent_guides_state.dirty = true;
18355                self.refresh_active_diagnostics(cx);
18356                self.refresh_code_actions(window, cx);
18357                self.refresh_selected_text_highlights(true, window, cx);
18358                refresh_matching_bracket_highlights(self, window, cx);
18359                if self.has_active_inline_completion() {
18360                    self.update_visible_inline_completion(window, cx);
18361                }
18362                if let Some(buffer) = buffer_edited {
18363                    let buffer_id = buffer.read(cx).remote_id();
18364                    if !self.registered_buffers.contains_key(&buffer_id) {
18365                        if let Some(project) = self.project.as_ref() {
18366                            project.update(cx, |project, cx| {
18367                                self.registered_buffers.insert(
18368                                    buffer_id,
18369                                    project.register_buffer_with_language_servers(&buffer, cx),
18370                                );
18371                            })
18372                        }
18373                    }
18374                }
18375                cx.emit(EditorEvent::BufferEdited);
18376                cx.emit(SearchEvent::MatchesInvalidated);
18377                if *singleton_buffer_edited {
18378                    if let Some(project) = &self.project {
18379                        #[allow(clippy::mutable_key_type)]
18380                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18381                            multibuffer
18382                                .all_buffers()
18383                                .into_iter()
18384                                .filter_map(|buffer| {
18385                                    buffer.update(cx, |buffer, cx| {
18386                                        let language = buffer.language()?;
18387                                        let should_discard = project.update(cx, |project, cx| {
18388                                            project.is_local()
18389                                                && !project.has_language_servers_for(buffer, cx)
18390                                        });
18391                                        should_discard.not().then_some(language.clone())
18392                                    })
18393                                })
18394                                .collect::<HashSet<_>>()
18395                        });
18396                        if !languages_affected.is_empty() {
18397                            self.refresh_inlay_hints(
18398                                InlayHintRefreshReason::BufferEdited(languages_affected),
18399                                cx,
18400                            );
18401                        }
18402                    }
18403                }
18404
18405                let Some(project) = &self.project else { return };
18406                let (telemetry, is_via_ssh) = {
18407                    let project = project.read(cx);
18408                    let telemetry = project.client().telemetry().clone();
18409                    let is_via_ssh = project.is_via_ssh();
18410                    (telemetry, is_via_ssh)
18411                };
18412                refresh_linked_ranges(self, window, cx);
18413                telemetry.log_edit_event("editor", is_via_ssh);
18414            }
18415            multi_buffer::Event::ExcerptsAdded {
18416                buffer,
18417                predecessor,
18418                excerpts,
18419            } => {
18420                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18421                let buffer_id = buffer.read(cx).remote_id();
18422                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18423                    if let Some(project) = &self.project {
18424                        update_uncommitted_diff_for_buffer(
18425                            cx.entity(),
18426                            project,
18427                            [buffer.clone()],
18428                            self.buffer.clone(),
18429                            cx,
18430                        )
18431                        .detach();
18432                    }
18433                }
18434                cx.emit(EditorEvent::ExcerptsAdded {
18435                    buffer: buffer.clone(),
18436                    predecessor: *predecessor,
18437                    excerpts: excerpts.clone(),
18438                });
18439                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18440            }
18441            multi_buffer::Event::ExcerptsRemoved {
18442                ids,
18443                removed_buffer_ids,
18444            } => {
18445                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18446                let buffer = self.buffer.read(cx);
18447                self.registered_buffers
18448                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18449                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18450                cx.emit(EditorEvent::ExcerptsRemoved {
18451                    ids: ids.clone(),
18452                    removed_buffer_ids: removed_buffer_ids.clone(),
18453                })
18454            }
18455            multi_buffer::Event::ExcerptsEdited {
18456                excerpt_ids,
18457                buffer_ids,
18458            } => {
18459                self.display_map.update(cx, |map, cx| {
18460                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18461                });
18462                cx.emit(EditorEvent::ExcerptsEdited {
18463                    ids: excerpt_ids.clone(),
18464                })
18465            }
18466            multi_buffer::Event::ExcerptsExpanded { ids } => {
18467                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18468                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18469            }
18470            multi_buffer::Event::Reparsed(buffer_id) => {
18471                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18472                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18473
18474                cx.emit(EditorEvent::Reparsed(*buffer_id));
18475            }
18476            multi_buffer::Event::DiffHunksToggled => {
18477                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18478            }
18479            multi_buffer::Event::LanguageChanged(buffer_id) => {
18480                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18481                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18482                cx.emit(EditorEvent::Reparsed(*buffer_id));
18483                cx.notify();
18484            }
18485            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18486            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18487            multi_buffer::Event::FileHandleChanged
18488            | multi_buffer::Event::Reloaded
18489            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18490            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18491            multi_buffer::Event::DiagnosticsUpdated => {
18492                self.refresh_active_diagnostics(cx);
18493                self.refresh_inline_diagnostics(true, window, cx);
18494                self.scrollbar_marker_state.dirty = true;
18495                cx.notify();
18496            }
18497            _ => {}
18498        };
18499    }
18500
18501    pub fn start_temporary_diff_override(&mut self) {
18502        self.load_diff_task.take();
18503        self.temporary_diff_override = true;
18504    }
18505
18506    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18507        self.temporary_diff_override = false;
18508        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18509        self.buffer.update(cx, |buffer, cx| {
18510            buffer.set_all_diff_hunks_collapsed(cx);
18511        });
18512
18513        if let Some(project) = self.project.clone() {
18514            self.load_diff_task = Some(
18515                update_uncommitted_diff_for_buffer(
18516                    cx.entity(),
18517                    &project,
18518                    self.buffer.read(cx).all_buffers(),
18519                    self.buffer.clone(),
18520                    cx,
18521                )
18522                .shared(),
18523            );
18524        }
18525    }
18526
18527    fn on_display_map_changed(
18528        &mut self,
18529        _: Entity<DisplayMap>,
18530        _: &mut Window,
18531        cx: &mut Context<Self>,
18532    ) {
18533        cx.notify();
18534    }
18535
18536    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18537        let new_severity = if self.diagnostics_enabled() {
18538            EditorSettings::get_global(cx)
18539                .diagnostics_max_severity
18540                .unwrap_or(DiagnosticSeverity::Hint)
18541        } else {
18542            DiagnosticSeverity::Off
18543        };
18544        self.set_max_diagnostics_severity(new_severity, cx);
18545        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18546        self.update_edit_prediction_settings(cx);
18547        self.refresh_inline_completion(true, false, window, cx);
18548        self.refresh_inlay_hints(
18549            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18550                self.selections.newest_anchor().head(),
18551                &self.buffer.read(cx).snapshot(cx),
18552                cx,
18553            )),
18554            cx,
18555        );
18556
18557        let old_cursor_shape = self.cursor_shape;
18558
18559        {
18560            let editor_settings = EditorSettings::get_global(cx);
18561            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18562            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18563            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18564            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18565        }
18566
18567        if old_cursor_shape != self.cursor_shape {
18568            cx.emit(EditorEvent::CursorShapeChanged);
18569        }
18570
18571        let project_settings = ProjectSettings::get_global(cx);
18572        self.serialize_dirty_buffers =
18573            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18574
18575        if self.mode.is_full() {
18576            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18577            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18578            if self.show_inline_diagnostics != show_inline_diagnostics {
18579                self.show_inline_diagnostics = show_inline_diagnostics;
18580                self.refresh_inline_diagnostics(false, window, cx);
18581            }
18582
18583            if self.git_blame_inline_enabled != inline_blame_enabled {
18584                self.toggle_git_blame_inline_internal(false, window, cx);
18585            }
18586
18587            let minimap_settings = EditorSettings::get_global(cx).minimap;
18588            if self.minimap_visibility.settings_visibility() != minimap_settings.minimap_enabled() {
18589                self.set_minimap_visibility(
18590                    MinimapVisibility::for_mode(self.mode(), cx),
18591                    window,
18592                    cx,
18593                );
18594            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18595                minimap_entity.update(cx, |minimap_editor, cx| {
18596                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18597                })
18598            }
18599        }
18600
18601        cx.notify();
18602    }
18603
18604    pub fn set_searchable(&mut self, searchable: bool) {
18605        self.searchable = searchable;
18606    }
18607
18608    pub fn searchable(&self) -> bool {
18609        self.searchable
18610    }
18611
18612    fn open_proposed_changes_editor(
18613        &mut self,
18614        _: &OpenProposedChangesEditor,
18615        window: &mut Window,
18616        cx: &mut Context<Self>,
18617    ) {
18618        let Some(workspace) = self.workspace() else {
18619            cx.propagate();
18620            return;
18621        };
18622
18623        let selections = self.selections.all::<usize>(cx);
18624        let multi_buffer = self.buffer.read(cx);
18625        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18626        let mut new_selections_by_buffer = HashMap::default();
18627        for selection in selections {
18628            for (buffer, range, _) in
18629                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18630            {
18631                let mut range = range.to_point(buffer);
18632                range.start.column = 0;
18633                range.end.column = buffer.line_len(range.end.row);
18634                new_selections_by_buffer
18635                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18636                    .or_insert(Vec::new())
18637                    .push(range)
18638            }
18639        }
18640
18641        let proposed_changes_buffers = new_selections_by_buffer
18642            .into_iter()
18643            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18644            .collect::<Vec<_>>();
18645        let proposed_changes_editor = cx.new(|cx| {
18646            ProposedChangesEditor::new(
18647                "Proposed changes",
18648                proposed_changes_buffers,
18649                self.project.clone(),
18650                window,
18651                cx,
18652            )
18653        });
18654
18655        window.defer(cx, move |window, cx| {
18656            workspace.update(cx, |workspace, cx| {
18657                workspace.active_pane().update(cx, |pane, cx| {
18658                    pane.add_item(
18659                        Box::new(proposed_changes_editor),
18660                        true,
18661                        true,
18662                        None,
18663                        window,
18664                        cx,
18665                    );
18666                });
18667            });
18668        });
18669    }
18670
18671    pub fn open_excerpts_in_split(
18672        &mut self,
18673        _: &OpenExcerptsSplit,
18674        window: &mut Window,
18675        cx: &mut Context<Self>,
18676    ) {
18677        self.open_excerpts_common(None, true, window, cx)
18678    }
18679
18680    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18681        self.open_excerpts_common(None, false, window, cx)
18682    }
18683
18684    fn open_excerpts_common(
18685        &mut self,
18686        jump_data: Option<JumpData>,
18687        split: bool,
18688        window: &mut Window,
18689        cx: &mut Context<Self>,
18690    ) {
18691        let Some(workspace) = self.workspace() else {
18692            cx.propagate();
18693            return;
18694        };
18695
18696        if self.buffer.read(cx).is_singleton() {
18697            cx.propagate();
18698            return;
18699        }
18700
18701        let mut new_selections_by_buffer = HashMap::default();
18702        match &jump_data {
18703            Some(JumpData::MultiBufferPoint {
18704                excerpt_id,
18705                position,
18706                anchor,
18707                line_offset_from_top,
18708            }) => {
18709                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18710                if let Some(buffer) = multi_buffer_snapshot
18711                    .buffer_id_for_excerpt(*excerpt_id)
18712                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18713                {
18714                    let buffer_snapshot = buffer.read(cx).snapshot();
18715                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18716                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18717                    } else {
18718                        buffer_snapshot.clip_point(*position, Bias::Left)
18719                    };
18720                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18721                    new_selections_by_buffer.insert(
18722                        buffer,
18723                        (
18724                            vec![jump_to_offset..jump_to_offset],
18725                            Some(*line_offset_from_top),
18726                        ),
18727                    );
18728                }
18729            }
18730            Some(JumpData::MultiBufferRow {
18731                row,
18732                line_offset_from_top,
18733            }) => {
18734                let point = MultiBufferPoint::new(row.0, 0);
18735                if let Some((buffer, buffer_point, _)) =
18736                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18737                {
18738                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18739                    new_selections_by_buffer
18740                        .entry(buffer)
18741                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18742                        .0
18743                        .push(buffer_offset..buffer_offset)
18744                }
18745            }
18746            None => {
18747                let selections = self.selections.all::<usize>(cx);
18748                let multi_buffer = self.buffer.read(cx);
18749                for selection in selections {
18750                    for (snapshot, range, _, anchor) in multi_buffer
18751                        .snapshot(cx)
18752                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18753                    {
18754                        if let Some(anchor) = anchor {
18755                            // selection is in a deleted hunk
18756                            let Some(buffer_id) = anchor.buffer_id else {
18757                                continue;
18758                            };
18759                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18760                                continue;
18761                            };
18762                            let offset = text::ToOffset::to_offset(
18763                                &anchor.text_anchor,
18764                                &buffer_handle.read(cx).snapshot(),
18765                            );
18766                            let range = offset..offset;
18767                            new_selections_by_buffer
18768                                .entry(buffer_handle)
18769                                .or_insert((Vec::new(), None))
18770                                .0
18771                                .push(range)
18772                        } else {
18773                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18774                            else {
18775                                continue;
18776                            };
18777                            new_selections_by_buffer
18778                                .entry(buffer_handle)
18779                                .or_insert((Vec::new(), None))
18780                                .0
18781                                .push(range)
18782                        }
18783                    }
18784                }
18785            }
18786        }
18787
18788        new_selections_by_buffer
18789            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18790
18791        if new_selections_by_buffer.is_empty() {
18792            return;
18793        }
18794
18795        // We defer the pane interaction because we ourselves are a workspace item
18796        // and activating a new item causes the pane to call a method on us reentrantly,
18797        // which panics if we're on the stack.
18798        window.defer(cx, move |window, cx| {
18799            workspace.update(cx, |workspace, cx| {
18800                let pane = if split {
18801                    workspace.adjacent_pane(window, cx)
18802                } else {
18803                    workspace.active_pane().clone()
18804                };
18805
18806                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18807                    let editor = buffer
18808                        .read(cx)
18809                        .file()
18810                        .is_none()
18811                        .then(|| {
18812                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18813                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18814                            // Instead, we try to activate the existing editor in the pane first.
18815                            let (editor, pane_item_index) =
18816                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18817                                    let editor = item.downcast::<Editor>()?;
18818                                    let singleton_buffer =
18819                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18820                                    if singleton_buffer == buffer {
18821                                        Some((editor, i))
18822                                    } else {
18823                                        None
18824                                    }
18825                                })?;
18826                            pane.update(cx, |pane, cx| {
18827                                pane.activate_item(pane_item_index, true, true, window, cx)
18828                            });
18829                            Some(editor)
18830                        })
18831                        .flatten()
18832                        .unwrap_or_else(|| {
18833                            workspace.open_project_item::<Self>(
18834                                pane.clone(),
18835                                buffer,
18836                                true,
18837                                true,
18838                                window,
18839                                cx,
18840                            )
18841                        });
18842
18843                    editor.update(cx, |editor, cx| {
18844                        let autoscroll = match scroll_offset {
18845                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18846                            None => Autoscroll::newest(),
18847                        };
18848                        let nav_history = editor.nav_history.take();
18849                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18850                            s.select_ranges(ranges);
18851                        });
18852                        editor.nav_history = nav_history;
18853                    });
18854                }
18855            })
18856        });
18857    }
18858
18859    // For now, don't allow opening excerpts in buffers that aren't backed by
18860    // regular project files.
18861    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18862        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18863    }
18864
18865    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18866        let snapshot = self.buffer.read(cx).read(cx);
18867        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18868        Some(
18869            ranges
18870                .iter()
18871                .map(move |range| {
18872                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18873                })
18874                .collect(),
18875        )
18876    }
18877
18878    fn selection_replacement_ranges(
18879        &self,
18880        range: Range<OffsetUtf16>,
18881        cx: &mut App,
18882    ) -> Vec<Range<OffsetUtf16>> {
18883        let selections = self.selections.all::<OffsetUtf16>(cx);
18884        let newest_selection = selections
18885            .iter()
18886            .max_by_key(|selection| selection.id)
18887            .unwrap();
18888        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18889        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18890        let snapshot = self.buffer.read(cx).read(cx);
18891        selections
18892            .into_iter()
18893            .map(|mut selection| {
18894                selection.start.0 =
18895                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18896                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18897                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18898                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18899            })
18900            .collect()
18901    }
18902
18903    fn report_editor_event(
18904        &self,
18905        event_type: &'static str,
18906        file_extension: Option<String>,
18907        cx: &App,
18908    ) {
18909        if cfg!(any(test, feature = "test-support")) {
18910            return;
18911        }
18912
18913        let Some(project) = &self.project else { return };
18914
18915        // If None, we are in a file without an extension
18916        let file = self
18917            .buffer
18918            .read(cx)
18919            .as_singleton()
18920            .and_then(|b| b.read(cx).file());
18921        let file_extension = file_extension.or(file
18922            .as_ref()
18923            .and_then(|file| Path::new(file.file_name(cx)).extension())
18924            .and_then(|e| e.to_str())
18925            .map(|a| a.to_string()));
18926
18927        let vim_mode = vim_enabled(cx);
18928
18929        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18930        let copilot_enabled = edit_predictions_provider
18931            == language::language_settings::EditPredictionProvider::Copilot;
18932        let copilot_enabled_for_language = self
18933            .buffer
18934            .read(cx)
18935            .language_settings(cx)
18936            .show_edit_predictions;
18937
18938        let project = project.read(cx);
18939        telemetry::event!(
18940            event_type,
18941            file_extension,
18942            vim_mode,
18943            copilot_enabled,
18944            copilot_enabled_for_language,
18945            edit_predictions_provider,
18946            is_via_ssh = project.is_via_ssh(),
18947        );
18948    }
18949
18950    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18951    /// with each line being an array of {text, highlight} objects.
18952    fn copy_highlight_json(
18953        &mut self,
18954        _: &CopyHighlightJson,
18955        window: &mut Window,
18956        cx: &mut Context<Self>,
18957    ) {
18958        #[derive(Serialize)]
18959        struct Chunk<'a> {
18960            text: String,
18961            highlight: Option<&'a str>,
18962        }
18963
18964        let snapshot = self.buffer.read(cx).snapshot(cx);
18965        let range = self
18966            .selected_text_range(false, window, cx)
18967            .and_then(|selection| {
18968                if selection.range.is_empty() {
18969                    None
18970                } else {
18971                    Some(selection.range)
18972                }
18973            })
18974            .unwrap_or_else(|| 0..snapshot.len());
18975
18976        let chunks = snapshot.chunks(range, true);
18977        let mut lines = Vec::new();
18978        let mut line: VecDeque<Chunk> = VecDeque::new();
18979
18980        let Some(style) = self.style.as_ref() else {
18981            return;
18982        };
18983
18984        for chunk in chunks {
18985            let highlight = chunk
18986                .syntax_highlight_id
18987                .and_then(|id| id.name(&style.syntax));
18988            let mut chunk_lines = chunk.text.split('\n').peekable();
18989            while let Some(text) = chunk_lines.next() {
18990                let mut merged_with_last_token = false;
18991                if let Some(last_token) = line.back_mut() {
18992                    if last_token.highlight == highlight {
18993                        last_token.text.push_str(text);
18994                        merged_with_last_token = true;
18995                    }
18996                }
18997
18998                if !merged_with_last_token {
18999                    line.push_back(Chunk {
19000                        text: text.into(),
19001                        highlight,
19002                    });
19003                }
19004
19005                if chunk_lines.peek().is_some() {
19006                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19007                        line.pop_front();
19008                    }
19009                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19010                        line.pop_back();
19011                    }
19012
19013                    lines.push(mem::take(&mut line));
19014                }
19015            }
19016        }
19017
19018        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19019            return;
19020        };
19021        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19022    }
19023
19024    pub fn open_context_menu(
19025        &mut self,
19026        _: &OpenContextMenu,
19027        window: &mut Window,
19028        cx: &mut Context<Self>,
19029    ) {
19030        self.request_autoscroll(Autoscroll::newest(), cx);
19031        let position = self.selections.newest_display(cx).start;
19032        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19033    }
19034
19035    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19036        &self.inlay_hint_cache
19037    }
19038
19039    pub fn replay_insert_event(
19040        &mut self,
19041        text: &str,
19042        relative_utf16_range: Option<Range<isize>>,
19043        window: &mut Window,
19044        cx: &mut Context<Self>,
19045    ) {
19046        if !self.input_enabled {
19047            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19048            return;
19049        }
19050        if let Some(relative_utf16_range) = relative_utf16_range {
19051            let selections = self.selections.all::<OffsetUtf16>(cx);
19052            self.change_selections(None, window, cx, |s| {
19053                let new_ranges = selections.into_iter().map(|range| {
19054                    let start = OffsetUtf16(
19055                        range
19056                            .head()
19057                            .0
19058                            .saturating_add_signed(relative_utf16_range.start),
19059                    );
19060                    let end = OffsetUtf16(
19061                        range
19062                            .head()
19063                            .0
19064                            .saturating_add_signed(relative_utf16_range.end),
19065                    );
19066                    start..end
19067                });
19068                s.select_ranges(new_ranges);
19069            });
19070        }
19071
19072        self.handle_input(text, window, cx);
19073    }
19074
19075    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19076        let Some(provider) = self.semantics_provider.as_ref() else {
19077            return false;
19078        };
19079
19080        let mut supports = false;
19081        self.buffer().update(cx, |this, cx| {
19082            this.for_each_buffer(|buffer| {
19083                supports |= provider.supports_inlay_hints(buffer, cx);
19084            });
19085        });
19086
19087        supports
19088    }
19089
19090    pub fn is_focused(&self, window: &Window) -> bool {
19091        self.focus_handle.is_focused(window)
19092    }
19093
19094    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19095        cx.emit(EditorEvent::Focused);
19096
19097        if let Some(descendant) = self
19098            .last_focused_descendant
19099            .take()
19100            .and_then(|descendant| descendant.upgrade())
19101        {
19102            window.focus(&descendant);
19103        } else {
19104            if let Some(blame) = self.blame.as_ref() {
19105                blame.update(cx, GitBlame::focus)
19106            }
19107
19108            self.blink_manager.update(cx, BlinkManager::enable);
19109            self.show_cursor_names(window, cx);
19110            self.buffer.update(cx, |buffer, cx| {
19111                buffer.finalize_last_transaction(cx);
19112                if self.leader_id.is_none() {
19113                    buffer.set_active_selections(
19114                        &self.selections.disjoint_anchors(),
19115                        self.selections.line_mode,
19116                        self.cursor_shape,
19117                        cx,
19118                    );
19119                }
19120            });
19121        }
19122    }
19123
19124    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19125        cx.emit(EditorEvent::FocusedIn)
19126    }
19127
19128    fn handle_focus_out(
19129        &mut self,
19130        event: FocusOutEvent,
19131        _window: &mut Window,
19132        cx: &mut Context<Self>,
19133    ) {
19134        if event.blurred != self.focus_handle {
19135            self.last_focused_descendant = Some(event.blurred);
19136        }
19137        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19138    }
19139
19140    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19141        self.blink_manager.update(cx, BlinkManager::disable);
19142        self.buffer
19143            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19144
19145        if let Some(blame) = self.blame.as_ref() {
19146            blame.update(cx, GitBlame::blur)
19147        }
19148        if !self.hover_state.focused(window, cx) {
19149            hide_hover(self, cx);
19150        }
19151        if !self
19152            .context_menu
19153            .borrow()
19154            .as_ref()
19155            .is_some_and(|context_menu| context_menu.focused(window, cx))
19156        {
19157            self.hide_context_menu(window, cx);
19158        }
19159        self.discard_inline_completion(false, cx);
19160        cx.emit(EditorEvent::Blurred);
19161        cx.notify();
19162    }
19163
19164    pub fn register_action<A: Action>(
19165        &mut self,
19166        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19167    ) -> Subscription {
19168        let id = self.next_editor_action_id.post_inc();
19169        let listener = Arc::new(listener);
19170        self.editor_actions.borrow_mut().insert(
19171            id,
19172            Box::new(move |window, _| {
19173                let listener = listener.clone();
19174                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19175                    let action = action.downcast_ref().unwrap();
19176                    if phase == DispatchPhase::Bubble {
19177                        listener(action, window, cx)
19178                    }
19179                })
19180            }),
19181        );
19182
19183        let editor_actions = self.editor_actions.clone();
19184        Subscription::new(move || {
19185            editor_actions.borrow_mut().remove(&id);
19186        })
19187    }
19188
19189    pub fn file_header_size(&self) -> u32 {
19190        FILE_HEADER_HEIGHT
19191    }
19192
19193    pub fn restore(
19194        &mut self,
19195        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19196        window: &mut Window,
19197        cx: &mut Context<Self>,
19198    ) {
19199        let workspace = self.workspace();
19200        let project = self.project.as_ref();
19201        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19202            let mut tasks = Vec::new();
19203            for (buffer_id, changes) in revert_changes {
19204                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19205                    buffer.update(cx, |buffer, cx| {
19206                        buffer.edit(
19207                            changes
19208                                .into_iter()
19209                                .map(|(range, text)| (range, text.to_string())),
19210                            None,
19211                            cx,
19212                        );
19213                    });
19214
19215                    if let Some(project) =
19216                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19217                    {
19218                        project.update(cx, |project, cx| {
19219                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19220                        })
19221                    }
19222                }
19223            }
19224            tasks
19225        });
19226        cx.spawn_in(window, async move |_, cx| {
19227            for (buffer, task) in save_tasks {
19228                let result = task.await;
19229                if result.is_err() {
19230                    let Some(path) = buffer
19231                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19232                        .ok()
19233                    else {
19234                        continue;
19235                    };
19236                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19237                        let Some(task) = cx
19238                            .update_window_entity(&workspace, |workspace, window, cx| {
19239                                workspace
19240                                    .open_path_preview(path, None, false, false, false, window, cx)
19241                            })
19242                            .ok()
19243                        else {
19244                            continue;
19245                        };
19246                        task.await.log_err();
19247                    }
19248                }
19249            }
19250        })
19251        .detach();
19252        self.change_selections(None, window, cx, |selections| selections.refresh());
19253    }
19254
19255    pub fn to_pixel_point(
19256        &self,
19257        source: multi_buffer::Anchor,
19258        editor_snapshot: &EditorSnapshot,
19259        window: &mut Window,
19260    ) -> Option<gpui::Point<Pixels>> {
19261        let source_point = source.to_display_point(editor_snapshot);
19262        self.display_to_pixel_point(source_point, editor_snapshot, window)
19263    }
19264
19265    pub fn display_to_pixel_point(
19266        &self,
19267        source: DisplayPoint,
19268        editor_snapshot: &EditorSnapshot,
19269        window: &mut Window,
19270    ) -> Option<gpui::Point<Pixels>> {
19271        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19272        let text_layout_details = self.text_layout_details(window);
19273        let scroll_top = text_layout_details
19274            .scroll_anchor
19275            .scroll_position(editor_snapshot)
19276            .y;
19277
19278        if source.row().as_f32() < scroll_top.floor() {
19279            return None;
19280        }
19281        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19282        let source_y = line_height * (source.row().as_f32() - scroll_top);
19283        Some(gpui::Point::new(source_x, source_y))
19284    }
19285
19286    pub fn has_visible_completions_menu(&self) -> bool {
19287        !self.edit_prediction_preview_is_active()
19288            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19289                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19290            })
19291    }
19292
19293    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19294        if self.mode.is_minimap() {
19295            return;
19296        }
19297        self.addons
19298            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19299    }
19300
19301    pub fn unregister_addon<T: Addon>(&mut self) {
19302        self.addons.remove(&std::any::TypeId::of::<T>());
19303    }
19304
19305    pub fn addon<T: Addon>(&self) -> Option<&T> {
19306        let type_id = std::any::TypeId::of::<T>();
19307        self.addons
19308            .get(&type_id)
19309            .and_then(|item| item.to_any().downcast_ref::<T>())
19310    }
19311
19312    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19313        let type_id = std::any::TypeId::of::<T>();
19314        self.addons
19315            .get_mut(&type_id)
19316            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19317    }
19318
19319    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19320        let text_layout_details = self.text_layout_details(window);
19321        let style = &text_layout_details.editor_style;
19322        let font_id = window.text_system().resolve_font(&style.text.font());
19323        let font_size = style.text.font_size.to_pixels(window.rem_size());
19324        let line_height = style.text.line_height_in_pixels(window.rem_size());
19325        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19326
19327        gpui::Size::new(em_width, line_height)
19328    }
19329
19330    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19331        self.load_diff_task.clone()
19332    }
19333
19334    fn read_metadata_from_db(
19335        &mut self,
19336        item_id: u64,
19337        workspace_id: WorkspaceId,
19338        window: &mut Window,
19339        cx: &mut Context<Editor>,
19340    ) {
19341        if self.is_singleton(cx)
19342            && !self.mode.is_minimap()
19343            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19344        {
19345            let buffer_snapshot = OnceCell::new();
19346
19347            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19348                if !folds.is_empty() {
19349                    let snapshot =
19350                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19351                    self.fold_ranges(
19352                        folds
19353                            .into_iter()
19354                            .map(|(start, end)| {
19355                                snapshot.clip_offset(start, Bias::Left)
19356                                    ..snapshot.clip_offset(end, Bias::Right)
19357                            })
19358                            .collect(),
19359                        false,
19360                        window,
19361                        cx,
19362                    );
19363                }
19364            }
19365
19366            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19367                if !selections.is_empty() {
19368                    let snapshot =
19369                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19370                    self.change_selections(None, window, cx, |s| {
19371                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19372                            snapshot.clip_offset(start, Bias::Left)
19373                                ..snapshot.clip_offset(end, Bias::Right)
19374                        }));
19375                    });
19376                }
19377            };
19378        }
19379
19380        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19381    }
19382}
19383
19384fn vim_enabled(cx: &App) -> bool {
19385    cx.global::<SettingsStore>()
19386        .raw_user_settings()
19387        .get("vim_mode")
19388        == Some(&serde_json::Value::Bool(true))
19389}
19390
19391// Consider user intent and default settings
19392fn choose_completion_range(
19393    completion: &Completion,
19394    intent: CompletionIntent,
19395    buffer: &Entity<Buffer>,
19396    cx: &mut Context<Editor>,
19397) -> Range<usize> {
19398    fn should_replace(
19399        completion: &Completion,
19400        insert_range: &Range<text::Anchor>,
19401        intent: CompletionIntent,
19402        completion_mode_setting: LspInsertMode,
19403        buffer: &Buffer,
19404    ) -> bool {
19405        // specific actions take precedence over settings
19406        match intent {
19407            CompletionIntent::CompleteWithInsert => return false,
19408            CompletionIntent::CompleteWithReplace => return true,
19409            CompletionIntent::Complete | CompletionIntent::Compose => {}
19410        }
19411
19412        match completion_mode_setting {
19413            LspInsertMode::Insert => false,
19414            LspInsertMode::Replace => true,
19415            LspInsertMode::ReplaceSubsequence => {
19416                let mut text_to_replace = buffer.chars_for_range(
19417                    buffer.anchor_before(completion.replace_range.start)
19418                        ..buffer.anchor_after(completion.replace_range.end),
19419                );
19420                let mut completion_text = completion.new_text.chars();
19421
19422                // is `text_to_replace` a subsequence of `completion_text`
19423                text_to_replace
19424                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19425            }
19426            LspInsertMode::ReplaceSuffix => {
19427                let range_after_cursor = insert_range.end..completion.replace_range.end;
19428
19429                let text_after_cursor = buffer
19430                    .text_for_range(
19431                        buffer.anchor_before(range_after_cursor.start)
19432                            ..buffer.anchor_after(range_after_cursor.end),
19433                    )
19434                    .collect::<String>();
19435                completion.new_text.ends_with(&text_after_cursor)
19436            }
19437        }
19438    }
19439
19440    let buffer = buffer.read(cx);
19441
19442    if let CompletionSource::Lsp {
19443        insert_range: Some(insert_range),
19444        ..
19445    } = &completion.source
19446    {
19447        let completion_mode_setting =
19448            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19449                .completions
19450                .lsp_insert_mode;
19451
19452        if !should_replace(
19453            completion,
19454            &insert_range,
19455            intent,
19456            completion_mode_setting,
19457            buffer,
19458        ) {
19459            return insert_range.to_offset(buffer);
19460        }
19461    }
19462
19463    completion.replace_range.to_offset(buffer)
19464}
19465
19466fn insert_extra_newline_brackets(
19467    buffer: &MultiBufferSnapshot,
19468    range: Range<usize>,
19469    language: &language::LanguageScope,
19470) -> bool {
19471    let leading_whitespace_len = buffer
19472        .reversed_chars_at(range.start)
19473        .take_while(|c| c.is_whitespace() && *c != '\n')
19474        .map(|c| c.len_utf8())
19475        .sum::<usize>();
19476    let trailing_whitespace_len = buffer
19477        .chars_at(range.end)
19478        .take_while(|c| c.is_whitespace() && *c != '\n')
19479        .map(|c| c.len_utf8())
19480        .sum::<usize>();
19481    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19482
19483    language.brackets().any(|(pair, enabled)| {
19484        let pair_start = pair.start.trim_end();
19485        let pair_end = pair.end.trim_start();
19486
19487        enabled
19488            && pair.newline
19489            && buffer.contains_str_at(range.end, pair_end)
19490            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19491    })
19492}
19493
19494fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19495    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19496        [(buffer, range, _)] => (*buffer, range.clone()),
19497        _ => return false,
19498    };
19499    let pair = {
19500        let mut result: Option<BracketMatch> = None;
19501
19502        for pair in buffer
19503            .all_bracket_ranges(range.clone())
19504            .filter(move |pair| {
19505                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19506            })
19507        {
19508            let len = pair.close_range.end - pair.open_range.start;
19509
19510            if let Some(existing) = &result {
19511                let existing_len = existing.close_range.end - existing.open_range.start;
19512                if len > existing_len {
19513                    continue;
19514                }
19515            }
19516
19517            result = Some(pair);
19518        }
19519
19520        result
19521    };
19522    let Some(pair) = pair else {
19523        return false;
19524    };
19525    pair.newline_only
19526        && buffer
19527            .chars_for_range(pair.open_range.end..range.start)
19528            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19529            .all(|c| c.is_whitespace() && c != '\n')
19530}
19531
19532fn update_uncommitted_diff_for_buffer(
19533    editor: Entity<Editor>,
19534    project: &Entity<Project>,
19535    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19536    buffer: Entity<MultiBuffer>,
19537    cx: &mut App,
19538) -> Task<()> {
19539    let mut tasks = Vec::new();
19540    project.update(cx, |project, cx| {
19541        for buffer in buffers {
19542            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19543                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19544            }
19545        }
19546    });
19547    cx.spawn(async move |cx| {
19548        let diffs = future::join_all(tasks).await;
19549        if editor
19550            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19551            .unwrap_or(false)
19552        {
19553            return;
19554        }
19555
19556        buffer
19557            .update(cx, |buffer, cx| {
19558                for diff in diffs.into_iter().flatten() {
19559                    buffer.add_diff(diff, cx);
19560                }
19561            })
19562            .ok();
19563    })
19564}
19565
19566pub trait CollaborationHub {
19567    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19568    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19569    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19570}
19571
19572impl CollaborationHub for Entity<Project> {
19573    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19574        self.read(cx).collaborators()
19575    }
19576
19577    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19578        self.read(cx).user_store().read(cx).participant_indices()
19579    }
19580
19581    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19582        let this = self.read(cx);
19583        let user_ids = this.collaborators().values().map(|c| c.user_id);
19584        this.user_store().read(cx).participant_names(user_ids, cx)
19585    }
19586}
19587
19588pub trait SemanticsProvider {
19589    fn hover(
19590        &self,
19591        buffer: &Entity<Buffer>,
19592        position: text::Anchor,
19593        cx: &mut App,
19594    ) -> Option<Task<Vec<project::Hover>>>;
19595
19596    fn inline_values(
19597        &self,
19598        buffer_handle: Entity<Buffer>,
19599        range: Range<text::Anchor>,
19600        cx: &mut App,
19601    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19602
19603    fn inlay_hints(
19604        &self,
19605        buffer_handle: Entity<Buffer>,
19606        range: Range<text::Anchor>,
19607        cx: &mut App,
19608    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19609
19610    fn resolve_inlay_hint(
19611        &self,
19612        hint: InlayHint,
19613        buffer_handle: Entity<Buffer>,
19614        server_id: LanguageServerId,
19615        cx: &mut App,
19616    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19617
19618    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19619
19620    fn document_highlights(
19621        &self,
19622        buffer: &Entity<Buffer>,
19623        position: text::Anchor,
19624        cx: &mut App,
19625    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19626
19627    fn definitions(
19628        &self,
19629        buffer: &Entity<Buffer>,
19630        position: text::Anchor,
19631        kind: GotoDefinitionKind,
19632        cx: &mut App,
19633    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19634
19635    fn range_for_rename(
19636        &self,
19637        buffer: &Entity<Buffer>,
19638        position: text::Anchor,
19639        cx: &mut App,
19640    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19641
19642    fn perform_rename(
19643        &self,
19644        buffer: &Entity<Buffer>,
19645        position: text::Anchor,
19646        new_name: String,
19647        cx: &mut App,
19648    ) -> Option<Task<Result<ProjectTransaction>>>;
19649}
19650
19651pub trait CompletionProvider {
19652    fn completions(
19653        &self,
19654        excerpt_id: ExcerptId,
19655        buffer: &Entity<Buffer>,
19656        buffer_position: text::Anchor,
19657        trigger: CompletionContext,
19658        window: &mut Window,
19659        cx: &mut Context<Editor>,
19660    ) -> Task<Result<Option<Vec<Completion>>>>;
19661
19662    fn resolve_completions(
19663        &self,
19664        buffer: Entity<Buffer>,
19665        completion_indices: Vec<usize>,
19666        completions: Rc<RefCell<Box<[Completion]>>>,
19667        cx: &mut Context<Editor>,
19668    ) -> Task<Result<bool>>;
19669
19670    fn apply_additional_edits_for_completion(
19671        &self,
19672        _buffer: Entity<Buffer>,
19673        _completions: Rc<RefCell<Box<[Completion]>>>,
19674        _completion_index: usize,
19675        _push_to_history: bool,
19676        _cx: &mut Context<Editor>,
19677    ) -> Task<Result<Option<language::Transaction>>> {
19678        Task::ready(Ok(None))
19679    }
19680
19681    fn is_completion_trigger(
19682        &self,
19683        buffer: &Entity<Buffer>,
19684        position: language::Anchor,
19685        text: &str,
19686        trigger_in_words: bool,
19687        cx: &mut Context<Editor>,
19688    ) -> bool;
19689
19690    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
19691
19692    fn sort_completions(&self) -> bool {
19693        true
19694    }
19695
19696    fn filter_completions(&self) -> bool {
19697        true
19698    }
19699}
19700
19701pub trait CodeActionProvider {
19702    fn id(&self) -> Arc<str>;
19703
19704    fn code_actions(
19705        &self,
19706        buffer: &Entity<Buffer>,
19707        range: Range<text::Anchor>,
19708        window: &mut Window,
19709        cx: &mut App,
19710    ) -> Task<Result<Vec<CodeAction>>>;
19711
19712    fn apply_code_action(
19713        &self,
19714        buffer_handle: Entity<Buffer>,
19715        action: CodeAction,
19716        excerpt_id: ExcerptId,
19717        push_to_history: bool,
19718        window: &mut Window,
19719        cx: &mut App,
19720    ) -> Task<Result<ProjectTransaction>>;
19721}
19722
19723impl CodeActionProvider for Entity<Project> {
19724    fn id(&self) -> Arc<str> {
19725        "project".into()
19726    }
19727
19728    fn code_actions(
19729        &self,
19730        buffer: &Entity<Buffer>,
19731        range: Range<text::Anchor>,
19732        _window: &mut Window,
19733        cx: &mut App,
19734    ) -> Task<Result<Vec<CodeAction>>> {
19735        self.update(cx, |project, cx| {
19736            let code_lens = project.code_lens(buffer, range.clone(), cx);
19737            let code_actions = project.code_actions(buffer, range, None, cx);
19738            cx.background_spawn(async move {
19739                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19740                Ok(code_lens
19741                    .context("code lens fetch")?
19742                    .into_iter()
19743                    .chain(code_actions.context("code action fetch")?)
19744                    .collect())
19745            })
19746        })
19747    }
19748
19749    fn apply_code_action(
19750        &self,
19751        buffer_handle: Entity<Buffer>,
19752        action: CodeAction,
19753        _excerpt_id: ExcerptId,
19754        push_to_history: bool,
19755        _window: &mut Window,
19756        cx: &mut App,
19757    ) -> Task<Result<ProjectTransaction>> {
19758        self.update(cx, |project, cx| {
19759            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19760        })
19761    }
19762}
19763
19764fn snippet_completions(
19765    project: &Project,
19766    buffer: &Entity<Buffer>,
19767    buffer_position: text::Anchor,
19768    cx: &mut App,
19769) -> Task<Result<Vec<Completion>>> {
19770    let languages = buffer.read(cx).languages_at(buffer_position);
19771    let snippet_store = project.snippets().read(cx);
19772
19773    let scopes: Vec<_> = languages
19774        .iter()
19775        .filter_map(|language| {
19776            let language_name = language.lsp_id();
19777            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19778
19779            if snippets.is_empty() {
19780                None
19781            } else {
19782                Some((language.default_scope(), snippets))
19783            }
19784        })
19785        .collect();
19786
19787    if scopes.is_empty() {
19788        return Task::ready(Ok(vec![]));
19789    }
19790
19791    let snapshot = buffer.read(cx).text_snapshot();
19792    let chars: String = snapshot
19793        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19794        .collect();
19795    let executor = cx.background_executor().clone();
19796
19797    cx.background_spawn(async move {
19798        let mut all_results: Vec<Completion> = Vec::new();
19799        for (scope, snippets) in scopes.into_iter() {
19800            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19801            let mut last_word = chars
19802                .chars()
19803                .take_while(|c| classifier.is_word(*c))
19804                .collect::<String>();
19805            last_word = last_word.chars().rev().collect();
19806
19807            if last_word.is_empty() {
19808                return Ok(vec![]);
19809            }
19810
19811            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19812            let to_lsp = |point: &text::Anchor| {
19813                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19814                point_to_lsp(end)
19815            };
19816            let lsp_end = to_lsp(&buffer_position);
19817
19818            let candidates = snippets
19819                .iter()
19820                .enumerate()
19821                .flat_map(|(ix, snippet)| {
19822                    snippet
19823                        .prefix
19824                        .iter()
19825                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19826                })
19827                .collect::<Vec<StringMatchCandidate>>();
19828
19829            let mut matches = fuzzy::match_strings(
19830                &candidates,
19831                &last_word,
19832                last_word.chars().any(|c| c.is_uppercase()),
19833                100,
19834                &Default::default(),
19835                executor.clone(),
19836            )
19837            .await;
19838
19839            // Remove all candidates where the query's start does not match the start of any word in the candidate
19840            if let Some(query_start) = last_word.chars().next() {
19841                matches.retain(|string_match| {
19842                    split_words(&string_match.string).any(|word| {
19843                        // Check that the first codepoint of the word as lowercase matches the first
19844                        // codepoint of the query as lowercase
19845                        word.chars()
19846                            .flat_map(|codepoint| codepoint.to_lowercase())
19847                            .zip(query_start.to_lowercase())
19848                            .all(|(word_cp, query_cp)| word_cp == query_cp)
19849                    })
19850                });
19851            }
19852
19853            let matched_strings = matches
19854                .into_iter()
19855                .map(|m| m.string)
19856                .collect::<HashSet<_>>();
19857
19858            let mut result: Vec<Completion> = snippets
19859                .iter()
19860                .filter_map(|snippet| {
19861                    let matching_prefix = snippet
19862                        .prefix
19863                        .iter()
19864                        .find(|prefix| matched_strings.contains(*prefix))?;
19865                    let start = as_offset - last_word.len();
19866                    let start = snapshot.anchor_before(start);
19867                    let range = start..buffer_position;
19868                    let lsp_start = to_lsp(&start);
19869                    let lsp_range = lsp::Range {
19870                        start: lsp_start,
19871                        end: lsp_end,
19872                    };
19873                    Some(Completion {
19874                        replace_range: range,
19875                        new_text: snippet.body.clone(),
19876                        source: CompletionSource::Lsp {
19877                            insert_range: None,
19878                            server_id: LanguageServerId(usize::MAX),
19879                            resolved: true,
19880                            lsp_completion: Box::new(lsp::CompletionItem {
19881                                label: snippet.prefix.first().unwrap().clone(),
19882                                kind: Some(CompletionItemKind::SNIPPET),
19883                                label_details: snippet.description.as_ref().map(|description| {
19884                                    lsp::CompletionItemLabelDetails {
19885                                        detail: Some(description.clone()),
19886                                        description: None,
19887                                    }
19888                                }),
19889                                insert_text_format: Some(InsertTextFormat::SNIPPET),
19890                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
19891                                    lsp::InsertReplaceEdit {
19892                                        new_text: snippet.body.clone(),
19893                                        insert: lsp_range,
19894                                        replace: lsp_range,
19895                                    },
19896                                )),
19897                                filter_text: Some(snippet.body.clone()),
19898                                sort_text: Some(char::MAX.to_string()),
19899                                ..lsp::CompletionItem::default()
19900                            }),
19901                            lsp_defaults: None,
19902                        },
19903                        label: CodeLabel {
19904                            text: matching_prefix.clone(),
19905                            runs: Vec::new(),
19906                            filter_range: 0..matching_prefix.len(),
19907                        },
19908                        icon_path: None,
19909                        documentation: Some(
19910                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
19911                                single_line: snippet.name.clone().into(),
19912                                plain_text: snippet
19913                                    .description
19914                                    .clone()
19915                                    .map(|description| description.into()),
19916                            },
19917                        ),
19918                        insert_text_mode: None,
19919                        confirm: None,
19920                    })
19921                })
19922                .collect();
19923
19924            all_results.append(&mut result);
19925        }
19926
19927        Ok(all_results)
19928    })
19929}
19930
19931impl CompletionProvider for Entity<Project> {
19932    fn completions(
19933        &self,
19934        _excerpt_id: ExcerptId,
19935        buffer: &Entity<Buffer>,
19936        buffer_position: text::Anchor,
19937        options: CompletionContext,
19938        _window: &mut Window,
19939        cx: &mut Context<Editor>,
19940    ) -> Task<Result<Option<Vec<Completion>>>> {
19941        self.update(cx, |project, cx| {
19942            let snippets = snippet_completions(project, buffer, buffer_position, cx);
19943            let project_completions = project.completions(buffer, buffer_position, options, cx);
19944            cx.background_spawn(async move {
19945                let snippets_completions = snippets.await?;
19946                match project_completions.await? {
19947                    Some(mut completions) => {
19948                        completions.extend(snippets_completions);
19949                        Ok(Some(completions))
19950                    }
19951                    None => {
19952                        if snippets_completions.is_empty() {
19953                            Ok(None)
19954                        } else {
19955                            Ok(Some(snippets_completions))
19956                        }
19957                    }
19958                }
19959            })
19960        })
19961    }
19962
19963    fn resolve_completions(
19964        &self,
19965        buffer: Entity<Buffer>,
19966        completion_indices: Vec<usize>,
19967        completions: Rc<RefCell<Box<[Completion]>>>,
19968        cx: &mut Context<Editor>,
19969    ) -> Task<Result<bool>> {
19970        self.update(cx, |project, cx| {
19971            project.lsp_store().update(cx, |lsp_store, cx| {
19972                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
19973            })
19974        })
19975    }
19976
19977    fn apply_additional_edits_for_completion(
19978        &self,
19979        buffer: Entity<Buffer>,
19980        completions: Rc<RefCell<Box<[Completion]>>>,
19981        completion_index: usize,
19982        push_to_history: bool,
19983        cx: &mut Context<Editor>,
19984    ) -> Task<Result<Option<language::Transaction>>> {
19985        self.update(cx, |project, cx| {
19986            project.lsp_store().update(cx, |lsp_store, cx| {
19987                lsp_store.apply_additional_edits_for_completion(
19988                    buffer,
19989                    completions,
19990                    completion_index,
19991                    push_to_history,
19992                    cx,
19993                )
19994            })
19995        })
19996    }
19997
19998    fn is_completion_trigger(
19999        &self,
20000        buffer: &Entity<Buffer>,
20001        position: language::Anchor,
20002        text: &str,
20003        trigger_in_words: bool,
20004        cx: &mut Context<Editor>,
20005    ) -> bool {
20006        let mut chars = text.chars();
20007        let char = if let Some(char) = chars.next() {
20008            char
20009        } else {
20010            return false;
20011        };
20012        if chars.next().is_some() {
20013            return false;
20014        }
20015
20016        let buffer = buffer.read(cx);
20017        let snapshot = buffer.snapshot();
20018        if !snapshot.settings_at(position, cx).show_completions_on_input {
20019            return false;
20020        }
20021        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20022        if trigger_in_words && classifier.is_word(char) {
20023            return true;
20024        }
20025
20026        buffer.completion_triggers().contains(text)
20027    }
20028}
20029
20030impl SemanticsProvider for Entity<Project> {
20031    fn hover(
20032        &self,
20033        buffer: &Entity<Buffer>,
20034        position: text::Anchor,
20035        cx: &mut App,
20036    ) -> Option<Task<Vec<project::Hover>>> {
20037        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20038    }
20039
20040    fn document_highlights(
20041        &self,
20042        buffer: &Entity<Buffer>,
20043        position: text::Anchor,
20044        cx: &mut App,
20045    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20046        Some(self.update(cx, |project, cx| {
20047            project.document_highlights(buffer, position, cx)
20048        }))
20049    }
20050
20051    fn definitions(
20052        &self,
20053        buffer: &Entity<Buffer>,
20054        position: text::Anchor,
20055        kind: GotoDefinitionKind,
20056        cx: &mut App,
20057    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20058        Some(self.update(cx, |project, cx| match kind {
20059            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20060            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20061            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20062            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20063        }))
20064    }
20065
20066    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20067        // TODO: make this work for remote projects
20068        self.update(cx, |project, cx| {
20069            if project
20070                .active_debug_session(cx)
20071                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20072            {
20073                return true;
20074            }
20075
20076            buffer.update(cx, |buffer, cx| {
20077                project.any_language_server_supports_inlay_hints(buffer, cx)
20078            })
20079        })
20080    }
20081
20082    fn inline_values(
20083        &self,
20084        buffer_handle: Entity<Buffer>,
20085
20086        range: Range<text::Anchor>,
20087        cx: &mut App,
20088    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20089        self.update(cx, |project, cx| {
20090            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20091
20092            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20093        })
20094    }
20095
20096    fn inlay_hints(
20097        &self,
20098        buffer_handle: Entity<Buffer>,
20099        range: Range<text::Anchor>,
20100        cx: &mut App,
20101    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20102        Some(self.update(cx, |project, cx| {
20103            project.inlay_hints(buffer_handle, range, cx)
20104        }))
20105    }
20106
20107    fn resolve_inlay_hint(
20108        &self,
20109        hint: InlayHint,
20110        buffer_handle: Entity<Buffer>,
20111        server_id: LanguageServerId,
20112        cx: &mut App,
20113    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20114        Some(self.update(cx, |project, cx| {
20115            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20116        }))
20117    }
20118
20119    fn range_for_rename(
20120        &self,
20121        buffer: &Entity<Buffer>,
20122        position: text::Anchor,
20123        cx: &mut App,
20124    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20125        Some(self.update(cx, |project, cx| {
20126            let buffer = buffer.clone();
20127            let task = project.prepare_rename(buffer.clone(), position, cx);
20128            cx.spawn(async move |_, cx| {
20129                Ok(match task.await? {
20130                    PrepareRenameResponse::Success(range) => Some(range),
20131                    PrepareRenameResponse::InvalidPosition => None,
20132                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20133                        // Fallback on using TreeSitter info to determine identifier range
20134                        buffer.read_with(cx, |buffer, _| {
20135                            let snapshot = buffer.snapshot();
20136                            let (range, kind) = snapshot.surrounding_word(position);
20137                            if kind != Some(CharKind::Word) {
20138                                return None;
20139                            }
20140                            Some(
20141                                snapshot.anchor_before(range.start)
20142                                    ..snapshot.anchor_after(range.end),
20143                            )
20144                        })?
20145                    }
20146                })
20147            })
20148        }))
20149    }
20150
20151    fn perform_rename(
20152        &self,
20153        buffer: &Entity<Buffer>,
20154        position: text::Anchor,
20155        new_name: String,
20156        cx: &mut App,
20157    ) -> Option<Task<Result<ProjectTransaction>>> {
20158        Some(self.update(cx, |project, cx| {
20159            project.perform_rename(buffer.clone(), position, new_name, cx)
20160        }))
20161    }
20162}
20163
20164fn inlay_hint_settings(
20165    location: Anchor,
20166    snapshot: &MultiBufferSnapshot,
20167    cx: &mut Context<Editor>,
20168) -> InlayHintSettings {
20169    let file = snapshot.file_at(location);
20170    let language = snapshot.language_at(location).map(|l| l.name());
20171    language_settings(language, file, cx).inlay_hints
20172}
20173
20174fn consume_contiguous_rows(
20175    contiguous_row_selections: &mut Vec<Selection<Point>>,
20176    selection: &Selection<Point>,
20177    display_map: &DisplaySnapshot,
20178    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20179) -> (MultiBufferRow, MultiBufferRow) {
20180    contiguous_row_selections.push(selection.clone());
20181    let start_row = MultiBufferRow(selection.start.row);
20182    let mut end_row = ending_row(selection, display_map);
20183
20184    while let Some(next_selection) = selections.peek() {
20185        if next_selection.start.row <= end_row.0 {
20186            end_row = ending_row(next_selection, display_map);
20187            contiguous_row_selections.push(selections.next().unwrap().clone());
20188        } else {
20189            break;
20190        }
20191    }
20192    (start_row, end_row)
20193}
20194
20195fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20196    if next_selection.end.column > 0 || next_selection.is_empty() {
20197        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20198    } else {
20199        MultiBufferRow(next_selection.end.row)
20200    }
20201}
20202
20203impl EditorSnapshot {
20204    pub fn remote_selections_in_range<'a>(
20205        &'a self,
20206        range: &'a Range<Anchor>,
20207        collaboration_hub: &dyn CollaborationHub,
20208        cx: &'a App,
20209    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20210        let participant_names = collaboration_hub.user_names(cx);
20211        let participant_indices = collaboration_hub.user_participant_indices(cx);
20212        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20213        let collaborators_by_replica_id = collaborators_by_peer_id
20214            .values()
20215            .map(|collaborator| (collaborator.replica_id, collaborator))
20216            .collect::<HashMap<_, _>>();
20217        self.buffer_snapshot
20218            .selections_in_range(range, false)
20219            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20220                if replica_id == AGENT_REPLICA_ID {
20221                    Some(RemoteSelection {
20222                        replica_id,
20223                        selection,
20224                        cursor_shape,
20225                        line_mode,
20226                        collaborator_id: CollaboratorId::Agent,
20227                        user_name: Some("Agent".into()),
20228                        color: cx.theme().players().agent(),
20229                    })
20230                } else {
20231                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20232                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20233                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20234                    Some(RemoteSelection {
20235                        replica_id,
20236                        selection,
20237                        cursor_shape,
20238                        line_mode,
20239                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20240                        user_name,
20241                        color: if let Some(index) = participant_index {
20242                            cx.theme().players().color_for_participant(index.0)
20243                        } else {
20244                            cx.theme().players().absent()
20245                        },
20246                    })
20247                }
20248            })
20249    }
20250
20251    pub fn hunks_for_ranges(
20252        &self,
20253        ranges: impl IntoIterator<Item = Range<Point>>,
20254    ) -> Vec<MultiBufferDiffHunk> {
20255        let mut hunks = Vec::new();
20256        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20257            HashMap::default();
20258        for query_range in ranges {
20259            let query_rows =
20260                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20261            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20262                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20263            ) {
20264                // Include deleted hunks that are adjacent to the query range, because
20265                // otherwise they would be missed.
20266                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20267                if hunk.status().is_deleted() {
20268                    intersects_range |= hunk.row_range.start == query_rows.end;
20269                    intersects_range |= hunk.row_range.end == query_rows.start;
20270                }
20271                if intersects_range {
20272                    if !processed_buffer_rows
20273                        .entry(hunk.buffer_id)
20274                        .or_default()
20275                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20276                    {
20277                        continue;
20278                    }
20279                    hunks.push(hunk);
20280                }
20281            }
20282        }
20283
20284        hunks
20285    }
20286
20287    fn display_diff_hunks_for_rows<'a>(
20288        &'a self,
20289        display_rows: Range<DisplayRow>,
20290        folded_buffers: &'a HashSet<BufferId>,
20291    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20292        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20293        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20294
20295        self.buffer_snapshot
20296            .diff_hunks_in_range(buffer_start..buffer_end)
20297            .filter_map(|hunk| {
20298                if folded_buffers.contains(&hunk.buffer_id) {
20299                    return None;
20300                }
20301
20302                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20303                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20304
20305                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20306                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20307
20308                let display_hunk = if hunk_display_start.column() != 0 {
20309                    DisplayDiffHunk::Folded {
20310                        display_row: hunk_display_start.row(),
20311                    }
20312                } else {
20313                    let mut end_row = hunk_display_end.row();
20314                    if hunk_display_end.column() > 0 {
20315                        end_row.0 += 1;
20316                    }
20317                    let is_created_file = hunk.is_created_file();
20318                    DisplayDiffHunk::Unfolded {
20319                        status: hunk.status(),
20320                        diff_base_byte_range: hunk.diff_base_byte_range,
20321                        display_row_range: hunk_display_start.row()..end_row,
20322                        multi_buffer_range: Anchor::range_in_buffer(
20323                            hunk.excerpt_id,
20324                            hunk.buffer_id,
20325                            hunk.buffer_range,
20326                        ),
20327                        is_created_file,
20328                    }
20329                };
20330
20331                Some(display_hunk)
20332            })
20333    }
20334
20335    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20336        self.display_snapshot.buffer_snapshot.language_at(position)
20337    }
20338
20339    pub fn is_focused(&self) -> bool {
20340        self.is_focused
20341    }
20342
20343    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20344        self.placeholder_text.as_ref()
20345    }
20346
20347    pub fn scroll_position(&self) -> gpui::Point<f32> {
20348        self.scroll_anchor.scroll_position(&self.display_snapshot)
20349    }
20350
20351    fn gutter_dimensions(
20352        &self,
20353        font_id: FontId,
20354        font_size: Pixels,
20355        max_line_number_width: Pixels,
20356        cx: &App,
20357    ) -> Option<GutterDimensions> {
20358        if !self.show_gutter {
20359            return None;
20360        }
20361
20362        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20363        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20364
20365        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20366            matches!(
20367                ProjectSettings::get_global(cx).git.git_gutter,
20368                Some(GitGutterSetting::TrackedFiles)
20369            )
20370        });
20371        let gutter_settings = EditorSettings::get_global(cx).gutter;
20372        let show_line_numbers = self
20373            .show_line_numbers
20374            .unwrap_or(gutter_settings.line_numbers);
20375        let line_gutter_width = if show_line_numbers {
20376            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20377            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20378            max_line_number_width.max(min_width_for_number_on_gutter)
20379        } else {
20380            0.0.into()
20381        };
20382
20383        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20384        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20385
20386        let git_blame_entries_width =
20387            self.git_blame_gutter_max_author_length
20388                .map(|max_author_length| {
20389                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20390                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20391
20392                    /// The number of characters to dedicate to gaps and margins.
20393                    const SPACING_WIDTH: usize = 4;
20394
20395                    let max_char_count = max_author_length.min(renderer.max_author_length())
20396                        + ::git::SHORT_SHA_LENGTH
20397                        + MAX_RELATIVE_TIMESTAMP.len()
20398                        + SPACING_WIDTH;
20399
20400                    em_advance * max_char_count
20401                });
20402
20403        let is_singleton = self.buffer_snapshot.is_singleton();
20404
20405        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20406        left_padding += if !is_singleton {
20407            em_width * 4.0
20408        } else if show_runnables || show_breakpoints {
20409            em_width * 3.0
20410        } else if show_git_gutter && show_line_numbers {
20411            em_width * 2.0
20412        } else if show_git_gutter || show_line_numbers {
20413            em_width
20414        } else {
20415            px(0.)
20416        };
20417
20418        let shows_folds = is_singleton && gutter_settings.folds;
20419
20420        let right_padding = if shows_folds && show_line_numbers {
20421            em_width * 4.0
20422        } else if shows_folds || (!is_singleton && show_line_numbers) {
20423            em_width * 3.0
20424        } else if show_line_numbers {
20425            em_width
20426        } else {
20427            px(0.)
20428        };
20429
20430        Some(GutterDimensions {
20431            left_padding,
20432            right_padding,
20433            width: line_gutter_width + left_padding + right_padding,
20434            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20435            git_blame_entries_width,
20436        })
20437    }
20438
20439    pub fn render_crease_toggle(
20440        &self,
20441        buffer_row: MultiBufferRow,
20442        row_contains_cursor: bool,
20443        editor: Entity<Editor>,
20444        window: &mut Window,
20445        cx: &mut App,
20446    ) -> Option<AnyElement> {
20447        let folded = self.is_line_folded(buffer_row);
20448        let mut is_foldable = false;
20449
20450        if let Some(crease) = self
20451            .crease_snapshot
20452            .query_row(buffer_row, &self.buffer_snapshot)
20453        {
20454            is_foldable = true;
20455            match crease {
20456                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20457                    if let Some(render_toggle) = render_toggle {
20458                        let toggle_callback =
20459                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20460                                if folded {
20461                                    editor.update(cx, |editor, cx| {
20462                                        editor.fold_at(buffer_row, window, cx)
20463                                    });
20464                                } else {
20465                                    editor.update(cx, |editor, cx| {
20466                                        editor.unfold_at(buffer_row, window, cx)
20467                                    });
20468                                }
20469                            });
20470                        return Some((render_toggle)(
20471                            buffer_row,
20472                            folded,
20473                            toggle_callback,
20474                            window,
20475                            cx,
20476                        ));
20477                    }
20478                }
20479            }
20480        }
20481
20482        is_foldable |= self.starts_indent(buffer_row);
20483
20484        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20485            Some(
20486                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20487                    .toggle_state(folded)
20488                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20489                        if folded {
20490                            this.unfold_at(buffer_row, window, cx);
20491                        } else {
20492                            this.fold_at(buffer_row, window, cx);
20493                        }
20494                    }))
20495                    .into_any_element(),
20496            )
20497        } else {
20498            None
20499        }
20500    }
20501
20502    pub fn render_crease_trailer(
20503        &self,
20504        buffer_row: MultiBufferRow,
20505        window: &mut Window,
20506        cx: &mut App,
20507    ) -> Option<AnyElement> {
20508        let folded = self.is_line_folded(buffer_row);
20509        if let Crease::Inline { render_trailer, .. } = self
20510            .crease_snapshot
20511            .query_row(buffer_row, &self.buffer_snapshot)?
20512        {
20513            let render_trailer = render_trailer.as_ref()?;
20514            Some(render_trailer(buffer_row, folded, window, cx))
20515        } else {
20516            None
20517        }
20518    }
20519}
20520
20521impl Deref for EditorSnapshot {
20522    type Target = DisplaySnapshot;
20523
20524    fn deref(&self) -> &Self::Target {
20525        &self.display_snapshot
20526    }
20527}
20528
20529#[derive(Clone, Debug, PartialEq, Eq)]
20530pub enum EditorEvent {
20531    InputIgnored {
20532        text: Arc<str>,
20533    },
20534    InputHandled {
20535        utf16_range_to_replace: Option<Range<isize>>,
20536        text: Arc<str>,
20537    },
20538    ExcerptsAdded {
20539        buffer: Entity<Buffer>,
20540        predecessor: ExcerptId,
20541        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20542    },
20543    ExcerptsRemoved {
20544        ids: Vec<ExcerptId>,
20545        removed_buffer_ids: Vec<BufferId>,
20546    },
20547    BufferFoldToggled {
20548        ids: Vec<ExcerptId>,
20549        folded: bool,
20550    },
20551    ExcerptsEdited {
20552        ids: Vec<ExcerptId>,
20553    },
20554    ExcerptsExpanded {
20555        ids: Vec<ExcerptId>,
20556    },
20557    BufferEdited,
20558    Edited {
20559        transaction_id: clock::Lamport,
20560    },
20561    Reparsed(BufferId),
20562    Focused,
20563    FocusedIn,
20564    Blurred,
20565    DirtyChanged,
20566    Saved,
20567    TitleChanged,
20568    DiffBaseChanged,
20569    SelectionsChanged {
20570        local: bool,
20571    },
20572    ScrollPositionChanged {
20573        local: bool,
20574        autoscroll: bool,
20575    },
20576    Closed,
20577    TransactionUndone {
20578        transaction_id: clock::Lamport,
20579    },
20580    TransactionBegun {
20581        transaction_id: clock::Lamport,
20582    },
20583    Reloaded,
20584    CursorShapeChanged,
20585    PushedToNavHistory {
20586        anchor: Anchor,
20587        is_deactivate: bool,
20588    },
20589}
20590
20591impl EventEmitter<EditorEvent> for Editor {}
20592
20593impl Focusable for Editor {
20594    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20595        self.focus_handle.clone()
20596    }
20597}
20598
20599impl Render for Editor {
20600    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20601        let settings = ThemeSettings::get_global(cx);
20602
20603        let mut text_style = match self.mode {
20604            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20605                color: cx.theme().colors().editor_foreground,
20606                font_family: settings.ui_font.family.clone(),
20607                font_features: settings.ui_font.features.clone(),
20608                font_fallbacks: settings.ui_font.fallbacks.clone(),
20609                font_size: rems(0.875).into(),
20610                font_weight: settings.ui_font.weight,
20611                line_height: relative(settings.buffer_line_height.value()),
20612                ..Default::default()
20613            },
20614            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20615                color: cx.theme().colors().editor_foreground,
20616                font_family: settings.buffer_font.family.clone(),
20617                font_features: settings.buffer_font.features.clone(),
20618                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20619                font_size: settings.buffer_font_size(cx).into(),
20620                font_weight: settings.buffer_font.weight,
20621                line_height: relative(settings.buffer_line_height.value()),
20622                ..Default::default()
20623            },
20624        };
20625        if let Some(text_style_refinement) = &self.text_style_refinement {
20626            text_style.refine(text_style_refinement)
20627        }
20628
20629        let background = match self.mode {
20630            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20631            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20632            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20633            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20634        };
20635
20636        EditorElement::new(
20637            &cx.entity(),
20638            EditorStyle {
20639                background,
20640                local_player: cx.theme().players().local(),
20641                text: text_style,
20642                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20643                syntax: cx.theme().syntax().clone(),
20644                status: cx.theme().status().clone(),
20645                inlay_hints_style: make_inlay_hints_style(cx),
20646                inline_completion_styles: make_suggestion_styles(cx),
20647                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20648                show_underlines: !self.mode.is_minimap(),
20649            },
20650        )
20651    }
20652}
20653
20654impl EntityInputHandler for Editor {
20655    fn text_for_range(
20656        &mut self,
20657        range_utf16: Range<usize>,
20658        adjusted_range: &mut Option<Range<usize>>,
20659        _: &mut Window,
20660        cx: &mut Context<Self>,
20661    ) -> Option<String> {
20662        let snapshot = self.buffer.read(cx).read(cx);
20663        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20664        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20665        if (start.0..end.0) != range_utf16 {
20666            adjusted_range.replace(start.0..end.0);
20667        }
20668        Some(snapshot.text_for_range(start..end).collect())
20669    }
20670
20671    fn selected_text_range(
20672        &mut self,
20673        ignore_disabled_input: bool,
20674        _: &mut Window,
20675        cx: &mut Context<Self>,
20676    ) -> Option<UTF16Selection> {
20677        // Prevent the IME menu from appearing when holding down an alphabetic key
20678        // while input is disabled.
20679        if !ignore_disabled_input && !self.input_enabled {
20680            return None;
20681        }
20682
20683        let selection = self.selections.newest::<OffsetUtf16>(cx);
20684        let range = selection.range();
20685
20686        Some(UTF16Selection {
20687            range: range.start.0..range.end.0,
20688            reversed: selection.reversed,
20689        })
20690    }
20691
20692    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20693        let snapshot = self.buffer.read(cx).read(cx);
20694        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20695        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20696    }
20697
20698    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20699        self.clear_highlights::<InputComposition>(cx);
20700        self.ime_transaction.take();
20701    }
20702
20703    fn replace_text_in_range(
20704        &mut self,
20705        range_utf16: Option<Range<usize>>,
20706        text: &str,
20707        window: &mut Window,
20708        cx: &mut Context<Self>,
20709    ) {
20710        if !self.input_enabled {
20711            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20712            return;
20713        }
20714
20715        self.transact(window, cx, |this, window, cx| {
20716            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20717                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20718                Some(this.selection_replacement_ranges(range_utf16, cx))
20719            } else {
20720                this.marked_text_ranges(cx)
20721            };
20722
20723            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20724                let newest_selection_id = this.selections.newest_anchor().id;
20725                this.selections
20726                    .all::<OffsetUtf16>(cx)
20727                    .iter()
20728                    .zip(ranges_to_replace.iter())
20729                    .find_map(|(selection, range)| {
20730                        if selection.id == newest_selection_id {
20731                            Some(
20732                                (range.start.0 as isize - selection.head().0 as isize)
20733                                    ..(range.end.0 as isize - selection.head().0 as isize),
20734                            )
20735                        } else {
20736                            None
20737                        }
20738                    })
20739            });
20740
20741            cx.emit(EditorEvent::InputHandled {
20742                utf16_range_to_replace: range_to_replace,
20743                text: text.into(),
20744            });
20745
20746            if let Some(new_selected_ranges) = new_selected_ranges {
20747                this.change_selections(None, window, cx, |selections| {
20748                    selections.select_ranges(new_selected_ranges)
20749                });
20750                this.backspace(&Default::default(), window, cx);
20751            }
20752
20753            this.handle_input(text, window, cx);
20754        });
20755
20756        if let Some(transaction) = self.ime_transaction {
20757            self.buffer.update(cx, |buffer, cx| {
20758                buffer.group_until_transaction(transaction, cx);
20759            });
20760        }
20761
20762        self.unmark_text(window, cx);
20763    }
20764
20765    fn replace_and_mark_text_in_range(
20766        &mut self,
20767        range_utf16: Option<Range<usize>>,
20768        text: &str,
20769        new_selected_range_utf16: Option<Range<usize>>,
20770        window: &mut Window,
20771        cx: &mut Context<Self>,
20772    ) {
20773        if !self.input_enabled {
20774            return;
20775        }
20776
20777        let transaction = self.transact(window, cx, |this, window, cx| {
20778            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20779                let snapshot = this.buffer.read(cx).read(cx);
20780                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20781                    for marked_range in &mut marked_ranges {
20782                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20783                        marked_range.start.0 += relative_range_utf16.start;
20784                        marked_range.start =
20785                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20786                        marked_range.end =
20787                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20788                    }
20789                }
20790                Some(marked_ranges)
20791            } else if let Some(range_utf16) = range_utf16 {
20792                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20793                Some(this.selection_replacement_ranges(range_utf16, cx))
20794            } else {
20795                None
20796            };
20797
20798            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20799                let newest_selection_id = this.selections.newest_anchor().id;
20800                this.selections
20801                    .all::<OffsetUtf16>(cx)
20802                    .iter()
20803                    .zip(ranges_to_replace.iter())
20804                    .find_map(|(selection, range)| {
20805                        if selection.id == newest_selection_id {
20806                            Some(
20807                                (range.start.0 as isize - selection.head().0 as isize)
20808                                    ..(range.end.0 as isize - selection.head().0 as isize),
20809                            )
20810                        } else {
20811                            None
20812                        }
20813                    })
20814            });
20815
20816            cx.emit(EditorEvent::InputHandled {
20817                utf16_range_to_replace: range_to_replace,
20818                text: text.into(),
20819            });
20820
20821            if let Some(ranges) = ranges_to_replace {
20822                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20823            }
20824
20825            let marked_ranges = {
20826                let snapshot = this.buffer.read(cx).read(cx);
20827                this.selections
20828                    .disjoint_anchors()
20829                    .iter()
20830                    .map(|selection| {
20831                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20832                    })
20833                    .collect::<Vec<_>>()
20834            };
20835
20836            if text.is_empty() {
20837                this.unmark_text(window, cx);
20838            } else {
20839                this.highlight_text::<InputComposition>(
20840                    marked_ranges.clone(),
20841                    HighlightStyle {
20842                        underline: Some(UnderlineStyle {
20843                            thickness: px(1.),
20844                            color: None,
20845                            wavy: false,
20846                        }),
20847                        ..Default::default()
20848                    },
20849                    cx,
20850                );
20851            }
20852
20853            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
20854            let use_autoclose = this.use_autoclose;
20855            let use_auto_surround = this.use_auto_surround;
20856            this.set_use_autoclose(false);
20857            this.set_use_auto_surround(false);
20858            this.handle_input(text, window, cx);
20859            this.set_use_autoclose(use_autoclose);
20860            this.set_use_auto_surround(use_auto_surround);
20861
20862            if let Some(new_selected_range) = new_selected_range_utf16 {
20863                let snapshot = this.buffer.read(cx).read(cx);
20864                let new_selected_ranges = marked_ranges
20865                    .into_iter()
20866                    .map(|marked_range| {
20867                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
20868                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
20869                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
20870                        snapshot.clip_offset_utf16(new_start, Bias::Left)
20871                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
20872                    })
20873                    .collect::<Vec<_>>();
20874
20875                drop(snapshot);
20876                this.change_selections(None, window, cx, |selections| {
20877                    selections.select_ranges(new_selected_ranges)
20878                });
20879            }
20880        });
20881
20882        self.ime_transaction = self.ime_transaction.or(transaction);
20883        if let Some(transaction) = self.ime_transaction {
20884            self.buffer.update(cx, |buffer, cx| {
20885                buffer.group_until_transaction(transaction, cx);
20886            });
20887        }
20888
20889        if self.text_highlights::<InputComposition>(cx).is_none() {
20890            self.ime_transaction.take();
20891        }
20892    }
20893
20894    fn bounds_for_range(
20895        &mut self,
20896        range_utf16: Range<usize>,
20897        element_bounds: gpui::Bounds<Pixels>,
20898        window: &mut Window,
20899        cx: &mut Context<Self>,
20900    ) -> Option<gpui::Bounds<Pixels>> {
20901        let text_layout_details = self.text_layout_details(window);
20902        let gpui::Size {
20903            width: em_width,
20904            height: line_height,
20905        } = self.character_size(window);
20906
20907        let snapshot = self.snapshot(window, cx);
20908        let scroll_position = snapshot.scroll_position();
20909        let scroll_left = scroll_position.x * em_width;
20910
20911        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
20912        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
20913            + self.gutter_dimensions.width
20914            + self.gutter_dimensions.margin;
20915        let y = line_height * (start.row().as_f32() - scroll_position.y);
20916
20917        Some(Bounds {
20918            origin: element_bounds.origin + point(x, y),
20919            size: size(em_width, line_height),
20920        })
20921    }
20922
20923    fn character_index_for_point(
20924        &mut self,
20925        point: gpui::Point<Pixels>,
20926        _window: &mut Window,
20927        _cx: &mut Context<Self>,
20928    ) -> Option<usize> {
20929        let position_map = self.last_position_map.as_ref()?;
20930        if !position_map.text_hitbox.contains(&point) {
20931            return None;
20932        }
20933        let display_point = position_map.point_for_position(point).previous_valid;
20934        let anchor = position_map
20935            .snapshot
20936            .display_point_to_anchor(display_point, Bias::Left);
20937        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
20938        Some(utf16_offset.0)
20939    }
20940}
20941
20942trait SelectionExt {
20943    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
20944    fn spanned_rows(
20945        &self,
20946        include_end_if_at_line_start: bool,
20947        map: &DisplaySnapshot,
20948    ) -> Range<MultiBufferRow>;
20949}
20950
20951impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
20952    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
20953        let start = self
20954            .start
20955            .to_point(&map.buffer_snapshot)
20956            .to_display_point(map);
20957        let end = self
20958            .end
20959            .to_point(&map.buffer_snapshot)
20960            .to_display_point(map);
20961        if self.reversed {
20962            end..start
20963        } else {
20964            start..end
20965        }
20966    }
20967
20968    fn spanned_rows(
20969        &self,
20970        include_end_if_at_line_start: bool,
20971        map: &DisplaySnapshot,
20972    ) -> Range<MultiBufferRow> {
20973        let start = self.start.to_point(&map.buffer_snapshot);
20974        let mut end = self.end.to_point(&map.buffer_snapshot);
20975        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
20976            end.row -= 1;
20977        }
20978
20979        let buffer_start = map.prev_line_boundary(start).0;
20980        let buffer_end = map.next_line_boundary(end).0;
20981        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
20982    }
20983}
20984
20985impl<T: InvalidationRegion> InvalidationStack<T> {
20986    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
20987    where
20988        S: Clone + ToOffset,
20989    {
20990        while let Some(region) = self.last() {
20991            let all_selections_inside_invalidation_ranges =
20992                if selections.len() == region.ranges().len() {
20993                    selections
20994                        .iter()
20995                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
20996                        .all(|(selection, invalidation_range)| {
20997                            let head = selection.head().to_offset(buffer);
20998                            invalidation_range.start <= head && invalidation_range.end >= head
20999                        })
21000                } else {
21001                    false
21002                };
21003
21004            if all_selections_inside_invalidation_ranges {
21005                break;
21006            } else {
21007                self.pop();
21008            }
21009        }
21010    }
21011}
21012
21013impl<T> Default for InvalidationStack<T> {
21014    fn default() -> Self {
21015        Self(Default::default())
21016    }
21017}
21018
21019impl<T> Deref for InvalidationStack<T> {
21020    type Target = Vec<T>;
21021
21022    fn deref(&self) -> &Self::Target {
21023        &self.0
21024    }
21025}
21026
21027impl<T> DerefMut for InvalidationStack<T> {
21028    fn deref_mut(&mut self) -> &mut Self::Target {
21029        &mut self.0
21030    }
21031}
21032
21033impl InvalidationRegion for SnippetState {
21034    fn ranges(&self) -> &[Range<Anchor>] {
21035        &self.ranges[self.active_index]
21036    }
21037}
21038
21039fn inline_completion_edit_text(
21040    current_snapshot: &BufferSnapshot,
21041    edits: &[(Range<Anchor>, String)],
21042    edit_preview: &EditPreview,
21043    include_deletions: bool,
21044    cx: &App,
21045) -> HighlightedText {
21046    let edits = edits
21047        .iter()
21048        .map(|(anchor, text)| {
21049            (
21050                anchor.start.text_anchor..anchor.end.text_anchor,
21051                text.clone(),
21052            )
21053        })
21054        .collect::<Vec<_>>();
21055
21056    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21057}
21058
21059pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21060    match severity {
21061        lsp::DiagnosticSeverity::ERROR => colors.error,
21062        lsp::DiagnosticSeverity::WARNING => colors.warning,
21063        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21064        lsp::DiagnosticSeverity::HINT => colors.info,
21065        _ => colors.ignored,
21066    }
21067}
21068
21069pub fn styled_runs_for_code_label<'a>(
21070    label: &'a CodeLabel,
21071    syntax_theme: &'a theme::SyntaxTheme,
21072) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21073    let fade_out = HighlightStyle {
21074        fade_out: Some(0.35),
21075        ..Default::default()
21076    };
21077
21078    let mut prev_end = label.filter_range.end;
21079    label
21080        .runs
21081        .iter()
21082        .enumerate()
21083        .flat_map(move |(ix, (range, highlight_id))| {
21084            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21085                style
21086            } else {
21087                return Default::default();
21088            };
21089            let mut muted_style = style;
21090            muted_style.highlight(fade_out);
21091
21092            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21093            if range.start >= label.filter_range.end {
21094                if range.start > prev_end {
21095                    runs.push((prev_end..range.start, fade_out));
21096                }
21097                runs.push((range.clone(), muted_style));
21098            } else if range.end <= label.filter_range.end {
21099                runs.push((range.clone(), style));
21100            } else {
21101                runs.push((range.start..label.filter_range.end, style));
21102                runs.push((label.filter_range.end..range.end, muted_style));
21103            }
21104            prev_end = cmp::max(prev_end, range.end);
21105
21106            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21107                runs.push((prev_end..label.text.len(), fade_out));
21108            }
21109
21110            runs
21111        })
21112}
21113
21114pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21115    let mut prev_index = 0;
21116    let mut prev_codepoint: Option<char> = None;
21117    text.char_indices()
21118        .chain([(text.len(), '\0')])
21119        .filter_map(move |(index, codepoint)| {
21120            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21121            let is_boundary = index == text.len()
21122                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21123                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21124            if is_boundary {
21125                let chunk = &text[prev_index..index];
21126                prev_index = index;
21127                Some(chunk)
21128            } else {
21129                None
21130            }
21131        })
21132}
21133
21134pub trait RangeToAnchorExt: Sized {
21135    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21136
21137    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21138        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21139        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21140    }
21141}
21142
21143impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21144    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21145        let start_offset = self.start.to_offset(snapshot);
21146        let end_offset = self.end.to_offset(snapshot);
21147        if start_offset == end_offset {
21148            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21149        } else {
21150            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21151        }
21152    }
21153}
21154
21155pub trait RowExt {
21156    fn as_f32(&self) -> f32;
21157
21158    fn next_row(&self) -> Self;
21159
21160    fn previous_row(&self) -> Self;
21161
21162    fn minus(&self, other: Self) -> u32;
21163}
21164
21165impl RowExt for DisplayRow {
21166    fn as_f32(&self) -> f32 {
21167        self.0 as f32
21168    }
21169
21170    fn next_row(&self) -> Self {
21171        Self(self.0 + 1)
21172    }
21173
21174    fn previous_row(&self) -> Self {
21175        Self(self.0.saturating_sub(1))
21176    }
21177
21178    fn minus(&self, other: Self) -> u32 {
21179        self.0 - other.0
21180    }
21181}
21182
21183impl RowExt for MultiBufferRow {
21184    fn as_f32(&self) -> f32 {
21185        self.0 as f32
21186    }
21187
21188    fn next_row(&self) -> Self {
21189        Self(self.0 + 1)
21190    }
21191
21192    fn previous_row(&self) -> Self {
21193        Self(self.0.saturating_sub(1))
21194    }
21195
21196    fn minus(&self, other: Self) -> u32 {
21197        self.0 - other.0
21198    }
21199}
21200
21201trait RowRangeExt {
21202    type Row;
21203
21204    fn len(&self) -> usize;
21205
21206    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21207}
21208
21209impl RowRangeExt for Range<MultiBufferRow> {
21210    type Row = MultiBufferRow;
21211
21212    fn len(&self) -> usize {
21213        (self.end.0 - self.start.0) as usize
21214    }
21215
21216    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21217        (self.start.0..self.end.0).map(MultiBufferRow)
21218    }
21219}
21220
21221impl RowRangeExt for Range<DisplayRow> {
21222    type Row = DisplayRow;
21223
21224    fn len(&self) -> usize {
21225        (self.end.0 - self.start.0) as usize
21226    }
21227
21228    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21229        (self.start.0..self.end.0).map(DisplayRow)
21230    }
21231}
21232
21233/// If select range has more than one line, we
21234/// just point the cursor to range.start.
21235fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21236    if range.start.row == range.end.row {
21237        range
21238    } else {
21239        range.start..range.start
21240    }
21241}
21242pub struct KillRing(ClipboardItem);
21243impl Global for KillRing {}
21244
21245const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21246
21247enum BreakpointPromptEditAction {
21248    Log,
21249    Condition,
21250    HitCondition,
21251}
21252
21253struct BreakpointPromptEditor {
21254    pub(crate) prompt: Entity<Editor>,
21255    editor: WeakEntity<Editor>,
21256    breakpoint_anchor: Anchor,
21257    breakpoint: Breakpoint,
21258    edit_action: BreakpointPromptEditAction,
21259    block_ids: HashSet<CustomBlockId>,
21260    editor_margins: Arc<Mutex<EditorMargins>>,
21261    _subscriptions: Vec<Subscription>,
21262}
21263
21264impl BreakpointPromptEditor {
21265    const MAX_LINES: u8 = 4;
21266
21267    fn new(
21268        editor: WeakEntity<Editor>,
21269        breakpoint_anchor: Anchor,
21270        breakpoint: Breakpoint,
21271        edit_action: BreakpointPromptEditAction,
21272        window: &mut Window,
21273        cx: &mut Context<Self>,
21274    ) -> Self {
21275        let base_text = match edit_action {
21276            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21277            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21278            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21279        }
21280        .map(|msg| msg.to_string())
21281        .unwrap_or_default();
21282
21283        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21284        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21285
21286        let prompt = cx.new(|cx| {
21287            let mut prompt = Editor::new(
21288                EditorMode::AutoHeight {
21289                    max_lines: Self::MAX_LINES as usize,
21290                },
21291                buffer,
21292                None,
21293                window,
21294                cx,
21295            );
21296            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21297            prompt.set_show_cursor_when_unfocused(false, cx);
21298            prompt.set_placeholder_text(
21299                match edit_action {
21300                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21301                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21302                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21303                },
21304                cx,
21305            );
21306
21307            prompt
21308        });
21309
21310        Self {
21311            prompt,
21312            editor,
21313            breakpoint_anchor,
21314            breakpoint,
21315            edit_action,
21316            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21317            block_ids: Default::default(),
21318            _subscriptions: vec![],
21319        }
21320    }
21321
21322    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21323        self.block_ids.extend(block_ids)
21324    }
21325
21326    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21327        if let Some(editor) = self.editor.upgrade() {
21328            let message = self
21329                .prompt
21330                .read(cx)
21331                .buffer
21332                .read(cx)
21333                .as_singleton()
21334                .expect("A multi buffer in breakpoint prompt isn't possible")
21335                .read(cx)
21336                .as_rope()
21337                .to_string();
21338
21339            editor.update(cx, |editor, cx| {
21340                editor.edit_breakpoint_at_anchor(
21341                    self.breakpoint_anchor,
21342                    self.breakpoint.clone(),
21343                    match self.edit_action {
21344                        BreakpointPromptEditAction::Log => {
21345                            BreakpointEditAction::EditLogMessage(message.into())
21346                        }
21347                        BreakpointPromptEditAction::Condition => {
21348                            BreakpointEditAction::EditCondition(message.into())
21349                        }
21350                        BreakpointPromptEditAction::HitCondition => {
21351                            BreakpointEditAction::EditHitCondition(message.into())
21352                        }
21353                    },
21354                    cx,
21355                );
21356
21357                editor.remove_blocks(self.block_ids.clone(), None, cx);
21358                cx.focus_self(window);
21359            });
21360        }
21361    }
21362
21363    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21364        self.editor
21365            .update(cx, |editor, cx| {
21366                editor.remove_blocks(self.block_ids.clone(), None, cx);
21367                window.focus(&editor.focus_handle);
21368            })
21369            .log_err();
21370    }
21371
21372    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21373        let settings = ThemeSettings::get_global(cx);
21374        let text_style = TextStyle {
21375            color: if self.prompt.read(cx).read_only(cx) {
21376                cx.theme().colors().text_disabled
21377            } else {
21378                cx.theme().colors().text
21379            },
21380            font_family: settings.buffer_font.family.clone(),
21381            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21382            font_size: settings.buffer_font_size(cx).into(),
21383            font_weight: settings.buffer_font.weight,
21384            line_height: relative(settings.buffer_line_height.value()),
21385            ..Default::default()
21386        };
21387        EditorElement::new(
21388            &self.prompt,
21389            EditorStyle {
21390                background: cx.theme().colors().editor_background,
21391                local_player: cx.theme().players().local(),
21392                text: text_style,
21393                ..Default::default()
21394            },
21395        )
21396    }
21397}
21398
21399impl Render for BreakpointPromptEditor {
21400    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21401        let editor_margins = *self.editor_margins.lock();
21402        let gutter_dimensions = editor_margins.gutter;
21403        h_flex()
21404            .key_context("Editor")
21405            .bg(cx.theme().colors().editor_background)
21406            .border_y_1()
21407            .border_color(cx.theme().status().info_border)
21408            .size_full()
21409            .py(window.line_height() / 2.5)
21410            .on_action(cx.listener(Self::confirm))
21411            .on_action(cx.listener(Self::cancel))
21412            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21413            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21414    }
21415}
21416
21417impl Focusable for BreakpointPromptEditor {
21418    fn focus_handle(&self, cx: &App) -> FocusHandle {
21419        self.prompt.focus_handle(cx)
21420    }
21421}
21422
21423fn all_edits_insertions_or_deletions(
21424    edits: &Vec<(Range<Anchor>, String)>,
21425    snapshot: &MultiBufferSnapshot,
21426) -> bool {
21427    let mut all_insertions = true;
21428    let mut all_deletions = true;
21429
21430    for (range, new_text) in edits.iter() {
21431        let range_is_empty = range.to_offset(&snapshot).is_empty();
21432        let text_is_empty = new_text.is_empty();
21433
21434        if range_is_empty != text_is_empty {
21435            if range_is_empty {
21436                all_deletions = false;
21437            } else {
21438                all_insertions = false;
21439            }
21440        } else {
21441            return false;
21442        }
21443
21444        if !all_insertions && !all_deletions {
21445            return false;
21446        }
21447    }
21448    all_insertions || all_deletions
21449}
21450
21451struct MissingEditPredictionKeybindingTooltip;
21452
21453impl Render for MissingEditPredictionKeybindingTooltip {
21454    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21455        ui::tooltip_container(window, cx, |container, _, cx| {
21456            container
21457                .flex_shrink_0()
21458                .max_w_80()
21459                .min_h(rems_from_px(124.))
21460                .justify_between()
21461                .child(
21462                    v_flex()
21463                        .flex_1()
21464                        .text_ui_sm(cx)
21465                        .child(Label::new("Conflict with Accept Keybinding"))
21466                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21467                )
21468                .child(
21469                    h_flex()
21470                        .pb_1()
21471                        .gap_1()
21472                        .items_end()
21473                        .w_full()
21474                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21475                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21476                        }))
21477                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21478                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21479                        })),
21480                )
21481        })
21482    }
21483}
21484
21485#[derive(Debug, Clone, Copy, PartialEq)]
21486pub struct LineHighlight {
21487    pub background: Background,
21488    pub border: Option<gpui::Hsla>,
21489    pub include_gutter: bool,
21490    pub type_id: Option<TypeId>,
21491}
21492
21493fn render_diff_hunk_controls(
21494    row: u32,
21495    status: &DiffHunkStatus,
21496    hunk_range: Range<Anchor>,
21497    is_created_file: bool,
21498    line_height: Pixels,
21499    editor: &Entity<Editor>,
21500    _window: &mut Window,
21501    cx: &mut App,
21502) -> AnyElement {
21503    h_flex()
21504        .h(line_height)
21505        .mr_1()
21506        .gap_1()
21507        .px_0p5()
21508        .pb_1()
21509        .border_x_1()
21510        .border_b_1()
21511        .border_color(cx.theme().colors().border_variant)
21512        .rounded_b_lg()
21513        .bg(cx.theme().colors().editor_background)
21514        .gap_1()
21515        .stop_mouse_events_except_scroll()
21516        .shadow_md()
21517        .child(if status.has_secondary_hunk() {
21518            Button::new(("stage", row as u64), "Stage")
21519                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21520                .tooltip({
21521                    let focus_handle = editor.focus_handle(cx);
21522                    move |window, cx| {
21523                        Tooltip::for_action_in(
21524                            "Stage Hunk",
21525                            &::git::ToggleStaged,
21526                            &focus_handle,
21527                            window,
21528                            cx,
21529                        )
21530                    }
21531                })
21532                .on_click({
21533                    let editor = editor.clone();
21534                    move |_event, _window, cx| {
21535                        editor.update(cx, |editor, cx| {
21536                            editor.stage_or_unstage_diff_hunks(
21537                                true,
21538                                vec![hunk_range.start..hunk_range.start],
21539                                cx,
21540                            );
21541                        });
21542                    }
21543                })
21544        } else {
21545            Button::new(("unstage", row as u64), "Unstage")
21546                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21547                .tooltip({
21548                    let focus_handle = editor.focus_handle(cx);
21549                    move |window, cx| {
21550                        Tooltip::for_action_in(
21551                            "Unstage Hunk",
21552                            &::git::ToggleStaged,
21553                            &focus_handle,
21554                            window,
21555                            cx,
21556                        )
21557                    }
21558                })
21559                .on_click({
21560                    let editor = editor.clone();
21561                    move |_event, _window, cx| {
21562                        editor.update(cx, |editor, cx| {
21563                            editor.stage_or_unstage_diff_hunks(
21564                                false,
21565                                vec![hunk_range.start..hunk_range.start],
21566                                cx,
21567                            );
21568                        });
21569                    }
21570                })
21571        })
21572        .child(
21573            Button::new(("restore", row as u64), "Restore")
21574                .tooltip({
21575                    let focus_handle = editor.focus_handle(cx);
21576                    move |window, cx| {
21577                        Tooltip::for_action_in(
21578                            "Restore Hunk",
21579                            &::git::Restore,
21580                            &focus_handle,
21581                            window,
21582                            cx,
21583                        )
21584                    }
21585                })
21586                .on_click({
21587                    let editor = editor.clone();
21588                    move |_event, window, cx| {
21589                        editor.update(cx, |editor, cx| {
21590                            let snapshot = editor.snapshot(window, cx);
21591                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21592                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21593                        });
21594                    }
21595                })
21596                .disabled(is_created_file),
21597        )
21598        .when(
21599            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21600            |el| {
21601                el.child(
21602                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21603                        .shape(IconButtonShape::Square)
21604                        .icon_size(IconSize::Small)
21605                        // .disabled(!has_multiple_hunks)
21606                        .tooltip({
21607                            let focus_handle = editor.focus_handle(cx);
21608                            move |window, cx| {
21609                                Tooltip::for_action_in(
21610                                    "Next Hunk",
21611                                    &GoToHunk,
21612                                    &focus_handle,
21613                                    window,
21614                                    cx,
21615                                )
21616                            }
21617                        })
21618                        .on_click({
21619                            let editor = editor.clone();
21620                            move |_event, window, cx| {
21621                                editor.update(cx, |editor, cx| {
21622                                    let snapshot = editor.snapshot(window, cx);
21623                                    let position =
21624                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21625                                    editor.go_to_hunk_before_or_after_position(
21626                                        &snapshot,
21627                                        position,
21628                                        Direction::Next,
21629                                        window,
21630                                        cx,
21631                                    );
21632                                    editor.expand_selected_diff_hunks(cx);
21633                                });
21634                            }
21635                        }),
21636                )
21637                .child(
21638                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21639                        .shape(IconButtonShape::Square)
21640                        .icon_size(IconSize::Small)
21641                        // .disabled(!has_multiple_hunks)
21642                        .tooltip({
21643                            let focus_handle = editor.focus_handle(cx);
21644                            move |window, cx| {
21645                                Tooltip::for_action_in(
21646                                    "Previous Hunk",
21647                                    &GoToPreviousHunk,
21648                                    &focus_handle,
21649                                    window,
21650                                    cx,
21651                                )
21652                            }
21653                        })
21654                        .on_click({
21655                            let editor = editor.clone();
21656                            move |_event, window, cx| {
21657                                editor.update(cx, |editor, cx| {
21658                                    let snapshot = editor.snapshot(window, cx);
21659                                    let point =
21660                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21661                                    editor.go_to_hunk_before_or_after_position(
21662                                        &snapshot,
21663                                        point,
21664                                        Direction::Prev,
21665                                        window,
21666                                        cx,
21667                                    );
21668                                    editor.expand_selected_diff_hunks(cx);
21669                                });
21670                            }
21671                        }),
21672                )
21673            },
21674        )
21675        .into_any_element()
21676}