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;
   18mod 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 display_map::*;
   63pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   64pub use editor_settings::{
   65    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   66    ShowScrollbar,
   67};
   68use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   69pub use editor_settings_controls::*;
   70use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   71pub use element::{
   72    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   73};
   74use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   75use futures::{
   76    FutureExt,
   77    future::{self, Shared, join},
   78};
   79use fuzzy::StringMatchCandidate;
   80
   81use ::git::blame::BlameEntry;
   82use ::git::{Restore, blame::ParsedCommitMessage};
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use git::blame::{GitBlame, GlobalBlameRenderer};
   88use gpui::{
   89    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   90    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   91    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   92    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   93    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   94    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   95    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   96    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   97};
   98use highlight_matching_bracket::refresh_matching_bracket_highlights;
   99use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  100pub use hover_popover::hover_markdown_style;
  101use hover_popover::{HoverState, hide_hover};
  102use indent_guides::ActiveIndentGuidesState;
  103use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  104pub use inline_completion::Direction;
  105use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  106pub use items::MAX_TAB_TITLE_LEN;
  107use itertools::Itertools;
  108use language::{
  109    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  110    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  111    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  112    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  113    language_settings::{
  114        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  115        all_language_settings, language_settings,
  116    },
  117    point_from_lsp, text_diff_with_options,
  118};
  119use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  120use linked_editing_ranges::refresh_linked_ranges;
  121use markdown::Markdown;
  122use mouse_context_menu::MouseContextMenu;
  123use persistence::DB;
  124use project::{
  125    BreakpointWithPosition, ProjectPath,
  126    debugger::{
  127        breakpoint_store::{
  128            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  129            BreakpointStoreEvent,
  130        },
  131        session::{Session, SessionEvent},
  132    },
  133    project_settings::DiagnosticSeverity,
  134};
  135
  136pub use git::blame::BlameRenderer;
  137pub use proposed_changes_editor::{
  138    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  139};
  140use smallvec::smallvec;
  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;
  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};
  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(bool),
  720}
  721
  722impl MinimapVisibility {
  723    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  724        if mode.is_full() {
  725            Self::Enabled(EditorSettings::get_global(cx).minimap.minimap_enabled())
  726        } else {
  727            Self::Disabled
  728        }
  729    }
  730
  731    fn disabled(&self) -> bool {
  732        match *self {
  733            Self::Disabled => true,
  734            _ => false,
  735        }
  736    }
  737
  738    fn visible(&self) -> bool {
  739        match *self {
  740            Self::Enabled(visible) => visible,
  741            _ => false,
  742        }
  743    }
  744
  745    fn toggle_visibility(&self) -> Self {
  746        match *self {
  747            Self::Enabled(visible) => Self::Enabled(!visible),
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751}
  752
  753#[derive(Clone, Debug)]
  754struct RunnableTasks {
  755    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  756    offset: multi_buffer::Anchor,
  757    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  758    column: u32,
  759    // Values of all named captures, including those starting with '_'
  760    extra_variables: HashMap<String, String>,
  761    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  762    context_range: Range<BufferOffset>,
  763}
  764
  765impl RunnableTasks {
  766    fn resolve<'a>(
  767        &'a self,
  768        cx: &'a task::TaskContext,
  769    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  770        self.templates.iter().filter_map(|(kind, template)| {
  771            template
  772                .resolve_task(&kind.to_id_base(), cx)
  773                .map(|task| (kind.clone(), task))
  774        })
  775    }
  776}
  777
  778#[derive(Clone)]
  779struct ResolvedTasks {
  780    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  781    position: Anchor,
  782}
  783
  784#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  785struct BufferOffset(usize);
  786
  787// Addons allow storing per-editor state in other crates (e.g. Vim)
  788pub trait Addon: 'static {
  789    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  790
  791    fn render_buffer_header_controls(
  792        &self,
  793        _: &ExcerptInfo,
  794        _: &Window,
  795        _: &App,
  796    ) -> Option<AnyElement> {
  797        None
  798    }
  799
  800    fn to_any(&self) -> &dyn std::any::Any;
  801
  802    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  803        None
  804    }
  805}
  806
  807/// A set of caret positions, registered when the editor was edited.
  808pub struct ChangeList {
  809    changes: Vec<Vec<Anchor>>,
  810    /// Currently "selected" change.
  811    position: Option<usize>,
  812}
  813
  814impl ChangeList {
  815    pub fn new() -> Self {
  816        Self {
  817            changes: Vec::new(),
  818            position: None,
  819        }
  820    }
  821
  822    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  823    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  824    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  825        if self.changes.is_empty() {
  826            return None;
  827        }
  828
  829        let prev = self.position.unwrap_or(self.changes.len());
  830        let next = if direction == Direction::Prev {
  831            prev.saturating_sub(count)
  832        } else {
  833            (prev + count).min(self.changes.len() - 1)
  834        };
  835        self.position = Some(next);
  836        self.changes.get(next).map(|anchors| anchors.as_slice())
  837    }
  838
  839    /// Adds a new change to the list, resetting the change list position.
  840    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  841        self.position.take();
  842        if pop_state {
  843            self.changes.pop();
  844        }
  845        self.changes.push(new_positions.clone());
  846    }
  847
  848    pub fn last(&self) -> Option<&[Anchor]> {
  849        self.changes.last().map(|anchors| anchors.as_slice())
  850    }
  851}
  852
  853#[derive(Clone)]
  854struct InlineBlamePopoverState {
  855    scroll_handle: ScrollHandle,
  856    commit_message: Option<ParsedCommitMessage>,
  857    markdown: Entity<Markdown>,
  858}
  859
  860struct InlineBlamePopover {
  861    position: gpui::Point<Pixels>,
  862    show_task: Option<Task<()>>,
  863    hide_task: Option<Task<()>>,
  864    popover_bounds: Option<Bounds<Pixels>>,
  865    popover_state: InlineBlamePopoverState,
  866}
  867
  868/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  869/// a breakpoint on them.
  870#[derive(Clone, Copy, Debug)]
  871struct PhantomBreakpointIndicator {
  872    display_row: DisplayRow,
  873    /// There's a small debounce between hovering over the line and showing the indicator.
  874    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  875    is_active: bool,
  876    collides_with_existing_breakpoint: bool,
  877}
  878/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  879///
  880/// See the [module level documentation](self) for more information.
  881pub struct Editor {
  882    focus_handle: FocusHandle,
  883    last_focused_descendant: Option<WeakFocusHandle>,
  884    /// The text buffer being edited
  885    buffer: Entity<MultiBuffer>,
  886    /// Map of how text in the buffer should be displayed.
  887    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  888    pub display_map: Entity<DisplayMap>,
  889    pub selections: SelectionsCollection,
  890    pub scroll_manager: ScrollManager,
  891    /// When inline assist editors are linked, they all render cursors because
  892    /// typing enters text into each of them, even the ones that aren't focused.
  893    pub(crate) show_cursor_when_unfocused: bool,
  894    columnar_selection_tail: Option<Anchor>,
  895    add_selections_state: Option<AddSelectionsState>,
  896    select_next_state: Option<SelectNextState>,
  897    select_prev_state: Option<SelectNextState>,
  898    selection_history: SelectionHistory,
  899    autoclose_regions: Vec<AutocloseRegion>,
  900    snippet_stack: InvalidationStack<SnippetState>,
  901    select_syntax_node_history: SelectSyntaxNodeHistory,
  902    ime_transaction: Option<TransactionId>,
  903    pub diagnostics_max_severity: DiagnosticSeverity,
  904    active_diagnostics: ActiveDiagnostic,
  905    show_inline_diagnostics: bool,
  906    inline_diagnostics_update: Task<()>,
  907    inline_diagnostics_enabled: bool,
  908    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  909    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  910    hard_wrap: Option<usize>,
  911
  912    // TODO: make this a access method
  913    pub project: Option<Entity<Project>>,
  914    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  915    completion_provider: Option<Box<dyn CompletionProvider>>,
  916    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  917    blink_manager: Entity<BlinkManager>,
  918    show_cursor_names: bool,
  919    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  920    pub show_local_selections: bool,
  921    mode: EditorMode,
  922    show_breadcrumbs: bool,
  923    show_gutter: bool,
  924    show_scrollbars: bool,
  925    minimap_visibility: MinimapVisibility,
  926    disable_expand_excerpt_buttons: bool,
  927    show_line_numbers: Option<bool>,
  928    use_relative_line_numbers: Option<bool>,
  929    show_git_diff_gutter: Option<bool>,
  930    show_code_actions: Option<bool>,
  931    show_runnables: Option<bool>,
  932    show_breakpoints: Option<bool>,
  933    show_wrap_guides: Option<bool>,
  934    show_indent_guides: Option<bool>,
  935    placeholder_text: Option<Arc<str>>,
  936    highlight_order: usize,
  937    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  938    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  939    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  940    scrollbar_marker_state: ScrollbarMarkerState,
  941    active_indent_guides_state: ActiveIndentGuidesState,
  942    nav_history: Option<ItemNavHistory>,
  943    context_menu: RefCell<Option<CodeContextMenu>>,
  944    context_menu_options: Option<ContextMenuOptions>,
  945    mouse_context_menu: Option<MouseContextMenu>,
  946    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  947    inline_blame_popover: Option<InlineBlamePopover>,
  948    signature_help_state: SignatureHelpState,
  949    auto_signature_help: Option<bool>,
  950    find_all_references_task_sources: Vec<Anchor>,
  951    next_completion_id: CompletionId,
  952    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  953    code_actions_task: Option<Task<Result<()>>>,
  954    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  955    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  956    document_highlights_task: Option<Task<()>>,
  957    linked_editing_range_task: Option<Task<Option<()>>>,
  958    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  959    pending_rename: Option<RenameState>,
  960    searchable: bool,
  961    cursor_shape: CursorShape,
  962    current_line_highlight: Option<CurrentLineHighlight>,
  963    collapse_matches: bool,
  964    autoindent_mode: Option<AutoindentMode>,
  965    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  966    input_enabled: bool,
  967    use_modal_editing: bool,
  968    read_only: bool,
  969    leader_id: Option<CollaboratorId>,
  970    remote_id: Option<ViewId>,
  971    pub hover_state: HoverState,
  972    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  973    gutter_hovered: bool,
  974    hovered_link_state: Option<HoveredLinkState>,
  975    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  976    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  977    active_inline_completion: Option<InlineCompletionState>,
  978    /// Used to prevent flickering as the user types while the menu is open
  979    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  980    edit_prediction_settings: EditPredictionSettings,
  981    inline_completions_hidden_for_vim_mode: bool,
  982    show_inline_completions_override: Option<bool>,
  983    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  984    edit_prediction_preview: EditPredictionPreview,
  985    edit_prediction_indent_conflict: bool,
  986    edit_prediction_requires_modifier_in_indent_conflict: bool,
  987    inlay_hint_cache: InlayHintCache,
  988    next_inlay_id: usize,
  989    _subscriptions: Vec<Subscription>,
  990    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  991    gutter_dimensions: GutterDimensions,
  992    style: Option<EditorStyle>,
  993    text_style_refinement: Option<TextStyleRefinement>,
  994    next_editor_action_id: EditorActionId,
  995    editor_actions:
  996        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  997    use_autoclose: bool,
  998    use_auto_surround: bool,
  999    auto_replace_emoji_shortcode: bool,
 1000    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1001    show_git_blame_gutter: bool,
 1002    show_git_blame_inline: bool,
 1003    show_git_blame_inline_delay_task: Option<Task<()>>,
 1004    git_blame_inline_enabled: bool,
 1005    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1006    serialize_dirty_buffers: bool,
 1007    show_selection_menu: Option<bool>,
 1008    blame: Option<Entity<GitBlame>>,
 1009    blame_subscription: Option<Subscription>,
 1010    custom_context_menu: Option<
 1011        Box<
 1012            dyn 'static
 1013                + Fn(
 1014                    &mut Self,
 1015                    DisplayPoint,
 1016                    &mut Window,
 1017                    &mut Context<Self>,
 1018                ) -> Option<Entity<ui::ContextMenu>>,
 1019        >,
 1020    >,
 1021    last_bounds: Option<Bounds<Pixels>>,
 1022    last_position_map: Option<Rc<PositionMap>>,
 1023    expect_bounds_change: Option<Bounds<Pixels>>,
 1024    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1025    tasks_update_task: Option<Task<()>>,
 1026    breakpoint_store: Option<Entity<BreakpointStore>>,
 1027    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1028    in_project_search: bool,
 1029    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1030    breadcrumb_header: Option<String>,
 1031    focused_block: Option<FocusedBlock>,
 1032    next_scroll_position: NextScrollCursorCenterTopBottom,
 1033    addons: HashMap<TypeId, Box<dyn Addon>>,
 1034    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1035    load_diff_task: Option<Shared<Task<()>>>,
 1036    /// Whether we are temporarily displaying a diff other than git's
 1037    temporary_diff_override: bool,
 1038    selection_mark_mode: bool,
 1039    toggle_fold_multiple_buffers: Task<()>,
 1040    _scroll_cursor_center_top_bottom_task: Task<()>,
 1041    serialize_selections: Task<()>,
 1042    serialize_folds: Task<()>,
 1043    mouse_cursor_hidden: bool,
 1044    minimap: Option<Entity<Self>>,
 1045    hide_mouse_mode: HideMouseMode,
 1046    pub change_list: ChangeList,
 1047    inline_value_cache: InlineValueCache,
 1048}
 1049
 1050#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1051enum NextScrollCursorCenterTopBottom {
 1052    #[default]
 1053    Center,
 1054    Top,
 1055    Bottom,
 1056}
 1057
 1058impl NextScrollCursorCenterTopBottom {
 1059    fn next(&self) -> Self {
 1060        match self {
 1061            Self::Center => Self::Top,
 1062            Self::Top => Self::Bottom,
 1063            Self::Bottom => Self::Center,
 1064        }
 1065    }
 1066}
 1067
 1068#[derive(Clone)]
 1069pub struct EditorSnapshot {
 1070    pub mode: EditorMode,
 1071    show_gutter: bool,
 1072    show_line_numbers: Option<bool>,
 1073    show_git_diff_gutter: Option<bool>,
 1074    show_runnables: Option<bool>,
 1075    show_breakpoints: Option<bool>,
 1076    git_blame_gutter_max_author_length: Option<usize>,
 1077    pub display_snapshot: DisplaySnapshot,
 1078    pub placeholder_text: Option<Arc<str>>,
 1079    is_focused: bool,
 1080    scroll_anchor: ScrollAnchor,
 1081    ongoing_scroll: OngoingScroll,
 1082    current_line_highlight: CurrentLineHighlight,
 1083    gutter_hovered: bool,
 1084}
 1085
 1086#[derive(Default, Debug, Clone, Copy)]
 1087pub struct GutterDimensions {
 1088    pub left_padding: Pixels,
 1089    pub right_padding: Pixels,
 1090    pub width: Pixels,
 1091    pub margin: Pixels,
 1092    pub git_blame_entries_width: Option<Pixels>,
 1093}
 1094
 1095impl GutterDimensions {
 1096    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1097        Self {
 1098            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1099            ..Default::default()
 1100        }
 1101    }
 1102
 1103    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1104        -cx.text_system().descent(font_id, font_size)
 1105    }
 1106    /// The full width of the space taken up by the gutter.
 1107    pub fn full_width(&self) -> Pixels {
 1108        self.margin + self.width
 1109    }
 1110
 1111    /// The width of the space reserved for the fold indicators,
 1112    /// use alongside 'justify_end' and `gutter_width` to
 1113    /// right align content with the line numbers
 1114    pub fn fold_area_width(&self) -> Pixels {
 1115        self.margin + self.right_padding
 1116    }
 1117}
 1118
 1119#[derive(Debug)]
 1120pub struct RemoteSelection {
 1121    pub replica_id: ReplicaId,
 1122    pub selection: Selection<Anchor>,
 1123    pub cursor_shape: CursorShape,
 1124    pub collaborator_id: CollaboratorId,
 1125    pub line_mode: bool,
 1126    pub user_name: Option<SharedString>,
 1127    pub color: PlayerColor,
 1128}
 1129
 1130#[derive(Clone, Debug)]
 1131struct SelectionHistoryEntry {
 1132    selections: Arc<[Selection<Anchor>]>,
 1133    select_next_state: Option<SelectNextState>,
 1134    select_prev_state: Option<SelectNextState>,
 1135    add_selections_state: Option<AddSelectionsState>,
 1136}
 1137
 1138enum SelectionHistoryMode {
 1139    Normal,
 1140    Undoing,
 1141    Redoing,
 1142}
 1143
 1144#[derive(Clone, PartialEq, Eq, Hash)]
 1145struct HoveredCursor {
 1146    replica_id: u16,
 1147    selection_id: usize,
 1148}
 1149
 1150impl Default for SelectionHistoryMode {
 1151    fn default() -> Self {
 1152        Self::Normal
 1153    }
 1154}
 1155
 1156#[derive(Default)]
 1157struct SelectionHistory {
 1158    #[allow(clippy::type_complexity)]
 1159    selections_by_transaction:
 1160        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1161    mode: SelectionHistoryMode,
 1162    undo_stack: VecDeque<SelectionHistoryEntry>,
 1163    redo_stack: VecDeque<SelectionHistoryEntry>,
 1164}
 1165
 1166impl SelectionHistory {
 1167    fn insert_transaction(
 1168        &mut self,
 1169        transaction_id: TransactionId,
 1170        selections: Arc<[Selection<Anchor>]>,
 1171    ) {
 1172        self.selections_by_transaction
 1173            .insert(transaction_id, (selections, None));
 1174    }
 1175
 1176    #[allow(clippy::type_complexity)]
 1177    fn transaction(
 1178        &self,
 1179        transaction_id: TransactionId,
 1180    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1181        self.selections_by_transaction.get(&transaction_id)
 1182    }
 1183
 1184    #[allow(clippy::type_complexity)]
 1185    fn transaction_mut(
 1186        &mut self,
 1187        transaction_id: TransactionId,
 1188    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1189        self.selections_by_transaction.get_mut(&transaction_id)
 1190    }
 1191
 1192    fn push(&mut self, entry: SelectionHistoryEntry) {
 1193        if !entry.selections.is_empty() {
 1194            match self.mode {
 1195                SelectionHistoryMode::Normal => {
 1196                    self.push_undo(entry);
 1197                    self.redo_stack.clear();
 1198                }
 1199                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1200                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1201            }
 1202        }
 1203    }
 1204
 1205    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1206        if self
 1207            .undo_stack
 1208            .back()
 1209            .map_or(true, |e| e.selections != entry.selections)
 1210        {
 1211            self.undo_stack.push_back(entry);
 1212            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1213                self.undo_stack.pop_front();
 1214            }
 1215        }
 1216    }
 1217
 1218    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1219        if self
 1220            .redo_stack
 1221            .back()
 1222            .map_or(true, |e| e.selections != entry.selections)
 1223        {
 1224            self.redo_stack.push_back(entry);
 1225            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1226                self.redo_stack.pop_front();
 1227            }
 1228        }
 1229    }
 1230}
 1231
 1232#[derive(Clone, Copy)]
 1233pub struct RowHighlightOptions {
 1234    pub autoscroll: bool,
 1235    pub include_gutter: bool,
 1236}
 1237
 1238impl Default for RowHighlightOptions {
 1239    fn default() -> Self {
 1240        Self {
 1241            autoscroll: Default::default(),
 1242            include_gutter: true,
 1243        }
 1244    }
 1245}
 1246
 1247struct RowHighlight {
 1248    index: usize,
 1249    range: Range<Anchor>,
 1250    color: Hsla,
 1251    options: RowHighlightOptions,
 1252    type_id: TypeId,
 1253}
 1254
 1255#[derive(Clone, Debug)]
 1256struct AddSelectionsState {
 1257    above: bool,
 1258    stack: Vec<usize>,
 1259}
 1260
 1261#[derive(Clone)]
 1262struct SelectNextState {
 1263    query: AhoCorasick,
 1264    wordwise: bool,
 1265    done: bool,
 1266}
 1267
 1268impl std::fmt::Debug for SelectNextState {
 1269    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1270        f.debug_struct(std::any::type_name::<Self>())
 1271            .field("wordwise", &self.wordwise)
 1272            .field("done", &self.done)
 1273            .finish()
 1274    }
 1275}
 1276
 1277#[derive(Debug)]
 1278struct AutocloseRegion {
 1279    selection_id: usize,
 1280    range: Range<Anchor>,
 1281    pair: BracketPair,
 1282}
 1283
 1284#[derive(Debug)]
 1285struct SnippetState {
 1286    ranges: Vec<Vec<Range<Anchor>>>,
 1287    active_index: usize,
 1288    choices: Vec<Option<Vec<String>>>,
 1289}
 1290
 1291#[doc(hidden)]
 1292pub struct RenameState {
 1293    pub range: Range<Anchor>,
 1294    pub old_name: Arc<str>,
 1295    pub editor: Entity<Editor>,
 1296    block_id: CustomBlockId,
 1297}
 1298
 1299struct InvalidationStack<T>(Vec<T>);
 1300
 1301struct RegisteredInlineCompletionProvider {
 1302    provider: Arc<dyn InlineCompletionProviderHandle>,
 1303    _subscription: Subscription,
 1304}
 1305
 1306#[derive(Debug, PartialEq, Eq)]
 1307pub struct ActiveDiagnosticGroup {
 1308    pub active_range: Range<Anchor>,
 1309    pub active_message: String,
 1310    pub group_id: usize,
 1311    pub blocks: HashSet<CustomBlockId>,
 1312}
 1313
 1314#[derive(Debug, PartialEq, Eq)]
 1315
 1316pub(crate) enum ActiveDiagnostic {
 1317    None,
 1318    All,
 1319    Group(ActiveDiagnosticGroup),
 1320}
 1321
 1322#[derive(Serialize, Deserialize, Clone, Debug)]
 1323pub struct ClipboardSelection {
 1324    /// The number of bytes in this selection.
 1325    pub len: usize,
 1326    /// Whether this was a full-line selection.
 1327    pub is_entire_line: bool,
 1328    /// The indentation of the first line when this content was originally copied.
 1329    pub first_line_indent: u32,
 1330}
 1331
 1332// selections, scroll behavior, was newest selection reversed
 1333type SelectSyntaxNodeHistoryState = (
 1334    Box<[Selection<usize>]>,
 1335    SelectSyntaxNodeScrollBehavior,
 1336    bool,
 1337);
 1338
 1339#[derive(Default)]
 1340struct SelectSyntaxNodeHistory {
 1341    stack: Vec<SelectSyntaxNodeHistoryState>,
 1342    // disable temporarily to allow changing selections without losing the stack
 1343    pub disable_clearing: bool,
 1344}
 1345
 1346impl SelectSyntaxNodeHistory {
 1347    pub fn try_clear(&mut self) {
 1348        if !self.disable_clearing {
 1349            self.stack.clear();
 1350        }
 1351    }
 1352
 1353    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1354        self.stack.push(selection);
 1355    }
 1356
 1357    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1358        self.stack.pop()
 1359    }
 1360}
 1361
 1362enum SelectSyntaxNodeScrollBehavior {
 1363    CursorTop,
 1364    FitSelection,
 1365    CursorBottom,
 1366}
 1367
 1368#[derive(Debug)]
 1369pub(crate) struct NavigationData {
 1370    cursor_anchor: Anchor,
 1371    cursor_position: Point,
 1372    scroll_anchor: ScrollAnchor,
 1373    scroll_top_row: u32,
 1374}
 1375
 1376#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1377pub enum GotoDefinitionKind {
 1378    Symbol,
 1379    Declaration,
 1380    Type,
 1381    Implementation,
 1382}
 1383
 1384#[derive(Debug, Clone)]
 1385enum InlayHintRefreshReason {
 1386    ModifiersChanged(bool),
 1387    Toggle(bool),
 1388    SettingsChange(InlayHintSettings),
 1389    NewLinesShown,
 1390    BufferEdited(HashSet<Arc<Language>>),
 1391    RefreshRequested,
 1392    ExcerptsRemoved(Vec<ExcerptId>),
 1393}
 1394
 1395impl InlayHintRefreshReason {
 1396    fn description(&self) -> &'static str {
 1397        match self {
 1398            Self::ModifiersChanged(_) => "modifiers changed",
 1399            Self::Toggle(_) => "toggle",
 1400            Self::SettingsChange(_) => "settings change",
 1401            Self::NewLinesShown => "new lines shown",
 1402            Self::BufferEdited(_) => "buffer edited",
 1403            Self::RefreshRequested => "refresh requested",
 1404            Self::ExcerptsRemoved(_) => "excerpts removed",
 1405        }
 1406    }
 1407}
 1408
 1409pub enum FormatTarget {
 1410    Buffers,
 1411    Ranges(Vec<Range<MultiBufferPoint>>),
 1412}
 1413
 1414pub(crate) struct FocusedBlock {
 1415    id: BlockId,
 1416    focus_handle: WeakFocusHandle,
 1417}
 1418
 1419#[derive(Clone)]
 1420enum JumpData {
 1421    MultiBufferRow {
 1422        row: MultiBufferRow,
 1423        line_offset_from_top: u32,
 1424    },
 1425    MultiBufferPoint {
 1426        excerpt_id: ExcerptId,
 1427        position: Point,
 1428        anchor: text::Anchor,
 1429        line_offset_from_top: u32,
 1430    },
 1431}
 1432
 1433pub enum MultibufferSelectionMode {
 1434    First,
 1435    All,
 1436}
 1437
 1438#[derive(Clone, Copy, Debug, Default)]
 1439pub struct RewrapOptions {
 1440    pub override_language_settings: bool,
 1441    pub preserve_existing_whitespace: bool,
 1442}
 1443
 1444impl Editor {
 1445    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1446        let buffer = cx.new(|cx| Buffer::local("", cx));
 1447        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1448        Self::new(
 1449            EditorMode::SingleLine { auto_width: false },
 1450            buffer,
 1451            None,
 1452            window,
 1453            cx,
 1454        )
 1455    }
 1456
 1457    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1458        let buffer = cx.new(|cx| Buffer::local("", cx));
 1459        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1460        Self::new(EditorMode::full(), buffer, None, window, cx)
 1461    }
 1462
 1463    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1464        let buffer = cx.new(|cx| Buffer::local("", cx));
 1465        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1466        Self::new(
 1467            EditorMode::SingleLine { auto_width: true },
 1468            buffer,
 1469            None,
 1470            window,
 1471            cx,
 1472        )
 1473    }
 1474
 1475    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1476        let buffer = cx.new(|cx| Buffer::local("", cx));
 1477        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1478        Self::new(
 1479            EditorMode::AutoHeight { max_lines },
 1480            buffer,
 1481            None,
 1482            window,
 1483            cx,
 1484        )
 1485    }
 1486
 1487    pub fn for_buffer(
 1488        buffer: Entity<Buffer>,
 1489        project: Option<Entity<Project>>,
 1490        window: &mut Window,
 1491        cx: &mut Context<Self>,
 1492    ) -> Self {
 1493        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1494        Self::new(EditorMode::full(), buffer, project, window, cx)
 1495    }
 1496
 1497    pub fn for_multibuffer(
 1498        buffer: Entity<MultiBuffer>,
 1499        project: Option<Entity<Project>>,
 1500        window: &mut Window,
 1501        cx: &mut Context<Self>,
 1502    ) -> Self {
 1503        Self::new(EditorMode::full(), buffer, project, window, cx)
 1504    }
 1505
 1506    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1507        let mut clone = Self::new(
 1508            self.mode.clone(),
 1509            self.buffer.clone(),
 1510            self.project.clone(),
 1511            window,
 1512            cx,
 1513        );
 1514        self.display_map.update(cx, |display_map, cx| {
 1515            let snapshot = display_map.snapshot(cx);
 1516            clone.display_map.update(cx, |display_map, cx| {
 1517                display_map.set_state(&snapshot, cx);
 1518            });
 1519        });
 1520        clone.folds_did_change(cx);
 1521        clone.selections.clone_state(&self.selections);
 1522        clone.scroll_manager.clone_state(&self.scroll_manager);
 1523        clone.searchable = self.searchable;
 1524        clone.read_only = self.read_only;
 1525        clone
 1526    }
 1527
 1528    pub fn new(
 1529        mode: EditorMode,
 1530        buffer: Entity<MultiBuffer>,
 1531        project: Option<Entity<Project>>,
 1532        window: &mut Window,
 1533        cx: &mut Context<Self>,
 1534    ) -> Self {
 1535        Editor::new_internal(mode, buffer, project, None, window, cx)
 1536    }
 1537
 1538    fn new_internal(
 1539        mode: EditorMode,
 1540        buffer: Entity<MultiBuffer>,
 1541        project: Option<Entity<Project>>,
 1542        display_map: Option<Entity<DisplayMap>>,
 1543        window: &mut Window,
 1544        cx: &mut Context<Self>,
 1545    ) -> Self {
 1546        debug_assert!(
 1547            display_map.is_none() || mode.is_minimap(),
 1548            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1549        );
 1550
 1551        let full_mode = mode.is_full();
 1552        let diagnostics_max_severity = if full_mode {
 1553            EditorSettings::get_global(cx)
 1554                .diagnostics_max_severity
 1555                .unwrap_or(DiagnosticSeverity::Hint)
 1556        } else {
 1557            DiagnosticSeverity::Off
 1558        };
 1559        let style = window.text_style();
 1560        let font_size = style.font_size.to_pixels(window.rem_size());
 1561        let editor = cx.entity().downgrade();
 1562        let fold_placeholder = FoldPlaceholder {
 1563            constrain_width: true,
 1564            render: Arc::new(move |fold_id, fold_range, cx| {
 1565                let editor = editor.clone();
 1566                div()
 1567                    .id(fold_id)
 1568                    .bg(cx.theme().colors().ghost_element_background)
 1569                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1570                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1571                    .rounded_xs()
 1572                    .size_full()
 1573                    .cursor_pointer()
 1574                    .child("")
 1575                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1576                    .on_click(move |_, _window, cx| {
 1577                        editor
 1578                            .update(cx, |editor, cx| {
 1579                                editor.unfold_ranges(
 1580                                    &[fold_range.start..fold_range.end],
 1581                                    true,
 1582                                    false,
 1583                                    cx,
 1584                                );
 1585                                cx.stop_propagation();
 1586                            })
 1587                            .ok();
 1588                    })
 1589                    .into_any()
 1590            }),
 1591            merge_adjacent: true,
 1592            ..FoldPlaceholder::default()
 1593        };
 1594        let display_map = display_map.unwrap_or_else(|| {
 1595            cx.new(|cx| {
 1596                DisplayMap::new(
 1597                    buffer.clone(),
 1598                    style.font(),
 1599                    font_size,
 1600                    None,
 1601                    FILE_HEADER_HEIGHT,
 1602                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1603                    fold_placeholder,
 1604                    diagnostics_max_severity,
 1605                    cx,
 1606                )
 1607            })
 1608        });
 1609
 1610        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1611
 1612        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1613
 1614        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1615            .then(|| language_settings::SoftWrap::None);
 1616
 1617        let mut project_subscriptions = Vec::new();
 1618        if mode.is_full() {
 1619            if let Some(project) = project.as_ref() {
 1620                project_subscriptions.push(cx.subscribe_in(
 1621                    project,
 1622                    window,
 1623                    |editor, _, event, window, cx| match event {
 1624                        project::Event::RefreshCodeLens => {
 1625                            // we always query lens with actions, without storing them, always refreshing them
 1626                        }
 1627                        project::Event::RefreshInlayHints => {
 1628                            editor
 1629                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1630                        }
 1631                        project::Event::SnippetEdit(id, snippet_edits) => {
 1632                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1633                                let focus_handle = editor.focus_handle(cx);
 1634                                if focus_handle.is_focused(window) {
 1635                                    let snapshot = buffer.read(cx).snapshot();
 1636                                    for (range, snippet) in snippet_edits {
 1637                                        let editor_range =
 1638                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1639                                        editor
 1640                                            .insert_snippet(
 1641                                                &[editor_range],
 1642                                                snippet.clone(),
 1643                                                window,
 1644                                                cx,
 1645                                            )
 1646                                            .ok();
 1647                                    }
 1648                                }
 1649                            }
 1650                        }
 1651                        _ => {}
 1652                    },
 1653                ));
 1654                if let Some(task_inventory) = project
 1655                    .read(cx)
 1656                    .task_store()
 1657                    .read(cx)
 1658                    .task_inventory()
 1659                    .cloned()
 1660                {
 1661                    project_subscriptions.push(cx.observe_in(
 1662                        &task_inventory,
 1663                        window,
 1664                        |editor, _, window, cx| {
 1665                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1666                        },
 1667                    ));
 1668                };
 1669
 1670                project_subscriptions.push(cx.subscribe_in(
 1671                    &project.read(cx).breakpoint_store(),
 1672                    window,
 1673                    |editor, _, event, window, cx| match event {
 1674                        BreakpointStoreEvent::ClearDebugLines => {
 1675                            editor.clear_row_highlights::<ActiveDebugLine>();
 1676                            editor.refresh_inline_values(cx);
 1677                        }
 1678                        BreakpointStoreEvent::SetDebugLine => {
 1679                            if editor.go_to_active_debug_line(window, cx) {
 1680                                cx.stop_propagation();
 1681                            }
 1682
 1683                            editor.refresh_inline_values(cx);
 1684                        }
 1685                        _ => {}
 1686                    },
 1687                ));
 1688            }
 1689        }
 1690
 1691        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1692
 1693        let inlay_hint_settings =
 1694            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1695        let focus_handle = cx.focus_handle();
 1696        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1697            .detach();
 1698        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1699            .detach();
 1700        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1701            .detach();
 1702        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1703            .detach();
 1704
 1705        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1706            Some(false)
 1707        } else {
 1708            None
 1709        };
 1710
 1711        let breakpoint_store = match (&mode, project.as_ref()) {
 1712            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1713            _ => None,
 1714        };
 1715
 1716        let mut code_action_providers = Vec::new();
 1717        let mut load_uncommitted_diff = None;
 1718        if let Some(project) = project.clone() {
 1719            load_uncommitted_diff = Some(
 1720                update_uncommitted_diff_for_buffer(
 1721                    cx.entity(),
 1722                    &project,
 1723                    buffer.read(cx).all_buffers(),
 1724                    buffer.clone(),
 1725                    cx,
 1726                )
 1727                .shared(),
 1728            );
 1729            code_action_providers.push(Rc::new(project) as Rc<_>);
 1730        }
 1731
 1732        let mut this = Self {
 1733            focus_handle,
 1734            show_cursor_when_unfocused: false,
 1735            last_focused_descendant: None,
 1736            buffer: buffer.clone(),
 1737            display_map: display_map.clone(),
 1738            selections,
 1739            scroll_manager: ScrollManager::new(cx),
 1740            columnar_selection_tail: None,
 1741            add_selections_state: None,
 1742            select_next_state: None,
 1743            select_prev_state: None,
 1744            selection_history: SelectionHistory::default(),
 1745            autoclose_regions: Vec::new(),
 1746            snippet_stack: InvalidationStack::default(),
 1747            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1748            ime_transaction: None,
 1749            active_diagnostics: ActiveDiagnostic::None,
 1750            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1751            inline_diagnostics_update: Task::ready(()),
 1752            inline_diagnostics: Vec::new(),
 1753            soft_wrap_mode_override,
 1754            diagnostics_max_severity,
 1755            hard_wrap: None,
 1756            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1757            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1758            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1759            project,
 1760            blink_manager: blink_manager.clone(),
 1761            show_local_selections: true,
 1762            show_scrollbars: full_mode,
 1763            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1764            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1765            show_gutter: mode.is_full(),
 1766            show_line_numbers: None,
 1767            use_relative_line_numbers: None,
 1768            disable_expand_excerpt_buttons: false,
 1769            show_git_diff_gutter: None,
 1770            show_code_actions: None,
 1771            show_runnables: None,
 1772            show_breakpoints: None,
 1773            show_wrap_guides: None,
 1774            show_indent_guides,
 1775            placeholder_text: None,
 1776            highlight_order: 0,
 1777            highlighted_rows: HashMap::default(),
 1778            background_highlights: TreeMap::default(),
 1779            gutter_highlights: TreeMap::default(),
 1780            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1781            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1782            nav_history: None,
 1783            context_menu: RefCell::new(None),
 1784            context_menu_options: None,
 1785            mouse_context_menu: None,
 1786            completion_tasks: Vec::new(),
 1787            inline_blame_popover: None,
 1788            signature_help_state: SignatureHelpState::default(),
 1789            auto_signature_help: None,
 1790            find_all_references_task_sources: Vec::new(),
 1791            next_completion_id: 0,
 1792            next_inlay_id: 0,
 1793            code_action_providers,
 1794            available_code_actions: None,
 1795            code_actions_task: None,
 1796            quick_selection_highlight_task: None,
 1797            debounced_selection_highlight_task: None,
 1798            document_highlights_task: None,
 1799            linked_editing_range_task: None,
 1800            pending_rename: None,
 1801            searchable: true,
 1802            cursor_shape: EditorSettings::get_global(cx)
 1803                .cursor_shape
 1804                .unwrap_or_default(),
 1805            current_line_highlight: None,
 1806            autoindent_mode: Some(AutoindentMode::EachLine),
 1807            collapse_matches: false,
 1808            workspace: None,
 1809            input_enabled: true,
 1810            use_modal_editing: mode.is_full(),
 1811            read_only: mode.is_minimap(),
 1812            use_autoclose: true,
 1813            use_auto_surround: true,
 1814            auto_replace_emoji_shortcode: false,
 1815            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1816            leader_id: None,
 1817            remote_id: None,
 1818            hover_state: HoverState::default(),
 1819            pending_mouse_down: None,
 1820            hovered_link_state: None,
 1821            edit_prediction_provider: None,
 1822            active_inline_completion: None,
 1823            stale_inline_completion_in_menu: None,
 1824            edit_prediction_preview: EditPredictionPreview::Inactive {
 1825                released_too_fast: false,
 1826            },
 1827            inline_diagnostics_enabled: mode.is_full(),
 1828            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1829            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1830
 1831            gutter_hovered: false,
 1832            pixel_position_of_newest_cursor: None,
 1833            last_bounds: None,
 1834            last_position_map: None,
 1835            expect_bounds_change: None,
 1836            gutter_dimensions: GutterDimensions::default(),
 1837            style: None,
 1838            show_cursor_names: false,
 1839            hovered_cursors: HashMap::default(),
 1840            next_editor_action_id: EditorActionId::default(),
 1841            editor_actions: Rc::default(),
 1842            inline_completions_hidden_for_vim_mode: false,
 1843            show_inline_completions_override: None,
 1844            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1845            edit_prediction_settings: EditPredictionSettings::Disabled,
 1846            edit_prediction_indent_conflict: false,
 1847            edit_prediction_requires_modifier_in_indent_conflict: true,
 1848            custom_context_menu: None,
 1849            show_git_blame_gutter: false,
 1850            show_git_blame_inline: false,
 1851            show_selection_menu: None,
 1852            show_git_blame_inline_delay_task: None,
 1853            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1854            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1855            serialize_dirty_buffers: !mode.is_minimap()
 1856                && ProjectSettings::get_global(cx)
 1857                    .session
 1858                    .restore_unsaved_buffers,
 1859            blame: None,
 1860            blame_subscription: None,
 1861            tasks: BTreeMap::default(),
 1862
 1863            breakpoint_store,
 1864            gutter_breakpoint_indicator: (None, None),
 1865            _subscriptions: vec![
 1866                cx.observe(&buffer, Self::on_buffer_changed),
 1867                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1868                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1869                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1870                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1871                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1872                cx.observe_window_activation(window, |editor, window, cx| {
 1873                    let active = window.is_window_active();
 1874                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1875                        if active {
 1876                            blink_manager.enable(cx);
 1877                        } else {
 1878                            blink_manager.disable(cx);
 1879                        }
 1880                    });
 1881                }),
 1882            ],
 1883            tasks_update_task: None,
 1884            linked_edit_ranges: Default::default(),
 1885            in_project_search: false,
 1886            previous_search_ranges: None,
 1887            breadcrumb_header: None,
 1888            focused_block: None,
 1889            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1890            addons: HashMap::default(),
 1891            registered_buffers: HashMap::default(),
 1892            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1893            selection_mark_mode: false,
 1894            toggle_fold_multiple_buffers: Task::ready(()),
 1895            serialize_selections: Task::ready(()),
 1896            serialize_folds: Task::ready(()),
 1897            text_style_refinement: None,
 1898            load_diff_task: load_uncommitted_diff,
 1899            temporary_diff_override: false,
 1900            mouse_cursor_hidden: false,
 1901            minimap: None,
 1902            hide_mouse_mode: EditorSettings::get_global(cx)
 1903                .hide_mouse
 1904                .unwrap_or_default(),
 1905            change_list: ChangeList::new(),
 1906            mode,
 1907        };
 1908        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1909            this._subscriptions
 1910                .push(cx.observe(breakpoints, |_, _, cx| {
 1911                    cx.notify();
 1912                }));
 1913        }
 1914        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1915        this._subscriptions.extend(project_subscriptions);
 1916
 1917        this._subscriptions.push(cx.subscribe_in(
 1918            &cx.entity(),
 1919            window,
 1920            |editor, _, e: &EditorEvent, window, cx| match e {
 1921                EditorEvent::ScrollPositionChanged { local, .. } => {
 1922                    if *local {
 1923                        let new_anchor = editor.scroll_manager.anchor();
 1924                        let snapshot = editor.snapshot(window, cx);
 1925                        editor.update_restoration_data(cx, move |data| {
 1926                            data.scroll_position = (
 1927                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1928                                new_anchor.offset,
 1929                            );
 1930                        });
 1931                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1932                        editor.inline_blame_popover.take();
 1933                    }
 1934                }
 1935                EditorEvent::Edited { .. } => {
 1936                    if !vim_enabled(cx) {
 1937                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1938                        let pop_state = editor
 1939                            .change_list
 1940                            .last()
 1941                            .map(|previous| {
 1942                                previous.len() == selections.len()
 1943                                    && previous.iter().enumerate().all(|(ix, p)| {
 1944                                        p.to_display_point(&map).row()
 1945                                            == selections[ix].head().row()
 1946                                    })
 1947                            })
 1948                            .unwrap_or(false);
 1949                        let new_positions = selections
 1950                            .into_iter()
 1951                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1952                            .collect();
 1953                        editor
 1954                            .change_list
 1955                            .push_to_change_list(pop_state, new_positions);
 1956                    }
 1957                }
 1958                _ => (),
 1959            },
 1960        ));
 1961
 1962        if let Some(dap_store) = this
 1963            .project
 1964            .as_ref()
 1965            .map(|project| project.read(cx).dap_store())
 1966        {
 1967            let weak_editor = cx.weak_entity();
 1968
 1969            this._subscriptions
 1970                .push(
 1971                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1972                        let session_entity = cx.entity();
 1973                        weak_editor
 1974                            .update(cx, |editor, cx| {
 1975                                editor._subscriptions.push(
 1976                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1977                                );
 1978                            })
 1979                            .ok();
 1980                    }),
 1981                );
 1982
 1983            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1984                this._subscriptions
 1985                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1986            }
 1987        }
 1988
 1989        this.end_selection(window, cx);
 1990        this.scroll_manager.show_scrollbars(window, cx);
 1991        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1992
 1993        if full_mode {
 1994            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1995            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1996
 1997            if this.git_blame_inline_enabled {
 1998                this.start_git_blame_inline(false, window, cx);
 1999            }
 2000
 2001            this.go_to_active_debug_line(window, cx);
 2002
 2003            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2004                if let Some(project) = this.project.as_ref() {
 2005                    let handle = project.update(cx, |project, cx| {
 2006                        project.register_buffer_with_language_servers(&buffer, cx)
 2007                    });
 2008                    this.registered_buffers
 2009                        .insert(buffer.read(cx).remote_id(), handle);
 2010                }
 2011            }
 2012
 2013            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2014        }
 2015
 2016        this.report_editor_event("Editor Opened", None, cx);
 2017        this
 2018    }
 2019
 2020    pub fn deploy_mouse_context_menu(
 2021        &mut self,
 2022        position: gpui::Point<Pixels>,
 2023        context_menu: Entity<ContextMenu>,
 2024        window: &mut Window,
 2025        cx: &mut Context<Self>,
 2026    ) {
 2027        self.mouse_context_menu = Some(MouseContextMenu::new(
 2028            self,
 2029            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2030            context_menu,
 2031            window,
 2032            cx,
 2033        ));
 2034    }
 2035
 2036    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2037        self.mouse_context_menu
 2038            .as_ref()
 2039            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2040    }
 2041
 2042    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2043        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2044    }
 2045
 2046    fn key_context_internal(
 2047        &self,
 2048        has_active_edit_prediction: bool,
 2049        window: &Window,
 2050        cx: &App,
 2051    ) -> KeyContext {
 2052        let mut key_context = KeyContext::new_with_defaults();
 2053        key_context.add("Editor");
 2054        let mode = match self.mode {
 2055            EditorMode::SingleLine { .. } => "single_line",
 2056            EditorMode::AutoHeight { .. } => "auto_height",
 2057            EditorMode::Minimap { .. } => "minimap",
 2058            EditorMode::Full { .. } => "full",
 2059        };
 2060
 2061        if EditorSettings::jupyter_enabled(cx) {
 2062            key_context.add("jupyter");
 2063        }
 2064
 2065        key_context.set("mode", mode);
 2066        if self.pending_rename.is_some() {
 2067            key_context.add("renaming");
 2068        }
 2069
 2070        match self.context_menu.borrow().as_ref() {
 2071            Some(CodeContextMenu::Completions(_)) => {
 2072                key_context.add("menu");
 2073                key_context.add("showing_completions");
 2074            }
 2075            Some(CodeContextMenu::CodeActions(_)) => {
 2076                key_context.add("menu");
 2077                key_context.add("showing_code_actions")
 2078            }
 2079            None => {}
 2080        }
 2081
 2082        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2083        if !self.focus_handle(cx).contains_focused(window, cx)
 2084            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2085        {
 2086            for addon in self.addons.values() {
 2087                addon.extend_key_context(&mut key_context, cx)
 2088            }
 2089        }
 2090
 2091        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2092            if let Some(extension) = singleton_buffer
 2093                .read(cx)
 2094                .file()
 2095                .and_then(|file| file.path().extension()?.to_str())
 2096            {
 2097                key_context.set("extension", extension.to_string());
 2098            }
 2099        } else {
 2100            key_context.add("multibuffer");
 2101        }
 2102
 2103        if has_active_edit_prediction {
 2104            if self.edit_prediction_in_conflict() {
 2105                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2106            } else {
 2107                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2108                key_context.add("copilot_suggestion");
 2109            }
 2110        }
 2111
 2112        if self.selection_mark_mode {
 2113            key_context.add("selection_mode");
 2114        }
 2115
 2116        key_context
 2117    }
 2118
 2119    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2120        self.mouse_cursor_hidden = match origin {
 2121            HideMouseCursorOrigin::TypingAction => {
 2122                matches!(
 2123                    self.hide_mouse_mode,
 2124                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2125                )
 2126            }
 2127            HideMouseCursorOrigin::MovementAction => {
 2128                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2129            }
 2130        };
 2131    }
 2132
 2133    pub fn edit_prediction_in_conflict(&self) -> bool {
 2134        if !self.show_edit_predictions_in_menu() {
 2135            return false;
 2136        }
 2137
 2138        let showing_completions = self
 2139            .context_menu
 2140            .borrow()
 2141            .as_ref()
 2142            .map_or(false, |context| {
 2143                matches!(context, CodeContextMenu::Completions(_))
 2144            });
 2145
 2146        showing_completions
 2147            || self.edit_prediction_requires_modifier()
 2148            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2149            // bindings to insert tab characters.
 2150            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2151    }
 2152
 2153    pub fn accept_edit_prediction_keybind(
 2154        &self,
 2155        window: &Window,
 2156        cx: &App,
 2157    ) -> AcceptEditPredictionBinding {
 2158        let key_context = self.key_context_internal(true, window, cx);
 2159        let in_conflict = self.edit_prediction_in_conflict();
 2160
 2161        AcceptEditPredictionBinding(
 2162            window
 2163                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2164                .into_iter()
 2165                .filter(|binding| {
 2166                    !in_conflict
 2167                        || binding
 2168                            .keystrokes()
 2169                            .first()
 2170                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2171                })
 2172                .rev()
 2173                .min_by_key(|binding| {
 2174                    binding
 2175                        .keystrokes()
 2176                        .first()
 2177                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2178                }),
 2179        )
 2180    }
 2181
 2182    pub fn new_file(
 2183        workspace: &mut Workspace,
 2184        _: &workspace::NewFile,
 2185        window: &mut Window,
 2186        cx: &mut Context<Workspace>,
 2187    ) {
 2188        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2189            "Failed to create buffer",
 2190            window,
 2191            cx,
 2192            |e, _, _| match e.error_code() {
 2193                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2194                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2195                e.error_tag("required").unwrap_or("the latest version")
 2196            )),
 2197                _ => None,
 2198            },
 2199        );
 2200    }
 2201
 2202    pub fn new_in_workspace(
 2203        workspace: &mut Workspace,
 2204        window: &mut Window,
 2205        cx: &mut Context<Workspace>,
 2206    ) -> Task<Result<Entity<Editor>>> {
 2207        let project = workspace.project().clone();
 2208        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2209
 2210        cx.spawn_in(window, async move |workspace, cx| {
 2211            let buffer = create.await?;
 2212            workspace.update_in(cx, |workspace, window, cx| {
 2213                let editor =
 2214                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2215                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2216                editor
 2217            })
 2218        })
 2219    }
 2220
 2221    fn new_file_vertical(
 2222        workspace: &mut Workspace,
 2223        _: &workspace::NewFileSplitVertical,
 2224        window: &mut Window,
 2225        cx: &mut Context<Workspace>,
 2226    ) {
 2227        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2228    }
 2229
 2230    fn new_file_horizontal(
 2231        workspace: &mut Workspace,
 2232        _: &workspace::NewFileSplitHorizontal,
 2233        window: &mut Window,
 2234        cx: &mut Context<Workspace>,
 2235    ) {
 2236        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2237    }
 2238
 2239    fn new_file_in_direction(
 2240        workspace: &mut Workspace,
 2241        direction: SplitDirection,
 2242        window: &mut Window,
 2243        cx: &mut Context<Workspace>,
 2244    ) {
 2245        let project = workspace.project().clone();
 2246        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2247
 2248        cx.spawn_in(window, async move |workspace, cx| {
 2249            let buffer = create.await?;
 2250            workspace.update_in(cx, move |workspace, window, cx| {
 2251                workspace.split_item(
 2252                    direction,
 2253                    Box::new(
 2254                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2255                    ),
 2256                    window,
 2257                    cx,
 2258                )
 2259            })?;
 2260            anyhow::Ok(())
 2261        })
 2262        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2263            match e.error_code() {
 2264                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2265                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2266                e.error_tag("required").unwrap_or("the latest version")
 2267            )),
 2268                _ => None,
 2269            }
 2270        });
 2271    }
 2272
 2273    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2274        self.leader_id
 2275    }
 2276
 2277    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2278        &self.buffer
 2279    }
 2280
 2281    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2282        self.workspace.as_ref()?.0.upgrade()
 2283    }
 2284
 2285    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2286        self.buffer().read(cx).title(cx)
 2287    }
 2288
 2289    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2290        let git_blame_gutter_max_author_length = self
 2291            .render_git_blame_gutter(cx)
 2292            .then(|| {
 2293                if let Some(blame) = self.blame.as_ref() {
 2294                    let max_author_length =
 2295                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2296                    Some(max_author_length)
 2297                } else {
 2298                    None
 2299                }
 2300            })
 2301            .flatten();
 2302
 2303        EditorSnapshot {
 2304            mode: self.mode.clone(),
 2305            show_gutter: self.show_gutter,
 2306            show_line_numbers: self.show_line_numbers,
 2307            show_git_diff_gutter: self.show_git_diff_gutter,
 2308            show_runnables: self.show_runnables,
 2309            show_breakpoints: self.show_breakpoints,
 2310            git_blame_gutter_max_author_length,
 2311            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2312            scroll_anchor: self.scroll_manager.anchor(),
 2313            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2314            placeholder_text: self.placeholder_text.clone(),
 2315            is_focused: self.focus_handle.is_focused(window),
 2316            current_line_highlight: self
 2317                .current_line_highlight
 2318                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2319            gutter_hovered: self.gutter_hovered,
 2320        }
 2321    }
 2322
 2323    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2324        self.buffer.read(cx).language_at(point, cx)
 2325    }
 2326
 2327    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2328        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2329    }
 2330
 2331    pub fn active_excerpt(
 2332        &self,
 2333        cx: &App,
 2334    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2335        self.buffer
 2336            .read(cx)
 2337            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2338    }
 2339
 2340    pub fn mode(&self) -> &EditorMode {
 2341        &self.mode
 2342    }
 2343
 2344    pub fn set_mode(&mut self, mode: EditorMode) {
 2345        self.mode = mode;
 2346    }
 2347
 2348    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2349        self.collaboration_hub.as_deref()
 2350    }
 2351
 2352    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2353        self.collaboration_hub = Some(hub);
 2354    }
 2355
 2356    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2357        self.in_project_search = in_project_search;
 2358    }
 2359
 2360    pub fn set_custom_context_menu(
 2361        &mut self,
 2362        f: impl 'static
 2363        + Fn(
 2364            &mut Self,
 2365            DisplayPoint,
 2366            &mut Window,
 2367            &mut Context<Self>,
 2368        ) -> Option<Entity<ui::ContextMenu>>,
 2369    ) {
 2370        self.custom_context_menu = Some(Box::new(f))
 2371    }
 2372
 2373    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2374        self.completion_provider = provider;
 2375    }
 2376
 2377    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2378        self.semantics_provider.clone()
 2379    }
 2380
 2381    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2382        self.semantics_provider = provider;
 2383    }
 2384
 2385    pub fn set_edit_prediction_provider<T>(
 2386        &mut self,
 2387        provider: Option<Entity<T>>,
 2388        window: &mut Window,
 2389        cx: &mut Context<Self>,
 2390    ) where
 2391        T: EditPredictionProvider,
 2392    {
 2393        self.edit_prediction_provider =
 2394            provider.map(|provider| RegisteredInlineCompletionProvider {
 2395                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2396                    if this.focus_handle.is_focused(window) {
 2397                        this.update_visible_inline_completion(window, cx);
 2398                    }
 2399                }),
 2400                provider: Arc::new(provider),
 2401            });
 2402        self.update_edit_prediction_settings(cx);
 2403        self.refresh_inline_completion(false, false, window, cx);
 2404    }
 2405
 2406    pub fn placeholder_text(&self) -> Option<&str> {
 2407        self.placeholder_text.as_deref()
 2408    }
 2409
 2410    pub fn set_placeholder_text(
 2411        &mut self,
 2412        placeholder_text: impl Into<Arc<str>>,
 2413        cx: &mut Context<Self>,
 2414    ) {
 2415        let placeholder_text = Some(placeholder_text.into());
 2416        if self.placeholder_text != placeholder_text {
 2417            self.placeholder_text = placeholder_text;
 2418            cx.notify();
 2419        }
 2420    }
 2421
 2422    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2423        self.cursor_shape = cursor_shape;
 2424
 2425        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2426        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2427
 2428        cx.notify();
 2429    }
 2430
 2431    pub fn set_current_line_highlight(
 2432        &mut self,
 2433        current_line_highlight: Option<CurrentLineHighlight>,
 2434    ) {
 2435        self.current_line_highlight = current_line_highlight;
 2436    }
 2437
 2438    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2439        self.collapse_matches = collapse_matches;
 2440    }
 2441
 2442    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2443        let buffers = self.buffer.read(cx).all_buffers();
 2444        let Some(project) = self.project.as_ref() else {
 2445            return;
 2446        };
 2447        project.update(cx, |project, cx| {
 2448            for buffer in buffers {
 2449                self.registered_buffers
 2450                    .entry(buffer.read(cx).remote_id())
 2451                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2452            }
 2453        })
 2454    }
 2455
 2456    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2457        if self.collapse_matches {
 2458            return range.start..range.start;
 2459        }
 2460        range.clone()
 2461    }
 2462
 2463    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2464        if self.display_map.read(cx).clip_at_line_ends != clip {
 2465            self.display_map
 2466                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2467        }
 2468    }
 2469
 2470    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2471        self.input_enabled = input_enabled;
 2472    }
 2473
 2474    pub fn set_inline_completions_hidden_for_vim_mode(
 2475        &mut self,
 2476        hidden: bool,
 2477        window: &mut Window,
 2478        cx: &mut Context<Self>,
 2479    ) {
 2480        if hidden != self.inline_completions_hidden_for_vim_mode {
 2481            self.inline_completions_hidden_for_vim_mode = hidden;
 2482            if hidden {
 2483                self.update_visible_inline_completion(window, cx);
 2484            } else {
 2485                self.refresh_inline_completion(true, false, window, cx);
 2486            }
 2487        }
 2488    }
 2489
 2490    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2491        self.menu_inline_completions_policy = value;
 2492    }
 2493
 2494    pub fn set_autoindent(&mut self, autoindent: bool) {
 2495        if autoindent {
 2496            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2497        } else {
 2498            self.autoindent_mode = None;
 2499        }
 2500    }
 2501
 2502    pub fn read_only(&self, cx: &App) -> bool {
 2503        self.read_only || self.buffer.read(cx).read_only()
 2504    }
 2505
 2506    pub fn set_read_only(&mut self, read_only: bool) {
 2507        self.read_only = read_only;
 2508    }
 2509
 2510    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2511        self.use_autoclose = autoclose;
 2512    }
 2513
 2514    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2515        self.use_auto_surround = auto_surround;
 2516    }
 2517
 2518    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2519        self.auto_replace_emoji_shortcode = auto_replace;
 2520    }
 2521
 2522    pub fn toggle_edit_predictions(
 2523        &mut self,
 2524        _: &ToggleEditPrediction,
 2525        window: &mut Window,
 2526        cx: &mut Context<Self>,
 2527    ) {
 2528        if self.show_inline_completions_override.is_some() {
 2529            self.set_show_edit_predictions(None, window, cx);
 2530        } else {
 2531            let show_edit_predictions = !self.edit_predictions_enabled();
 2532            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2533        }
 2534    }
 2535
 2536    pub fn set_show_edit_predictions(
 2537        &mut self,
 2538        show_edit_predictions: Option<bool>,
 2539        window: &mut Window,
 2540        cx: &mut Context<Self>,
 2541    ) {
 2542        self.show_inline_completions_override = show_edit_predictions;
 2543        self.update_edit_prediction_settings(cx);
 2544
 2545        if let Some(false) = show_edit_predictions {
 2546            self.discard_inline_completion(false, cx);
 2547        } else {
 2548            self.refresh_inline_completion(false, true, window, cx);
 2549        }
 2550    }
 2551
 2552    fn inline_completions_disabled_in_scope(
 2553        &self,
 2554        buffer: &Entity<Buffer>,
 2555        buffer_position: language::Anchor,
 2556        cx: &App,
 2557    ) -> bool {
 2558        let snapshot = buffer.read(cx).snapshot();
 2559        let settings = snapshot.settings_at(buffer_position, cx);
 2560
 2561        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2562            return false;
 2563        };
 2564
 2565        scope.override_name().map_or(false, |scope_name| {
 2566            settings
 2567                .edit_predictions_disabled_in
 2568                .iter()
 2569                .any(|s| s == scope_name)
 2570        })
 2571    }
 2572
 2573    pub fn set_use_modal_editing(&mut self, to: bool) {
 2574        self.use_modal_editing = to;
 2575    }
 2576
 2577    pub fn use_modal_editing(&self) -> bool {
 2578        self.use_modal_editing
 2579    }
 2580
 2581    fn selections_did_change(
 2582        &mut self,
 2583        local: bool,
 2584        old_cursor_position: &Anchor,
 2585        show_completions: bool,
 2586        window: &mut Window,
 2587        cx: &mut Context<Self>,
 2588    ) {
 2589        window.invalidate_character_coordinates();
 2590
 2591        // Copy selections to primary selection buffer
 2592        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2593        if local {
 2594            let selections = self.selections.all::<usize>(cx);
 2595            let buffer_handle = self.buffer.read(cx).read(cx);
 2596
 2597            let mut text = String::new();
 2598            for (index, selection) in selections.iter().enumerate() {
 2599                let text_for_selection = buffer_handle
 2600                    .text_for_range(selection.start..selection.end)
 2601                    .collect::<String>();
 2602
 2603                text.push_str(&text_for_selection);
 2604                if index != selections.len() - 1 {
 2605                    text.push('\n');
 2606                }
 2607            }
 2608
 2609            if !text.is_empty() {
 2610                cx.write_to_primary(ClipboardItem::new_string(text));
 2611            }
 2612        }
 2613
 2614        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2615            self.buffer.update(cx, |buffer, cx| {
 2616                buffer.set_active_selections(
 2617                    &self.selections.disjoint_anchors(),
 2618                    self.selections.line_mode,
 2619                    self.cursor_shape,
 2620                    cx,
 2621                )
 2622            });
 2623        }
 2624        let display_map = self
 2625            .display_map
 2626            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2627        let buffer = &display_map.buffer_snapshot;
 2628        self.add_selections_state = None;
 2629        self.select_next_state = None;
 2630        self.select_prev_state = None;
 2631        self.select_syntax_node_history.try_clear();
 2632        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2633        self.snippet_stack
 2634            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2635        self.take_rename(false, window, cx);
 2636
 2637        let new_cursor_position = self.selections.newest_anchor().head();
 2638
 2639        self.push_to_nav_history(
 2640            *old_cursor_position,
 2641            Some(new_cursor_position.to_point(buffer)),
 2642            false,
 2643            cx,
 2644        );
 2645
 2646        if local {
 2647            let new_cursor_position = self.selections.newest_anchor().head();
 2648            let mut context_menu = self.context_menu.borrow_mut();
 2649            let completion_menu = match context_menu.as_ref() {
 2650                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2651                _ => {
 2652                    *context_menu = None;
 2653                    None
 2654                }
 2655            };
 2656            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2657                if !self.registered_buffers.contains_key(&buffer_id) {
 2658                    if let Some(project) = self.project.as_ref() {
 2659                        project.update(cx, |project, cx| {
 2660                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2661                                return;
 2662                            };
 2663                            self.registered_buffers.insert(
 2664                                buffer_id,
 2665                                project.register_buffer_with_language_servers(&buffer, cx),
 2666                            );
 2667                        })
 2668                    }
 2669                }
 2670            }
 2671
 2672            if let Some(completion_menu) = completion_menu {
 2673                let cursor_position = new_cursor_position.to_offset(buffer);
 2674                let (word_range, kind) =
 2675                    buffer.surrounding_word(completion_menu.initial_position, true);
 2676                if kind == Some(CharKind::Word)
 2677                    && word_range.to_inclusive().contains(&cursor_position)
 2678                {
 2679                    let mut completion_menu = completion_menu.clone();
 2680                    drop(context_menu);
 2681
 2682                    let query = Self::completion_query(buffer, cursor_position);
 2683                    cx.spawn(async move |this, cx| {
 2684                        completion_menu
 2685                            .filter(query.as_deref(), cx.background_executor().clone())
 2686                            .await;
 2687
 2688                        this.update(cx, |this, cx| {
 2689                            let mut context_menu = this.context_menu.borrow_mut();
 2690                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2691                            else {
 2692                                return;
 2693                            };
 2694
 2695                            if menu.id > completion_menu.id {
 2696                                return;
 2697                            }
 2698
 2699                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2700                            drop(context_menu);
 2701                            cx.notify();
 2702                        })
 2703                    })
 2704                    .detach();
 2705
 2706                    if show_completions {
 2707                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2708                    }
 2709                } else {
 2710                    drop(context_menu);
 2711                    self.hide_context_menu(window, cx);
 2712                }
 2713            } else {
 2714                drop(context_menu);
 2715            }
 2716
 2717            hide_hover(self, cx);
 2718
 2719            if old_cursor_position.to_display_point(&display_map).row()
 2720                != new_cursor_position.to_display_point(&display_map).row()
 2721            {
 2722                self.available_code_actions.take();
 2723            }
 2724            self.refresh_code_actions(window, cx);
 2725            self.refresh_document_highlights(cx);
 2726            self.refresh_selected_text_highlights(false, window, cx);
 2727            refresh_matching_bracket_highlights(self, window, cx);
 2728            self.update_visible_inline_completion(window, cx);
 2729            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2730            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2731            self.inline_blame_popover.take();
 2732            if self.git_blame_inline_enabled {
 2733                self.start_inline_blame_timer(window, cx);
 2734            }
 2735        }
 2736
 2737        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2738        cx.emit(EditorEvent::SelectionsChanged { local });
 2739
 2740        let selections = &self.selections.disjoint;
 2741        if selections.len() == 1 {
 2742            cx.emit(SearchEvent::ActiveMatchChanged)
 2743        }
 2744        if local {
 2745            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2746                let inmemory_selections = selections
 2747                    .iter()
 2748                    .map(|s| {
 2749                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2750                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2751                    })
 2752                    .collect();
 2753                self.update_restoration_data(cx, |data| {
 2754                    data.selections = inmemory_selections;
 2755                });
 2756
 2757                if WorkspaceSettings::get(None, cx).restore_on_startup
 2758                    != RestoreOnStartupBehavior::None
 2759                {
 2760                    if let Some(workspace_id) =
 2761                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2762                    {
 2763                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2764                        let selections = selections.clone();
 2765                        let background_executor = cx.background_executor().clone();
 2766                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2767                        self.serialize_selections = cx.background_spawn(async move {
 2768                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2769                    let db_selections = selections
 2770                        .iter()
 2771                        .map(|selection| {
 2772                            (
 2773                                selection.start.to_offset(&snapshot),
 2774                                selection.end.to_offset(&snapshot),
 2775                            )
 2776                        })
 2777                        .collect();
 2778
 2779                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2780                        .await
 2781                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2782                        .log_err();
 2783                });
 2784                    }
 2785                }
 2786            }
 2787        }
 2788
 2789        cx.notify();
 2790    }
 2791
 2792    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2793        use text::ToOffset as _;
 2794        use text::ToPoint as _;
 2795
 2796        if self.mode.is_minimap()
 2797            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2798        {
 2799            return;
 2800        }
 2801
 2802        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2803            return;
 2804        };
 2805
 2806        let snapshot = singleton.read(cx).snapshot();
 2807        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2808            let display_snapshot = display_map.snapshot(cx);
 2809
 2810            display_snapshot
 2811                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2812                .map(|fold| {
 2813                    fold.range.start.text_anchor.to_point(&snapshot)
 2814                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2815                })
 2816                .collect()
 2817        });
 2818        self.update_restoration_data(cx, |data| {
 2819            data.folds = inmemory_folds;
 2820        });
 2821
 2822        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2823            return;
 2824        };
 2825        let background_executor = cx.background_executor().clone();
 2826        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2827        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2828            display_map
 2829                .snapshot(cx)
 2830                .folds_in_range(0..snapshot.len())
 2831                .map(|fold| {
 2832                    (
 2833                        fold.range.start.text_anchor.to_offset(&snapshot),
 2834                        fold.range.end.text_anchor.to_offset(&snapshot),
 2835                    )
 2836                })
 2837                .collect()
 2838        });
 2839        self.serialize_folds = cx.background_spawn(async move {
 2840            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2841            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2842                .await
 2843                .with_context(|| {
 2844                    format!(
 2845                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2846                    )
 2847                })
 2848                .log_err();
 2849        });
 2850    }
 2851
 2852    pub fn sync_selections(
 2853        &mut self,
 2854        other: Entity<Editor>,
 2855        cx: &mut Context<Self>,
 2856    ) -> gpui::Subscription {
 2857        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2858        self.selections.change_with(cx, |selections| {
 2859            selections.select_anchors(other_selections);
 2860        });
 2861
 2862        let other_subscription =
 2863            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2864                EditorEvent::SelectionsChanged { local: true } => {
 2865                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2866                    if other_selections.is_empty() {
 2867                        return;
 2868                    }
 2869                    this.selections.change_with(cx, |selections| {
 2870                        selections.select_anchors(other_selections);
 2871                    });
 2872                }
 2873                _ => {}
 2874            });
 2875
 2876        let this_subscription =
 2877            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2878                EditorEvent::SelectionsChanged { local: true } => {
 2879                    let these_selections = this.selections.disjoint.to_vec();
 2880                    if these_selections.is_empty() {
 2881                        return;
 2882                    }
 2883                    other.update(cx, |other_editor, cx| {
 2884                        other_editor.selections.change_with(cx, |selections| {
 2885                            selections.select_anchors(these_selections);
 2886                        })
 2887                    });
 2888                }
 2889                _ => {}
 2890            });
 2891
 2892        Subscription::join(other_subscription, this_subscription)
 2893    }
 2894
 2895    pub fn change_selections<R>(
 2896        &mut self,
 2897        autoscroll: Option<Autoscroll>,
 2898        window: &mut Window,
 2899        cx: &mut Context<Self>,
 2900        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2901    ) -> R {
 2902        self.change_selections_inner(autoscroll, true, window, cx, change)
 2903    }
 2904
 2905    fn change_selections_inner<R>(
 2906        &mut self,
 2907        autoscroll: Option<Autoscroll>,
 2908        request_completions: bool,
 2909        window: &mut Window,
 2910        cx: &mut Context<Self>,
 2911        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2912    ) -> R {
 2913        let old_cursor_position = self.selections.newest_anchor().head();
 2914        self.push_to_selection_history();
 2915
 2916        let (changed, result) = self.selections.change_with(cx, change);
 2917
 2918        if changed {
 2919            if let Some(autoscroll) = autoscroll {
 2920                self.request_autoscroll(autoscroll, cx);
 2921            }
 2922            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2923
 2924            if self.should_open_signature_help_automatically(
 2925                &old_cursor_position,
 2926                self.signature_help_state.backspace_pressed(),
 2927                cx,
 2928            ) {
 2929                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2930            }
 2931            self.signature_help_state.set_backspace_pressed(false);
 2932        }
 2933
 2934        result
 2935    }
 2936
 2937    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2938    where
 2939        I: IntoIterator<Item = (Range<S>, T)>,
 2940        S: ToOffset,
 2941        T: Into<Arc<str>>,
 2942    {
 2943        if self.read_only(cx) {
 2944            return;
 2945        }
 2946
 2947        self.buffer
 2948            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2949    }
 2950
 2951    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2952    where
 2953        I: IntoIterator<Item = (Range<S>, T)>,
 2954        S: ToOffset,
 2955        T: Into<Arc<str>>,
 2956    {
 2957        if self.read_only(cx) {
 2958            return;
 2959        }
 2960
 2961        self.buffer.update(cx, |buffer, cx| {
 2962            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2963        });
 2964    }
 2965
 2966    pub fn edit_with_block_indent<I, S, T>(
 2967        &mut self,
 2968        edits: I,
 2969        original_indent_columns: Vec<Option<u32>>,
 2970        cx: &mut Context<Self>,
 2971    ) where
 2972        I: IntoIterator<Item = (Range<S>, T)>,
 2973        S: ToOffset,
 2974        T: Into<Arc<str>>,
 2975    {
 2976        if self.read_only(cx) {
 2977            return;
 2978        }
 2979
 2980        self.buffer.update(cx, |buffer, cx| {
 2981            buffer.edit(
 2982                edits,
 2983                Some(AutoindentMode::Block {
 2984                    original_indent_columns,
 2985                }),
 2986                cx,
 2987            )
 2988        });
 2989    }
 2990
 2991    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2992        self.hide_context_menu(window, cx);
 2993
 2994        match phase {
 2995            SelectPhase::Begin {
 2996                position,
 2997                add,
 2998                click_count,
 2999            } => self.begin_selection(position, add, click_count, window, cx),
 3000            SelectPhase::BeginColumnar {
 3001                position,
 3002                goal_column,
 3003                reset,
 3004            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3005            SelectPhase::Extend {
 3006                position,
 3007                click_count,
 3008            } => self.extend_selection(position, click_count, window, cx),
 3009            SelectPhase::Update {
 3010                position,
 3011                goal_column,
 3012                scroll_delta,
 3013            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3014            SelectPhase::End => self.end_selection(window, cx),
 3015        }
 3016    }
 3017
 3018    fn extend_selection(
 3019        &mut self,
 3020        position: DisplayPoint,
 3021        click_count: usize,
 3022        window: &mut Window,
 3023        cx: &mut Context<Self>,
 3024    ) {
 3025        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3026        let tail = self.selections.newest::<usize>(cx).tail();
 3027        self.begin_selection(position, false, click_count, window, cx);
 3028
 3029        let position = position.to_offset(&display_map, Bias::Left);
 3030        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3031
 3032        let mut pending_selection = self
 3033            .selections
 3034            .pending_anchor()
 3035            .expect("extend_selection not called with pending selection");
 3036        if position >= tail {
 3037            pending_selection.start = tail_anchor;
 3038        } else {
 3039            pending_selection.end = tail_anchor;
 3040            pending_selection.reversed = true;
 3041        }
 3042
 3043        let mut pending_mode = self.selections.pending_mode().unwrap();
 3044        match &mut pending_mode {
 3045            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3046            _ => {}
 3047        }
 3048
 3049        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3050
 3051        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3052            s.set_pending(pending_selection, pending_mode)
 3053        });
 3054    }
 3055
 3056    fn begin_selection(
 3057        &mut self,
 3058        position: DisplayPoint,
 3059        add: bool,
 3060        click_count: usize,
 3061        window: &mut Window,
 3062        cx: &mut Context<Self>,
 3063    ) {
 3064        if !self.focus_handle.is_focused(window) {
 3065            self.last_focused_descendant = None;
 3066            window.focus(&self.focus_handle);
 3067        }
 3068
 3069        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3070        let buffer = &display_map.buffer_snapshot;
 3071        let position = display_map.clip_point(position, Bias::Left);
 3072
 3073        let start;
 3074        let end;
 3075        let mode;
 3076        let mut auto_scroll;
 3077        match click_count {
 3078            1 => {
 3079                start = buffer.anchor_before(position.to_point(&display_map));
 3080                end = start;
 3081                mode = SelectMode::Character;
 3082                auto_scroll = true;
 3083            }
 3084            2 => {
 3085                let range = movement::surrounding_word(&display_map, position);
 3086                start = buffer.anchor_before(range.start.to_point(&display_map));
 3087                end = buffer.anchor_before(range.end.to_point(&display_map));
 3088                mode = SelectMode::Word(start..end);
 3089                auto_scroll = true;
 3090            }
 3091            3 => {
 3092                let position = display_map
 3093                    .clip_point(position, Bias::Left)
 3094                    .to_point(&display_map);
 3095                let line_start = display_map.prev_line_boundary(position).0;
 3096                let next_line_start = buffer.clip_point(
 3097                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3098                    Bias::Left,
 3099                );
 3100                start = buffer.anchor_before(line_start);
 3101                end = buffer.anchor_before(next_line_start);
 3102                mode = SelectMode::Line(start..end);
 3103                auto_scroll = true;
 3104            }
 3105            _ => {
 3106                start = buffer.anchor_before(0);
 3107                end = buffer.anchor_before(buffer.len());
 3108                mode = SelectMode::All;
 3109                auto_scroll = false;
 3110            }
 3111        }
 3112        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3113
 3114        let point_to_delete: Option<usize> = {
 3115            let selected_points: Vec<Selection<Point>> =
 3116                self.selections.disjoint_in_range(start..end, cx);
 3117
 3118            if !add || click_count > 1 {
 3119                None
 3120            } else if !selected_points.is_empty() {
 3121                Some(selected_points[0].id)
 3122            } else {
 3123                let clicked_point_already_selected =
 3124                    self.selections.disjoint.iter().find(|selection| {
 3125                        selection.start.to_point(buffer) == start.to_point(buffer)
 3126                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3127                    });
 3128
 3129                clicked_point_already_selected.map(|selection| selection.id)
 3130            }
 3131        };
 3132
 3133        let selections_count = self.selections.count();
 3134
 3135        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3136            if let Some(point_to_delete) = point_to_delete {
 3137                s.delete(point_to_delete);
 3138
 3139                if selections_count == 1 {
 3140                    s.set_pending_anchor_range(start..end, mode);
 3141                }
 3142            } else {
 3143                if !add {
 3144                    s.clear_disjoint();
 3145                }
 3146
 3147                s.set_pending_anchor_range(start..end, mode);
 3148            }
 3149        });
 3150    }
 3151
 3152    fn begin_columnar_selection(
 3153        &mut self,
 3154        position: DisplayPoint,
 3155        goal_column: u32,
 3156        reset: bool,
 3157        window: &mut Window,
 3158        cx: &mut Context<Self>,
 3159    ) {
 3160        if !self.focus_handle.is_focused(window) {
 3161            self.last_focused_descendant = None;
 3162            window.focus(&self.focus_handle);
 3163        }
 3164
 3165        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3166
 3167        if reset {
 3168            let pointer_position = display_map
 3169                .buffer_snapshot
 3170                .anchor_before(position.to_point(&display_map));
 3171
 3172            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3173                s.clear_disjoint();
 3174                s.set_pending_anchor_range(
 3175                    pointer_position..pointer_position,
 3176                    SelectMode::Character,
 3177                );
 3178            });
 3179        }
 3180
 3181        let tail = self.selections.newest::<Point>(cx).tail();
 3182        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3183
 3184        if !reset {
 3185            self.select_columns(
 3186                tail.to_display_point(&display_map),
 3187                position,
 3188                goal_column,
 3189                &display_map,
 3190                window,
 3191                cx,
 3192            );
 3193        }
 3194    }
 3195
 3196    fn update_selection(
 3197        &mut self,
 3198        position: DisplayPoint,
 3199        goal_column: u32,
 3200        scroll_delta: gpui::Point<f32>,
 3201        window: &mut Window,
 3202        cx: &mut Context<Self>,
 3203    ) {
 3204        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3205
 3206        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3207            let tail = tail.to_display_point(&display_map);
 3208            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3209        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3210            let buffer = self.buffer.read(cx).snapshot(cx);
 3211            let head;
 3212            let tail;
 3213            let mode = self.selections.pending_mode().unwrap();
 3214            match &mode {
 3215                SelectMode::Character => {
 3216                    head = position.to_point(&display_map);
 3217                    tail = pending.tail().to_point(&buffer);
 3218                }
 3219                SelectMode::Word(original_range) => {
 3220                    let original_display_range = original_range.start.to_display_point(&display_map)
 3221                        ..original_range.end.to_display_point(&display_map);
 3222                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3223                        ..original_display_range.end.to_point(&display_map);
 3224                    if movement::is_inside_word(&display_map, position)
 3225                        || original_display_range.contains(&position)
 3226                    {
 3227                        let word_range = movement::surrounding_word(&display_map, position);
 3228                        if word_range.start < original_display_range.start {
 3229                            head = word_range.start.to_point(&display_map);
 3230                        } else {
 3231                            head = word_range.end.to_point(&display_map);
 3232                        }
 3233                    } else {
 3234                        head = position.to_point(&display_map);
 3235                    }
 3236
 3237                    if head <= original_buffer_range.start {
 3238                        tail = original_buffer_range.end;
 3239                    } else {
 3240                        tail = original_buffer_range.start;
 3241                    }
 3242                }
 3243                SelectMode::Line(original_range) => {
 3244                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3245
 3246                    let position = display_map
 3247                        .clip_point(position, Bias::Left)
 3248                        .to_point(&display_map);
 3249                    let line_start = display_map.prev_line_boundary(position).0;
 3250                    let next_line_start = buffer.clip_point(
 3251                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3252                        Bias::Left,
 3253                    );
 3254
 3255                    if line_start < original_range.start {
 3256                        head = line_start
 3257                    } else {
 3258                        head = next_line_start
 3259                    }
 3260
 3261                    if head <= original_range.start {
 3262                        tail = original_range.end;
 3263                    } else {
 3264                        tail = original_range.start;
 3265                    }
 3266                }
 3267                SelectMode::All => {
 3268                    return;
 3269                }
 3270            };
 3271
 3272            if head < tail {
 3273                pending.start = buffer.anchor_before(head);
 3274                pending.end = buffer.anchor_before(tail);
 3275                pending.reversed = true;
 3276            } else {
 3277                pending.start = buffer.anchor_before(tail);
 3278                pending.end = buffer.anchor_before(head);
 3279                pending.reversed = false;
 3280            }
 3281
 3282            self.change_selections(None, window, cx, |s| {
 3283                s.set_pending(pending, mode);
 3284            });
 3285        } else {
 3286            log::error!("update_selection dispatched with no pending selection");
 3287            return;
 3288        }
 3289
 3290        self.apply_scroll_delta(scroll_delta, window, cx);
 3291        cx.notify();
 3292    }
 3293
 3294    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3295        self.columnar_selection_tail.take();
 3296        if self.selections.pending_anchor().is_some() {
 3297            let selections = self.selections.all::<usize>(cx);
 3298            self.change_selections(None, window, cx, |s| {
 3299                s.select(selections);
 3300                s.clear_pending();
 3301            });
 3302        }
 3303    }
 3304
 3305    fn select_columns(
 3306        &mut self,
 3307        tail: DisplayPoint,
 3308        head: DisplayPoint,
 3309        goal_column: u32,
 3310        display_map: &DisplaySnapshot,
 3311        window: &mut Window,
 3312        cx: &mut Context<Self>,
 3313    ) {
 3314        let start_row = cmp::min(tail.row(), head.row());
 3315        let end_row = cmp::max(tail.row(), head.row());
 3316        let start_column = cmp::min(tail.column(), goal_column);
 3317        let end_column = cmp::max(tail.column(), goal_column);
 3318        let reversed = start_column < tail.column();
 3319
 3320        let selection_ranges = (start_row.0..=end_row.0)
 3321            .map(DisplayRow)
 3322            .filter_map(|row| {
 3323                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3324                    let start = display_map
 3325                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3326                        .to_point(display_map);
 3327                    let end = display_map
 3328                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3329                        .to_point(display_map);
 3330                    if reversed {
 3331                        Some(end..start)
 3332                    } else {
 3333                        Some(start..end)
 3334                    }
 3335                } else {
 3336                    None
 3337                }
 3338            })
 3339            .collect::<Vec<_>>();
 3340
 3341        self.change_selections(None, window, cx, |s| {
 3342            s.select_ranges(selection_ranges);
 3343        });
 3344        cx.notify();
 3345    }
 3346
 3347    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3348        self.selections
 3349            .all_adjusted(cx)
 3350            .iter()
 3351            .any(|selection| !selection.is_empty())
 3352    }
 3353
 3354    pub fn has_pending_nonempty_selection(&self) -> bool {
 3355        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3356            Some(Selection { start, end, .. }) => start != end,
 3357            None => false,
 3358        };
 3359
 3360        pending_nonempty_selection
 3361            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3362    }
 3363
 3364    pub fn has_pending_selection(&self) -> bool {
 3365        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3366    }
 3367
 3368    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3369        self.selection_mark_mode = false;
 3370
 3371        if self.clear_expanded_diff_hunks(cx) {
 3372            cx.notify();
 3373            return;
 3374        }
 3375        if self.dismiss_menus_and_popups(true, window, cx) {
 3376            return;
 3377        }
 3378
 3379        if self.mode.is_full()
 3380            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3381        {
 3382            return;
 3383        }
 3384
 3385        cx.propagate();
 3386    }
 3387
 3388    pub fn dismiss_menus_and_popups(
 3389        &mut self,
 3390        is_user_requested: bool,
 3391        window: &mut Window,
 3392        cx: &mut Context<Self>,
 3393    ) -> bool {
 3394        if self.take_rename(false, window, cx).is_some() {
 3395            return true;
 3396        }
 3397
 3398        if hide_hover(self, cx) {
 3399            return true;
 3400        }
 3401
 3402        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3403            return true;
 3404        }
 3405
 3406        if self.hide_context_menu(window, cx).is_some() {
 3407            return true;
 3408        }
 3409
 3410        if self.mouse_context_menu.take().is_some() {
 3411            return true;
 3412        }
 3413
 3414        if is_user_requested && self.discard_inline_completion(true, cx) {
 3415            return true;
 3416        }
 3417
 3418        if self.snippet_stack.pop().is_some() {
 3419            return true;
 3420        }
 3421
 3422        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3423            self.dismiss_diagnostics(cx);
 3424            return true;
 3425        }
 3426
 3427        false
 3428    }
 3429
 3430    fn linked_editing_ranges_for(
 3431        &self,
 3432        selection: Range<text::Anchor>,
 3433        cx: &App,
 3434    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3435        if self.linked_edit_ranges.is_empty() {
 3436            return None;
 3437        }
 3438        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3439            selection.end.buffer_id.and_then(|end_buffer_id| {
 3440                if selection.start.buffer_id != Some(end_buffer_id) {
 3441                    return None;
 3442                }
 3443                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3444                let snapshot = buffer.read(cx).snapshot();
 3445                self.linked_edit_ranges
 3446                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3447                    .map(|ranges| (ranges, snapshot, buffer))
 3448            })?;
 3449        use text::ToOffset as TO;
 3450        // find offset from the start of current range to current cursor position
 3451        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3452
 3453        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3454        let start_difference = start_offset - start_byte_offset;
 3455        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3456        let end_difference = end_offset - start_byte_offset;
 3457        // Current range has associated linked ranges.
 3458        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3459        for range in linked_ranges.iter() {
 3460            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3461            let end_offset = start_offset + end_difference;
 3462            let start_offset = start_offset + start_difference;
 3463            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3464                continue;
 3465            }
 3466            if self.selections.disjoint_anchor_ranges().any(|s| {
 3467                if s.start.buffer_id != selection.start.buffer_id
 3468                    || s.end.buffer_id != selection.end.buffer_id
 3469                {
 3470                    return false;
 3471                }
 3472                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3473                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3474            }) {
 3475                continue;
 3476            }
 3477            let start = buffer_snapshot.anchor_after(start_offset);
 3478            let end = buffer_snapshot.anchor_after(end_offset);
 3479            linked_edits
 3480                .entry(buffer.clone())
 3481                .or_default()
 3482                .push(start..end);
 3483        }
 3484        Some(linked_edits)
 3485    }
 3486
 3487    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3488        let text: Arc<str> = text.into();
 3489
 3490        if self.read_only(cx) {
 3491            return;
 3492        }
 3493
 3494        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3495
 3496        let selections = self.selections.all_adjusted(cx);
 3497        let mut bracket_inserted = false;
 3498        let mut edits = Vec::new();
 3499        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3500        let mut new_selections = Vec::with_capacity(selections.len());
 3501        let mut new_autoclose_regions = Vec::new();
 3502        let snapshot = self.buffer.read(cx).read(cx);
 3503        let mut clear_linked_edit_ranges = false;
 3504
 3505        for (selection, autoclose_region) in
 3506            self.selections_with_autoclose_regions(selections, &snapshot)
 3507        {
 3508            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3509                // Determine if the inserted text matches the opening or closing
 3510                // bracket of any of this language's bracket pairs.
 3511                let mut bracket_pair = None;
 3512                let mut is_bracket_pair_start = false;
 3513                let mut is_bracket_pair_end = false;
 3514                if !text.is_empty() {
 3515                    let mut bracket_pair_matching_end = None;
 3516                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3517                    //  and they are removing the character that triggered IME popup.
 3518                    for (pair, enabled) in scope.brackets() {
 3519                        if !pair.close && !pair.surround {
 3520                            continue;
 3521                        }
 3522
 3523                        if enabled && pair.start.ends_with(text.as_ref()) {
 3524                            let prefix_len = pair.start.len() - text.len();
 3525                            let preceding_text_matches_prefix = prefix_len == 0
 3526                                || (selection.start.column >= (prefix_len as u32)
 3527                                    && snapshot.contains_str_at(
 3528                                        Point::new(
 3529                                            selection.start.row,
 3530                                            selection.start.column - (prefix_len as u32),
 3531                                        ),
 3532                                        &pair.start[..prefix_len],
 3533                                    ));
 3534                            if preceding_text_matches_prefix {
 3535                                bracket_pair = Some(pair.clone());
 3536                                is_bracket_pair_start = true;
 3537                                break;
 3538                            }
 3539                        }
 3540                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3541                        {
 3542                            // take first bracket pair matching end, but don't break in case a later bracket
 3543                            // pair matches start
 3544                            bracket_pair_matching_end = Some(pair.clone());
 3545                        }
 3546                    }
 3547                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3548                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3549                        is_bracket_pair_end = true;
 3550                    }
 3551                }
 3552
 3553                if let Some(bracket_pair) = bracket_pair {
 3554                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3555                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3556                    let auto_surround =
 3557                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3558                    if selection.is_empty() {
 3559                        if is_bracket_pair_start {
 3560                            // If the inserted text is a suffix of an opening bracket and the
 3561                            // selection is preceded by the rest of the opening bracket, then
 3562                            // insert the closing bracket.
 3563                            let following_text_allows_autoclose = snapshot
 3564                                .chars_at(selection.start)
 3565                                .next()
 3566                                .map_or(true, |c| scope.should_autoclose_before(c));
 3567
 3568                            let preceding_text_allows_autoclose = selection.start.column == 0
 3569                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3570                                    true,
 3571                                    |c| {
 3572                                        bracket_pair.start != bracket_pair.end
 3573                                            || !snapshot
 3574                                                .char_classifier_at(selection.start)
 3575                                                .is_word(c)
 3576                                    },
 3577                                );
 3578
 3579                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3580                                && bracket_pair.start.len() == 1
 3581                            {
 3582                                let target = bracket_pair.start.chars().next().unwrap();
 3583                                let current_line_count = snapshot
 3584                                    .reversed_chars_at(selection.start)
 3585                                    .take_while(|&c| c != '\n')
 3586                                    .filter(|&c| c == target)
 3587                                    .count();
 3588                                current_line_count % 2 == 1
 3589                            } else {
 3590                                false
 3591                            };
 3592
 3593                            if autoclose
 3594                                && bracket_pair.close
 3595                                && following_text_allows_autoclose
 3596                                && preceding_text_allows_autoclose
 3597                                && !is_closing_quote
 3598                            {
 3599                                let anchor = snapshot.anchor_before(selection.end);
 3600                                new_selections.push((selection.map(|_| anchor), text.len()));
 3601                                new_autoclose_regions.push((
 3602                                    anchor,
 3603                                    text.len(),
 3604                                    selection.id,
 3605                                    bracket_pair.clone(),
 3606                                ));
 3607                                edits.push((
 3608                                    selection.range(),
 3609                                    format!("{}{}", text, bracket_pair.end).into(),
 3610                                ));
 3611                                bracket_inserted = true;
 3612                                continue;
 3613                            }
 3614                        }
 3615
 3616                        if let Some(region) = autoclose_region {
 3617                            // If the selection is followed by an auto-inserted closing bracket,
 3618                            // then don't insert that closing bracket again; just move the selection
 3619                            // past the closing bracket.
 3620                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3621                                && text.as_ref() == region.pair.end.as_str();
 3622                            if should_skip {
 3623                                let anchor = snapshot.anchor_after(selection.end);
 3624                                new_selections
 3625                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3626                                continue;
 3627                            }
 3628                        }
 3629
 3630                        let always_treat_brackets_as_autoclosed = snapshot
 3631                            .language_settings_at(selection.start, cx)
 3632                            .always_treat_brackets_as_autoclosed;
 3633                        if always_treat_brackets_as_autoclosed
 3634                            && is_bracket_pair_end
 3635                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3636                        {
 3637                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3638                            // and the inserted text is a closing bracket and the selection is followed
 3639                            // by the closing bracket then move the selection past the closing bracket.
 3640                            let anchor = snapshot.anchor_after(selection.end);
 3641                            new_selections.push((selection.map(|_| anchor), text.len()));
 3642                            continue;
 3643                        }
 3644                    }
 3645                    // If an opening bracket is 1 character long and is typed while
 3646                    // text is selected, then surround that text with the bracket pair.
 3647                    else if auto_surround
 3648                        && bracket_pair.surround
 3649                        && is_bracket_pair_start
 3650                        && bracket_pair.start.chars().count() == 1
 3651                    {
 3652                        edits.push((selection.start..selection.start, text.clone()));
 3653                        edits.push((
 3654                            selection.end..selection.end,
 3655                            bracket_pair.end.as_str().into(),
 3656                        ));
 3657                        bracket_inserted = true;
 3658                        new_selections.push((
 3659                            Selection {
 3660                                id: selection.id,
 3661                                start: snapshot.anchor_after(selection.start),
 3662                                end: snapshot.anchor_before(selection.end),
 3663                                reversed: selection.reversed,
 3664                                goal: selection.goal,
 3665                            },
 3666                            0,
 3667                        ));
 3668                        continue;
 3669                    }
 3670                }
 3671            }
 3672
 3673            if self.auto_replace_emoji_shortcode
 3674                && selection.is_empty()
 3675                && text.as_ref().ends_with(':')
 3676            {
 3677                if let Some(possible_emoji_short_code) =
 3678                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3679                {
 3680                    if !possible_emoji_short_code.is_empty() {
 3681                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3682                            let emoji_shortcode_start = Point::new(
 3683                                selection.start.row,
 3684                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3685                            );
 3686
 3687                            // Remove shortcode from buffer
 3688                            edits.push((
 3689                                emoji_shortcode_start..selection.start,
 3690                                "".to_string().into(),
 3691                            ));
 3692                            new_selections.push((
 3693                                Selection {
 3694                                    id: selection.id,
 3695                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3696                                    end: snapshot.anchor_before(selection.start),
 3697                                    reversed: selection.reversed,
 3698                                    goal: selection.goal,
 3699                                },
 3700                                0,
 3701                            ));
 3702
 3703                            // Insert emoji
 3704                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3705                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3706                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3707
 3708                            continue;
 3709                        }
 3710                    }
 3711                }
 3712            }
 3713
 3714            // If not handling any auto-close operation, then just replace the selected
 3715            // text with the given input and move the selection to the end of the
 3716            // newly inserted text.
 3717            let anchor = snapshot.anchor_after(selection.end);
 3718            if !self.linked_edit_ranges.is_empty() {
 3719                let start_anchor = snapshot.anchor_before(selection.start);
 3720
 3721                let is_word_char = text.chars().next().map_or(true, |char| {
 3722                    let classifier = snapshot
 3723                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3724                        .ignore_punctuation(true);
 3725                    classifier.is_word(char)
 3726                });
 3727
 3728                if is_word_char {
 3729                    if let Some(ranges) = self
 3730                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3731                    {
 3732                        for (buffer, edits) in ranges {
 3733                            linked_edits
 3734                                .entry(buffer.clone())
 3735                                .or_default()
 3736                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3737                        }
 3738                    }
 3739                } else {
 3740                    clear_linked_edit_ranges = true;
 3741                }
 3742            }
 3743
 3744            new_selections.push((selection.map(|_| anchor), 0));
 3745            edits.push((selection.start..selection.end, text.clone()));
 3746        }
 3747
 3748        drop(snapshot);
 3749
 3750        self.transact(window, cx, |this, window, cx| {
 3751            if clear_linked_edit_ranges {
 3752                this.linked_edit_ranges.clear();
 3753            }
 3754            let initial_buffer_versions =
 3755                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3756
 3757            this.buffer.update(cx, |buffer, cx| {
 3758                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3759            });
 3760            for (buffer, edits) in linked_edits {
 3761                buffer.update(cx, |buffer, cx| {
 3762                    let snapshot = buffer.snapshot();
 3763                    let edits = edits
 3764                        .into_iter()
 3765                        .map(|(range, text)| {
 3766                            use text::ToPoint as TP;
 3767                            let end_point = TP::to_point(&range.end, &snapshot);
 3768                            let start_point = TP::to_point(&range.start, &snapshot);
 3769                            (start_point..end_point, text)
 3770                        })
 3771                        .sorted_by_key(|(range, _)| range.start);
 3772                    buffer.edit(edits, None, cx);
 3773                })
 3774            }
 3775            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3776            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3777            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3778            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3779                .zip(new_selection_deltas)
 3780                .map(|(selection, delta)| Selection {
 3781                    id: selection.id,
 3782                    start: selection.start + delta,
 3783                    end: selection.end + delta,
 3784                    reversed: selection.reversed,
 3785                    goal: SelectionGoal::None,
 3786                })
 3787                .collect::<Vec<_>>();
 3788
 3789            let mut i = 0;
 3790            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3791                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3792                let start = map.buffer_snapshot.anchor_before(position);
 3793                let end = map.buffer_snapshot.anchor_after(position);
 3794                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3795                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3796                        Ordering::Less => i += 1,
 3797                        Ordering::Greater => break,
 3798                        Ordering::Equal => {
 3799                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3800                                Ordering::Less => i += 1,
 3801                                Ordering::Equal => break,
 3802                                Ordering::Greater => break,
 3803                            }
 3804                        }
 3805                    }
 3806                }
 3807                this.autoclose_regions.insert(
 3808                    i,
 3809                    AutocloseRegion {
 3810                        selection_id,
 3811                        range: start..end,
 3812                        pair,
 3813                    },
 3814                );
 3815            }
 3816
 3817            let had_active_inline_completion = this.has_active_inline_completion();
 3818            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3819                s.select(new_selections)
 3820            });
 3821
 3822            if !bracket_inserted {
 3823                if let Some(on_type_format_task) =
 3824                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3825                {
 3826                    on_type_format_task.detach_and_log_err(cx);
 3827                }
 3828            }
 3829
 3830            let editor_settings = EditorSettings::get_global(cx);
 3831            if bracket_inserted
 3832                && (editor_settings.auto_signature_help
 3833                    || editor_settings.show_signature_help_after_edits)
 3834            {
 3835                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3836            }
 3837
 3838            let trigger_in_words =
 3839                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3840            if this.hard_wrap.is_some() {
 3841                let latest: Range<Point> = this.selections.newest(cx).range();
 3842                if latest.is_empty()
 3843                    && this
 3844                        .buffer()
 3845                        .read(cx)
 3846                        .snapshot(cx)
 3847                        .line_len(MultiBufferRow(latest.start.row))
 3848                        == latest.start.column
 3849                {
 3850                    this.rewrap_impl(
 3851                        RewrapOptions {
 3852                            override_language_settings: true,
 3853                            preserve_existing_whitespace: true,
 3854                        },
 3855                        cx,
 3856                    )
 3857                }
 3858            }
 3859            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3860            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3861            this.refresh_inline_completion(true, false, window, cx);
 3862            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3863        });
 3864    }
 3865
 3866    fn find_possible_emoji_shortcode_at_position(
 3867        snapshot: &MultiBufferSnapshot,
 3868        position: Point,
 3869    ) -> Option<String> {
 3870        let mut chars = Vec::new();
 3871        let mut found_colon = false;
 3872        for char in snapshot.reversed_chars_at(position).take(100) {
 3873            // Found a possible emoji shortcode in the middle of the buffer
 3874            if found_colon {
 3875                if char.is_whitespace() {
 3876                    chars.reverse();
 3877                    return Some(chars.iter().collect());
 3878                }
 3879                // If the previous character is not a whitespace, we are in the middle of a word
 3880                // and we only want to complete the shortcode if the word is made up of other emojis
 3881                let mut containing_word = String::new();
 3882                for ch in snapshot
 3883                    .reversed_chars_at(position)
 3884                    .skip(chars.len() + 1)
 3885                    .take(100)
 3886                {
 3887                    if ch.is_whitespace() {
 3888                        break;
 3889                    }
 3890                    containing_word.push(ch);
 3891                }
 3892                let containing_word = containing_word.chars().rev().collect::<String>();
 3893                if util::word_consists_of_emojis(containing_word.as_str()) {
 3894                    chars.reverse();
 3895                    return Some(chars.iter().collect());
 3896                }
 3897            }
 3898
 3899            if char.is_whitespace() || !char.is_ascii() {
 3900                return None;
 3901            }
 3902            if char == ':' {
 3903                found_colon = true;
 3904            } else {
 3905                chars.push(char);
 3906            }
 3907        }
 3908        // Found a possible emoji shortcode at the beginning of the buffer
 3909        chars.reverse();
 3910        Some(chars.iter().collect())
 3911    }
 3912
 3913    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3914        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3915        self.transact(window, cx, |this, window, cx| {
 3916            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3917                let selections = this.selections.all::<usize>(cx);
 3918                let multi_buffer = this.buffer.read(cx);
 3919                let buffer = multi_buffer.snapshot(cx);
 3920                selections
 3921                    .iter()
 3922                    .map(|selection| {
 3923                        let start_point = selection.start.to_point(&buffer);
 3924                        let mut existing_indent =
 3925                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3926                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3927                        let start = selection.start;
 3928                        let end = selection.end;
 3929                        let selection_is_empty = start == end;
 3930                        let language_scope = buffer.language_scope_at(start);
 3931                        let (
 3932                            comment_delimiter,
 3933                            doc_delimiter,
 3934                            insert_extra_newline,
 3935                            indent_on_newline,
 3936                            indent_on_extra_newline,
 3937                        ) = if let Some(language) = &language_scope {
 3938                            let mut insert_extra_newline =
 3939                                insert_extra_newline_brackets(&buffer, start..end, language)
 3940                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3941
 3942                            // Comment extension on newline is allowed only for cursor selections
 3943                            let comment_delimiter = maybe!({
 3944                                if !selection_is_empty {
 3945                                    return None;
 3946                                }
 3947
 3948                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3949                                    return None;
 3950                                }
 3951
 3952                                let delimiters = language.line_comment_prefixes();
 3953                                let max_len_of_delimiter =
 3954                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3955                                let (snapshot, range) =
 3956                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3957
 3958                                let num_of_whitespaces = snapshot
 3959                                    .chars_for_range(range.clone())
 3960                                    .take_while(|c| c.is_whitespace())
 3961                                    .count();
 3962                                let comment_candidate = snapshot
 3963                                    .chars_for_range(range)
 3964                                    .skip(num_of_whitespaces)
 3965                                    .take(max_len_of_delimiter)
 3966                                    .collect::<String>();
 3967                                let (delimiter, trimmed_len) = delimiters
 3968                                    .iter()
 3969                                    .filter_map(|delimiter| {
 3970                                        let prefix = delimiter.trim_end();
 3971                                        if comment_candidate.starts_with(prefix) {
 3972                                            Some((delimiter, prefix.len()))
 3973                                        } else {
 3974                                            None
 3975                                        }
 3976                                    })
 3977                                    .max_by_key(|(_, len)| *len)?;
 3978
 3979                                let cursor_is_placed_after_comment_marker =
 3980                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3981                                if cursor_is_placed_after_comment_marker {
 3982                                    Some(delimiter.clone())
 3983                                } else {
 3984                                    None
 3985                                }
 3986                            });
 3987
 3988                            let mut indent_on_newline = IndentSize::spaces(0);
 3989                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3990
 3991                            let doc_delimiter = maybe!({
 3992                                if !selection_is_empty {
 3993                                    return None;
 3994                                }
 3995
 3996                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3997                                    return None;
 3998                                }
 3999
 4000                                let DocumentationConfig {
 4001                                    start: start_tag,
 4002                                    end: end_tag,
 4003                                    prefix: delimiter,
 4004                                    tab_size: len,
 4005                                } = language.documentation()?;
 4006
 4007                                let (snapshot, range) =
 4008                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4009
 4010                                let num_of_whitespaces = snapshot
 4011                                    .chars_for_range(range.clone())
 4012                                    .take_while(|c| c.is_whitespace())
 4013                                    .count();
 4014
 4015                                let cursor_is_after_start_tag = {
 4016                                    let start_tag_len = start_tag.len();
 4017                                    let start_tag_line = snapshot
 4018                                        .chars_for_range(range.clone())
 4019                                        .skip(num_of_whitespaces)
 4020                                        .take(start_tag_len)
 4021                                        .collect::<String>();
 4022                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4023                                        num_of_whitespaces + start_tag_len
 4024                                            <= start_point.column as usize
 4025                                    } else {
 4026                                        false
 4027                                    }
 4028                                };
 4029
 4030                                let cursor_is_after_delimiter = {
 4031                                    let delimiter_trim = delimiter.trim_end();
 4032                                    let delimiter_line = snapshot
 4033                                        .chars_for_range(range.clone())
 4034                                        .skip(num_of_whitespaces)
 4035                                        .take(delimiter_trim.len())
 4036                                        .collect::<String>();
 4037                                    if delimiter_line.starts_with(delimiter_trim) {
 4038                                        num_of_whitespaces + delimiter_trim.len()
 4039                                            <= start_point.column as usize
 4040                                    } else {
 4041                                        false
 4042                                    }
 4043                                };
 4044
 4045                                let cursor_is_before_end_tag_if_exists = {
 4046                                    let num_of_whitespaces_rev = snapshot
 4047                                        .reversed_chars_for_range(range.clone())
 4048                                        .take_while(|c| c.is_whitespace())
 4049                                        .count();
 4050                                    let mut line_iter = snapshot
 4051                                        .reversed_chars_for_range(range)
 4052                                        .skip(num_of_whitespaces_rev);
 4053                                    let end_tag_exists = end_tag
 4054                                        .chars()
 4055                                        .rev()
 4056                                        .all(|char| line_iter.next() == Some(char));
 4057                                    if end_tag_exists {
 4058                                        let max_point = snapshot.line_len(start_point.row) as usize;
 4059                                        let ordering = (num_of_whitespaces_rev
 4060                                            + end_tag.len()
 4061                                            + start_point.column as usize)
 4062                                            .cmp(&max_point);
 4063                                        let cursor_is_before_end_tag =
 4064                                            ordering != Ordering::Greater;
 4065                                        if cursor_is_after_start_tag {
 4066                                            if cursor_is_before_end_tag {
 4067                                                insert_extra_newline = true;
 4068                                            }
 4069                                            let cursor_is_at_start_of_end_tag =
 4070                                                ordering == Ordering::Equal;
 4071                                            if cursor_is_at_start_of_end_tag {
 4072                                                indent_on_extra_newline.len = (*len).into();
 4073                                            }
 4074                                        }
 4075                                        cursor_is_before_end_tag
 4076                                    } else {
 4077                                        true
 4078                                    }
 4079                                };
 4080
 4081                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4082                                    && cursor_is_before_end_tag_if_exists
 4083                                {
 4084                                    if cursor_is_after_start_tag {
 4085                                        indent_on_newline.len = (*len).into();
 4086                                    }
 4087                                    Some(delimiter.clone())
 4088                                } else {
 4089                                    None
 4090                                }
 4091                            });
 4092
 4093                            (
 4094                                comment_delimiter,
 4095                                doc_delimiter,
 4096                                insert_extra_newline,
 4097                                indent_on_newline,
 4098                                indent_on_extra_newline,
 4099                            )
 4100                        } else {
 4101                            (
 4102                                None,
 4103                                None,
 4104                                false,
 4105                                IndentSize::default(),
 4106                                IndentSize::default(),
 4107                            )
 4108                        };
 4109
 4110                        let prevent_auto_indent = doc_delimiter.is_some();
 4111                        let delimiter = comment_delimiter.or(doc_delimiter);
 4112
 4113                        let capacity_for_delimiter =
 4114                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4115                        let mut new_text = String::with_capacity(
 4116                            1 + capacity_for_delimiter
 4117                                + existing_indent.len as usize
 4118                                + indent_on_newline.len as usize
 4119                                + indent_on_extra_newline.len as usize,
 4120                        );
 4121                        new_text.push('\n');
 4122                        new_text.extend(existing_indent.chars());
 4123                        new_text.extend(indent_on_newline.chars());
 4124
 4125                        if let Some(delimiter) = &delimiter {
 4126                            new_text.push_str(delimiter);
 4127                        }
 4128
 4129                        if insert_extra_newline {
 4130                            new_text.push('\n');
 4131                            new_text.extend(existing_indent.chars());
 4132                            new_text.extend(indent_on_extra_newline.chars());
 4133                        }
 4134
 4135                        let anchor = buffer.anchor_after(end);
 4136                        let new_selection = selection.map(|_| anchor);
 4137                        (
 4138                            ((start..end, new_text), prevent_auto_indent),
 4139                            (insert_extra_newline, new_selection),
 4140                        )
 4141                    })
 4142                    .unzip()
 4143            };
 4144
 4145            let mut auto_indent_edits = Vec::new();
 4146            let mut edits = Vec::new();
 4147            for (edit, prevent_auto_indent) in edits_with_flags {
 4148                if prevent_auto_indent {
 4149                    edits.push(edit);
 4150                } else {
 4151                    auto_indent_edits.push(edit);
 4152                }
 4153            }
 4154            if !edits.is_empty() {
 4155                this.edit(edits, cx);
 4156            }
 4157            if !auto_indent_edits.is_empty() {
 4158                this.edit_with_autoindent(auto_indent_edits, cx);
 4159            }
 4160
 4161            let buffer = this.buffer.read(cx).snapshot(cx);
 4162            let new_selections = selection_info
 4163                .into_iter()
 4164                .map(|(extra_newline_inserted, new_selection)| {
 4165                    let mut cursor = new_selection.end.to_point(&buffer);
 4166                    if extra_newline_inserted {
 4167                        cursor.row -= 1;
 4168                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4169                    }
 4170                    new_selection.map(|_| cursor)
 4171                })
 4172                .collect();
 4173
 4174            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4175                s.select(new_selections)
 4176            });
 4177            this.refresh_inline_completion(true, false, window, cx);
 4178        });
 4179    }
 4180
 4181    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4182        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4183
 4184        let buffer = self.buffer.read(cx);
 4185        let snapshot = buffer.snapshot(cx);
 4186
 4187        let mut edits = Vec::new();
 4188        let mut rows = Vec::new();
 4189
 4190        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4191            let cursor = selection.head();
 4192            let row = cursor.row;
 4193
 4194            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4195
 4196            let newline = "\n".to_string();
 4197            edits.push((start_of_line..start_of_line, newline));
 4198
 4199            rows.push(row + rows_inserted as u32);
 4200        }
 4201
 4202        self.transact(window, cx, |editor, window, cx| {
 4203            editor.edit(edits, cx);
 4204
 4205            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4206                let mut index = 0;
 4207                s.move_cursors_with(|map, _, _| {
 4208                    let row = rows[index];
 4209                    index += 1;
 4210
 4211                    let point = Point::new(row, 0);
 4212                    let boundary = map.next_line_boundary(point).1;
 4213                    let clipped = map.clip_point(boundary, Bias::Left);
 4214
 4215                    (clipped, SelectionGoal::None)
 4216                });
 4217            });
 4218
 4219            let mut indent_edits = Vec::new();
 4220            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4221            for row in rows {
 4222                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4223                for (row, indent) in indents {
 4224                    if indent.len == 0 {
 4225                        continue;
 4226                    }
 4227
 4228                    let text = match indent.kind {
 4229                        IndentKind::Space => " ".repeat(indent.len as usize),
 4230                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4231                    };
 4232                    let point = Point::new(row.0, 0);
 4233                    indent_edits.push((point..point, text));
 4234                }
 4235            }
 4236            editor.edit(indent_edits, cx);
 4237        });
 4238    }
 4239
 4240    pub fn newline_below(&mut self, _: &NewlineBelow, 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        let mut rows_inserted = 0;
 4249
 4250        for selection in self.selections.all_adjusted(cx) {
 4251            let cursor = selection.head();
 4252            let row = cursor.row;
 4253
 4254            let point = Point::new(row + 1, 0);
 4255            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4256
 4257            let newline = "\n".to_string();
 4258            edits.push((start_of_line..start_of_line, newline));
 4259
 4260            rows_inserted += 1;
 4261            rows.push(row + rows_inserted);
 4262        }
 4263
 4264        self.transact(window, cx, |editor, window, cx| {
 4265            editor.edit(edits, cx);
 4266
 4267            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4268                let mut index = 0;
 4269                s.move_cursors_with(|map, _, _| {
 4270                    let row = rows[index];
 4271                    index += 1;
 4272
 4273                    let point = Point::new(row, 0);
 4274                    let boundary = map.next_line_boundary(point).1;
 4275                    let clipped = map.clip_point(boundary, Bias::Left);
 4276
 4277                    (clipped, SelectionGoal::None)
 4278                });
 4279            });
 4280
 4281            let mut indent_edits = Vec::new();
 4282            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4283            for row in rows {
 4284                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4285                for (row, indent) in indents {
 4286                    if indent.len == 0 {
 4287                        continue;
 4288                    }
 4289
 4290                    let text = match indent.kind {
 4291                        IndentKind::Space => " ".repeat(indent.len as usize),
 4292                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4293                    };
 4294                    let point = Point::new(row.0, 0);
 4295                    indent_edits.push((point..point, text));
 4296                }
 4297            }
 4298            editor.edit(indent_edits, cx);
 4299        });
 4300    }
 4301
 4302    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4303        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4304            original_indent_columns: Vec::new(),
 4305        });
 4306        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4307    }
 4308
 4309    fn insert_with_autoindent_mode(
 4310        &mut self,
 4311        text: &str,
 4312        autoindent_mode: Option<AutoindentMode>,
 4313        window: &mut Window,
 4314        cx: &mut Context<Self>,
 4315    ) {
 4316        if self.read_only(cx) {
 4317            return;
 4318        }
 4319
 4320        let text: Arc<str> = text.into();
 4321        self.transact(window, cx, |this, window, cx| {
 4322            let old_selections = this.selections.all_adjusted(cx);
 4323            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4324                let anchors = {
 4325                    let snapshot = buffer.read(cx);
 4326                    old_selections
 4327                        .iter()
 4328                        .map(|s| {
 4329                            let anchor = snapshot.anchor_after(s.head());
 4330                            s.map(|_| anchor)
 4331                        })
 4332                        .collect::<Vec<_>>()
 4333                };
 4334                buffer.edit(
 4335                    old_selections
 4336                        .iter()
 4337                        .map(|s| (s.start..s.end, text.clone())),
 4338                    autoindent_mode,
 4339                    cx,
 4340                );
 4341                anchors
 4342            });
 4343
 4344            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4345                s.select_anchors(selection_anchors);
 4346            });
 4347
 4348            cx.notify();
 4349        });
 4350    }
 4351
 4352    fn trigger_completion_on_input(
 4353        &mut self,
 4354        text: &str,
 4355        trigger_in_words: bool,
 4356        window: &mut Window,
 4357        cx: &mut Context<Self>,
 4358    ) {
 4359        let ignore_completion_provider = self
 4360            .context_menu
 4361            .borrow()
 4362            .as_ref()
 4363            .map(|menu| match menu {
 4364                CodeContextMenu::Completions(completions_menu) => {
 4365                    completions_menu.ignore_completion_provider
 4366                }
 4367                CodeContextMenu::CodeActions(_) => false,
 4368            })
 4369            .unwrap_or(false);
 4370
 4371        if ignore_completion_provider {
 4372            self.show_word_completions(&ShowWordCompletions, window, cx);
 4373        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4374            self.show_completions(
 4375                &ShowCompletions {
 4376                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4377                },
 4378                window,
 4379                cx,
 4380            );
 4381        } else {
 4382            self.hide_context_menu(window, cx);
 4383        }
 4384    }
 4385
 4386    fn is_completion_trigger(
 4387        &self,
 4388        text: &str,
 4389        trigger_in_words: bool,
 4390        cx: &mut Context<Self>,
 4391    ) -> bool {
 4392        let position = self.selections.newest_anchor().head();
 4393        let multibuffer = self.buffer.read(cx);
 4394        let Some(buffer) = position
 4395            .buffer_id
 4396            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4397        else {
 4398            return false;
 4399        };
 4400
 4401        if let Some(completion_provider) = &self.completion_provider {
 4402            completion_provider.is_completion_trigger(
 4403                &buffer,
 4404                position.text_anchor,
 4405                text,
 4406                trigger_in_words,
 4407                cx,
 4408            )
 4409        } else {
 4410            false
 4411        }
 4412    }
 4413
 4414    /// If any empty selections is touching the start of its innermost containing autoclose
 4415    /// region, expand it to select the brackets.
 4416    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4417        let selections = self.selections.all::<usize>(cx);
 4418        let buffer = self.buffer.read(cx).read(cx);
 4419        let new_selections = self
 4420            .selections_with_autoclose_regions(selections, &buffer)
 4421            .map(|(mut selection, region)| {
 4422                if !selection.is_empty() {
 4423                    return selection;
 4424                }
 4425
 4426                if let Some(region) = region {
 4427                    let mut range = region.range.to_offset(&buffer);
 4428                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4429                        range.start -= region.pair.start.len();
 4430                        if buffer.contains_str_at(range.start, &region.pair.start)
 4431                            && buffer.contains_str_at(range.end, &region.pair.end)
 4432                        {
 4433                            range.end += region.pair.end.len();
 4434                            selection.start = range.start;
 4435                            selection.end = range.end;
 4436
 4437                            return selection;
 4438                        }
 4439                    }
 4440                }
 4441
 4442                let always_treat_brackets_as_autoclosed = buffer
 4443                    .language_settings_at(selection.start, cx)
 4444                    .always_treat_brackets_as_autoclosed;
 4445
 4446                if !always_treat_brackets_as_autoclosed {
 4447                    return selection;
 4448                }
 4449
 4450                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4451                    for (pair, enabled) in scope.brackets() {
 4452                        if !enabled || !pair.close {
 4453                            continue;
 4454                        }
 4455
 4456                        if buffer.contains_str_at(selection.start, &pair.end) {
 4457                            let pair_start_len = pair.start.len();
 4458                            if buffer.contains_str_at(
 4459                                selection.start.saturating_sub(pair_start_len),
 4460                                &pair.start,
 4461                            ) {
 4462                                selection.start -= pair_start_len;
 4463                                selection.end += pair.end.len();
 4464
 4465                                return selection;
 4466                            }
 4467                        }
 4468                    }
 4469                }
 4470
 4471                selection
 4472            })
 4473            .collect();
 4474
 4475        drop(buffer);
 4476        self.change_selections(None, window, cx, |selections| {
 4477            selections.select(new_selections)
 4478        });
 4479    }
 4480
 4481    /// Iterate the given selections, and for each one, find the smallest surrounding
 4482    /// autoclose region. This uses the ordering of the selections and the autoclose
 4483    /// regions to avoid repeated comparisons.
 4484    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4485        &'a self,
 4486        selections: impl IntoIterator<Item = Selection<D>>,
 4487        buffer: &'a MultiBufferSnapshot,
 4488    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4489        let mut i = 0;
 4490        let mut regions = self.autoclose_regions.as_slice();
 4491        selections.into_iter().map(move |selection| {
 4492            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4493
 4494            let mut enclosing = None;
 4495            while let Some(pair_state) = regions.get(i) {
 4496                if pair_state.range.end.to_offset(buffer) < range.start {
 4497                    regions = &regions[i + 1..];
 4498                    i = 0;
 4499                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4500                    break;
 4501                } else {
 4502                    if pair_state.selection_id == selection.id {
 4503                        enclosing = Some(pair_state);
 4504                    }
 4505                    i += 1;
 4506                }
 4507            }
 4508
 4509            (selection, enclosing)
 4510        })
 4511    }
 4512
 4513    /// Remove any autoclose regions that no longer contain their selection.
 4514    fn invalidate_autoclose_regions(
 4515        &mut self,
 4516        mut selections: &[Selection<Anchor>],
 4517        buffer: &MultiBufferSnapshot,
 4518    ) {
 4519        self.autoclose_regions.retain(|state| {
 4520            let mut i = 0;
 4521            while let Some(selection) = selections.get(i) {
 4522                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4523                    selections = &selections[1..];
 4524                    continue;
 4525                }
 4526                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4527                    break;
 4528                }
 4529                if selection.id == state.selection_id {
 4530                    return true;
 4531                } else {
 4532                    i += 1;
 4533                }
 4534            }
 4535            false
 4536        });
 4537    }
 4538
 4539    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4540        let offset = position.to_offset(buffer);
 4541        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4542        if offset > word_range.start && kind == Some(CharKind::Word) {
 4543            Some(
 4544                buffer
 4545                    .text_for_range(word_range.start..offset)
 4546                    .collect::<String>(),
 4547            )
 4548        } else {
 4549            None
 4550        }
 4551    }
 4552
 4553    pub fn toggle_inline_values(
 4554        &mut self,
 4555        _: &ToggleInlineValues,
 4556        _: &mut Window,
 4557        cx: &mut Context<Self>,
 4558    ) {
 4559        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4560
 4561        self.refresh_inline_values(cx);
 4562    }
 4563
 4564    pub fn toggle_inlay_hints(
 4565        &mut self,
 4566        _: &ToggleInlayHints,
 4567        _: &mut Window,
 4568        cx: &mut Context<Self>,
 4569    ) {
 4570        self.refresh_inlay_hints(
 4571            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4572            cx,
 4573        );
 4574    }
 4575
 4576    pub fn inlay_hints_enabled(&self) -> bool {
 4577        self.inlay_hint_cache.enabled
 4578    }
 4579
 4580    pub fn inline_values_enabled(&self) -> bool {
 4581        self.inline_value_cache.enabled
 4582    }
 4583
 4584    #[cfg(any(test, feature = "test-support"))]
 4585    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4586        self.display_map
 4587            .read(cx)
 4588            .current_inlays()
 4589            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4590            .cloned()
 4591            .collect()
 4592    }
 4593
 4594    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4595        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4596            return;
 4597        }
 4598
 4599        let reason_description = reason.description();
 4600        let ignore_debounce = matches!(
 4601            reason,
 4602            InlayHintRefreshReason::SettingsChange(_)
 4603                | InlayHintRefreshReason::Toggle(_)
 4604                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4605                | InlayHintRefreshReason::ModifiersChanged(_)
 4606        );
 4607        let (invalidate_cache, required_languages) = match reason {
 4608            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4609                match self.inlay_hint_cache.modifiers_override(enabled) {
 4610                    Some(enabled) => {
 4611                        if enabled {
 4612                            (InvalidationStrategy::RefreshRequested, None)
 4613                        } else {
 4614                            self.splice_inlays(
 4615                                &self
 4616                                    .visible_inlay_hints(cx)
 4617                                    .iter()
 4618                                    .map(|inlay| inlay.id)
 4619                                    .collect::<Vec<InlayId>>(),
 4620                                Vec::new(),
 4621                                cx,
 4622                            );
 4623                            return;
 4624                        }
 4625                    }
 4626                    None => return,
 4627                }
 4628            }
 4629            InlayHintRefreshReason::Toggle(enabled) => {
 4630                if self.inlay_hint_cache.toggle(enabled) {
 4631                    if enabled {
 4632                        (InvalidationStrategy::RefreshRequested, None)
 4633                    } else {
 4634                        self.splice_inlays(
 4635                            &self
 4636                                .visible_inlay_hints(cx)
 4637                                .iter()
 4638                                .map(|inlay| inlay.id)
 4639                                .collect::<Vec<InlayId>>(),
 4640                            Vec::new(),
 4641                            cx,
 4642                        );
 4643                        return;
 4644                    }
 4645                } else {
 4646                    return;
 4647                }
 4648            }
 4649            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4650                match self.inlay_hint_cache.update_settings(
 4651                    &self.buffer,
 4652                    new_settings,
 4653                    self.visible_inlay_hints(cx),
 4654                    cx,
 4655                ) {
 4656                    ControlFlow::Break(Some(InlaySplice {
 4657                        to_remove,
 4658                        to_insert,
 4659                    })) => {
 4660                        self.splice_inlays(&to_remove, to_insert, cx);
 4661                        return;
 4662                    }
 4663                    ControlFlow::Break(None) => return,
 4664                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4665                }
 4666            }
 4667            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4668                if let Some(InlaySplice {
 4669                    to_remove,
 4670                    to_insert,
 4671                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4672                {
 4673                    self.splice_inlays(&to_remove, to_insert, cx);
 4674                }
 4675                self.display_map.update(cx, |display_map, _| {
 4676                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4677                });
 4678                return;
 4679            }
 4680            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4681            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4682                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4683            }
 4684            InlayHintRefreshReason::RefreshRequested => {
 4685                (InvalidationStrategy::RefreshRequested, None)
 4686            }
 4687        };
 4688
 4689        if let Some(InlaySplice {
 4690            to_remove,
 4691            to_insert,
 4692        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4693            reason_description,
 4694            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4695            invalidate_cache,
 4696            ignore_debounce,
 4697            cx,
 4698        ) {
 4699            self.splice_inlays(&to_remove, to_insert, cx);
 4700        }
 4701    }
 4702
 4703    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4704        self.display_map
 4705            .read(cx)
 4706            .current_inlays()
 4707            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4708            .cloned()
 4709            .collect()
 4710    }
 4711
 4712    pub fn excerpts_for_inlay_hints_query(
 4713        &self,
 4714        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4715        cx: &mut Context<Editor>,
 4716    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4717        let Some(project) = self.project.as_ref() else {
 4718            return HashMap::default();
 4719        };
 4720        let project = project.read(cx);
 4721        let multi_buffer = self.buffer().read(cx);
 4722        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4723        let multi_buffer_visible_start = self
 4724            .scroll_manager
 4725            .anchor()
 4726            .anchor
 4727            .to_point(&multi_buffer_snapshot);
 4728        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4729            multi_buffer_visible_start
 4730                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4731            Bias::Left,
 4732        );
 4733        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4734        multi_buffer_snapshot
 4735            .range_to_buffer_ranges(multi_buffer_visible_range)
 4736            .into_iter()
 4737            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4738            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4739                let buffer_file = project::File::from_dyn(buffer.file())?;
 4740                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4741                let worktree_entry = buffer_worktree
 4742                    .read(cx)
 4743                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4744                if worktree_entry.is_ignored {
 4745                    return None;
 4746                }
 4747
 4748                let language = buffer.language()?;
 4749                if let Some(restrict_to_languages) = restrict_to_languages {
 4750                    if !restrict_to_languages.contains(language) {
 4751                        return None;
 4752                    }
 4753                }
 4754                Some((
 4755                    excerpt_id,
 4756                    (
 4757                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4758                        buffer.version().clone(),
 4759                        excerpt_visible_range,
 4760                    ),
 4761                ))
 4762            })
 4763            .collect()
 4764    }
 4765
 4766    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4767        TextLayoutDetails {
 4768            text_system: window.text_system().clone(),
 4769            editor_style: self.style.clone().unwrap(),
 4770            rem_size: window.rem_size(),
 4771            scroll_anchor: self.scroll_manager.anchor(),
 4772            visible_rows: self.visible_line_count(),
 4773            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4774        }
 4775    }
 4776
 4777    pub fn splice_inlays(
 4778        &self,
 4779        to_remove: &[InlayId],
 4780        to_insert: Vec<Inlay>,
 4781        cx: &mut Context<Self>,
 4782    ) {
 4783        self.display_map.update(cx, |display_map, cx| {
 4784            display_map.splice_inlays(to_remove, to_insert, cx)
 4785        });
 4786        cx.notify();
 4787    }
 4788
 4789    fn trigger_on_type_formatting(
 4790        &self,
 4791        input: String,
 4792        window: &mut Window,
 4793        cx: &mut Context<Self>,
 4794    ) -> Option<Task<Result<()>>> {
 4795        if input.len() != 1 {
 4796            return None;
 4797        }
 4798
 4799        let project = self.project.as_ref()?;
 4800        let position = self.selections.newest_anchor().head();
 4801        let (buffer, buffer_position) = self
 4802            .buffer
 4803            .read(cx)
 4804            .text_anchor_for_position(position, cx)?;
 4805
 4806        let settings = language_settings::language_settings(
 4807            buffer
 4808                .read(cx)
 4809                .language_at(buffer_position)
 4810                .map(|l| l.name()),
 4811            buffer.read(cx).file(),
 4812            cx,
 4813        );
 4814        if !settings.use_on_type_format {
 4815            return None;
 4816        }
 4817
 4818        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4819        // hence we do LSP request & edit on host side only — add formats to host's history.
 4820        let push_to_lsp_host_history = true;
 4821        // If this is not the host, append its history with new edits.
 4822        let push_to_client_history = project.read(cx).is_via_collab();
 4823
 4824        let on_type_formatting = project.update(cx, |project, cx| {
 4825            project.on_type_format(
 4826                buffer.clone(),
 4827                buffer_position,
 4828                input,
 4829                push_to_lsp_host_history,
 4830                cx,
 4831            )
 4832        });
 4833        Some(cx.spawn_in(window, async move |editor, cx| {
 4834            if let Some(transaction) = on_type_formatting.await? {
 4835                if push_to_client_history {
 4836                    buffer
 4837                        .update(cx, |buffer, _| {
 4838                            buffer.push_transaction(transaction, Instant::now());
 4839                            buffer.finalize_last_transaction();
 4840                        })
 4841                        .ok();
 4842                }
 4843                editor.update(cx, |editor, cx| {
 4844                    editor.refresh_document_highlights(cx);
 4845                })?;
 4846            }
 4847            Ok(())
 4848        }))
 4849    }
 4850
 4851    pub fn show_word_completions(
 4852        &mut self,
 4853        _: &ShowWordCompletions,
 4854        window: &mut Window,
 4855        cx: &mut Context<Self>,
 4856    ) {
 4857        self.open_completions_menu(true, None, window, cx);
 4858    }
 4859
 4860    pub fn show_completions(
 4861        &mut self,
 4862        options: &ShowCompletions,
 4863        window: &mut Window,
 4864        cx: &mut Context<Self>,
 4865    ) {
 4866        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4867    }
 4868
 4869    fn open_completions_menu(
 4870        &mut self,
 4871        ignore_completion_provider: bool,
 4872        trigger: Option<&str>,
 4873        window: &mut Window,
 4874        cx: &mut Context<Self>,
 4875    ) {
 4876        if self.pending_rename.is_some() {
 4877            return;
 4878        }
 4879        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4880            return;
 4881        }
 4882
 4883        let position = self.selections.newest_anchor().head();
 4884        if position.diff_base_anchor.is_some() {
 4885            return;
 4886        }
 4887        let (buffer, buffer_position) =
 4888            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4889                output
 4890            } else {
 4891                return;
 4892            };
 4893        let buffer_snapshot = buffer.read(cx).snapshot();
 4894        let show_completion_documentation = buffer_snapshot
 4895            .settings_at(buffer_position, cx)
 4896            .show_completion_documentation;
 4897
 4898        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4899
 4900        let trigger_kind = match trigger {
 4901            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4902                CompletionTriggerKind::TRIGGER_CHARACTER
 4903            }
 4904            _ => CompletionTriggerKind::INVOKED,
 4905        };
 4906        let completion_context = CompletionContext {
 4907            trigger_character: trigger.and_then(|trigger| {
 4908                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4909                    Some(String::from(trigger))
 4910                } else {
 4911                    None
 4912                }
 4913            }),
 4914            trigger_kind,
 4915        };
 4916
 4917        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4918        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4919            let word_to_exclude = buffer_snapshot
 4920                .text_for_range(old_range.clone())
 4921                .collect::<String>();
 4922            (
 4923                buffer_snapshot.anchor_before(old_range.start)
 4924                    ..buffer_snapshot.anchor_after(old_range.end),
 4925                Some(word_to_exclude),
 4926            )
 4927        } else {
 4928            (buffer_position..buffer_position, None)
 4929        };
 4930
 4931        let completion_settings = language_settings(
 4932            buffer_snapshot
 4933                .language_at(buffer_position)
 4934                .map(|language| language.name()),
 4935            buffer_snapshot.file(),
 4936            cx,
 4937        )
 4938        .completions;
 4939
 4940        // The document can be large, so stay in reasonable bounds when searching for words,
 4941        // otherwise completion pop-up might be slow to appear.
 4942        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4943        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4944        let min_word_search = buffer_snapshot.clip_point(
 4945            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4946            Bias::Left,
 4947        );
 4948        let max_word_search = buffer_snapshot.clip_point(
 4949            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4950            Bias::Right,
 4951        );
 4952        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4953            ..buffer_snapshot.point_to_offset(max_word_search);
 4954
 4955        let provider = self
 4956            .completion_provider
 4957            .as_ref()
 4958            .filter(|_| !ignore_completion_provider);
 4959        let skip_digits = query
 4960            .as_ref()
 4961            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4962
 4963        let (mut words, provided_completions) = match provider {
 4964            Some(provider) => {
 4965                let completions = provider.completions(
 4966                    position.excerpt_id,
 4967                    &buffer,
 4968                    buffer_position,
 4969                    completion_context,
 4970                    window,
 4971                    cx,
 4972                );
 4973
 4974                let words = match completion_settings.words {
 4975                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4976                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4977                        .background_spawn(async move {
 4978                            buffer_snapshot.words_in_range(WordsQuery {
 4979                                fuzzy_contents: None,
 4980                                range: word_search_range,
 4981                                skip_digits,
 4982                            })
 4983                        }),
 4984                };
 4985
 4986                (words, completions)
 4987            }
 4988            None => (
 4989                cx.background_spawn(async move {
 4990                    buffer_snapshot.words_in_range(WordsQuery {
 4991                        fuzzy_contents: None,
 4992                        range: word_search_range,
 4993                        skip_digits,
 4994                    })
 4995                }),
 4996                Task::ready(Ok(None)),
 4997            ),
 4998        };
 4999
 5000        let sort_completions = provider
 5001            .as_ref()
 5002            .map_or(false, |provider| provider.sort_completions());
 5003
 5004        let filter_completions = provider
 5005            .as_ref()
 5006            .map_or(true, |provider| provider.filter_completions());
 5007
 5008        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5009
 5010        let id = post_inc(&mut self.next_completion_id);
 5011        let task = cx.spawn_in(window, async move |editor, cx| {
 5012            async move {
 5013                editor.update(cx, |this, _| {
 5014                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5015                })?;
 5016
 5017                let mut completions = Vec::new();
 5018                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5019                    completions.extend(provided_completions);
 5020                    if completion_settings.words == WordsCompletionMode::Fallback {
 5021                        words = Task::ready(BTreeMap::default());
 5022                    }
 5023                }
 5024
 5025                let mut words = words.await;
 5026                if let Some(word_to_exclude) = &word_to_exclude {
 5027                    words.remove(word_to_exclude);
 5028                }
 5029                for lsp_completion in &completions {
 5030                    words.remove(&lsp_completion.new_text);
 5031                }
 5032                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5033                    replace_range: old_range.clone(),
 5034                    new_text: word.clone(),
 5035                    label: CodeLabel::plain(word, None),
 5036                    icon_path: None,
 5037                    documentation: None,
 5038                    source: CompletionSource::BufferWord {
 5039                        word_range,
 5040                        resolved: false,
 5041                    },
 5042                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5043                    confirm: None,
 5044                }));
 5045
 5046                let menu = if completions.is_empty() {
 5047                    None
 5048                } else {
 5049                    let mut menu = CompletionsMenu::new(
 5050                        id,
 5051                        sort_completions,
 5052                        show_completion_documentation,
 5053                        ignore_completion_provider,
 5054                        position,
 5055                        buffer.clone(),
 5056                        completions.into(),
 5057                        snippet_sort_order,
 5058                    );
 5059
 5060                    menu.filter(
 5061                        if filter_completions {
 5062                            query.as_deref()
 5063                        } else {
 5064                            None
 5065                        },
 5066                        cx.background_executor().clone(),
 5067                    )
 5068                    .await;
 5069
 5070                    menu.visible().then_some(menu)
 5071                };
 5072
 5073                editor.update_in(cx, |editor, window, cx| {
 5074                    match editor.context_menu.borrow().as_ref() {
 5075                        None => {}
 5076                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5077                            if prev_menu.id > id {
 5078                                return;
 5079                            }
 5080                        }
 5081                        _ => return,
 5082                    }
 5083
 5084                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5085                        let mut menu = menu.unwrap();
 5086                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5087                        crate::hover_popover::hide_hover(editor, cx);
 5088                        *editor.context_menu.borrow_mut() =
 5089                            Some(CodeContextMenu::Completions(menu));
 5090
 5091                        if editor.show_edit_predictions_in_menu() {
 5092                            editor.update_visible_inline_completion(window, cx);
 5093                        } else {
 5094                            editor.discard_inline_completion(false, cx);
 5095                        }
 5096
 5097                        cx.notify();
 5098                    } else if editor.completion_tasks.len() <= 1 {
 5099                        // If there are no more completion tasks and the last menu was
 5100                        // empty, we should hide it.
 5101                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5102                        // If it was already hidden and we don't show inline
 5103                        // completions in the menu, we should also show the
 5104                        // inline-completion when available.
 5105                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5106                            editor.update_visible_inline_completion(window, cx);
 5107                        }
 5108                    }
 5109                })?;
 5110
 5111                anyhow::Ok(())
 5112            }
 5113            .log_err()
 5114            .await
 5115        });
 5116
 5117        self.completion_tasks.push((id, task));
 5118    }
 5119
 5120    #[cfg(feature = "test-support")]
 5121    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5122        let menu = self.context_menu.borrow();
 5123        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5124            let completions = menu.completions.borrow();
 5125            Some(completions.to_vec())
 5126        } else {
 5127            None
 5128        }
 5129    }
 5130
 5131    pub fn confirm_completion(
 5132        &mut self,
 5133        action: &ConfirmCompletion,
 5134        window: &mut Window,
 5135        cx: &mut Context<Self>,
 5136    ) -> Option<Task<Result<()>>> {
 5137        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5138        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5139    }
 5140
 5141    pub fn confirm_completion_insert(
 5142        &mut self,
 5143        _: &ConfirmCompletionInsert,
 5144        window: &mut Window,
 5145        cx: &mut Context<Self>,
 5146    ) -> Option<Task<Result<()>>> {
 5147        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5148        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5149    }
 5150
 5151    pub fn confirm_completion_replace(
 5152        &mut self,
 5153        _: &ConfirmCompletionReplace,
 5154        window: &mut Window,
 5155        cx: &mut Context<Self>,
 5156    ) -> Option<Task<Result<()>>> {
 5157        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5158        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5159    }
 5160
 5161    pub fn compose_completion(
 5162        &mut self,
 5163        action: &ComposeCompletion,
 5164        window: &mut Window,
 5165        cx: &mut Context<Self>,
 5166    ) -> Option<Task<Result<()>>> {
 5167        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5168        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5169    }
 5170
 5171    fn do_completion(
 5172        &mut self,
 5173        item_ix: Option<usize>,
 5174        intent: CompletionIntent,
 5175        window: &mut Window,
 5176        cx: &mut Context<Editor>,
 5177    ) -> Option<Task<Result<()>>> {
 5178        use language::ToOffset as _;
 5179
 5180        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5181        else {
 5182            return None;
 5183        };
 5184
 5185        let candidate_id = {
 5186            let entries = completions_menu.entries.borrow();
 5187            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5188            if self.show_edit_predictions_in_menu() {
 5189                self.discard_inline_completion(true, cx);
 5190            }
 5191            mat.candidate_id
 5192        };
 5193
 5194        let buffer_handle = completions_menu.buffer;
 5195        let completion = completions_menu
 5196            .completions
 5197            .borrow()
 5198            .get(candidate_id)?
 5199            .clone();
 5200        cx.stop_propagation();
 5201
 5202        let snapshot = self.buffer.read(cx).snapshot(cx);
 5203        let newest_anchor = self.selections.newest_anchor();
 5204
 5205        let snippet;
 5206        let new_text;
 5207        if completion.is_snippet() {
 5208            let mut snippet_source = completion.new_text.clone();
 5209            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5210                if scope.prefers_label_for_snippet_in_completion() {
 5211                    if let Some(label) = completion.label() {
 5212                        if matches!(
 5213                            completion.kind(),
 5214                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5215                        ) {
 5216                            snippet_source = label;
 5217                        }
 5218                    }
 5219                }
 5220            }
 5221            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5222            new_text = snippet.as_ref().unwrap().text.clone();
 5223        } else {
 5224            snippet = None;
 5225            new_text = completion.new_text.clone();
 5226        };
 5227
 5228        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5229        let buffer = buffer_handle.read(cx);
 5230        let replace_range_multibuffer = {
 5231            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5232            let multibuffer_anchor = snapshot
 5233                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5234                .unwrap()
 5235                ..snapshot
 5236                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5237                    .unwrap();
 5238            multibuffer_anchor.start.to_offset(&snapshot)
 5239                ..multibuffer_anchor.end.to_offset(&snapshot)
 5240        };
 5241        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5242            return None;
 5243        }
 5244
 5245        let old_text = buffer
 5246            .text_for_range(replace_range.clone())
 5247            .collect::<String>();
 5248        let lookbehind = newest_anchor
 5249            .start
 5250            .text_anchor
 5251            .to_offset(buffer)
 5252            .saturating_sub(replace_range.start);
 5253        let lookahead = replace_range
 5254            .end
 5255            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5256        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5257        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5258
 5259        let selections = self.selections.all::<usize>(cx);
 5260        let mut ranges = Vec::new();
 5261        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5262
 5263        for selection in &selections {
 5264            let range = if selection.id == newest_anchor.id {
 5265                replace_range_multibuffer.clone()
 5266            } else {
 5267                let mut range = selection.range();
 5268
 5269                // if prefix is present, don't duplicate it
 5270                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5271                    range.start = range.start.saturating_sub(lookbehind);
 5272
 5273                    // if suffix is also present, mimic the newest cursor and replace it
 5274                    if selection.id != newest_anchor.id
 5275                        && snapshot.contains_str_at(range.end, suffix)
 5276                    {
 5277                        range.end += lookahead;
 5278                    }
 5279                }
 5280                range
 5281            };
 5282
 5283            ranges.push(range.clone());
 5284
 5285            if !self.linked_edit_ranges.is_empty() {
 5286                let start_anchor = snapshot.anchor_before(range.start);
 5287                let end_anchor = snapshot.anchor_after(range.end);
 5288                if let Some(ranges) = self
 5289                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5290                {
 5291                    for (buffer, edits) in ranges {
 5292                        linked_edits
 5293                            .entry(buffer.clone())
 5294                            .or_default()
 5295                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5296                    }
 5297                }
 5298            }
 5299        }
 5300
 5301        cx.emit(EditorEvent::InputHandled {
 5302            utf16_range_to_replace: None,
 5303            text: new_text.clone().into(),
 5304        });
 5305
 5306        self.transact(window, cx, |this, window, cx| {
 5307            if let Some(mut snippet) = snippet {
 5308                snippet.text = new_text.to_string();
 5309                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5310            } else {
 5311                this.buffer.update(cx, |buffer, cx| {
 5312                    let auto_indent = match completion.insert_text_mode {
 5313                        Some(InsertTextMode::AS_IS) => None,
 5314                        _ => this.autoindent_mode.clone(),
 5315                    };
 5316                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5317                    buffer.edit(edits, auto_indent, cx);
 5318                });
 5319            }
 5320            for (buffer, edits) in linked_edits {
 5321                buffer.update(cx, |buffer, cx| {
 5322                    let snapshot = buffer.snapshot();
 5323                    let edits = edits
 5324                        .into_iter()
 5325                        .map(|(range, text)| {
 5326                            use text::ToPoint as TP;
 5327                            let end_point = TP::to_point(&range.end, &snapshot);
 5328                            let start_point = TP::to_point(&range.start, &snapshot);
 5329                            (start_point..end_point, text)
 5330                        })
 5331                        .sorted_by_key(|(range, _)| range.start);
 5332                    buffer.edit(edits, None, cx);
 5333                })
 5334            }
 5335
 5336            this.refresh_inline_completion(true, false, window, cx);
 5337        });
 5338
 5339        let show_new_completions_on_confirm = completion
 5340            .confirm
 5341            .as_ref()
 5342            .map_or(false, |confirm| confirm(intent, window, cx));
 5343        if show_new_completions_on_confirm {
 5344            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5345        }
 5346
 5347        let provider = self.completion_provider.as_ref()?;
 5348        drop(completion);
 5349        let apply_edits = provider.apply_additional_edits_for_completion(
 5350            buffer_handle,
 5351            completions_menu.completions.clone(),
 5352            candidate_id,
 5353            true,
 5354            cx,
 5355        );
 5356
 5357        let editor_settings = EditorSettings::get_global(cx);
 5358        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5359            // After the code completion is finished, users often want to know what signatures are needed.
 5360            // so we should automatically call signature_help
 5361            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5362        }
 5363
 5364        Some(cx.foreground_executor().spawn(async move {
 5365            apply_edits.await?;
 5366            Ok(())
 5367        }))
 5368    }
 5369
 5370    pub fn toggle_code_actions(
 5371        &mut self,
 5372        action: &ToggleCodeActions,
 5373        window: &mut Window,
 5374        cx: &mut Context<Self>,
 5375    ) {
 5376        let quick_launch = action.quick_launch;
 5377        let mut context_menu = self.context_menu.borrow_mut();
 5378        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5379            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5380                // Toggle if we're selecting the same one
 5381                *context_menu = None;
 5382                cx.notify();
 5383                return;
 5384            } else {
 5385                // Otherwise, clear it and start a new one
 5386                *context_menu = None;
 5387                cx.notify();
 5388            }
 5389        }
 5390        drop(context_menu);
 5391        let snapshot = self.snapshot(window, cx);
 5392        let deployed_from_indicator = action.deployed_from_indicator;
 5393        let mut task = self.code_actions_task.take();
 5394        let action = action.clone();
 5395        cx.spawn_in(window, async move |editor, cx| {
 5396            while let Some(prev_task) = task {
 5397                prev_task.await.log_err();
 5398                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5399            }
 5400
 5401            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5402                if editor.focus_handle.is_focused(window) {
 5403                    let multibuffer_point = action
 5404                        .deployed_from_indicator
 5405                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5406                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5407                    let (buffer, buffer_row) = snapshot
 5408                        .buffer_snapshot
 5409                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5410                        .and_then(|(buffer_snapshot, range)| {
 5411                            editor
 5412                                .buffer
 5413                                .read(cx)
 5414                                .buffer(buffer_snapshot.remote_id())
 5415                                .map(|buffer| (buffer, range.start.row))
 5416                        })?;
 5417                    let (_, code_actions) = editor
 5418                        .available_code_actions
 5419                        .clone()
 5420                        .and_then(|(location, code_actions)| {
 5421                            let snapshot = location.buffer.read(cx).snapshot();
 5422                            let point_range = location.range.to_point(&snapshot);
 5423                            let point_range = point_range.start.row..=point_range.end.row;
 5424                            if point_range.contains(&buffer_row) {
 5425                                Some((location, code_actions))
 5426                            } else {
 5427                                None
 5428                            }
 5429                        })
 5430                        .unzip();
 5431                    let buffer_id = buffer.read(cx).remote_id();
 5432                    let tasks = editor
 5433                        .tasks
 5434                        .get(&(buffer_id, buffer_row))
 5435                        .map(|t| Arc::new(t.to_owned()));
 5436                    if tasks.is_none() && code_actions.is_none() {
 5437                        return None;
 5438                    }
 5439
 5440                    editor.completion_tasks.clear();
 5441                    editor.discard_inline_completion(false, cx);
 5442                    let task_context =
 5443                        tasks
 5444                            .as_ref()
 5445                            .zip(editor.project.clone())
 5446                            .map(|(tasks, project)| {
 5447                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5448                            });
 5449
 5450                    Some(cx.spawn_in(window, async move |editor, cx| {
 5451                        let task_context = match task_context {
 5452                            Some(task_context) => task_context.await,
 5453                            None => None,
 5454                        };
 5455                        let resolved_tasks =
 5456                            tasks
 5457                                .zip(task_context.clone())
 5458                                .map(|(tasks, task_context)| ResolvedTasks {
 5459                                    templates: tasks.resolve(&task_context).collect(),
 5460                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5461                                        multibuffer_point.row,
 5462                                        tasks.column,
 5463                                    )),
 5464                                });
 5465                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5466                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5467                                maybe!({
 5468                                    let project = editor.project.as_ref()?;
 5469                                    let dap_store = project.read(cx).dap_store();
 5470                                    let mut scenarios = vec![];
 5471                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5472                                    let buffer = buffer.read(cx);
 5473                                    let language = buffer.language()?;
 5474                                    let file = buffer.file();
 5475                                    let debug_adapter =
 5476                                        language_settings(language.name().into(), file, cx)
 5477                                            .debuggers
 5478                                            .first()
 5479                                            .map(SharedString::from)
 5480                                            .or_else(|| {
 5481                                                language
 5482                                                    .config()
 5483                                                    .debuggers
 5484                                                    .first()
 5485                                                    .map(SharedString::from)
 5486                                            })?;
 5487
 5488                                    dap_store.update(cx, |dap_store, cx| {
 5489                                        for (_, task) in &resolved_tasks.templates {
 5490                                            if let Some(scenario) = dap_store
 5491                                                .debug_scenario_for_build_task(
 5492                                                    task.original_task().clone(),
 5493                                                    debug_adapter.clone().into(),
 5494                                                    task.display_label().to_owned().into(),
 5495                                                    cx,
 5496                                                )
 5497                                            {
 5498                                                scenarios.push(scenario);
 5499                                            }
 5500                                        }
 5501                                    });
 5502                                    Some(scenarios)
 5503                                })
 5504                                .unwrap_or_default()
 5505                            } else {
 5506                                vec![]
 5507                            }
 5508                        })?;
 5509                        let spawn_straight_away = quick_launch
 5510                            && resolved_tasks
 5511                                .as_ref()
 5512                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5513                            && code_actions
 5514                                .as_ref()
 5515                                .map_or(true, |actions| actions.is_empty())
 5516                            && debug_scenarios.is_empty();
 5517                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5518                            crate::hover_popover::hide_hover(editor, cx);
 5519                            *editor.context_menu.borrow_mut() =
 5520                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5521                                    buffer,
 5522                                    actions: CodeActionContents::new(
 5523                                        resolved_tasks,
 5524                                        code_actions,
 5525                                        debug_scenarios,
 5526                                        task_context.unwrap_or_default(),
 5527                                    ),
 5528                                    selected_item: Default::default(),
 5529                                    scroll_handle: UniformListScrollHandle::default(),
 5530                                    deployed_from_indicator,
 5531                                }));
 5532                            if spawn_straight_away {
 5533                                if let Some(task) = editor.confirm_code_action(
 5534                                    &ConfirmCodeAction { item_ix: Some(0) },
 5535                                    window,
 5536                                    cx,
 5537                                ) {
 5538                                    cx.notify();
 5539                                    return task;
 5540                                }
 5541                            }
 5542                            cx.notify();
 5543                            Task::ready(Ok(()))
 5544                        }) {
 5545                            task.await
 5546                        } else {
 5547                            Ok(())
 5548                        }
 5549                    }))
 5550                } else {
 5551                    Some(Task::ready(Ok(())))
 5552                }
 5553            })?;
 5554            if let Some(task) = spawned_test_task {
 5555                task.await?;
 5556            }
 5557
 5558            anyhow::Ok(())
 5559        })
 5560        .detach_and_log_err(cx);
 5561    }
 5562
 5563    pub fn confirm_code_action(
 5564        &mut self,
 5565        action: &ConfirmCodeAction,
 5566        window: &mut Window,
 5567        cx: &mut Context<Self>,
 5568    ) -> Option<Task<Result<()>>> {
 5569        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5570
 5571        let actions_menu =
 5572            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5573                menu
 5574            } else {
 5575                return None;
 5576            };
 5577
 5578        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5579        let action = actions_menu.actions.get(action_ix)?;
 5580        let title = action.label();
 5581        let buffer = actions_menu.buffer;
 5582        let workspace = self.workspace()?;
 5583
 5584        match action {
 5585            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5586                workspace.update(cx, |workspace, cx| {
 5587                    workspace.schedule_resolved_task(
 5588                        task_source_kind,
 5589                        resolved_task,
 5590                        false,
 5591                        window,
 5592                        cx,
 5593                    );
 5594
 5595                    Some(Task::ready(Ok(())))
 5596                })
 5597            }
 5598            CodeActionsItem::CodeAction {
 5599                excerpt_id,
 5600                action,
 5601                provider,
 5602            } => {
 5603                let apply_code_action =
 5604                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5605                let workspace = workspace.downgrade();
 5606                Some(cx.spawn_in(window, async move |editor, cx| {
 5607                    let project_transaction = apply_code_action.await?;
 5608                    Self::open_project_transaction(
 5609                        &editor,
 5610                        workspace,
 5611                        project_transaction,
 5612                        title,
 5613                        cx,
 5614                    )
 5615                    .await
 5616                }))
 5617            }
 5618            CodeActionsItem::DebugScenario(scenario) => {
 5619                let context = actions_menu.actions.context.clone();
 5620
 5621                workspace.update(cx, |workspace, cx| {
 5622                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5623                });
 5624                Some(Task::ready(Ok(())))
 5625            }
 5626        }
 5627    }
 5628
 5629    pub async fn open_project_transaction(
 5630        this: &WeakEntity<Editor>,
 5631        workspace: WeakEntity<Workspace>,
 5632        transaction: ProjectTransaction,
 5633        title: String,
 5634        cx: &mut AsyncWindowContext,
 5635    ) -> Result<()> {
 5636        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5637        cx.update(|_, cx| {
 5638            entries.sort_unstable_by_key(|(buffer, _)| {
 5639                buffer.read(cx).file().map(|f| f.path().clone())
 5640            });
 5641        })?;
 5642
 5643        // If the project transaction's edits are all contained within this editor, then
 5644        // avoid opening a new editor to display them.
 5645
 5646        if let Some((buffer, transaction)) = entries.first() {
 5647            if entries.len() == 1 {
 5648                let excerpt = this.update(cx, |editor, cx| {
 5649                    editor
 5650                        .buffer()
 5651                        .read(cx)
 5652                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5653                })?;
 5654                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5655                    if excerpted_buffer == *buffer {
 5656                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5657                            let excerpt_range = excerpt_range.to_offset(buffer);
 5658                            buffer
 5659                                .edited_ranges_for_transaction::<usize>(transaction)
 5660                                .all(|range| {
 5661                                    excerpt_range.start <= range.start
 5662                                        && excerpt_range.end >= range.end
 5663                                })
 5664                        })?;
 5665
 5666                        if all_edits_within_excerpt {
 5667                            return Ok(());
 5668                        }
 5669                    }
 5670                }
 5671            }
 5672        } else {
 5673            return Ok(());
 5674        }
 5675
 5676        let mut ranges_to_highlight = Vec::new();
 5677        let excerpt_buffer = cx.new(|cx| {
 5678            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5679            for (buffer_handle, transaction) in &entries {
 5680                let edited_ranges = buffer_handle
 5681                    .read(cx)
 5682                    .edited_ranges_for_transaction::<Point>(transaction)
 5683                    .collect::<Vec<_>>();
 5684                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5685                    PathKey::for_buffer(buffer_handle, cx),
 5686                    buffer_handle.clone(),
 5687                    edited_ranges,
 5688                    DEFAULT_MULTIBUFFER_CONTEXT,
 5689                    cx,
 5690                );
 5691
 5692                ranges_to_highlight.extend(ranges);
 5693            }
 5694            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5695            multibuffer
 5696        })?;
 5697
 5698        workspace.update_in(cx, |workspace, window, cx| {
 5699            let project = workspace.project().clone();
 5700            let editor =
 5701                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5702            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5703            editor.update(cx, |editor, cx| {
 5704                editor.highlight_background::<Self>(
 5705                    &ranges_to_highlight,
 5706                    |theme| theme.editor_highlighted_line_background,
 5707                    cx,
 5708                );
 5709            });
 5710        })?;
 5711
 5712        Ok(())
 5713    }
 5714
 5715    pub fn clear_code_action_providers(&mut self) {
 5716        self.code_action_providers.clear();
 5717        self.available_code_actions.take();
 5718    }
 5719
 5720    pub fn add_code_action_provider(
 5721        &mut self,
 5722        provider: Rc<dyn CodeActionProvider>,
 5723        window: &mut Window,
 5724        cx: &mut Context<Self>,
 5725    ) {
 5726        if self
 5727            .code_action_providers
 5728            .iter()
 5729            .any(|existing_provider| existing_provider.id() == provider.id())
 5730        {
 5731            return;
 5732        }
 5733
 5734        self.code_action_providers.push(provider);
 5735        self.refresh_code_actions(window, cx);
 5736    }
 5737
 5738    pub fn remove_code_action_provider(
 5739        &mut self,
 5740        id: Arc<str>,
 5741        window: &mut Window,
 5742        cx: &mut Context<Self>,
 5743    ) {
 5744        self.code_action_providers
 5745            .retain(|provider| provider.id() != id);
 5746        self.refresh_code_actions(window, cx);
 5747    }
 5748
 5749    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5750        let newest_selection = self.selections.newest_anchor().clone();
 5751        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5752        let buffer = self.buffer.read(cx);
 5753        if newest_selection.head().diff_base_anchor.is_some() {
 5754            return None;
 5755        }
 5756        let (start_buffer, start) =
 5757            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5758        let (end_buffer, end) =
 5759            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5760        if start_buffer != end_buffer {
 5761            return None;
 5762        }
 5763
 5764        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5765            cx.background_executor()
 5766                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5767                .await;
 5768
 5769            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5770                let providers = this.code_action_providers.clone();
 5771                let tasks = this
 5772                    .code_action_providers
 5773                    .iter()
 5774                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5775                    .collect::<Vec<_>>();
 5776                (providers, tasks)
 5777            })?;
 5778
 5779            let mut actions = Vec::new();
 5780            for (provider, provider_actions) in
 5781                providers.into_iter().zip(future::join_all(tasks).await)
 5782            {
 5783                if let Some(provider_actions) = provider_actions.log_err() {
 5784                    actions.extend(provider_actions.into_iter().map(|action| {
 5785                        AvailableCodeAction {
 5786                            excerpt_id: newest_selection.start.excerpt_id,
 5787                            action,
 5788                            provider: provider.clone(),
 5789                        }
 5790                    }));
 5791                }
 5792            }
 5793
 5794            this.update(cx, |this, cx| {
 5795                this.available_code_actions = if actions.is_empty() {
 5796                    None
 5797                } else {
 5798                    Some((
 5799                        Location {
 5800                            buffer: start_buffer,
 5801                            range: start..end,
 5802                        },
 5803                        actions.into(),
 5804                    ))
 5805                };
 5806                cx.notify();
 5807            })
 5808        }));
 5809        None
 5810    }
 5811
 5812    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5813        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5814            self.show_git_blame_inline = false;
 5815
 5816            self.show_git_blame_inline_delay_task =
 5817                Some(cx.spawn_in(window, async move |this, cx| {
 5818                    cx.background_executor().timer(delay).await;
 5819
 5820                    this.update(cx, |this, cx| {
 5821                        this.show_git_blame_inline = true;
 5822                        cx.notify();
 5823                    })
 5824                    .log_err();
 5825                }));
 5826        }
 5827    }
 5828
 5829    fn show_blame_popover(
 5830        &mut self,
 5831        blame_entry: &BlameEntry,
 5832        position: gpui::Point<Pixels>,
 5833        cx: &mut Context<Self>,
 5834    ) {
 5835        if let Some(state) = &mut self.inline_blame_popover {
 5836            state.hide_task.take();
 5837            cx.notify();
 5838        } else {
 5839            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5840            let show_task = cx.spawn(async move |editor, cx| {
 5841                cx.background_executor()
 5842                    .timer(std::time::Duration::from_millis(delay))
 5843                    .await;
 5844                editor
 5845                    .update(cx, |editor, cx| {
 5846                        if let Some(state) = &mut editor.inline_blame_popover {
 5847                            state.show_task = None;
 5848                            cx.notify();
 5849                        }
 5850                    })
 5851                    .ok();
 5852            });
 5853            let Some(blame) = self.blame.as_ref() else {
 5854                return;
 5855            };
 5856            let blame = blame.read(cx);
 5857            let details = blame.details_for_entry(&blame_entry);
 5858            let markdown = cx.new(|cx| {
 5859                Markdown::new(
 5860                    details
 5861                        .as_ref()
 5862                        .map(|message| message.message.clone())
 5863                        .unwrap_or_default(),
 5864                    None,
 5865                    None,
 5866                    cx,
 5867                )
 5868            });
 5869            self.inline_blame_popover = Some(InlineBlamePopover {
 5870                position,
 5871                show_task: Some(show_task),
 5872                hide_task: None,
 5873                popover_bounds: None,
 5874                popover_state: InlineBlamePopoverState {
 5875                    scroll_handle: ScrollHandle::new(),
 5876                    commit_message: details,
 5877                    markdown,
 5878                },
 5879            });
 5880        }
 5881    }
 5882
 5883    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5884        if let Some(state) = &mut self.inline_blame_popover {
 5885            if state.show_task.is_some() {
 5886                self.inline_blame_popover.take();
 5887                cx.notify();
 5888            } else {
 5889                let hide_task = cx.spawn(async move |editor, cx| {
 5890                    cx.background_executor()
 5891                        .timer(std::time::Duration::from_millis(100))
 5892                        .await;
 5893                    editor
 5894                        .update(cx, |editor, cx| {
 5895                            editor.inline_blame_popover.take();
 5896                            cx.notify();
 5897                        })
 5898                        .ok();
 5899                });
 5900                state.hide_task = Some(hide_task);
 5901            }
 5902        }
 5903    }
 5904
 5905    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5906        if self.pending_rename.is_some() {
 5907            return None;
 5908        }
 5909
 5910        let provider = self.semantics_provider.clone()?;
 5911        let buffer = self.buffer.read(cx);
 5912        let newest_selection = self.selections.newest_anchor().clone();
 5913        let cursor_position = newest_selection.head();
 5914        let (cursor_buffer, cursor_buffer_position) =
 5915            buffer.text_anchor_for_position(cursor_position, cx)?;
 5916        let (tail_buffer, tail_buffer_position) =
 5917            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5918        if cursor_buffer != tail_buffer {
 5919            return None;
 5920        }
 5921
 5922        let snapshot = cursor_buffer.read(cx).snapshot();
 5923        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5924        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5925        if start_word_range != end_word_range {
 5926            self.document_highlights_task.take();
 5927            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5928            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5929            return None;
 5930        }
 5931
 5932        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5933        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5934            cx.background_executor()
 5935                .timer(Duration::from_millis(debounce))
 5936                .await;
 5937
 5938            let highlights = if let Some(highlights) = cx
 5939                .update(|cx| {
 5940                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5941                })
 5942                .ok()
 5943                .flatten()
 5944            {
 5945                highlights.await.log_err()
 5946            } else {
 5947                None
 5948            };
 5949
 5950            if let Some(highlights) = highlights {
 5951                this.update(cx, |this, cx| {
 5952                    if this.pending_rename.is_some() {
 5953                        return;
 5954                    }
 5955
 5956                    let buffer_id = cursor_position.buffer_id;
 5957                    let buffer = this.buffer.read(cx);
 5958                    if !buffer
 5959                        .text_anchor_for_position(cursor_position, cx)
 5960                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5961                    {
 5962                        return;
 5963                    }
 5964
 5965                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5966                    let mut write_ranges = Vec::new();
 5967                    let mut read_ranges = Vec::new();
 5968                    for highlight in highlights {
 5969                        for (excerpt_id, excerpt_range) in
 5970                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5971                        {
 5972                            let start = highlight
 5973                                .range
 5974                                .start
 5975                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5976                            let end = highlight
 5977                                .range
 5978                                .end
 5979                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5980                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5981                                continue;
 5982                            }
 5983
 5984                            let range = Anchor {
 5985                                buffer_id,
 5986                                excerpt_id,
 5987                                text_anchor: start,
 5988                                diff_base_anchor: None,
 5989                            }..Anchor {
 5990                                buffer_id,
 5991                                excerpt_id,
 5992                                text_anchor: end,
 5993                                diff_base_anchor: None,
 5994                            };
 5995                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5996                                write_ranges.push(range);
 5997                            } else {
 5998                                read_ranges.push(range);
 5999                            }
 6000                        }
 6001                    }
 6002
 6003                    this.highlight_background::<DocumentHighlightRead>(
 6004                        &read_ranges,
 6005                        |theme| theme.editor_document_highlight_read_background,
 6006                        cx,
 6007                    );
 6008                    this.highlight_background::<DocumentHighlightWrite>(
 6009                        &write_ranges,
 6010                        |theme| theme.editor_document_highlight_write_background,
 6011                        cx,
 6012                    );
 6013                    cx.notify();
 6014                })
 6015                .log_err();
 6016            }
 6017        }));
 6018        None
 6019    }
 6020
 6021    fn prepare_highlight_query_from_selection(
 6022        &mut self,
 6023        cx: &mut Context<Editor>,
 6024    ) -> Option<(String, Range<Anchor>)> {
 6025        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6026            return None;
 6027        }
 6028        if !EditorSettings::get_global(cx).selection_highlight {
 6029            return None;
 6030        }
 6031        if self.selections.count() != 1 || self.selections.line_mode {
 6032            return None;
 6033        }
 6034        let selection = self.selections.newest::<Point>(cx);
 6035        if selection.is_empty() || selection.start.row != selection.end.row {
 6036            return None;
 6037        }
 6038        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6039        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6040        let query = multi_buffer_snapshot
 6041            .text_for_range(selection_anchor_range.clone())
 6042            .collect::<String>();
 6043        if query.trim().is_empty() {
 6044            return None;
 6045        }
 6046        Some((query, selection_anchor_range))
 6047    }
 6048
 6049    fn update_selection_occurrence_highlights(
 6050        &mut self,
 6051        query_text: String,
 6052        query_range: Range<Anchor>,
 6053        multi_buffer_range_to_query: Range<Point>,
 6054        use_debounce: bool,
 6055        window: &mut Window,
 6056        cx: &mut Context<Editor>,
 6057    ) -> Task<()> {
 6058        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6059        cx.spawn_in(window, async move |editor, cx| {
 6060            if use_debounce {
 6061                cx.background_executor()
 6062                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6063                    .await;
 6064            }
 6065            let match_task = cx.background_spawn(async move {
 6066                let buffer_ranges = multi_buffer_snapshot
 6067                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6068                    .into_iter()
 6069                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6070                let mut match_ranges = Vec::new();
 6071                let Ok(regex) = project::search::SearchQuery::text(
 6072                    query_text.clone(),
 6073                    false,
 6074                    false,
 6075                    false,
 6076                    Default::default(),
 6077                    Default::default(),
 6078                    false,
 6079                    None,
 6080                ) else {
 6081                    return Vec::default();
 6082                };
 6083                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6084                    match_ranges.extend(
 6085                        regex
 6086                            .search(&buffer_snapshot, Some(search_range.clone()))
 6087                            .await
 6088                            .into_iter()
 6089                            .filter_map(|match_range| {
 6090                                let match_start = buffer_snapshot
 6091                                    .anchor_after(search_range.start + match_range.start);
 6092                                let match_end = buffer_snapshot
 6093                                    .anchor_before(search_range.start + match_range.end);
 6094                                let match_anchor_range = Anchor::range_in_buffer(
 6095                                    excerpt_id,
 6096                                    buffer_snapshot.remote_id(),
 6097                                    match_start..match_end,
 6098                                );
 6099                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6100                            }),
 6101                    );
 6102                }
 6103                match_ranges
 6104            });
 6105            let match_ranges = match_task.await;
 6106            editor
 6107                .update_in(cx, |editor, _, cx| {
 6108                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6109                    if !match_ranges.is_empty() {
 6110                        editor.highlight_background::<SelectedTextHighlight>(
 6111                            &match_ranges,
 6112                            |theme| theme.editor_document_highlight_bracket_background,
 6113                            cx,
 6114                        )
 6115                    }
 6116                })
 6117                .log_err();
 6118        })
 6119    }
 6120
 6121    fn refresh_selected_text_highlights(
 6122        &mut self,
 6123        on_buffer_edit: bool,
 6124        window: &mut Window,
 6125        cx: &mut Context<Editor>,
 6126    ) {
 6127        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6128        else {
 6129            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6130            self.quick_selection_highlight_task.take();
 6131            self.debounced_selection_highlight_task.take();
 6132            return;
 6133        };
 6134        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6135        if on_buffer_edit
 6136            || self
 6137                .quick_selection_highlight_task
 6138                .as_ref()
 6139                .map_or(true, |(prev_anchor_range, _)| {
 6140                    prev_anchor_range != &query_range
 6141                })
 6142        {
 6143            let multi_buffer_visible_start = self
 6144                .scroll_manager
 6145                .anchor()
 6146                .anchor
 6147                .to_point(&multi_buffer_snapshot);
 6148            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6149                multi_buffer_visible_start
 6150                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6151                Bias::Left,
 6152            );
 6153            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6154            self.quick_selection_highlight_task = Some((
 6155                query_range.clone(),
 6156                self.update_selection_occurrence_highlights(
 6157                    query_text.clone(),
 6158                    query_range.clone(),
 6159                    multi_buffer_visible_range,
 6160                    false,
 6161                    window,
 6162                    cx,
 6163                ),
 6164            ));
 6165        }
 6166        if on_buffer_edit
 6167            || self
 6168                .debounced_selection_highlight_task
 6169                .as_ref()
 6170                .map_or(true, |(prev_anchor_range, _)| {
 6171                    prev_anchor_range != &query_range
 6172                })
 6173        {
 6174            let multi_buffer_start = multi_buffer_snapshot
 6175                .anchor_before(0)
 6176                .to_point(&multi_buffer_snapshot);
 6177            let multi_buffer_end = multi_buffer_snapshot
 6178                .anchor_after(multi_buffer_snapshot.len())
 6179                .to_point(&multi_buffer_snapshot);
 6180            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6181            self.debounced_selection_highlight_task = Some((
 6182                query_range.clone(),
 6183                self.update_selection_occurrence_highlights(
 6184                    query_text,
 6185                    query_range,
 6186                    multi_buffer_full_range,
 6187                    true,
 6188                    window,
 6189                    cx,
 6190                ),
 6191            ));
 6192        }
 6193    }
 6194
 6195    pub fn refresh_inline_completion(
 6196        &mut self,
 6197        debounce: bool,
 6198        user_requested: bool,
 6199        window: &mut Window,
 6200        cx: &mut Context<Self>,
 6201    ) -> Option<()> {
 6202        let provider = self.edit_prediction_provider()?;
 6203        let cursor = self.selections.newest_anchor().head();
 6204        let (buffer, cursor_buffer_position) =
 6205            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6206
 6207        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6208            self.discard_inline_completion(false, cx);
 6209            return None;
 6210        }
 6211
 6212        if !user_requested
 6213            && (!self.should_show_edit_predictions()
 6214                || !self.is_focused(window)
 6215                || buffer.read(cx).is_empty())
 6216        {
 6217            self.discard_inline_completion(false, cx);
 6218            return None;
 6219        }
 6220
 6221        self.update_visible_inline_completion(window, cx);
 6222        provider.refresh(
 6223            self.project.clone(),
 6224            buffer,
 6225            cursor_buffer_position,
 6226            debounce,
 6227            cx,
 6228        );
 6229        Some(())
 6230    }
 6231
 6232    fn show_edit_predictions_in_menu(&self) -> bool {
 6233        match self.edit_prediction_settings {
 6234            EditPredictionSettings::Disabled => false,
 6235            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6236        }
 6237    }
 6238
 6239    pub fn edit_predictions_enabled(&self) -> bool {
 6240        match self.edit_prediction_settings {
 6241            EditPredictionSettings::Disabled => false,
 6242            EditPredictionSettings::Enabled { .. } => true,
 6243        }
 6244    }
 6245
 6246    fn edit_prediction_requires_modifier(&self) -> bool {
 6247        match self.edit_prediction_settings {
 6248            EditPredictionSettings::Disabled => false,
 6249            EditPredictionSettings::Enabled {
 6250                preview_requires_modifier,
 6251                ..
 6252            } => preview_requires_modifier,
 6253        }
 6254    }
 6255
 6256    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6257        if self.edit_prediction_provider.is_none() {
 6258            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6259        } else {
 6260            let selection = self.selections.newest_anchor();
 6261            let cursor = selection.head();
 6262
 6263            if let Some((buffer, cursor_buffer_position)) =
 6264                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6265            {
 6266                self.edit_prediction_settings =
 6267                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6268            }
 6269        }
 6270    }
 6271
 6272    fn edit_prediction_settings_at_position(
 6273        &self,
 6274        buffer: &Entity<Buffer>,
 6275        buffer_position: language::Anchor,
 6276        cx: &App,
 6277    ) -> EditPredictionSettings {
 6278        if !self.mode.is_full()
 6279            || !self.show_inline_completions_override.unwrap_or(true)
 6280            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6281        {
 6282            return EditPredictionSettings::Disabled;
 6283        }
 6284
 6285        let buffer = buffer.read(cx);
 6286
 6287        let file = buffer.file();
 6288
 6289        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6290            return EditPredictionSettings::Disabled;
 6291        };
 6292
 6293        let by_provider = matches!(
 6294            self.menu_inline_completions_policy,
 6295            MenuInlineCompletionsPolicy::ByProvider
 6296        );
 6297
 6298        let show_in_menu = by_provider
 6299            && self
 6300                .edit_prediction_provider
 6301                .as_ref()
 6302                .map_or(false, |provider| {
 6303                    provider.provider.show_completions_in_menu()
 6304                });
 6305
 6306        let preview_requires_modifier =
 6307            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6308
 6309        EditPredictionSettings::Enabled {
 6310            show_in_menu,
 6311            preview_requires_modifier,
 6312        }
 6313    }
 6314
 6315    fn should_show_edit_predictions(&self) -> bool {
 6316        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6317    }
 6318
 6319    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6320        matches!(
 6321            self.edit_prediction_preview,
 6322            EditPredictionPreview::Active { .. }
 6323        )
 6324    }
 6325
 6326    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6327        let cursor = self.selections.newest_anchor().head();
 6328        if let Some((buffer, cursor_position)) =
 6329            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6330        {
 6331            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6332        } else {
 6333            false
 6334        }
 6335    }
 6336
 6337    pub fn supports_minimap(&self, cx: &App) -> bool {
 6338        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6339    }
 6340
 6341    fn edit_predictions_enabled_in_buffer(
 6342        &self,
 6343        buffer: &Entity<Buffer>,
 6344        buffer_position: language::Anchor,
 6345        cx: &App,
 6346    ) -> bool {
 6347        maybe!({
 6348            if self.read_only(cx) {
 6349                return Some(false);
 6350            }
 6351            let provider = self.edit_prediction_provider()?;
 6352            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6353                return Some(false);
 6354            }
 6355            let buffer = buffer.read(cx);
 6356            let Some(file) = buffer.file() else {
 6357                return Some(true);
 6358            };
 6359            let settings = all_language_settings(Some(file), cx);
 6360            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6361        })
 6362        .unwrap_or(false)
 6363    }
 6364
 6365    fn cycle_inline_completion(
 6366        &mut self,
 6367        direction: Direction,
 6368        window: &mut Window,
 6369        cx: &mut Context<Self>,
 6370    ) -> Option<()> {
 6371        let provider = self.edit_prediction_provider()?;
 6372        let cursor = self.selections.newest_anchor().head();
 6373        let (buffer, cursor_buffer_position) =
 6374            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6375        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6376            return None;
 6377        }
 6378
 6379        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6380        self.update_visible_inline_completion(window, cx);
 6381
 6382        Some(())
 6383    }
 6384
 6385    pub fn show_inline_completion(
 6386        &mut self,
 6387        _: &ShowEditPrediction,
 6388        window: &mut Window,
 6389        cx: &mut Context<Self>,
 6390    ) {
 6391        if !self.has_active_inline_completion() {
 6392            self.refresh_inline_completion(false, true, window, cx);
 6393            return;
 6394        }
 6395
 6396        self.update_visible_inline_completion(window, cx);
 6397    }
 6398
 6399    pub fn display_cursor_names(
 6400        &mut self,
 6401        _: &DisplayCursorNames,
 6402        window: &mut Window,
 6403        cx: &mut Context<Self>,
 6404    ) {
 6405        self.show_cursor_names(window, cx);
 6406    }
 6407
 6408    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6409        self.show_cursor_names = true;
 6410        cx.notify();
 6411        cx.spawn_in(window, async move |this, cx| {
 6412            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6413            this.update(cx, |this, cx| {
 6414                this.show_cursor_names = false;
 6415                cx.notify()
 6416            })
 6417            .ok()
 6418        })
 6419        .detach();
 6420    }
 6421
 6422    pub fn next_edit_prediction(
 6423        &mut self,
 6424        _: &NextEditPrediction,
 6425        window: &mut Window,
 6426        cx: &mut Context<Self>,
 6427    ) {
 6428        if self.has_active_inline_completion() {
 6429            self.cycle_inline_completion(Direction::Next, window, cx);
 6430        } else {
 6431            let is_copilot_disabled = self
 6432                .refresh_inline_completion(false, true, window, cx)
 6433                .is_none();
 6434            if is_copilot_disabled {
 6435                cx.propagate();
 6436            }
 6437        }
 6438    }
 6439
 6440    pub fn previous_edit_prediction(
 6441        &mut self,
 6442        _: &PreviousEditPrediction,
 6443        window: &mut Window,
 6444        cx: &mut Context<Self>,
 6445    ) {
 6446        if self.has_active_inline_completion() {
 6447            self.cycle_inline_completion(Direction::Prev, window, cx);
 6448        } else {
 6449            let is_copilot_disabled = self
 6450                .refresh_inline_completion(false, true, window, cx)
 6451                .is_none();
 6452            if is_copilot_disabled {
 6453                cx.propagate();
 6454            }
 6455        }
 6456    }
 6457
 6458    pub fn accept_edit_prediction(
 6459        &mut self,
 6460        _: &AcceptEditPrediction,
 6461        window: &mut Window,
 6462        cx: &mut Context<Self>,
 6463    ) {
 6464        if self.show_edit_predictions_in_menu() {
 6465            self.hide_context_menu(window, cx);
 6466        }
 6467
 6468        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6469            return;
 6470        };
 6471
 6472        self.report_inline_completion_event(
 6473            active_inline_completion.completion_id.clone(),
 6474            true,
 6475            cx,
 6476        );
 6477
 6478        match &active_inline_completion.completion {
 6479            InlineCompletion::Move { target, .. } => {
 6480                let target = *target;
 6481
 6482                if let Some(position_map) = &self.last_position_map {
 6483                    if position_map
 6484                        .visible_row_range
 6485                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6486                        || !self.edit_prediction_requires_modifier()
 6487                    {
 6488                        self.unfold_ranges(&[target..target], true, false, cx);
 6489                        // Note that this is also done in vim's handler of the Tab action.
 6490                        self.change_selections(
 6491                            Some(Autoscroll::newest()),
 6492                            window,
 6493                            cx,
 6494                            |selections| {
 6495                                selections.select_anchor_ranges([target..target]);
 6496                            },
 6497                        );
 6498                        self.clear_row_highlights::<EditPredictionPreview>();
 6499
 6500                        self.edit_prediction_preview
 6501                            .set_previous_scroll_position(None);
 6502                    } else {
 6503                        self.edit_prediction_preview
 6504                            .set_previous_scroll_position(Some(
 6505                                position_map.snapshot.scroll_anchor,
 6506                            ));
 6507
 6508                        self.highlight_rows::<EditPredictionPreview>(
 6509                            target..target,
 6510                            cx.theme().colors().editor_highlighted_line_background,
 6511                            RowHighlightOptions {
 6512                                autoscroll: true,
 6513                                ..Default::default()
 6514                            },
 6515                            cx,
 6516                        );
 6517                        self.request_autoscroll(Autoscroll::fit(), cx);
 6518                    }
 6519                }
 6520            }
 6521            InlineCompletion::Edit { edits, .. } => {
 6522                if let Some(provider) = self.edit_prediction_provider() {
 6523                    provider.accept(cx);
 6524                }
 6525
 6526                // Store the transaction ID and selections before applying the edit
 6527                let transaction_id_prev =
 6528                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
 6529
 6530                let snapshot = self.buffer.read(cx).snapshot(cx);
 6531                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6532
 6533                self.buffer.update(cx, |buffer, cx| {
 6534                    buffer.edit(edits.iter().cloned(), None, cx)
 6535                });
 6536
 6537                self.change_selections(None, window, cx, |s| {
 6538                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6539                });
 6540
 6541                let selections = self.selections.disjoint_anchors();
 6542                if let Some(transaction_id_now) =
 6543                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
 6544                {
 6545                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6546                    if has_new_transaction {
 6547                        self.selection_history
 6548                            .insert_transaction(transaction_id_now, selections);
 6549                    }
 6550                }
 6551
 6552                self.update_visible_inline_completion(window, cx);
 6553                if self.active_inline_completion.is_none() {
 6554                    self.refresh_inline_completion(true, true, window, cx);
 6555                }
 6556
 6557                cx.notify();
 6558            }
 6559        }
 6560
 6561        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6562    }
 6563
 6564    pub fn accept_partial_inline_completion(
 6565        &mut self,
 6566        _: &AcceptPartialEditPrediction,
 6567        window: &mut Window,
 6568        cx: &mut Context<Self>,
 6569    ) {
 6570        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6571            return;
 6572        };
 6573        if self.selections.count() != 1 {
 6574            return;
 6575        }
 6576
 6577        self.report_inline_completion_event(
 6578            active_inline_completion.completion_id.clone(),
 6579            true,
 6580            cx,
 6581        );
 6582
 6583        match &active_inline_completion.completion {
 6584            InlineCompletion::Move { target, .. } => {
 6585                let target = *target;
 6586                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6587                    selections.select_anchor_ranges([target..target]);
 6588                });
 6589            }
 6590            InlineCompletion::Edit { edits, .. } => {
 6591                // Find an insertion that starts at the cursor position.
 6592                let snapshot = self.buffer.read(cx).snapshot(cx);
 6593                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6594                let insertion = edits.iter().find_map(|(range, text)| {
 6595                    let range = range.to_offset(&snapshot);
 6596                    if range.is_empty() && range.start == cursor_offset {
 6597                        Some(text)
 6598                    } else {
 6599                        None
 6600                    }
 6601                });
 6602
 6603                if let Some(text) = insertion {
 6604                    let mut partial_completion = text
 6605                        .chars()
 6606                        .by_ref()
 6607                        .take_while(|c| c.is_alphabetic())
 6608                        .collect::<String>();
 6609                    if partial_completion.is_empty() {
 6610                        partial_completion = text
 6611                            .chars()
 6612                            .by_ref()
 6613                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6614                            .collect::<String>();
 6615                    }
 6616
 6617                    cx.emit(EditorEvent::InputHandled {
 6618                        utf16_range_to_replace: None,
 6619                        text: partial_completion.clone().into(),
 6620                    });
 6621
 6622                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6623
 6624                    self.refresh_inline_completion(true, true, window, cx);
 6625                    cx.notify();
 6626                } else {
 6627                    self.accept_edit_prediction(&Default::default(), window, cx);
 6628                }
 6629            }
 6630        }
 6631    }
 6632
 6633    fn discard_inline_completion(
 6634        &mut self,
 6635        should_report_inline_completion_event: bool,
 6636        cx: &mut Context<Self>,
 6637    ) -> bool {
 6638        if should_report_inline_completion_event {
 6639            let completion_id = self
 6640                .active_inline_completion
 6641                .as_ref()
 6642                .and_then(|active_completion| active_completion.completion_id.clone());
 6643
 6644            self.report_inline_completion_event(completion_id, false, cx);
 6645        }
 6646
 6647        if let Some(provider) = self.edit_prediction_provider() {
 6648            provider.discard(cx);
 6649        }
 6650
 6651        self.take_active_inline_completion(cx)
 6652    }
 6653
 6654    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6655        let Some(provider) = self.edit_prediction_provider() else {
 6656            return;
 6657        };
 6658
 6659        let Some((_, buffer, _)) = self
 6660            .buffer
 6661            .read(cx)
 6662            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6663        else {
 6664            return;
 6665        };
 6666
 6667        let extension = buffer
 6668            .read(cx)
 6669            .file()
 6670            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6671
 6672        let event_type = match accepted {
 6673            true => "Edit Prediction Accepted",
 6674            false => "Edit Prediction Discarded",
 6675        };
 6676        telemetry::event!(
 6677            event_type,
 6678            provider = provider.name(),
 6679            prediction_id = id,
 6680            suggestion_accepted = accepted,
 6681            file_extension = extension,
 6682        );
 6683    }
 6684
 6685    pub fn has_active_inline_completion(&self) -> bool {
 6686        self.active_inline_completion.is_some()
 6687    }
 6688
 6689    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6690        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6691            return false;
 6692        };
 6693
 6694        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6695        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6696        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6697        true
 6698    }
 6699
 6700    /// Returns true when we're displaying the edit prediction popover below the cursor
 6701    /// like we are not previewing and the LSP autocomplete menu is visible
 6702    /// or we are in `when_holding_modifier` mode.
 6703    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6704        if self.edit_prediction_preview_is_active()
 6705            || !self.show_edit_predictions_in_menu()
 6706            || !self.edit_predictions_enabled()
 6707        {
 6708            return false;
 6709        }
 6710
 6711        if self.has_visible_completions_menu() {
 6712            return true;
 6713        }
 6714
 6715        has_completion && self.edit_prediction_requires_modifier()
 6716    }
 6717
 6718    fn handle_modifiers_changed(
 6719        &mut self,
 6720        modifiers: Modifiers,
 6721        position_map: &PositionMap,
 6722        window: &mut Window,
 6723        cx: &mut Context<Self>,
 6724    ) {
 6725        if self.show_edit_predictions_in_menu() {
 6726            self.update_edit_prediction_preview(&modifiers, window, cx);
 6727        }
 6728
 6729        self.update_selection_mode(&modifiers, position_map, window, cx);
 6730
 6731        let mouse_position = window.mouse_position();
 6732        if !position_map.text_hitbox.is_hovered(window) {
 6733            return;
 6734        }
 6735
 6736        self.update_hovered_link(
 6737            position_map.point_for_position(mouse_position),
 6738            &position_map.snapshot,
 6739            modifiers,
 6740            window,
 6741            cx,
 6742        )
 6743    }
 6744
 6745    fn update_selection_mode(
 6746        &mut self,
 6747        modifiers: &Modifiers,
 6748        position_map: &PositionMap,
 6749        window: &mut Window,
 6750        cx: &mut Context<Self>,
 6751    ) {
 6752        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6753            return;
 6754        }
 6755
 6756        let mouse_position = window.mouse_position();
 6757        let point_for_position = position_map.point_for_position(mouse_position);
 6758        let position = point_for_position.previous_valid;
 6759
 6760        self.select(
 6761            SelectPhase::BeginColumnar {
 6762                position,
 6763                reset: false,
 6764                goal_column: point_for_position.exact_unclipped.column(),
 6765            },
 6766            window,
 6767            cx,
 6768        );
 6769    }
 6770
 6771    fn update_edit_prediction_preview(
 6772        &mut self,
 6773        modifiers: &Modifiers,
 6774        window: &mut Window,
 6775        cx: &mut Context<Self>,
 6776    ) {
 6777        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6778        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6779            return;
 6780        };
 6781
 6782        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6783            if matches!(
 6784                self.edit_prediction_preview,
 6785                EditPredictionPreview::Inactive { .. }
 6786            ) {
 6787                self.edit_prediction_preview = EditPredictionPreview::Active {
 6788                    previous_scroll_position: None,
 6789                    since: Instant::now(),
 6790                };
 6791
 6792                self.update_visible_inline_completion(window, cx);
 6793                cx.notify();
 6794            }
 6795        } else if let EditPredictionPreview::Active {
 6796            previous_scroll_position,
 6797            since,
 6798        } = self.edit_prediction_preview
 6799        {
 6800            if let (Some(previous_scroll_position), Some(position_map)) =
 6801                (previous_scroll_position, self.last_position_map.as_ref())
 6802            {
 6803                self.set_scroll_position(
 6804                    previous_scroll_position
 6805                        .scroll_position(&position_map.snapshot.display_snapshot),
 6806                    window,
 6807                    cx,
 6808                );
 6809            }
 6810
 6811            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6812                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6813            };
 6814            self.clear_row_highlights::<EditPredictionPreview>();
 6815            self.update_visible_inline_completion(window, cx);
 6816            cx.notify();
 6817        }
 6818    }
 6819
 6820    fn update_visible_inline_completion(
 6821        &mut self,
 6822        _window: &mut Window,
 6823        cx: &mut Context<Self>,
 6824    ) -> Option<()> {
 6825        let selection = self.selections.newest_anchor();
 6826        let cursor = selection.head();
 6827        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6828        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6829        let excerpt_id = cursor.excerpt_id;
 6830
 6831        let show_in_menu = self.show_edit_predictions_in_menu();
 6832        let completions_menu_has_precedence = !show_in_menu
 6833            && (self.context_menu.borrow().is_some()
 6834                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6835
 6836        if completions_menu_has_precedence
 6837            || !offset_selection.is_empty()
 6838            || self
 6839                .active_inline_completion
 6840                .as_ref()
 6841                .map_or(false, |completion| {
 6842                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6843                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6844                    !invalidation_range.contains(&offset_selection.head())
 6845                })
 6846        {
 6847            self.discard_inline_completion(false, cx);
 6848            return None;
 6849        }
 6850
 6851        self.take_active_inline_completion(cx);
 6852        let Some(provider) = self.edit_prediction_provider() else {
 6853            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6854            return None;
 6855        };
 6856
 6857        let (buffer, cursor_buffer_position) =
 6858            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6859
 6860        self.edit_prediction_settings =
 6861            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6862
 6863        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6864
 6865        if self.edit_prediction_indent_conflict {
 6866            let cursor_point = cursor.to_point(&multibuffer);
 6867
 6868            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6869
 6870            if let Some((_, indent)) = indents.iter().next() {
 6871                if indent.len == cursor_point.column {
 6872                    self.edit_prediction_indent_conflict = false;
 6873                }
 6874            }
 6875        }
 6876
 6877        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6878        let edits = inline_completion
 6879            .edits
 6880            .into_iter()
 6881            .flat_map(|(range, new_text)| {
 6882                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6883                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6884                Some((start..end, new_text))
 6885            })
 6886            .collect::<Vec<_>>();
 6887        if edits.is_empty() {
 6888            return None;
 6889        }
 6890
 6891        let first_edit_start = edits.first().unwrap().0.start;
 6892        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6893        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6894
 6895        let last_edit_end = edits.last().unwrap().0.end;
 6896        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6897        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6898
 6899        let cursor_row = cursor.to_point(&multibuffer).row;
 6900
 6901        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6902
 6903        let mut inlay_ids = Vec::new();
 6904        let invalidation_row_range;
 6905        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6906            Some(cursor_row..edit_end_row)
 6907        } else if cursor_row > edit_end_row {
 6908            Some(edit_start_row..cursor_row)
 6909        } else {
 6910            None
 6911        };
 6912        let is_move =
 6913            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6914        let completion = if is_move {
 6915            invalidation_row_range =
 6916                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6917            let target = first_edit_start;
 6918            InlineCompletion::Move { target, snapshot }
 6919        } else {
 6920            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6921                && !self.inline_completions_hidden_for_vim_mode;
 6922
 6923            if show_completions_in_buffer {
 6924                if edits
 6925                    .iter()
 6926                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6927                {
 6928                    let mut inlays = Vec::new();
 6929                    for (range, new_text) in &edits {
 6930                        let inlay = Inlay::inline_completion(
 6931                            post_inc(&mut self.next_inlay_id),
 6932                            range.start,
 6933                            new_text.as_str(),
 6934                        );
 6935                        inlay_ids.push(inlay.id);
 6936                        inlays.push(inlay);
 6937                    }
 6938
 6939                    self.splice_inlays(&[], inlays, cx);
 6940                } else {
 6941                    let background_color = cx.theme().status().deleted_background;
 6942                    self.highlight_text::<InlineCompletionHighlight>(
 6943                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6944                        HighlightStyle {
 6945                            background_color: Some(background_color),
 6946                            ..Default::default()
 6947                        },
 6948                        cx,
 6949                    );
 6950                }
 6951            }
 6952
 6953            invalidation_row_range = edit_start_row..edit_end_row;
 6954
 6955            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6956                if provider.show_tab_accept_marker() {
 6957                    EditDisplayMode::TabAccept
 6958                } else {
 6959                    EditDisplayMode::Inline
 6960                }
 6961            } else {
 6962                EditDisplayMode::DiffPopover
 6963            };
 6964
 6965            InlineCompletion::Edit {
 6966                edits,
 6967                edit_preview: inline_completion.edit_preview,
 6968                display_mode,
 6969                snapshot,
 6970            }
 6971        };
 6972
 6973        let invalidation_range = multibuffer
 6974            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6975            ..multibuffer.anchor_after(Point::new(
 6976                invalidation_row_range.end,
 6977                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6978            ));
 6979
 6980        self.stale_inline_completion_in_menu = None;
 6981        self.active_inline_completion = Some(InlineCompletionState {
 6982            inlay_ids,
 6983            completion,
 6984            completion_id: inline_completion.id,
 6985            invalidation_range,
 6986        });
 6987
 6988        cx.notify();
 6989
 6990        Some(())
 6991    }
 6992
 6993    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6994        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6995    }
 6996
 6997    fn clear_tasks(&mut self) {
 6998        self.tasks.clear()
 6999    }
 7000
 7001    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7002        if self.tasks.insert(key, value).is_some() {
 7003            // This case should hopefully be rare, but just in case...
 7004            log::error!(
 7005                "multiple different run targets found on a single line, only the last target will be rendered"
 7006            )
 7007        }
 7008    }
 7009
 7010    /// Get all display points of breakpoints that will be rendered within editor
 7011    ///
 7012    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7013    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7014    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7015    fn active_breakpoints(
 7016        &self,
 7017        range: Range<DisplayRow>,
 7018        window: &mut Window,
 7019        cx: &mut Context<Self>,
 7020    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7021        let mut breakpoint_display_points = HashMap::default();
 7022
 7023        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7024            return breakpoint_display_points;
 7025        };
 7026
 7027        let snapshot = self.snapshot(window, cx);
 7028
 7029        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7030        let Some(project) = self.project.as_ref() else {
 7031            return breakpoint_display_points;
 7032        };
 7033
 7034        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7035            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7036
 7037        for (buffer_snapshot, range, excerpt_id) in
 7038            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7039        {
 7040            let Some(buffer) = project.read_with(cx, |this, cx| {
 7041                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7042            }) else {
 7043                continue;
 7044            };
 7045            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7046                &buffer,
 7047                Some(
 7048                    buffer_snapshot.anchor_before(range.start)
 7049                        ..buffer_snapshot.anchor_after(range.end),
 7050                ),
 7051                buffer_snapshot,
 7052                cx,
 7053            );
 7054            for (breakpoint, state) in breakpoints {
 7055                let multi_buffer_anchor =
 7056                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7057                let position = multi_buffer_anchor
 7058                    .to_point(&multi_buffer_snapshot)
 7059                    .to_display_point(&snapshot);
 7060
 7061                breakpoint_display_points.insert(
 7062                    position.row(),
 7063                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7064                );
 7065            }
 7066        }
 7067
 7068        breakpoint_display_points
 7069    }
 7070
 7071    fn breakpoint_context_menu(
 7072        &self,
 7073        anchor: Anchor,
 7074        window: &mut Window,
 7075        cx: &mut Context<Self>,
 7076    ) -> Entity<ui::ContextMenu> {
 7077        let weak_editor = cx.weak_entity();
 7078        let focus_handle = self.focus_handle(cx);
 7079
 7080        let row = self
 7081            .buffer
 7082            .read(cx)
 7083            .snapshot(cx)
 7084            .summary_for_anchor::<Point>(&anchor)
 7085            .row;
 7086
 7087        let breakpoint = self
 7088            .breakpoint_at_row(row, window, cx)
 7089            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7090
 7091        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7092            "Edit Log Breakpoint"
 7093        } else {
 7094            "Set Log Breakpoint"
 7095        };
 7096
 7097        let condition_breakpoint_msg = if breakpoint
 7098            .as_ref()
 7099            .is_some_and(|bp| bp.1.condition.is_some())
 7100        {
 7101            "Edit Condition Breakpoint"
 7102        } else {
 7103            "Set Condition Breakpoint"
 7104        };
 7105
 7106        let hit_condition_breakpoint_msg = if breakpoint
 7107            .as_ref()
 7108            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7109        {
 7110            "Edit Hit Condition Breakpoint"
 7111        } else {
 7112            "Set Hit Condition Breakpoint"
 7113        };
 7114
 7115        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7116            "Unset Breakpoint"
 7117        } else {
 7118            "Set Breakpoint"
 7119        };
 7120
 7121        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7122            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7123
 7124        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7125            BreakpointState::Enabled => Some("Disable"),
 7126            BreakpointState::Disabled => Some("Enable"),
 7127        });
 7128
 7129        let (anchor, breakpoint) =
 7130            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7131
 7132        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7133            menu.on_blur_subscription(Subscription::new(|| {}))
 7134                .context(focus_handle)
 7135                .when(run_to_cursor, |this| {
 7136                    let weak_editor = weak_editor.clone();
 7137                    this.entry("Run to cursor", None, move |window, cx| {
 7138                        weak_editor
 7139                            .update(cx, |editor, cx| {
 7140                                editor.change_selections(None, window, cx, |s| {
 7141                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7142                                });
 7143                            })
 7144                            .ok();
 7145
 7146                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7147                    })
 7148                    .separator()
 7149                })
 7150                .when_some(toggle_state_msg, |this, msg| {
 7151                    this.entry(msg, None, {
 7152                        let weak_editor = weak_editor.clone();
 7153                        let breakpoint = breakpoint.clone();
 7154                        move |_window, cx| {
 7155                            weak_editor
 7156                                .update(cx, |this, cx| {
 7157                                    this.edit_breakpoint_at_anchor(
 7158                                        anchor,
 7159                                        breakpoint.as_ref().clone(),
 7160                                        BreakpointEditAction::InvertState,
 7161                                        cx,
 7162                                    );
 7163                                })
 7164                                .log_err();
 7165                        }
 7166                    })
 7167                })
 7168                .entry(set_breakpoint_msg, None, {
 7169                    let weak_editor = weak_editor.clone();
 7170                    let breakpoint = breakpoint.clone();
 7171                    move |_window, cx| {
 7172                        weak_editor
 7173                            .update(cx, |this, cx| {
 7174                                this.edit_breakpoint_at_anchor(
 7175                                    anchor,
 7176                                    breakpoint.as_ref().clone(),
 7177                                    BreakpointEditAction::Toggle,
 7178                                    cx,
 7179                                );
 7180                            })
 7181                            .log_err();
 7182                    }
 7183                })
 7184                .entry(log_breakpoint_msg, None, {
 7185                    let breakpoint = breakpoint.clone();
 7186                    let weak_editor = weak_editor.clone();
 7187                    move |window, cx| {
 7188                        weak_editor
 7189                            .update(cx, |this, cx| {
 7190                                this.add_edit_breakpoint_block(
 7191                                    anchor,
 7192                                    breakpoint.as_ref(),
 7193                                    BreakpointPromptEditAction::Log,
 7194                                    window,
 7195                                    cx,
 7196                                );
 7197                            })
 7198                            .log_err();
 7199                    }
 7200                })
 7201                .entry(condition_breakpoint_msg, None, {
 7202                    let breakpoint = breakpoint.clone();
 7203                    let weak_editor = weak_editor.clone();
 7204                    move |window, cx| {
 7205                        weak_editor
 7206                            .update(cx, |this, cx| {
 7207                                this.add_edit_breakpoint_block(
 7208                                    anchor,
 7209                                    breakpoint.as_ref(),
 7210                                    BreakpointPromptEditAction::Condition,
 7211                                    window,
 7212                                    cx,
 7213                                );
 7214                            })
 7215                            .log_err();
 7216                    }
 7217                })
 7218                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7219                    weak_editor
 7220                        .update(cx, |this, cx| {
 7221                            this.add_edit_breakpoint_block(
 7222                                anchor,
 7223                                breakpoint.as_ref(),
 7224                                BreakpointPromptEditAction::HitCondition,
 7225                                window,
 7226                                cx,
 7227                            );
 7228                        })
 7229                        .log_err();
 7230                })
 7231        })
 7232    }
 7233
 7234    fn render_breakpoint(
 7235        &self,
 7236        position: Anchor,
 7237        row: DisplayRow,
 7238        breakpoint: &Breakpoint,
 7239        state: Option<BreakpointSessionState>,
 7240        cx: &mut Context<Self>,
 7241    ) -> IconButton {
 7242        let is_rejected = state.is_some_and(|s| !s.verified);
 7243        // Is it a breakpoint that shows up when hovering over gutter?
 7244        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7245            (false, false),
 7246            |PhantomBreakpointIndicator {
 7247                 is_active,
 7248                 display_row,
 7249                 collides_with_existing_breakpoint,
 7250             }| {
 7251                (
 7252                    is_active && display_row == row,
 7253                    collides_with_existing_breakpoint,
 7254                )
 7255            },
 7256        );
 7257
 7258        let (color, icon) = {
 7259            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7260                (false, false) => ui::IconName::DebugBreakpoint,
 7261                (true, false) => ui::IconName::DebugLogBreakpoint,
 7262                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7263                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7264            };
 7265
 7266            let color = if is_phantom {
 7267                Color::Hint
 7268            } else if is_rejected {
 7269                Color::Disabled
 7270            } else {
 7271                Color::Debugger
 7272            };
 7273
 7274            (color, icon)
 7275        };
 7276
 7277        let breakpoint = Arc::from(breakpoint.clone());
 7278
 7279        let alt_as_text = gpui::Keystroke {
 7280            modifiers: Modifiers::secondary_key(),
 7281            ..Default::default()
 7282        };
 7283        let primary_action_text = if breakpoint.is_disabled() {
 7284            "Enable breakpoint"
 7285        } else if is_phantom && !collides_with_existing {
 7286            "Set breakpoint"
 7287        } else {
 7288            "Unset breakpoint"
 7289        };
 7290        let focus_handle = self.focus_handle.clone();
 7291
 7292        let meta = if is_rejected {
 7293            SharedString::from("No executable code is associated with this line.")
 7294        } else if collides_with_existing && !breakpoint.is_disabled() {
 7295            SharedString::from(format!(
 7296                "{alt_as_text}-click to disable,\nright-click for more options."
 7297            ))
 7298        } else {
 7299            SharedString::from("Right-click for more options.")
 7300        };
 7301        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7302            .icon_size(IconSize::XSmall)
 7303            .size(ui::ButtonSize::None)
 7304            .when(is_rejected, |this| {
 7305                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7306            })
 7307            .icon_color(color)
 7308            .style(ButtonStyle::Transparent)
 7309            .on_click(cx.listener({
 7310                let breakpoint = breakpoint.clone();
 7311
 7312                move |editor, event: &ClickEvent, window, cx| {
 7313                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7314                        BreakpointEditAction::InvertState
 7315                    } else {
 7316                        BreakpointEditAction::Toggle
 7317                    };
 7318
 7319                    window.focus(&editor.focus_handle(cx));
 7320                    editor.edit_breakpoint_at_anchor(
 7321                        position,
 7322                        breakpoint.as_ref().clone(),
 7323                        edit_action,
 7324                        cx,
 7325                    );
 7326                }
 7327            }))
 7328            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7329                editor.set_breakpoint_context_menu(
 7330                    row,
 7331                    Some(position),
 7332                    event.down.position,
 7333                    window,
 7334                    cx,
 7335                );
 7336            }))
 7337            .tooltip(move |window, cx| {
 7338                Tooltip::with_meta_in(
 7339                    primary_action_text,
 7340                    Some(&ToggleBreakpoint),
 7341                    meta.clone(),
 7342                    &focus_handle,
 7343                    window,
 7344                    cx,
 7345                )
 7346            })
 7347    }
 7348
 7349    fn build_tasks_context(
 7350        project: &Entity<Project>,
 7351        buffer: &Entity<Buffer>,
 7352        buffer_row: u32,
 7353        tasks: &Arc<RunnableTasks>,
 7354        cx: &mut Context<Self>,
 7355    ) -> Task<Option<task::TaskContext>> {
 7356        let position = Point::new(buffer_row, tasks.column);
 7357        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7358        let location = Location {
 7359            buffer: buffer.clone(),
 7360            range: range_start..range_start,
 7361        };
 7362        // Fill in the environmental variables from the tree-sitter captures
 7363        let mut captured_task_variables = TaskVariables::default();
 7364        for (capture_name, value) in tasks.extra_variables.clone() {
 7365            captured_task_variables.insert(
 7366                task::VariableName::Custom(capture_name.into()),
 7367                value.clone(),
 7368            );
 7369        }
 7370        project.update(cx, |project, cx| {
 7371            project.task_store().update(cx, |task_store, cx| {
 7372                task_store.task_context_for_location(captured_task_variables, location, cx)
 7373            })
 7374        })
 7375    }
 7376
 7377    pub fn spawn_nearest_task(
 7378        &mut self,
 7379        action: &SpawnNearestTask,
 7380        window: &mut Window,
 7381        cx: &mut Context<Self>,
 7382    ) {
 7383        let Some((workspace, _)) = self.workspace.clone() else {
 7384            return;
 7385        };
 7386        let Some(project) = self.project.clone() else {
 7387            return;
 7388        };
 7389
 7390        // Try to find a closest, enclosing node using tree-sitter that has a
 7391        // task
 7392        let Some((buffer, buffer_row, tasks)) = self
 7393            .find_enclosing_node_task(cx)
 7394            // Or find the task that's closest in row-distance.
 7395            .or_else(|| self.find_closest_task(cx))
 7396        else {
 7397            return;
 7398        };
 7399
 7400        let reveal_strategy = action.reveal;
 7401        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7402        cx.spawn_in(window, async move |_, cx| {
 7403            let context = task_context.await?;
 7404            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7405
 7406            let resolved = &mut resolved_task.resolved;
 7407            resolved.reveal = reveal_strategy;
 7408
 7409            workspace
 7410                .update_in(cx, |workspace, window, cx| {
 7411                    workspace.schedule_resolved_task(
 7412                        task_source_kind,
 7413                        resolved_task,
 7414                        false,
 7415                        window,
 7416                        cx,
 7417                    );
 7418                })
 7419                .ok()
 7420        })
 7421        .detach();
 7422    }
 7423
 7424    fn find_closest_task(
 7425        &mut self,
 7426        cx: &mut Context<Self>,
 7427    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7428        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7429
 7430        let ((buffer_id, row), tasks) = self
 7431            .tasks
 7432            .iter()
 7433            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7434
 7435        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7436        let tasks = Arc::new(tasks.to_owned());
 7437        Some((buffer, *row, tasks))
 7438    }
 7439
 7440    fn find_enclosing_node_task(
 7441        &mut self,
 7442        cx: &mut Context<Self>,
 7443    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7444        let snapshot = self.buffer.read(cx).snapshot(cx);
 7445        let offset = self.selections.newest::<usize>(cx).head();
 7446        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7447        let buffer_id = excerpt.buffer().remote_id();
 7448
 7449        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7450        let mut cursor = layer.node().walk();
 7451
 7452        while cursor.goto_first_child_for_byte(offset).is_some() {
 7453            if cursor.node().end_byte() == offset {
 7454                cursor.goto_next_sibling();
 7455            }
 7456        }
 7457
 7458        // Ascend to the smallest ancestor that contains the range and has a task.
 7459        loop {
 7460            let node = cursor.node();
 7461            let node_range = node.byte_range();
 7462            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7463
 7464            // Check if this node contains our offset
 7465            if node_range.start <= offset && node_range.end >= offset {
 7466                // If it contains offset, check for task
 7467                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7468                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7469                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7470                }
 7471            }
 7472
 7473            if !cursor.goto_parent() {
 7474                break;
 7475            }
 7476        }
 7477        None
 7478    }
 7479
 7480    fn render_run_indicator(
 7481        &self,
 7482        _style: &EditorStyle,
 7483        is_active: bool,
 7484        row: DisplayRow,
 7485        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7486        cx: &mut Context<Self>,
 7487    ) -> IconButton {
 7488        let color = Color::Muted;
 7489        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7490
 7491        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7492            .shape(ui::IconButtonShape::Square)
 7493            .icon_size(IconSize::XSmall)
 7494            .icon_color(color)
 7495            .toggle_state(is_active)
 7496            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7497                let quick_launch = e.down.button == MouseButton::Left;
 7498                window.focus(&editor.focus_handle(cx));
 7499                editor.toggle_code_actions(
 7500                    &ToggleCodeActions {
 7501                        deployed_from_indicator: Some(row),
 7502                        quick_launch,
 7503                    },
 7504                    window,
 7505                    cx,
 7506                );
 7507            }))
 7508            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7509                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7510            }))
 7511    }
 7512
 7513    pub fn context_menu_visible(&self) -> bool {
 7514        !self.edit_prediction_preview_is_active()
 7515            && self
 7516                .context_menu
 7517                .borrow()
 7518                .as_ref()
 7519                .map_or(false, |menu| menu.visible())
 7520    }
 7521
 7522    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7523        self.context_menu
 7524            .borrow()
 7525            .as_ref()
 7526            .map(|menu| menu.origin())
 7527    }
 7528
 7529    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7530        self.context_menu_options = Some(options);
 7531    }
 7532
 7533    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7534    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7535
 7536    fn render_edit_prediction_popover(
 7537        &mut self,
 7538        text_bounds: &Bounds<Pixels>,
 7539        content_origin: gpui::Point<Pixels>,
 7540        right_margin: Pixels,
 7541        editor_snapshot: &EditorSnapshot,
 7542        visible_row_range: Range<DisplayRow>,
 7543        scroll_top: f32,
 7544        scroll_bottom: f32,
 7545        line_layouts: &[LineWithInvisibles],
 7546        line_height: Pixels,
 7547        scroll_pixel_position: gpui::Point<Pixels>,
 7548        newest_selection_head: Option<DisplayPoint>,
 7549        editor_width: Pixels,
 7550        style: &EditorStyle,
 7551        window: &mut Window,
 7552        cx: &mut App,
 7553    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7554        if self.mode().is_minimap() {
 7555            return None;
 7556        }
 7557        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7558
 7559        if self.edit_prediction_visible_in_cursor_popover(true) {
 7560            return None;
 7561        }
 7562
 7563        match &active_inline_completion.completion {
 7564            InlineCompletion::Move { target, .. } => {
 7565                let target_display_point = target.to_display_point(editor_snapshot);
 7566
 7567                if self.edit_prediction_requires_modifier() {
 7568                    if !self.edit_prediction_preview_is_active() {
 7569                        return None;
 7570                    }
 7571
 7572                    self.render_edit_prediction_modifier_jump_popover(
 7573                        text_bounds,
 7574                        content_origin,
 7575                        visible_row_range,
 7576                        line_layouts,
 7577                        line_height,
 7578                        scroll_pixel_position,
 7579                        newest_selection_head,
 7580                        target_display_point,
 7581                        window,
 7582                        cx,
 7583                    )
 7584                } else {
 7585                    self.render_edit_prediction_eager_jump_popover(
 7586                        text_bounds,
 7587                        content_origin,
 7588                        editor_snapshot,
 7589                        visible_row_range,
 7590                        scroll_top,
 7591                        scroll_bottom,
 7592                        line_height,
 7593                        scroll_pixel_position,
 7594                        target_display_point,
 7595                        editor_width,
 7596                        window,
 7597                        cx,
 7598                    )
 7599                }
 7600            }
 7601            InlineCompletion::Edit {
 7602                display_mode: EditDisplayMode::Inline,
 7603                ..
 7604            } => None,
 7605            InlineCompletion::Edit {
 7606                display_mode: EditDisplayMode::TabAccept,
 7607                edits,
 7608                ..
 7609            } => {
 7610                let range = &edits.first()?.0;
 7611                let target_display_point = range.end.to_display_point(editor_snapshot);
 7612
 7613                self.render_edit_prediction_end_of_line_popover(
 7614                    "Accept",
 7615                    editor_snapshot,
 7616                    visible_row_range,
 7617                    target_display_point,
 7618                    line_height,
 7619                    scroll_pixel_position,
 7620                    content_origin,
 7621                    editor_width,
 7622                    window,
 7623                    cx,
 7624                )
 7625            }
 7626            InlineCompletion::Edit {
 7627                edits,
 7628                edit_preview,
 7629                display_mode: EditDisplayMode::DiffPopover,
 7630                snapshot,
 7631            } => self.render_edit_prediction_diff_popover(
 7632                text_bounds,
 7633                content_origin,
 7634                right_margin,
 7635                editor_snapshot,
 7636                visible_row_range,
 7637                line_layouts,
 7638                line_height,
 7639                scroll_pixel_position,
 7640                newest_selection_head,
 7641                editor_width,
 7642                style,
 7643                edits,
 7644                edit_preview,
 7645                snapshot,
 7646                window,
 7647                cx,
 7648            ),
 7649        }
 7650    }
 7651
 7652    fn render_edit_prediction_modifier_jump_popover(
 7653        &mut self,
 7654        text_bounds: &Bounds<Pixels>,
 7655        content_origin: gpui::Point<Pixels>,
 7656        visible_row_range: Range<DisplayRow>,
 7657        line_layouts: &[LineWithInvisibles],
 7658        line_height: Pixels,
 7659        scroll_pixel_position: gpui::Point<Pixels>,
 7660        newest_selection_head: Option<DisplayPoint>,
 7661        target_display_point: DisplayPoint,
 7662        window: &mut Window,
 7663        cx: &mut App,
 7664    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7665        let scrolled_content_origin =
 7666            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7667
 7668        const SCROLL_PADDING_Y: Pixels = px(12.);
 7669
 7670        if target_display_point.row() < visible_row_range.start {
 7671            return self.render_edit_prediction_scroll_popover(
 7672                |_| SCROLL_PADDING_Y,
 7673                IconName::ArrowUp,
 7674                visible_row_range,
 7675                line_layouts,
 7676                newest_selection_head,
 7677                scrolled_content_origin,
 7678                window,
 7679                cx,
 7680            );
 7681        } else if target_display_point.row() >= visible_row_range.end {
 7682            return self.render_edit_prediction_scroll_popover(
 7683                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7684                IconName::ArrowDown,
 7685                visible_row_range,
 7686                line_layouts,
 7687                newest_selection_head,
 7688                scrolled_content_origin,
 7689                window,
 7690                cx,
 7691            );
 7692        }
 7693
 7694        const POLE_WIDTH: Pixels = px(2.);
 7695
 7696        let line_layout =
 7697            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7698        let target_column = target_display_point.column() as usize;
 7699
 7700        let target_x = line_layout.x_for_index(target_column);
 7701        let target_y =
 7702            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7703
 7704        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7705
 7706        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7707        border_color.l += 0.001;
 7708
 7709        let mut element = v_flex()
 7710            .items_end()
 7711            .when(flag_on_right, |el| el.items_start())
 7712            .child(if flag_on_right {
 7713                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7714                    .rounded_bl(px(0.))
 7715                    .rounded_tl(px(0.))
 7716                    .border_l_2()
 7717                    .border_color(border_color)
 7718            } else {
 7719                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7720                    .rounded_br(px(0.))
 7721                    .rounded_tr(px(0.))
 7722                    .border_r_2()
 7723                    .border_color(border_color)
 7724            })
 7725            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7726            .into_any();
 7727
 7728        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7729
 7730        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7731            - point(
 7732                if flag_on_right {
 7733                    POLE_WIDTH
 7734                } else {
 7735                    size.width - POLE_WIDTH
 7736                },
 7737                size.height - line_height,
 7738            );
 7739
 7740        origin.x = origin.x.max(content_origin.x);
 7741
 7742        element.prepaint_at(origin, window, cx);
 7743
 7744        Some((element, origin))
 7745    }
 7746
 7747    fn render_edit_prediction_scroll_popover(
 7748        &mut self,
 7749        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7750        scroll_icon: IconName,
 7751        visible_row_range: Range<DisplayRow>,
 7752        line_layouts: &[LineWithInvisibles],
 7753        newest_selection_head: Option<DisplayPoint>,
 7754        scrolled_content_origin: gpui::Point<Pixels>,
 7755        window: &mut Window,
 7756        cx: &mut App,
 7757    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7758        let mut element = self
 7759            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7760            .into_any();
 7761
 7762        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7763
 7764        let cursor = newest_selection_head?;
 7765        let cursor_row_layout =
 7766            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7767        let cursor_column = cursor.column() as usize;
 7768
 7769        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7770
 7771        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7772
 7773        element.prepaint_at(origin, window, cx);
 7774        Some((element, origin))
 7775    }
 7776
 7777    fn render_edit_prediction_eager_jump_popover(
 7778        &mut self,
 7779        text_bounds: &Bounds<Pixels>,
 7780        content_origin: gpui::Point<Pixels>,
 7781        editor_snapshot: &EditorSnapshot,
 7782        visible_row_range: Range<DisplayRow>,
 7783        scroll_top: f32,
 7784        scroll_bottom: f32,
 7785        line_height: Pixels,
 7786        scroll_pixel_position: gpui::Point<Pixels>,
 7787        target_display_point: DisplayPoint,
 7788        editor_width: Pixels,
 7789        window: &mut Window,
 7790        cx: &mut App,
 7791    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7792        if target_display_point.row().as_f32() < scroll_top {
 7793            let mut element = self
 7794                .render_edit_prediction_line_popover(
 7795                    "Jump to Edit",
 7796                    Some(IconName::ArrowUp),
 7797                    window,
 7798                    cx,
 7799                )?
 7800                .into_any();
 7801
 7802            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7803            let offset = point(
 7804                (text_bounds.size.width - size.width) / 2.,
 7805                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7806            );
 7807
 7808            let origin = text_bounds.origin + offset;
 7809            element.prepaint_at(origin, window, cx);
 7810            Some((element, origin))
 7811        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7812            let mut element = self
 7813                .render_edit_prediction_line_popover(
 7814                    "Jump to Edit",
 7815                    Some(IconName::ArrowDown),
 7816                    window,
 7817                    cx,
 7818                )?
 7819                .into_any();
 7820
 7821            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7822            let offset = point(
 7823                (text_bounds.size.width - size.width) / 2.,
 7824                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7825            );
 7826
 7827            let origin = text_bounds.origin + offset;
 7828            element.prepaint_at(origin, window, cx);
 7829            Some((element, origin))
 7830        } else {
 7831            self.render_edit_prediction_end_of_line_popover(
 7832                "Jump to Edit",
 7833                editor_snapshot,
 7834                visible_row_range,
 7835                target_display_point,
 7836                line_height,
 7837                scroll_pixel_position,
 7838                content_origin,
 7839                editor_width,
 7840                window,
 7841                cx,
 7842            )
 7843        }
 7844    }
 7845
 7846    fn render_edit_prediction_end_of_line_popover(
 7847        self: &mut Editor,
 7848        label: &'static str,
 7849        editor_snapshot: &EditorSnapshot,
 7850        visible_row_range: Range<DisplayRow>,
 7851        target_display_point: DisplayPoint,
 7852        line_height: Pixels,
 7853        scroll_pixel_position: gpui::Point<Pixels>,
 7854        content_origin: gpui::Point<Pixels>,
 7855        editor_width: Pixels,
 7856        window: &mut Window,
 7857        cx: &mut App,
 7858    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7859        let target_line_end = DisplayPoint::new(
 7860            target_display_point.row(),
 7861            editor_snapshot.line_len(target_display_point.row()),
 7862        );
 7863
 7864        let mut element = self
 7865            .render_edit_prediction_line_popover(label, None, window, cx)?
 7866            .into_any();
 7867
 7868        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7869
 7870        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7871
 7872        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7873        let mut origin = start_point
 7874            + line_origin
 7875            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7876        origin.x = origin.x.max(content_origin.x);
 7877
 7878        let max_x = content_origin.x + editor_width - size.width;
 7879
 7880        if origin.x > max_x {
 7881            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7882
 7883            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7884                origin.y += offset;
 7885                IconName::ArrowUp
 7886            } else {
 7887                origin.y -= offset;
 7888                IconName::ArrowDown
 7889            };
 7890
 7891            element = self
 7892                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7893                .into_any();
 7894
 7895            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7896
 7897            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7898        }
 7899
 7900        element.prepaint_at(origin, window, cx);
 7901        Some((element, origin))
 7902    }
 7903
 7904    fn render_edit_prediction_diff_popover(
 7905        self: &Editor,
 7906        text_bounds: &Bounds<Pixels>,
 7907        content_origin: gpui::Point<Pixels>,
 7908        right_margin: Pixels,
 7909        editor_snapshot: &EditorSnapshot,
 7910        visible_row_range: Range<DisplayRow>,
 7911        line_layouts: &[LineWithInvisibles],
 7912        line_height: Pixels,
 7913        scroll_pixel_position: gpui::Point<Pixels>,
 7914        newest_selection_head: Option<DisplayPoint>,
 7915        editor_width: Pixels,
 7916        style: &EditorStyle,
 7917        edits: &Vec<(Range<Anchor>, String)>,
 7918        edit_preview: &Option<language::EditPreview>,
 7919        snapshot: &language::BufferSnapshot,
 7920        window: &mut Window,
 7921        cx: &mut App,
 7922    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7923        let edit_start = edits
 7924            .first()
 7925            .unwrap()
 7926            .0
 7927            .start
 7928            .to_display_point(editor_snapshot);
 7929        let edit_end = edits
 7930            .last()
 7931            .unwrap()
 7932            .0
 7933            .end
 7934            .to_display_point(editor_snapshot);
 7935
 7936        let is_visible = visible_row_range.contains(&edit_start.row())
 7937            || visible_row_range.contains(&edit_end.row());
 7938        if !is_visible {
 7939            return None;
 7940        }
 7941
 7942        let highlighted_edits =
 7943            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7944
 7945        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7946        let line_count = highlighted_edits.text.lines().count();
 7947
 7948        const BORDER_WIDTH: Pixels = px(1.);
 7949
 7950        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7951        let has_keybind = keybind.is_some();
 7952
 7953        let mut element = h_flex()
 7954            .items_start()
 7955            .child(
 7956                h_flex()
 7957                    .bg(cx.theme().colors().editor_background)
 7958                    .border(BORDER_WIDTH)
 7959                    .shadow_sm()
 7960                    .border_color(cx.theme().colors().border)
 7961                    .rounded_l_lg()
 7962                    .when(line_count > 1, |el| el.rounded_br_lg())
 7963                    .pr_1()
 7964                    .child(styled_text),
 7965            )
 7966            .child(
 7967                h_flex()
 7968                    .h(line_height + BORDER_WIDTH * 2.)
 7969                    .px_1p5()
 7970                    .gap_1()
 7971                    // Workaround: For some reason, there's a gap if we don't do this
 7972                    .ml(-BORDER_WIDTH)
 7973                    .shadow(smallvec![gpui::BoxShadow {
 7974                        color: gpui::black().opacity(0.05),
 7975                        offset: point(px(1.), px(1.)),
 7976                        blur_radius: px(2.),
 7977                        spread_radius: px(0.),
 7978                    }])
 7979                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7980                    .border(BORDER_WIDTH)
 7981                    .border_color(cx.theme().colors().border)
 7982                    .rounded_r_lg()
 7983                    .id("edit_prediction_diff_popover_keybind")
 7984                    .when(!has_keybind, |el| {
 7985                        let status_colors = cx.theme().status();
 7986
 7987                        el.bg(status_colors.error_background)
 7988                            .border_color(status_colors.error.opacity(0.6))
 7989                            .child(Icon::new(IconName::Info).color(Color::Error))
 7990                            .cursor_default()
 7991                            .hoverable_tooltip(move |_window, cx| {
 7992                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7993                            })
 7994                    })
 7995                    .children(keybind),
 7996            )
 7997            .into_any();
 7998
 7999        let longest_row =
 8000            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8001        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8002            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8003        } else {
 8004            layout_line(
 8005                longest_row,
 8006                editor_snapshot,
 8007                style,
 8008                editor_width,
 8009                |_| false,
 8010                window,
 8011                cx,
 8012            )
 8013            .width
 8014        };
 8015
 8016        let viewport_bounds =
 8017            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8018                right: -right_margin,
 8019                ..Default::default()
 8020            });
 8021
 8022        let x_after_longest =
 8023            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8024                - scroll_pixel_position.x;
 8025
 8026        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8027
 8028        // Fully visible if it can be displayed within the window (allow overlapping other
 8029        // panes). However, this is only allowed if the popover starts within text_bounds.
 8030        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8031            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8032
 8033        let mut origin = if can_position_to_the_right {
 8034            point(
 8035                x_after_longest,
 8036                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8037                    - scroll_pixel_position.y,
 8038            )
 8039        } else {
 8040            let cursor_row = newest_selection_head.map(|head| head.row());
 8041            let above_edit = edit_start
 8042                .row()
 8043                .0
 8044                .checked_sub(line_count as u32)
 8045                .map(DisplayRow);
 8046            let below_edit = Some(edit_end.row() + 1);
 8047            let above_cursor =
 8048                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8049            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8050
 8051            // Place the edit popover adjacent to the edit if there is a location
 8052            // available that is onscreen and does not obscure the cursor. Otherwise,
 8053            // place it adjacent to the cursor.
 8054            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8055                .into_iter()
 8056                .flatten()
 8057                .find(|&start_row| {
 8058                    let end_row = start_row + line_count as u32;
 8059                    visible_row_range.contains(&start_row)
 8060                        && visible_row_range.contains(&end_row)
 8061                        && cursor_row.map_or(true, |cursor_row| {
 8062                            !((start_row..end_row).contains(&cursor_row))
 8063                        })
 8064                })?;
 8065
 8066            content_origin
 8067                + point(
 8068                    -scroll_pixel_position.x,
 8069                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8070                )
 8071        };
 8072
 8073        origin.x -= BORDER_WIDTH;
 8074
 8075        window.defer_draw(element, origin, 1);
 8076
 8077        // Do not return an element, since it will already be drawn due to defer_draw.
 8078        None
 8079    }
 8080
 8081    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8082        px(30.)
 8083    }
 8084
 8085    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8086        if self.read_only(cx) {
 8087            cx.theme().players().read_only()
 8088        } else {
 8089            self.style.as_ref().unwrap().local_player
 8090        }
 8091    }
 8092
 8093    fn render_edit_prediction_accept_keybind(
 8094        &self,
 8095        window: &mut Window,
 8096        cx: &App,
 8097    ) -> Option<AnyElement> {
 8098        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8099        let accept_keystroke = accept_binding.keystroke()?;
 8100
 8101        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8102
 8103        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8104            Color::Accent
 8105        } else {
 8106            Color::Muted
 8107        };
 8108
 8109        h_flex()
 8110            .px_0p5()
 8111            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8112            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8113            .text_size(TextSize::XSmall.rems(cx))
 8114            .child(h_flex().children(ui::render_modifiers(
 8115                &accept_keystroke.modifiers,
 8116                PlatformStyle::platform(),
 8117                Some(modifiers_color),
 8118                Some(IconSize::XSmall.rems().into()),
 8119                true,
 8120            )))
 8121            .when(is_platform_style_mac, |parent| {
 8122                parent.child(accept_keystroke.key.clone())
 8123            })
 8124            .when(!is_platform_style_mac, |parent| {
 8125                parent.child(
 8126                    Key::new(
 8127                        util::capitalize(&accept_keystroke.key),
 8128                        Some(Color::Default),
 8129                    )
 8130                    .size(Some(IconSize::XSmall.rems().into())),
 8131                )
 8132            })
 8133            .into_any()
 8134            .into()
 8135    }
 8136
 8137    fn render_edit_prediction_line_popover(
 8138        &self,
 8139        label: impl Into<SharedString>,
 8140        icon: Option<IconName>,
 8141        window: &mut Window,
 8142        cx: &App,
 8143    ) -> Option<Stateful<Div>> {
 8144        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8145
 8146        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8147        let has_keybind = keybind.is_some();
 8148
 8149        let result = h_flex()
 8150            .id("ep-line-popover")
 8151            .py_0p5()
 8152            .pl_1()
 8153            .pr(padding_right)
 8154            .gap_1()
 8155            .rounded_md()
 8156            .border_1()
 8157            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8158            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8159            .shadow_sm()
 8160            .when(!has_keybind, |el| {
 8161                let status_colors = cx.theme().status();
 8162
 8163                el.bg(status_colors.error_background)
 8164                    .border_color(status_colors.error.opacity(0.6))
 8165                    .pl_2()
 8166                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8167                    .cursor_default()
 8168                    .hoverable_tooltip(move |_window, cx| {
 8169                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8170                    })
 8171            })
 8172            .children(keybind)
 8173            .child(
 8174                Label::new(label)
 8175                    .size(LabelSize::Small)
 8176                    .when(!has_keybind, |el| {
 8177                        el.color(cx.theme().status().error.into()).strikethrough()
 8178                    }),
 8179            )
 8180            .when(!has_keybind, |el| {
 8181                el.child(
 8182                    h_flex().ml_1().child(
 8183                        Icon::new(IconName::Info)
 8184                            .size(IconSize::Small)
 8185                            .color(cx.theme().status().error.into()),
 8186                    ),
 8187                )
 8188            })
 8189            .when_some(icon, |element, icon| {
 8190                element.child(
 8191                    div()
 8192                        .mt(px(1.5))
 8193                        .child(Icon::new(icon).size(IconSize::Small)),
 8194                )
 8195            });
 8196
 8197        Some(result)
 8198    }
 8199
 8200    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8201        let accent_color = cx.theme().colors().text_accent;
 8202        let editor_bg_color = cx.theme().colors().editor_background;
 8203        editor_bg_color.blend(accent_color.opacity(0.1))
 8204    }
 8205
 8206    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8207        let accent_color = cx.theme().colors().text_accent;
 8208        let editor_bg_color = cx.theme().colors().editor_background;
 8209        editor_bg_color.blend(accent_color.opacity(0.6))
 8210    }
 8211
 8212    fn render_edit_prediction_cursor_popover(
 8213        &self,
 8214        min_width: Pixels,
 8215        max_width: Pixels,
 8216        cursor_point: Point,
 8217        style: &EditorStyle,
 8218        accept_keystroke: Option<&gpui::Keystroke>,
 8219        _window: &Window,
 8220        cx: &mut Context<Editor>,
 8221    ) -> Option<AnyElement> {
 8222        let provider = self.edit_prediction_provider.as_ref()?;
 8223
 8224        if provider.provider.needs_terms_acceptance(cx) {
 8225            return Some(
 8226                h_flex()
 8227                    .min_w(min_width)
 8228                    .flex_1()
 8229                    .px_2()
 8230                    .py_1()
 8231                    .gap_3()
 8232                    .elevation_2(cx)
 8233                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8234                    .id("accept-terms")
 8235                    .cursor_pointer()
 8236                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8237                    .on_click(cx.listener(|this, _event, window, cx| {
 8238                        cx.stop_propagation();
 8239                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8240                        window.dispatch_action(
 8241                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8242                            cx,
 8243                        );
 8244                    }))
 8245                    .child(
 8246                        h_flex()
 8247                            .flex_1()
 8248                            .gap_2()
 8249                            .child(Icon::new(IconName::ZedPredict))
 8250                            .child(Label::new("Accept Terms of Service"))
 8251                            .child(div().w_full())
 8252                            .child(
 8253                                Icon::new(IconName::ArrowUpRight)
 8254                                    .color(Color::Muted)
 8255                                    .size(IconSize::Small),
 8256                            )
 8257                            .into_any_element(),
 8258                    )
 8259                    .into_any(),
 8260            );
 8261        }
 8262
 8263        let is_refreshing = provider.provider.is_refreshing(cx);
 8264
 8265        fn pending_completion_container() -> Div {
 8266            h_flex()
 8267                .h_full()
 8268                .flex_1()
 8269                .gap_2()
 8270                .child(Icon::new(IconName::ZedPredict))
 8271        }
 8272
 8273        let completion = match &self.active_inline_completion {
 8274            Some(prediction) => {
 8275                if !self.has_visible_completions_menu() {
 8276                    const RADIUS: Pixels = px(6.);
 8277                    const BORDER_WIDTH: Pixels = px(1.);
 8278
 8279                    return Some(
 8280                        h_flex()
 8281                            .elevation_2(cx)
 8282                            .border(BORDER_WIDTH)
 8283                            .border_color(cx.theme().colors().border)
 8284                            .when(accept_keystroke.is_none(), |el| {
 8285                                el.border_color(cx.theme().status().error)
 8286                            })
 8287                            .rounded(RADIUS)
 8288                            .rounded_tl(px(0.))
 8289                            .overflow_hidden()
 8290                            .child(div().px_1p5().child(match &prediction.completion {
 8291                                InlineCompletion::Move { target, snapshot } => {
 8292                                    use text::ToPoint as _;
 8293                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8294                                    {
 8295                                        Icon::new(IconName::ZedPredictDown)
 8296                                    } else {
 8297                                        Icon::new(IconName::ZedPredictUp)
 8298                                    }
 8299                                }
 8300                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8301                            }))
 8302                            .child(
 8303                                h_flex()
 8304                                    .gap_1()
 8305                                    .py_1()
 8306                                    .px_2()
 8307                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8308                                    .border_l_1()
 8309                                    .border_color(cx.theme().colors().border)
 8310                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8311                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8312                                        el.child(
 8313                                            Label::new("Hold")
 8314                                                .size(LabelSize::Small)
 8315                                                .when(accept_keystroke.is_none(), |el| {
 8316                                                    el.strikethrough()
 8317                                                })
 8318                                                .line_height_style(LineHeightStyle::UiLabel),
 8319                                        )
 8320                                    })
 8321                                    .id("edit_prediction_cursor_popover_keybind")
 8322                                    .when(accept_keystroke.is_none(), |el| {
 8323                                        let status_colors = cx.theme().status();
 8324
 8325                                        el.bg(status_colors.error_background)
 8326                                            .border_color(status_colors.error.opacity(0.6))
 8327                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8328                                            .cursor_default()
 8329                                            .hoverable_tooltip(move |_window, cx| {
 8330                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8331                                                    .into()
 8332                                            })
 8333                                    })
 8334                                    .when_some(
 8335                                        accept_keystroke.as_ref(),
 8336                                        |el, accept_keystroke| {
 8337                                            el.child(h_flex().children(ui::render_modifiers(
 8338                                                &accept_keystroke.modifiers,
 8339                                                PlatformStyle::platform(),
 8340                                                Some(Color::Default),
 8341                                                Some(IconSize::XSmall.rems().into()),
 8342                                                false,
 8343                                            )))
 8344                                        },
 8345                                    ),
 8346                            )
 8347                            .into_any(),
 8348                    );
 8349                }
 8350
 8351                self.render_edit_prediction_cursor_popover_preview(
 8352                    prediction,
 8353                    cursor_point,
 8354                    style,
 8355                    cx,
 8356                )?
 8357            }
 8358
 8359            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8360                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8361                    stale_completion,
 8362                    cursor_point,
 8363                    style,
 8364                    cx,
 8365                )?,
 8366
 8367                None => {
 8368                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8369                }
 8370            },
 8371
 8372            None => pending_completion_container().child(Label::new("No Prediction")),
 8373        };
 8374
 8375        let completion = if is_refreshing {
 8376            completion
 8377                .with_animation(
 8378                    "loading-completion",
 8379                    Animation::new(Duration::from_secs(2))
 8380                        .repeat()
 8381                        .with_easing(pulsating_between(0.4, 0.8)),
 8382                    |label, delta| label.opacity(delta),
 8383                )
 8384                .into_any_element()
 8385        } else {
 8386            completion.into_any_element()
 8387        };
 8388
 8389        let has_completion = self.active_inline_completion.is_some();
 8390
 8391        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8392        Some(
 8393            h_flex()
 8394                .min_w(min_width)
 8395                .max_w(max_width)
 8396                .flex_1()
 8397                .elevation_2(cx)
 8398                .border_color(cx.theme().colors().border)
 8399                .child(
 8400                    div()
 8401                        .flex_1()
 8402                        .py_1()
 8403                        .px_2()
 8404                        .overflow_hidden()
 8405                        .child(completion),
 8406                )
 8407                .when_some(accept_keystroke, |el, accept_keystroke| {
 8408                    if !accept_keystroke.modifiers.modified() {
 8409                        return el;
 8410                    }
 8411
 8412                    el.child(
 8413                        h_flex()
 8414                            .h_full()
 8415                            .border_l_1()
 8416                            .rounded_r_lg()
 8417                            .border_color(cx.theme().colors().border)
 8418                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8419                            .gap_1()
 8420                            .py_1()
 8421                            .px_2()
 8422                            .child(
 8423                                h_flex()
 8424                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8425                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8426                                    .child(h_flex().children(ui::render_modifiers(
 8427                                        &accept_keystroke.modifiers,
 8428                                        PlatformStyle::platform(),
 8429                                        Some(if !has_completion {
 8430                                            Color::Muted
 8431                                        } else {
 8432                                            Color::Default
 8433                                        }),
 8434                                        None,
 8435                                        false,
 8436                                    ))),
 8437                            )
 8438                            .child(Label::new("Preview").into_any_element())
 8439                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8440                    )
 8441                })
 8442                .into_any(),
 8443        )
 8444    }
 8445
 8446    fn render_edit_prediction_cursor_popover_preview(
 8447        &self,
 8448        completion: &InlineCompletionState,
 8449        cursor_point: Point,
 8450        style: &EditorStyle,
 8451        cx: &mut Context<Editor>,
 8452    ) -> Option<Div> {
 8453        use text::ToPoint as _;
 8454
 8455        fn render_relative_row_jump(
 8456            prefix: impl Into<String>,
 8457            current_row: u32,
 8458            target_row: u32,
 8459        ) -> Div {
 8460            let (row_diff, arrow) = if target_row < current_row {
 8461                (current_row - target_row, IconName::ArrowUp)
 8462            } else {
 8463                (target_row - current_row, IconName::ArrowDown)
 8464            };
 8465
 8466            h_flex()
 8467                .child(
 8468                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8469                        .color(Color::Muted)
 8470                        .size(LabelSize::Small),
 8471                )
 8472                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8473        }
 8474
 8475        match &completion.completion {
 8476            InlineCompletion::Move {
 8477                target, snapshot, ..
 8478            } => Some(
 8479                h_flex()
 8480                    .px_2()
 8481                    .gap_2()
 8482                    .flex_1()
 8483                    .child(
 8484                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8485                            Icon::new(IconName::ZedPredictDown)
 8486                        } else {
 8487                            Icon::new(IconName::ZedPredictUp)
 8488                        },
 8489                    )
 8490                    .child(Label::new("Jump to Edit")),
 8491            ),
 8492
 8493            InlineCompletion::Edit {
 8494                edits,
 8495                edit_preview,
 8496                snapshot,
 8497                display_mode: _,
 8498            } => {
 8499                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8500
 8501                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8502                    &snapshot,
 8503                    &edits,
 8504                    edit_preview.as_ref()?,
 8505                    true,
 8506                    cx,
 8507                )
 8508                .first_line_preview();
 8509
 8510                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8511                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8512
 8513                let preview = h_flex()
 8514                    .gap_1()
 8515                    .min_w_16()
 8516                    .child(styled_text)
 8517                    .when(has_more_lines, |parent| parent.child(""));
 8518
 8519                let left = if first_edit_row != cursor_point.row {
 8520                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8521                        .into_any_element()
 8522                } else {
 8523                    Icon::new(IconName::ZedPredict).into_any_element()
 8524                };
 8525
 8526                Some(
 8527                    h_flex()
 8528                        .h_full()
 8529                        .flex_1()
 8530                        .gap_2()
 8531                        .pr_1()
 8532                        .overflow_x_hidden()
 8533                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8534                        .child(left)
 8535                        .child(preview),
 8536                )
 8537            }
 8538        }
 8539    }
 8540
 8541    fn render_context_menu(
 8542        &self,
 8543        style: &EditorStyle,
 8544        max_height_in_lines: u32,
 8545        window: &mut Window,
 8546        cx: &mut Context<Editor>,
 8547    ) -> Option<AnyElement> {
 8548        let menu = self.context_menu.borrow();
 8549        let menu = menu.as_ref()?;
 8550        if !menu.visible() {
 8551            return None;
 8552        };
 8553        Some(menu.render(style, max_height_in_lines, window, cx))
 8554    }
 8555
 8556    fn render_context_menu_aside(
 8557        &mut self,
 8558        max_size: Size<Pixels>,
 8559        window: &mut Window,
 8560        cx: &mut Context<Editor>,
 8561    ) -> Option<AnyElement> {
 8562        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8563            if menu.visible() {
 8564                menu.render_aside(self, max_size, window, cx)
 8565            } else {
 8566                None
 8567            }
 8568        })
 8569    }
 8570
 8571    fn hide_context_menu(
 8572        &mut self,
 8573        window: &mut Window,
 8574        cx: &mut Context<Self>,
 8575    ) -> Option<CodeContextMenu> {
 8576        cx.notify();
 8577        self.completion_tasks.clear();
 8578        let context_menu = self.context_menu.borrow_mut().take();
 8579        self.stale_inline_completion_in_menu.take();
 8580        self.update_visible_inline_completion(window, cx);
 8581        context_menu
 8582    }
 8583
 8584    fn show_snippet_choices(
 8585        &mut self,
 8586        choices: &Vec<String>,
 8587        selection: Range<Anchor>,
 8588        cx: &mut Context<Self>,
 8589    ) {
 8590        if selection.start.buffer_id.is_none() {
 8591            return;
 8592        }
 8593        let buffer_id = selection.start.buffer_id.unwrap();
 8594        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8595        let id = post_inc(&mut self.next_completion_id);
 8596        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8597
 8598        if let Some(buffer) = buffer {
 8599            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8600                CompletionsMenu::new_snippet_choices(
 8601                    id,
 8602                    true,
 8603                    choices,
 8604                    selection,
 8605                    buffer,
 8606                    snippet_sort_order,
 8607                ),
 8608            ));
 8609        }
 8610    }
 8611
 8612    pub fn insert_snippet(
 8613        &mut self,
 8614        insertion_ranges: &[Range<usize>],
 8615        snippet: Snippet,
 8616        window: &mut Window,
 8617        cx: &mut Context<Self>,
 8618    ) -> Result<()> {
 8619        struct Tabstop<T> {
 8620            is_end_tabstop: bool,
 8621            ranges: Vec<Range<T>>,
 8622            choices: Option<Vec<String>>,
 8623        }
 8624
 8625        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8626            let snippet_text: Arc<str> = snippet.text.clone().into();
 8627            let edits = insertion_ranges
 8628                .iter()
 8629                .cloned()
 8630                .map(|range| (range, snippet_text.clone()));
 8631            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8632
 8633            let snapshot = &*buffer.read(cx);
 8634            let snippet = &snippet;
 8635            snippet
 8636                .tabstops
 8637                .iter()
 8638                .map(|tabstop| {
 8639                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8640                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8641                    });
 8642                    let mut tabstop_ranges = tabstop
 8643                        .ranges
 8644                        .iter()
 8645                        .flat_map(|tabstop_range| {
 8646                            let mut delta = 0_isize;
 8647                            insertion_ranges.iter().map(move |insertion_range| {
 8648                                let insertion_start = insertion_range.start as isize + delta;
 8649                                delta +=
 8650                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8651
 8652                                let start = ((insertion_start + tabstop_range.start) as usize)
 8653                                    .min(snapshot.len());
 8654                                let end = ((insertion_start + tabstop_range.end) as usize)
 8655                                    .min(snapshot.len());
 8656                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8657                            })
 8658                        })
 8659                        .collect::<Vec<_>>();
 8660                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8661
 8662                    Tabstop {
 8663                        is_end_tabstop,
 8664                        ranges: tabstop_ranges,
 8665                        choices: tabstop.choices.clone(),
 8666                    }
 8667                })
 8668                .collect::<Vec<_>>()
 8669        });
 8670        if let Some(tabstop) = tabstops.first() {
 8671            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8672                s.select_ranges(tabstop.ranges.iter().cloned());
 8673            });
 8674
 8675            if let Some(choices) = &tabstop.choices {
 8676                if let Some(selection) = tabstop.ranges.first() {
 8677                    self.show_snippet_choices(choices, selection.clone(), cx)
 8678                }
 8679            }
 8680
 8681            // If we're already at the last tabstop and it's at the end of the snippet,
 8682            // we're done, we don't need to keep the state around.
 8683            if !tabstop.is_end_tabstop {
 8684                let choices = tabstops
 8685                    .iter()
 8686                    .map(|tabstop| tabstop.choices.clone())
 8687                    .collect();
 8688
 8689                let ranges = tabstops
 8690                    .into_iter()
 8691                    .map(|tabstop| tabstop.ranges)
 8692                    .collect::<Vec<_>>();
 8693
 8694                self.snippet_stack.push(SnippetState {
 8695                    active_index: 0,
 8696                    ranges,
 8697                    choices,
 8698                });
 8699            }
 8700
 8701            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8702            if self.autoclose_regions.is_empty() {
 8703                let snapshot = self.buffer.read(cx).snapshot(cx);
 8704                for selection in &mut self.selections.all::<Point>(cx) {
 8705                    let selection_head = selection.head();
 8706                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8707                        continue;
 8708                    };
 8709
 8710                    let mut bracket_pair = None;
 8711                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8712                    let prev_chars = snapshot
 8713                        .reversed_chars_at(selection_head)
 8714                        .collect::<String>();
 8715                    for (pair, enabled) in scope.brackets() {
 8716                        if enabled
 8717                            && pair.close
 8718                            && prev_chars.starts_with(pair.start.as_str())
 8719                            && next_chars.starts_with(pair.end.as_str())
 8720                        {
 8721                            bracket_pair = Some(pair.clone());
 8722                            break;
 8723                        }
 8724                    }
 8725                    if let Some(pair) = bracket_pair {
 8726                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8727                        let autoclose_enabled =
 8728                            self.use_autoclose && snapshot_settings.use_autoclose;
 8729                        if autoclose_enabled {
 8730                            let start = snapshot.anchor_after(selection_head);
 8731                            let end = snapshot.anchor_after(selection_head);
 8732                            self.autoclose_regions.push(AutocloseRegion {
 8733                                selection_id: selection.id,
 8734                                range: start..end,
 8735                                pair,
 8736                            });
 8737                        }
 8738                    }
 8739                }
 8740            }
 8741        }
 8742        Ok(())
 8743    }
 8744
 8745    pub fn move_to_next_snippet_tabstop(
 8746        &mut self,
 8747        window: &mut Window,
 8748        cx: &mut Context<Self>,
 8749    ) -> bool {
 8750        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8751    }
 8752
 8753    pub fn move_to_prev_snippet_tabstop(
 8754        &mut self,
 8755        window: &mut Window,
 8756        cx: &mut Context<Self>,
 8757    ) -> bool {
 8758        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8759    }
 8760
 8761    pub fn move_to_snippet_tabstop(
 8762        &mut self,
 8763        bias: Bias,
 8764        window: &mut Window,
 8765        cx: &mut Context<Self>,
 8766    ) -> bool {
 8767        if let Some(mut snippet) = self.snippet_stack.pop() {
 8768            match bias {
 8769                Bias::Left => {
 8770                    if snippet.active_index > 0 {
 8771                        snippet.active_index -= 1;
 8772                    } else {
 8773                        self.snippet_stack.push(snippet);
 8774                        return false;
 8775                    }
 8776                }
 8777                Bias::Right => {
 8778                    if snippet.active_index + 1 < snippet.ranges.len() {
 8779                        snippet.active_index += 1;
 8780                    } else {
 8781                        self.snippet_stack.push(snippet);
 8782                        return false;
 8783                    }
 8784                }
 8785            }
 8786            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8787                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8788                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8789                });
 8790
 8791                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8792                    if let Some(selection) = current_ranges.first() {
 8793                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8794                    }
 8795                }
 8796
 8797                // If snippet state is not at the last tabstop, push it back on the stack
 8798                if snippet.active_index + 1 < snippet.ranges.len() {
 8799                    self.snippet_stack.push(snippet);
 8800                }
 8801                return true;
 8802            }
 8803        }
 8804
 8805        false
 8806    }
 8807
 8808    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8809        self.transact(window, cx, |this, window, cx| {
 8810            this.select_all(&SelectAll, window, cx);
 8811            this.insert("", window, cx);
 8812        });
 8813    }
 8814
 8815    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8816        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8817        self.transact(window, cx, |this, window, cx| {
 8818            this.select_autoclose_pair(window, cx);
 8819            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8820            if !this.linked_edit_ranges.is_empty() {
 8821                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8822                let snapshot = this.buffer.read(cx).snapshot(cx);
 8823
 8824                for selection in selections.iter() {
 8825                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8826                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8827                    if selection_start.buffer_id != selection_end.buffer_id {
 8828                        continue;
 8829                    }
 8830                    if let Some(ranges) =
 8831                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8832                    {
 8833                        for (buffer, entries) in ranges {
 8834                            linked_ranges.entry(buffer).or_default().extend(entries);
 8835                        }
 8836                    }
 8837                }
 8838            }
 8839
 8840            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8841            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8842            for selection in &mut selections {
 8843                if selection.is_empty() {
 8844                    let old_head = selection.head();
 8845                    let mut new_head =
 8846                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8847                            .to_point(&display_map);
 8848                    if let Some((buffer, line_buffer_range)) = display_map
 8849                        .buffer_snapshot
 8850                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8851                    {
 8852                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8853                        let indent_len = match indent_size.kind {
 8854                            IndentKind::Space => {
 8855                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8856                            }
 8857                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8858                        };
 8859                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8860                            let indent_len = indent_len.get();
 8861                            new_head = cmp::min(
 8862                                new_head,
 8863                                MultiBufferPoint::new(
 8864                                    old_head.row,
 8865                                    ((old_head.column - 1) / indent_len) * indent_len,
 8866                                ),
 8867                            );
 8868                        }
 8869                    }
 8870
 8871                    selection.set_head(new_head, SelectionGoal::None);
 8872                }
 8873            }
 8874
 8875            this.signature_help_state.set_backspace_pressed(true);
 8876            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8877                s.select(selections)
 8878            });
 8879            this.insert("", window, cx);
 8880            let empty_str: Arc<str> = Arc::from("");
 8881            for (buffer, edits) in linked_ranges {
 8882                let snapshot = buffer.read(cx).snapshot();
 8883                use text::ToPoint as TP;
 8884
 8885                let edits = edits
 8886                    .into_iter()
 8887                    .map(|range| {
 8888                        let end_point = TP::to_point(&range.end, &snapshot);
 8889                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8890
 8891                        if end_point == start_point {
 8892                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8893                                .saturating_sub(1);
 8894                            start_point =
 8895                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8896                        };
 8897
 8898                        (start_point..end_point, empty_str.clone())
 8899                    })
 8900                    .sorted_by_key(|(range, _)| range.start)
 8901                    .collect::<Vec<_>>();
 8902                buffer.update(cx, |this, cx| {
 8903                    this.edit(edits, None, cx);
 8904                })
 8905            }
 8906            this.refresh_inline_completion(true, false, window, cx);
 8907            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8908        });
 8909    }
 8910
 8911    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8912        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8913        self.transact(window, cx, |this, window, cx| {
 8914            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8915                s.move_with(|map, selection| {
 8916                    if selection.is_empty() {
 8917                        let cursor = movement::right(map, selection.head());
 8918                        selection.end = cursor;
 8919                        selection.reversed = true;
 8920                        selection.goal = SelectionGoal::None;
 8921                    }
 8922                })
 8923            });
 8924            this.insert("", window, cx);
 8925            this.refresh_inline_completion(true, false, window, cx);
 8926        });
 8927    }
 8928
 8929    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8930        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8931        if self.move_to_prev_snippet_tabstop(window, cx) {
 8932            return;
 8933        }
 8934        self.outdent(&Outdent, window, cx);
 8935    }
 8936
 8937    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8938        if self.move_to_next_snippet_tabstop(window, cx) {
 8939            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8940            return;
 8941        }
 8942        if self.read_only(cx) {
 8943            return;
 8944        }
 8945        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8946        let mut selections = self.selections.all_adjusted(cx);
 8947        let buffer = self.buffer.read(cx);
 8948        let snapshot = buffer.snapshot(cx);
 8949        let rows_iter = selections.iter().map(|s| s.head().row);
 8950        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8951
 8952        let has_some_cursor_in_whitespace = selections
 8953            .iter()
 8954            .filter(|selection| selection.is_empty())
 8955            .any(|selection| {
 8956                let cursor = selection.head();
 8957                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8958                cursor.column < current_indent.len
 8959            });
 8960
 8961        let mut edits = Vec::new();
 8962        let mut prev_edited_row = 0;
 8963        let mut row_delta = 0;
 8964        for selection in &mut selections {
 8965            if selection.start.row != prev_edited_row {
 8966                row_delta = 0;
 8967            }
 8968            prev_edited_row = selection.end.row;
 8969
 8970            // If the selection is non-empty, then increase the indentation of the selected lines.
 8971            if !selection.is_empty() {
 8972                row_delta =
 8973                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8974                continue;
 8975            }
 8976
 8977            let cursor = selection.head();
 8978            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8979            if let Some(suggested_indent) =
 8980                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8981            {
 8982                // Don't do anything if already at suggested indent
 8983                // and there is any other cursor which is not
 8984                if has_some_cursor_in_whitespace
 8985                    && cursor.column == current_indent.len
 8986                    && current_indent.len == suggested_indent.len
 8987                {
 8988                    continue;
 8989                }
 8990
 8991                // Adjust line and move cursor to suggested indent
 8992                // if cursor is not at suggested indent
 8993                if cursor.column < suggested_indent.len
 8994                    && cursor.column <= current_indent.len
 8995                    && current_indent.len <= suggested_indent.len
 8996                {
 8997                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8998                    selection.end = selection.start;
 8999                    if row_delta == 0 {
 9000                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9001                            cursor.row,
 9002                            current_indent,
 9003                            suggested_indent,
 9004                        ));
 9005                        row_delta = suggested_indent.len - current_indent.len;
 9006                    }
 9007                    continue;
 9008                }
 9009
 9010                // If current indent is more than suggested indent
 9011                // only move cursor to current indent and skip indent
 9012                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9013                    selection.start = Point::new(cursor.row, current_indent.len);
 9014                    selection.end = selection.start;
 9015                    continue;
 9016                }
 9017            }
 9018
 9019            // Otherwise, insert a hard or soft tab.
 9020            let settings = buffer.language_settings_at(cursor, cx);
 9021            let tab_size = if settings.hard_tabs {
 9022                IndentSize::tab()
 9023            } else {
 9024                let tab_size = settings.tab_size.get();
 9025                let indent_remainder = snapshot
 9026                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9027                    .flat_map(str::chars)
 9028                    .fold(row_delta % tab_size, |counter: u32, c| {
 9029                        if c == '\t' {
 9030                            0
 9031                        } else {
 9032                            (counter + 1) % tab_size
 9033                        }
 9034                    });
 9035
 9036                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9037                IndentSize::spaces(chars_to_next_tab_stop)
 9038            };
 9039            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9040            selection.end = selection.start;
 9041            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9042            row_delta += tab_size.len;
 9043        }
 9044
 9045        self.transact(window, cx, |this, window, cx| {
 9046            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9047            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9048                s.select(selections)
 9049            });
 9050            this.refresh_inline_completion(true, false, window, cx);
 9051        });
 9052    }
 9053
 9054    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9055        if self.read_only(cx) {
 9056            return;
 9057        }
 9058        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9059        let mut selections = self.selections.all::<Point>(cx);
 9060        let mut prev_edited_row = 0;
 9061        let mut row_delta = 0;
 9062        let mut edits = Vec::new();
 9063        let buffer = self.buffer.read(cx);
 9064        let snapshot = buffer.snapshot(cx);
 9065        for selection in &mut selections {
 9066            if selection.start.row != prev_edited_row {
 9067                row_delta = 0;
 9068            }
 9069            prev_edited_row = selection.end.row;
 9070
 9071            row_delta =
 9072                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9073        }
 9074
 9075        self.transact(window, cx, |this, window, cx| {
 9076            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9077            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9078                s.select(selections)
 9079            });
 9080        });
 9081    }
 9082
 9083    fn indent_selection(
 9084        buffer: &MultiBuffer,
 9085        snapshot: &MultiBufferSnapshot,
 9086        selection: &mut Selection<Point>,
 9087        edits: &mut Vec<(Range<Point>, String)>,
 9088        delta_for_start_row: u32,
 9089        cx: &App,
 9090    ) -> u32 {
 9091        let settings = buffer.language_settings_at(selection.start, cx);
 9092        let tab_size = settings.tab_size.get();
 9093        let indent_kind = if settings.hard_tabs {
 9094            IndentKind::Tab
 9095        } else {
 9096            IndentKind::Space
 9097        };
 9098        let mut start_row = selection.start.row;
 9099        let mut end_row = selection.end.row + 1;
 9100
 9101        // If a selection ends at the beginning of a line, don't indent
 9102        // that last line.
 9103        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9104            end_row -= 1;
 9105        }
 9106
 9107        // Avoid re-indenting a row that has already been indented by a
 9108        // previous selection, but still update this selection's column
 9109        // to reflect that indentation.
 9110        if delta_for_start_row > 0 {
 9111            start_row += 1;
 9112            selection.start.column += delta_for_start_row;
 9113            if selection.end.row == selection.start.row {
 9114                selection.end.column += delta_for_start_row;
 9115            }
 9116        }
 9117
 9118        let mut delta_for_end_row = 0;
 9119        let has_multiple_rows = start_row + 1 != end_row;
 9120        for row in start_row..end_row {
 9121            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9122            let indent_delta = match (current_indent.kind, indent_kind) {
 9123                (IndentKind::Space, IndentKind::Space) => {
 9124                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9125                    IndentSize::spaces(columns_to_next_tab_stop)
 9126                }
 9127                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9128                (_, IndentKind::Tab) => IndentSize::tab(),
 9129            };
 9130
 9131            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9132                0
 9133            } else {
 9134                selection.start.column
 9135            };
 9136            let row_start = Point::new(row, start);
 9137            edits.push((
 9138                row_start..row_start,
 9139                indent_delta.chars().collect::<String>(),
 9140            ));
 9141
 9142            // Update this selection's endpoints to reflect the indentation.
 9143            if row == selection.start.row {
 9144                selection.start.column += indent_delta.len;
 9145            }
 9146            if row == selection.end.row {
 9147                selection.end.column += indent_delta.len;
 9148                delta_for_end_row = indent_delta.len;
 9149            }
 9150        }
 9151
 9152        if selection.start.row == selection.end.row {
 9153            delta_for_start_row + delta_for_end_row
 9154        } else {
 9155            delta_for_end_row
 9156        }
 9157    }
 9158
 9159    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9160        if self.read_only(cx) {
 9161            return;
 9162        }
 9163        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9164        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9165        let selections = self.selections.all::<Point>(cx);
 9166        let mut deletion_ranges = Vec::new();
 9167        let mut last_outdent = None;
 9168        {
 9169            let buffer = self.buffer.read(cx);
 9170            let snapshot = buffer.snapshot(cx);
 9171            for selection in &selections {
 9172                let settings = buffer.language_settings_at(selection.start, cx);
 9173                let tab_size = settings.tab_size.get();
 9174                let mut rows = selection.spanned_rows(false, &display_map);
 9175
 9176                // Avoid re-outdenting a row that has already been outdented by a
 9177                // previous selection.
 9178                if let Some(last_row) = last_outdent {
 9179                    if last_row == rows.start {
 9180                        rows.start = rows.start.next_row();
 9181                    }
 9182                }
 9183                let has_multiple_rows = rows.len() > 1;
 9184                for row in rows.iter_rows() {
 9185                    let indent_size = snapshot.indent_size_for_line(row);
 9186                    if indent_size.len > 0 {
 9187                        let deletion_len = match indent_size.kind {
 9188                            IndentKind::Space => {
 9189                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9190                                if columns_to_prev_tab_stop == 0 {
 9191                                    tab_size
 9192                                } else {
 9193                                    columns_to_prev_tab_stop
 9194                                }
 9195                            }
 9196                            IndentKind::Tab => 1,
 9197                        };
 9198                        let start = if has_multiple_rows
 9199                            || deletion_len > selection.start.column
 9200                            || indent_size.len < selection.start.column
 9201                        {
 9202                            0
 9203                        } else {
 9204                            selection.start.column - deletion_len
 9205                        };
 9206                        deletion_ranges.push(
 9207                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9208                        );
 9209                        last_outdent = Some(row);
 9210                    }
 9211                }
 9212            }
 9213        }
 9214
 9215        self.transact(window, cx, |this, window, cx| {
 9216            this.buffer.update(cx, |buffer, cx| {
 9217                let empty_str: Arc<str> = Arc::default();
 9218                buffer.edit(
 9219                    deletion_ranges
 9220                        .into_iter()
 9221                        .map(|range| (range, empty_str.clone())),
 9222                    None,
 9223                    cx,
 9224                );
 9225            });
 9226            let selections = this.selections.all::<usize>(cx);
 9227            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9228                s.select(selections)
 9229            });
 9230        });
 9231    }
 9232
 9233    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9234        if self.read_only(cx) {
 9235            return;
 9236        }
 9237        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9238        let selections = self
 9239            .selections
 9240            .all::<usize>(cx)
 9241            .into_iter()
 9242            .map(|s| s.range());
 9243
 9244        self.transact(window, cx, |this, window, cx| {
 9245            this.buffer.update(cx, |buffer, cx| {
 9246                buffer.autoindent_ranges(selections, cx);
 9247            });
 9248            let selections = this.selections.all::<usize>(cx);
 9249            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9250                s.select(selections)
 9251            });
 9252        });
 9253    }
 9254
 9255    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9256        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9257        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9258        let selections = self.selections.all::<Point>(cx);
 9259
 9260        let mut new_cursors = Vec::new();
 9261        let mut edit_ranges = Vec::new();
 9262        let mut selections = selections.iter().peekable();
 9263        while let Some(selection) = selections.next() {
 9264            let mut rows = selection.spanned_rows(false, &display_map);
 9265            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9266
 9267            // Accumulate contiguous regions of rows that we want to delete.
 9268            while let Some(next_selection) = selections.peek() {
 9269                let next_rows = next_selection.spanned_rows(false, &display_map);
 9270                if next_rows.start <= rows.end {
 9271                    rows.end = next_rows.end;
 9272                    selections.next().unwrap();
 9273                } else {
 9274                    break;
 9275                }
 9276            }
 9277
 9278            let buffer = &display_map.buffer_snapshot;
 9279            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9280            let edit_end;
 9281            let cursor_buffer_row;
 9282            if buffer.max_point().row >= rows.end.0 {
 9283                // If there's a line after the range, delete the \n from the end of the row range
 9284                // and position the cursor on the next line.
 9285                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9286                cursor_buffer_row = rows.end;
 9287            } else {
 9288                // If there isn't a line after the range, delete the \n from the line before the
 9289                // start of the row range and position the cursor there.
 9290                edit_start = edit_start.saturating_sub(1);
 9291                edit_end = buffer.len();
 9292                cursor_buffer_row = rows.start.previous_row();
 9293            }
 9294
 9295            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9296            *cursor.column_mut() =
 9297                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9298
 9299            new_cursors.push((
 9300                selection.id,
 9301                buffer.anchor_after(cursor.to_point(&display_map)),
 9302            ));
 9303            edit_ranges.push(edit_start..edit_end);
 9304        }
 9305
 9306        self.transact(window, cx, |this, window, cx| {
 9307            let buffer = this.buffer.update(cx, |buffer, cx| {
 9308                let empty_str: Arc<str> = Arc::default();
 9309                buffer.edit(
 9310                    edit_ranges
 9311                        .into_iter()
 9312                        .map(|range| (range, empty_str.clone())),
 9313                    None,
 9314                    cx,
 9315                );
 9316                buffer.snapshot(cx)
 9317            });
 9318            let new_selections = new_cursors
 9319                .into_iter()
 9320                .map(|(id, cursor)| {
 9321                    let cursor = cursor.to_point(&buffer);
 9322                    Selection {
 9323                        id,
 9324                        start: cursor,
 9325                        end: cursor,
 9326                        reversed: false,
 9327                        goal: SelectionGoal::None,
 9328                    }
 9329                })
 9330                .collect();
 9331
 9332            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9333                s.select(new_selections);
 9334            });
 9335        });
 9336    }
 9337
 9338    pub fn join_lines_impl(
 9339        &mut self,
 9340        insert_whitespace: bool,
 9341        window: &mut Window,
 9342        cx: &mut Context<Self>,
 9343    ) {
 9344        if self.read_only(cx) {
 9345            return;
 9346        }
 9347        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9348        for selection in self.selections.all::<Point>(cx) {
 9349            let start = MultiBufferRow(selection.start.row);
 9350            // Treat single line selections as if they include the next line. Otherwise this action
 9351            // would do nothing for single line selections individual cursors.
 9352            let end = if selection.start.row == selection.end.row {
 9353                MultiBufferRow(selection.start.row + 1)
 9354            } else {
 9355                MultiBufferRow(selection.end.row)
 9356            };
 9357
 9358            if let Some(last_row_range) = row_ranges.last_mut() {
 9359                if start <= last_row_range.end {
 9360                    last_row_range.end = end;
 9361                    continue;
 9362                }
 9363            }
 9364            row_ranges.push(start..end);
 9365        }
 9366
 9367        let snapshot = self.buffer.read(cx).snapshot(cx);
 9368        let mut cursor_positions = Vec::new();
 9369        for row_range in &row_ranges {
 9370            let anchor = snapshot.anchor_before(Point::new(
 9371                row_range.end.previous_row().0,
 9372                snapshot.line_len(row_range.end.previous_row()),
 9373            ));
 9374            cursor_positions.push(anchor..anchor);
 9375        }
 9376
 9377        self.transact(window, cx, |this, window, cx| {
 9378            for row_range in row_ranges.into_iter().rev() {
 9379                for row in row_range.iter_rows().rev() {
 9380                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9381                    let next_line_row = row.next_row();
 9382                    let indent = snapshot.indent_size_for_line(next_line_row);
 9383                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9384
 9385                    let replace =
 9386                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9387                            " "
 9388                        } else {
 9389                            ""
 9390                        };
 9391
 9392                    this.buffer.update(cx, |buffer, cx| {
 9393                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9394                    });
 9395                }
 9396            }
 9397
 9398            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9399                s.select_anchor_ranges(cursor_positions)
 9400            });
 9401        });
 9402    }
 9403
 9404    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9405        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9406        self.join_lines_impl(true, window, cx);
 9407    }
 9408
 9409    pub fn sort_lines_case_sensitive(
 9410        &mut self,
 9411        _: &SortLinesCaseSensitive,
 9412        window: &mut Window,
 9413        cx: &mut Context<Self>,
 9414    ) {
 9415        self.manipulate_lines(window, cx, |lines| lines.sort())
 9416    }
 9417
 9418    pub fn sort_lines_case_insensitive(
 9419        &mut self,
 9420        _: &SortLinesCaseInsensitive,
 9421        window: &mut Window,
 9422        cx: &mut Context<Self>,
 9423    ) {
 9424        self.manipulate_lines(window, cx, |lines| {
 9425            lines.sort_by_key(|line| line.to_lowercase())
 9426        })
 9427    }
 9428
 9429    pub fn unique_lines_case_insensitive(
 9430        &mut self,
 9431        _: &UniqueLinesCaseInsensitive,
 9432        window: &mut Window,
 9433        cx: &mut Context<Self>,
 9434    ) {
 9435        self.manipulate_lines(window, cx, |lines| {
 9436            let mut seen = HashSet::default();
 9437            lines.retain(|line| seen.insert(line.to_lowercase()));
 9438        })
 9439    }
 9440
 9441    pub fn unique_lines_case_sensitive(
 9442        &mut self,
 9443        _: &UniqueLinesCaseSensitive,
 9444        window: &mut Window,
 9445        cx: &mut Context<Self>,
 9446    ) {
 9447        self.manipulate_lines(window, cx, |lines| {
 9448            let mut seen = HashSet::default();
 9449            lines.retain(|line| seen.insert(*line));
 9450        })
 9451    }
 9452
 9453    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9454        let Some(project) = self.project.clone() else {
 9455            return;
 9456        };
 9457        self.reload(project, window, cx)
 9458            .detach_and_notify_err(window, cx);
 9459    }
 9460
 9461    pub fn restore_file(
 9462        &mut self,
 9463        _: &::git::RestoreFile,
 9464        window: &mut Window,
 9465        cx: &mut Context<Self>,
 9466    ) {
 9467        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9468        let mut buffer_ids = HashSet::default();
 9469        let snapshot = self.buffer().read(cx).snapshot(cx);
 9470        for selection in self.selections.all::<usize>(cx) {
 9471            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9472        }
 9473
 9474        let buffer = self.buffer().read(cx);
 9475        let ranges = buffer_ids
 9476            .into_iter()
 9477            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9478            .collect::<Vec<_>>();
 9479
 9480        self.restore_hunks_in_ranges(ranges, window, cx);
 9481    }
 9482
 9483    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9484        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9485        let selections = self
 9486            .selections
 9487            .all(cx)
 9488            .into_iter()
 9489            .map(|s| s.range())
 9490            .collect();
 9491        self.restore_hunks_in_ranges(selections, window, cx);
 9492    }
 9493
 9494    pub fn restore_hunks_in_ranges(
 9495        &mut self,
 9496        ranges: Vec<Range<Point>>,
 9497        window: &mut Window,
 9498        cx: &mut Context<Editor>,
 9499    ) {
 9500        let mut revert_changes = HashMap::default();
 9501        let chunk_by = self
 9502            .snapshot(window, cx)
 9503            .hunks_for_ranges(ranges)
 9504            .into_iter()
 9505            .chunk_by(|hunk| hunk.buffer_id);
 9506        for (buffer_id, hunks) in &chunk_by {
 9507            let hunks = hunks.collect::<Vec<_>>();
 9508            for hunk in &hunks {
 9509                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9510            }
 9511            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9512        }
 9513        drop(chunk_by);
 9514        if !revert_changes.is_empty() {
 9515            self.transact(window, cx, |editor, window, cx| {
 9516                editor.restore(revert_changes, window, cx);
 9517            });
 9518        }
 9519    }
 9520
 9521    pub fn open_active_item_in_terminal(
 9522        &mut self,
 9523        _: &OpenInTerminal,
 9524        window: &mut Window,
 9525        cx: &mut Context<Self>,
 9526    ) {
 9527        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9528            let project_path = buffer.read(cx).project_path(cx)?;
 9529            let project = self.project.as_ref()?.read(cx);
 9530            let entry = project.entry_for_path(&project_path, cx)?;
 9531            let parent = match &entry.canonical_path {
 9532                Some(canonical_path) => canonical_path.to_path_buf(),
 9533                None => project.absolute_path(&project_path, cx)?,
 9534            }
 9535            .parent()?
 9536            .to_path_buf();
 9537            Some(parent)
 9538        }) {
 9539            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9540        }
 9541    }
 9542
 9543    fn set_breakpoint_context_menu(
 9544        &mut self,
 9545        display_row: DisplayRow,
 9546        position: Option<Anchor>,
 9547        clicked_point: gpui::Point<Pixels>,
 9548        window: &mut Window,
 9549        cx: &mut Context<Self>,
 9550    ) {
 9551        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9552            return;
 9553        }
 9554        let source = self
 9555            .buffer
 9556            .read(cx)
 9557            .snapshot(cx)
 9558            .anchor_before(Point::new(display_row.0, 0u32));
 9559
 9560        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9561
 9562        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9563            self,
 9564            source,
 9565            clicked_point,
 9566            context_menu,
 9567            window,
 9568            cx,
 9569        );
 9570    }
 9571
 9572    fn add_edit_breakpoint_block(
 9573        &mut self,
 9574        anchor: Anchor,
 9575        breakpoint: &Breakpoint,
 9576        edit_action: BreakpointPromptEditAction,
 9577        window: &mut Window,
 9578        cx: &mut Context<Self>,
 9579    ) {
 9580        let weak_editor = cx.weak_entity();
 9581        let bp_prompt = cx.new(|cx| {
 9582            BreakpointPromptEditor::new(
 9583                weak_editor,
 9584                anchor,
 9585                breakpoint.clone(),
 9586                edit_action,
 9587                window,
 9588                cx,
 9589            )
 9590        });
 9591
 9592        let height = bp_prompt.update(cx, |this, cx| {
 9593            this.prompt
 9594                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9595        });
 9596        let cloned_prompt = bp_prompt.clone();
 9597        let blocks = vec![BlockProperties {
 9598            style: BlockStyle::Sticky,
 9599            placement: BlockPlacement::Above(anchor),
 9600            height: Some(height),
 9601            render: Arc::new(move |cx| {
 9602                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9603                cloned_prompt.clone().into_any_element()
 9604            }),
 9605            priority: 0,
 9606            render_in_minimap: true,
 9607        }];
 9608
 9609        let focus_handle = bp_prompt.focus_handle(cx);
 9610        window.focus(&focus_handle);
 9611
 9612        let block_ids = self.insert_blocks(blocks, None, cx);
 9613        bp_prompt.update(cx, |prompt, _| {
 9614            prompt.add_block_ids(block_ids);
 9615        });
 9616    }
 9617
 9618    pub(crate) fn breakpoint_at_row(
 9619        &self,
 9620        row: u32,
 9621        window: &mut Window,
 9622        cx: &mut Context<Self>,
 9623    ) -> Option<(Anchor, Breakpoint)> {
 9624        let snapshot = self.snapshot(window, cx);
 9625        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9626
 9627        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9628    }
 9629
 9630    pub(crate) fn breakpoint_at_anchor(
 9631        &self,
 9632        breakpoint_position: Anchor,
 9633        snapshot: &EditorSnapshot,
 9634        cx: &mut Context<Self>,
 9635    ) -> Option<(Anchor, Breakpoint)> {
 9636        let project = self.project.clone()?;
 9637
 9638        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9639            snapshot
 9640                .buffer_snapshot
 9641                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9642        })?;
 9643
 9644        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9645        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9646        let buffer_snapshot = buffer.read(cx).snapshot();
 9647
 9648        let row = buffer_snapshot
 9649            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9650            .row;
 9651
 9652        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9653        let anchor_end = snapshot
 9654            .buffer_snapshot
 9655            .anchor_after(Point::new(row, line_len));
 9656
 9657        let bp = self
 9658            .breakpoint_store
 9659            .as_ref()?
 9660            .read_with(cx, |breakpoint_store, cx| {
 9661                breakpoint_store
 9662                    .breakpoints(
 9663                        &buffer,
 9664                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9665                        &buffer_snapshot,
 9666                        cx,
 9667                    )
 9668                    .next()
 9669                    .and_then(|(bp, _)| {
 9670                        let breakpoint_row = buffer_snapshot
 9671                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9672                            .row;
 9673
 9674                        if breakpoint_row == row {
 9675                            snapshot
 9676                                .buffer_snapshot
 9677                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9678                                .map(|position| (position, bp.bp.clone()))
 9679                        } else {
 9680                            None
 9681                        }
 9682                    })
 9683            });
 9684        bp
 9685    }
 9686
 9687    pub fn edit_log_breakpoint(
 9688        &mut self,
 9689        _: &EditLogBreakpoint,
 9690        window: &mut Window,
 9691        cx: &mut Context<Self>,
 9692    ) {
 9693        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9694            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9695                message: None,
 9696                state: BreakpointState::Enabled,
 9697                condition: None,
 9698                hit_condition: None,
 9699            });
 9700
 9701            self.add_edit_breakpoint_block(
 9702                anchor,
 9703                &breakpoint,
 9704                BreakpointPromptEditAction::Log,
 9705                window,
 9706                cx,
 9707            );
 9708        }
 9709    }
 9710
 9711    fn breakpoints_at_cursors(
 9712        &self,
 9713        window: &mut Window,
 9714        cx: &mut Context<Self>,
 9715    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9716        let snapshot = self.snapshot(window, cx);
 9717        let cursors = self
 9718            .selections
 9719            .disjoint_anchors()
 9720            .into_iter()
 9721            .map(|selection| {
 9722                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9723
 9724                let breakpoint_position = self
 9725                    .breakpoint_at_row(cursor_position.row, window, cx)
 9726                    .map(|bp| bp.0)
 9727                    .unwrap_or_else(|| {
 9728                        snapshot
 9729                            .display_snapshot
 9730                            .buffer_snapshot
 9731                            .anchor_after(Point::new(cursor_position.row, 0))
 9732                    });
 9733
 9734                let breakpoint = self
 9735                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9736                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9737
 9738                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9739            })
 9740            // 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.
 9741            .collect::<HashMap<Anchor, _>>();
 9742
 9743        cursors.into_iter().collect()
 9744    }
 9745
 9746    pub fn enable_breakpoint(
 9747        &mut self,
 9748        _: &crate::actions::EnableBreakpoint,
 9749        window: &mut Window,
 9750        cx: &mut Context<Self>,
 9751    ) {
 9752        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9753            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9754                continue;
 9755            };
 9756            self.edit_breakpoint_at_anchor(
 9757                anchor,
 9758                breakpoint,
 9759                BreakpointEditAction::InvertState,
 9760                cx,
 9761            );
 9762        }
 9763    }
 9764
 9765    pub fn disable_breakpoint(
 9766        &mut self,
 9767        _: &crate::actions::DisableBreakpoint,
 9768        window: &mut Window,
 9769        cx: &mut Context<Self>,
 9770    ) {
 9771        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9772            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9773                continue;
 9774            };
 9775            self.edit_breakpoint_at_anchor(
 9776                anchor,
 9777                breakpoint,
 9778                BreakpointEditAction::InvertState,
 9779                cx,
 9780            );
 9781        }
 9782    }
 9783
 9784    pub fn toggle_breakpoint(
 9785        &mut self,
 9786        _: &crate::actions::ToggleBreakpoint,
 9787        window: &mut Window,
 9788        cx: &mut Context<Self>,
 9789    ) {
 9790        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9791            if let Some(breakpoint) = breakpoint {
 9792                self.edit_breakpoint_at_anchor(
 9793                    anchor,
 9794                    breakpoint,
 9795                    BreakpointEditAction::Toggle,
 9796                    cx,
 9797                );
 9798            } else {
 9799                self.edit_breakpoint_at_anchor(
 9800                    anchor,
 9801                    Breakpoint::new_standard(),
 9802                    BreakpointEditAction::Toggle,
 9803                    cx,
 9804                );
 9805            }
 9806        }
 9807    }
 9808
 9809    pub fn edit_breakpoint_at_anchor(
 9810        &mut self,
 9811        breakpoint_position: Anchor,
 9812        breakpoint: Breakpoint,
 9813        edit_action: BreakpointEditAction,
 9814        cx: &mut Context<Self>,
 9815    ) {
 9816        let Some(breakpoint_store) = &self.breakpoint_store else {
 9817            return;
 9818        };
 9819
 9820        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9821            if breakpoint_position == Anchor::min() {
 9822                self.buffer()
 9823                    .read(cx)
 9824                    .excerpt_buffer_ids()
 9825                    .into_iter()
 9826                    .next()
 9827            } else {
 9828                None
 9829            }
 9830        }) else {
 9831            return;
 9832        };
 9833
 9834        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9835            return;
 9836        };
 9837
 9838        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9839            breakpoint_store.toggle_breakpoint(
 9840                buffer,
 9841                BreakpointWithPosition {
 9842                    position: breakpoint_position.text_anchor,
 9843                    bp: breakpoint,
 9844                },
 9845                edit_action,
 9846                cx,
 9847            );
 9848        });
 9849
 9850        cx.notify();
 9851    }
 9852
 9853    #[cfg(any(test, feature = "test-support"))]
 9854    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9855        self.breakpoint_store.clone()
 9856    }
 9857
 9858    pub fn prepare_restore_change(
 9859        &self,
 9860        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9861        hunk: &MultiBufferDiffHunk,
 9862        cx: &mut App,
 9863    ) -> Option<()> {
 9864        if hunk.is_created_file() {
 9865            return None;
 9866        }
 9867        let buffer = self.buffer.read(cx);
 9868        let diff = buffer.diff_for(hunk.buffer_id)?;
 9869        let buffer = buffer.buffer(hunk.buffer_id)?;
 9870        let buffer = buffer.read(cx);
 9871        let original_text = diff
 9872            .read(cx)
 9873            .base_text()
 9874            .as_rope()
 9875            .slice(hunk.diff_base_byte_range.clone());
 9876        let buffer_snapshot = buffer.snapshot();
 9877        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9878        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9879            probe
 9880                .0
 9881                .start
 9882                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9883                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9884        }) {
 9885            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9886            Some(())
 9887        } else {
 9888            None
 9889        }
 9890    }
 9891
 9892    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9893        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9894    }
 9895
 9896    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9897        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9898    }
 9899
 9900    fn manipulate_lines<Fn>(
 9901        &mut self,
 9902        window: &mut Window,
 9903        cx: &mut Context<Self>,
 9904        mut callback: Fn,
 9905    ) where
 9906        Fn: FnMut(&mut Vec<&str>),
 9907    {
 9908        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9909
 9910        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9911        let buffer = self.buffer.read(cx).snapshot(cx);
 9912
 9913        let mut edits = Vec::new();
 9914
 9915        let selections = self.selections.all::<Point>(cx);
 9916        let mut selections = selections.iter().peekable();
 9917        let mut contiguous_row_selections = Vec::new();
 9918        let mut new_selections = Vec::new();
 9919        let mut added_lines = 0;
 9920        let mut removed_lines = 0;
 9921
 9922        while let Some(selection) = selections.next() {
 9923            let (start_row, end_row) = consume_contiguous_rows(
 9924                &mut contiguous_row_selections,
 9925                selection,
 9926                &display_map,
 9927                &mut selections,
 9928            );
 9929
 9930            let start_point = Point::new(start_row.0, 0);
 9931            let end_point = Point::new(
 9932                end_row.previous_row().0,
 9933                buffer.line_len(end_row.previous_row()),
 9934            );
 9935            let text = buffer
 9936                .text_for_range(start_point..end_point)
 9937                .collect::<String>();
 9938
 9939            let mut lines = text.split('\n').collect_vec();
 9940
 9941            let lines_before = lines.len();
 9942            callback(&mut lines);
 9943            let lines_after = lines.len();
 9944
 9945            edits.push((start_point..end_point, lines.join("\n")));
 9946
 9947            // Selections must change based on added and removed line count
 9948            let start_row =
 9949                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9950            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9951            new_selections.push(Selection {
 9952                id: selection.id,
 9953                start: start_row,
 9954                end: end_row,
 9955                goal: SelectionGoal::None,
 9956                reversed: selection.reversed,
 9957            });
 9958
 9959            if lines_after > lines_before {
 9960                added_lines += lines_after - lines_before;
 9961            } else if lines_before > lines_after {
 9962                removed_lines += lines_before - lines_after;
 9963            }
 9964        }
 9965
 9966        self.transact(window, cx, |this, window, cx| {
 9967            let buffer = this.buffer.update(cx, |buffer, cx| {
 9968                buffer.edit(edits, None, cx);
 9969                buffer.snapshot(cx)
 9970            });
 9971
 9972            // Recalculate offsets on newly edited buffer
 9973            let new_selections = new_selections
 9974                .iter()
 9975                .map(|s| {
 9976                    let start_point = Point::new(s.start.0, 0);
 9977                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9978                    Selection {
 9979                        id: s.id,
 9980                        start: buffer.point_to_offset(start_point),
 9981                        end: buffer.point_to_offset(end_point),
 9982                        goal: s.goal,
 9983                        reversed: s.reversed,
 9984                    }
 9985                })
 9986                .collect();
 9987
 9988            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9989                s.select(new_selections);
 9990            });
 9991
 9992            this.request_autoscroll(Autoscroll::fit(), cx);
 9993        });
 9994    }
 9995
 9996    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9997        self.manipulate_text(window, cx, |text| {
 9998            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9999            if has_upper_case_characters {
10000                text.to_lowercase()
10001            } else {
10002                text.to_uppercase()
10003            }
10004        })
10005    }
10006
10007    pub fn convert_to_upper_case(
10008        &mut self,
10009        _: &ConvertToUpperCase,
10010        window: &mut Window,
10011        cx: &mut Context<Self>,
10012    ) {
10013        self.manipulate_text(window, cx, |text| text.to_uppercase())
10014    }
10015
10016    pub fn convert_to_lower_case(
10017        &mut self,
10018        _: &ConvertToLowerCase,
10019        window: &mut Window,
10020        cx: &mut Context<Self>,
10021    ) {
10022        self.manipulate_text(window, cx, |text| text.to_lowercase())
10023    }
10024
10025    pub fn convert_to_title_case(
10026        &mut self,
10027        _: &ConvertToTitleCase,
10028        window: &mut Window,
10029        cx: &mut Context<Self>,
10030    ) {
10031        self.manipulate_text(window, cx, |text| {
10032            text.split('\n')
10033                .map(|line| line.to_case(Case::Title))
10034                .join("\n")
10035        })
10036    }
10037
10038    pub fn convert_to_snake_case(
10039        &mut self,
10040        _: &ConvertToSnakeCase,
10041        window: &mut Window,
10042        cx: &mut Context<Self>,
10043    ) {
10044        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10045    }
10046
10047    pub fn convert_to_kebab_case(
10048        &mut self,
10049        _: &ConvertToKebabCase,
10050        window: &mut Window,
10051        cx: &mut Context<Self>,
10052    ) {
10053        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10054    }
10055
10056    pub fn convert_to_upper_camel_case(
10057        &mut self,
10058        _: &ConvertToUpperCamelCase,
10059        window: &mut Window,
10060        cx: &mut Context<Self>,
10061    ) {
10062        self.manipulate_text(window, cx, |text| {
10063            text.split('\n')
10064                .map(|line| line.to_case(Case::UpperCamel))
10065                .join("\n")
10066        })
10067    }
10068
10069    pub fn convert_to_lower_camel_case(
10070        &mut self,
10071        _: &ConvertToLowerCamelCase,
10072        window: &mut Window,
10073        cx: &mut Context<Self>,
10074    ) {
10075        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10076    }
10077
10078    pub fn convert_to_opposite_case(
10079        &mut self,
10080        _: &ConvertToOppositeCase,
10081        window: &mut Window,
10082        cx: &mut Context<Self>,
10083    ) {
10084        self.manipulate_text(window, cx, |text| {
10085            text.chars()
10086                .fold(String::with_capacity(text.len()), |mut t, c| {
10087                    if c.is_uppercase() {
10088                        t.extend(c.to_lowercase());
10089                    } else {
10090                        t.extend(c.to_uppercase());
10091                    }
10092                    t
10093                })
10094        })
10095    }
10096
10097    pub fn convert_to_rot13(
10098        &mut self,
10099        _: &ConvertToRot13,
10100        window: &mut Window,
10101        cx: &mut Context<Self>,
10102    ) {
10103        self.manipulate_text(window, cx, |text| {
10104            text.chars()
10105                .map(|c| match c {
10106                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10107                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10108                    _ => c,
10109                })
10110                .collect()
10111        })
10112    }
10113
10114    pub fn convert_to_rot47(
10115        &mut self,
10116        _: &ConvertToRot47,
10117        window: &mut Window,
10118        cx: &mut Context<Self>,
10119    ) {
10120        self.manipulate_text(window, cx, |text| {
10121            text.chars()
10122                .map(|c| {
10123                    let code_point = c as u32;
10124                    if code_point >= 33 && code_point <= 126 {
10125                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10126                    }
10127                    c
10128                })
10129                .collect()
10130        })
10131    }
10132
10133    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10134    where
10135        Fn: FnMut(&str) -> String,
10136    {
10137        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10138        let buffer = self.buffer.read(cx).snapshot(cx);
10139
10140        let mut new_selections = Vec::new();
10141        let mut edits = Vec::new();
10142        let mut selection_adjustment = 0i32;
10143
10144        for selection in self.selections.all::<usize>(cx) {
10145            let selection_is_empty = selection.is_empty();
10146
10147            let (start, end) = if selection_is_empty {
10148                let word_range = movement::surrounding_word(
10149                    &display_map,
10150                    selection.start.to_display_point(&display_map),
10151                );
10152                let start = word_range.start.to_offset(&display_map, Bias::Left);
10153                let end = word_range.end.to_offset(&display_map, Bias::Left);
10154                (start, end)
10155            } else {
10156                (selection.start, selection.end)
10157            };
10158
10159            let text = buffer.text_for_range(start..end).collect::<String>();
10160            let old_length = text.len() as i32;
10161            let text = callback(&text);
10162
10163            new_selections.push(Selection {
10164                start: (start as i32 - selection_adjustment) as usize,
10165                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10166                goal: SelectionGoal::None,
10167                ..selection
10168            });
10169
10170            selection_adjustment += old_length - text.len() as i32;
10171
10172            edits.push((start..end, text));
10173        }
10174
10175        self.transact(window, cx, |this, window, cx| {
10176            this.buffer.update(cx, |buffer, cx| {
10177                buffer.edit(edits, None, cx);
10178            });
10179
10180            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10181                s.select(new_selections);
10182            });
10183
10184            this.request_autoscroll(Autoscroll::fit(), cx);
10185        });
10186    }
10187
10188    pub fn duplicate(
10189        &mut self,
10190        upwards: bool,
10191        whole_lines: bool,
10192        window: &mut Window,
10193        cx: &mut Context<Self>,
10194    ) {
10195        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10196
10197        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10198        let buffer = &display_map.buffer_snapshot;
10199        let selections = self.selections.all::<Point>(cx);
10200
10201        let mut edits = Vec::new();
10202        let mut selections_iter = selections.iter().peekable();
10203        while let Some(selection) = selections_iter.next() {
10204            let mut rows = selection.spanned_rows(false, &display_map);
10205            // duplicate line-wise
10206            if whole_lines || selection.start == selection.end {
10207                // Avoid duplicating the same lines twice.
10208                while let Some(next_selection) = selections_iter.peek() {
10209                    let next_rows = next_selection.spanned_rows(false, &display_map);
10210                    if next_rows.start < rows.end {
10211                        rows.end = next_rows.end;
10212                        selections_iter.next().unwrap();
10213                    } else {
10214                        break;
10215                    }
10216                }
10217
10218                // Copy the text from the selected row region and splice it either at the start
10219                // or end of the region.
10220                let start = Point::new(rows.start.0, 0);
10221                let end = Point::new(
10222                    rows.end.previous_row().0,
10223                    buffer.line_len(rows.end.previous_row()),
10224                );
10225                let text = buffer
10226                    .text_for_range(start..end)
10227                    .chain(Some("\n"))
10228                    .collect::<String>();
10229                let insert_location = if upwards {
10230                    Point::new(rows.end.0, 0)
10231                } else {
10232                    start
10233                };
10234                edits.push((insert_location..insert_location, text));
10235            } else {
10236                // duplicate character-wise
10237                let start = selection.start;
10238                let end = selection.end;
10239                let text = buffer.text_for_range(start..end).collect::<String>();
10240                edits.push((selection.end..selection.end, text));
10241            }
10242        }
10243
10244        self.transact(window, cx, |this, _, cx| {
10245            this.buffer.update(cx, |buffer, cx| {
10246                buffer.edit(edits, None, cx);
10247            });
10248
10249            this.request_autoscroll(Autoscroll::fit(), cx);
10250        });
10251    }
10252
10253    pub fn duplicate_line_up(
10254        &mut self,
10255        _: &DuplicateLineUp,
10256        window: &mut Window,
10257        cx: &mut Context<Self>,
10258    ) {
10259        self.duplicate(true, true, window, cx);
10260    }
10261
10262    pub fn duplicate_line_down(
10263        &mut self,
10264        _: &DuplicateLineDown,
10265        window: &mut Window,
10266        cx: &mut Context<Self>,
10267    ) {
10268        self.duplicate(false, true, window, cx);
10269    }
10270
10271    pub fn duplicate_selection(
10272        &mut self,
10273        _: &DuplicateSelection,
10274        window: &mut Window,
10275        cx: &mut Context<Self>,
10276    ) {
10277        self.duplicate(false, false, window, cx);
10278    }
10279
10280    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10281        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10282
10283        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10284        let buffer = self.buffer.read(cx).snapshot(cx);
10285
10286        let mut edits = Vec::new();
10287        let mut unfold_ranges = Vec::new();
10288        let mut refold_creases = Vec::new();
10289
10290        let selections = self.selections.all::<Point>(cx);
10291        let mut selections = selections.iter().peekable();
10292        let mut contiguous_row_selections = Vec::new();
10293        let mut new_selections = Vec::new();
10294
10295        while let Some(selection) = selections.next() {
10296            // Find all the selections that span a contiguous row range
10297            let (start_row, end_row) = consume_contiguous_rows(
10298                &mut contiguous_row_selections,
10299                selection,
10300                &display_map,
10301                &mut selections,
10302            );
10303
10304            // Move the text spanned by the row range to be before the line preceding the row range
10305            if start_row.0 > 0 {
10306                let range_to_move = Point::new(
10307                    start_row.previous_row().0,
10308                    buffer.line_len(start_row.previous_row()),
10309                )
10310                    ..Point::new(
10311                        end_row.previous_row().0,
10312                        buffer.line_len(end_row.previous_row()),
10313                    );
10314                let insertion_point = display_map
10315                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10316                    .0;
10317
10318                // Don't move lines across excerpts
10319                if buffer
10320                    .excerpt_containing(insertion_point..range_to_move.end)
10321                    .is_some()
10322                {
10323                    let text = buffer
10324                        .text_for_range(range_to_move.clone())
10325                        .flat_map(|s| s.chars())
10326                        .skip(1)
10327                        .chain(['\n'])
10328                        .collect::<String>();
10329
10330                    edits.push((
10331                        buffer.anchor_after(range_to_move.start)
10332                            ..buffer.anchor_before(range_to_move.end),
10333                        String::new(),
10334                    ));
10335                    let insertion_anchor = buffer.anchor_after(insertion_point);
10336                    edits.push((insertion_anchor..insertion_anchor, text));
10337
10338                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10339
10340                    // Move selections up
10341                    new_selections.extend(contiguous_row_selections.drain(..).map(
10342                        |mut selection| {
10343                            selection.start.row -= row_delta;
10344                            selection.end.row -= row_delta;
10345                            selection
10346                        },
10347                    ));
10348
10349                    // Move folds up
10350                    unfold_ranges.push(range_to_move.clone());
10351                    for fold in display_map.folds_in_range(
10352                        buffer.anchor_before(range_to_move.start)
10353                            ..buffer.anchor_after(range_to_move.end),
10354                    ) {
10355                        let mut start = fold.range.start.to_point(&buffer);
10356                        let mut end = fold.range.end.to_point(&buffer);
10357                        start.row -= row_delta;
10358                        end.row -= row_delta;
10359                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10360                    }
10361                }
10362            }
10363
10364            // If we didn't move line(s), preserve the existing selections
10365            new_selections.append(&mut contiguous_row_selections);
10366        }
10367
10368        self.transact(window, cx, |this, window, cx| {
10369            this.unfold_ranges(&unfold_ranges, true, true, cx);
10370            this.buffer.update(cx, |buffer, cx| {
10371                for (range, text) in edits {
10372                    buffer.edit([(range, text)], None, cx);
10373                }
10374            });
10375            this.fold_creases(refold_creases, true, window, cx);
10376            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10377                s.select(new_selections);
10378            })
10379        });
10380    }
10381
10382    pub fn move_line_down(
10383        &mut self,
10384        _: &MoveLineDown,
10385        window: &mut Window,
10386        cx: &mut Context<Self>,
10387    ) {
10388        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10389
10390        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10391        let buffer = self.buffer.read(cx).snapshot(cx);
10392
10393        let mut edits = Vec::new();
10394        let mut unfold_ranges = Vec::new();
10395        let mut refold_creases = Vec::new();
10396
10397        let selections = self.selections.all::<Point>(cx);
10398        let mut selections = selections.iter().peekable();
10399        let mut contiguous_row_selections = Vec::new();
10400        let mut new_selections = Vec::new();
10401
10402        while let Some(selection) = selections.next() {
10403            // Find all the selections that span a contiguous row range
10404            let (start_row, end_row) = consume_contiguous_rows(
10405                &mut contiguous_row_selections,
10406                selection,
10407                &display_map,
10408                &mut selections,
10409            );
10410
10411            // Move the text spanned by the row range to be after the last line of the row range
10412            if end_row.0 <= buffer.max_point().row {
10413                let range_to_move =
10414                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10415                let insertion_point = display_map
10416                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10417                    .0;
10418
10419                // Don't move lines across excerpt boundaries
10420                if buffer
10421                    .excerpt_containing(range_to_move.start..insertion_point)
10422                    .is_some()
10423                {
10424                    let mut text = String::from("\n");
10425                    text.extend(buffer.text_for_range(range_to_move.clone()));
10426                    text.pop(); // Drop trailing newline
10427                    edits.push((
10428                        buffer.anchor_after(range_to_move.start)
10429                            ..buffer.anchor_before(range_to_move.end),
10430                        String::new(),
10431                    ));
10432                    let insertion_anchor = buffer.anchor_after(insertion_point);
10433                    edits.push((insertion_anchor..insertion_anchor, text));
10434
10435                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10436
10437                    // Move selections down
10438                    new_selections.extend(contiguous_row_selections.drain(..).map(
10439                        |mut selection| {
10440                            selection.start.row += row_delta;
10441                            selection.end.row += row_delta;
10442                            selection
10443                        },
10444                    ));
10445
10446                    // Move folds down
10447                    unfold_ranges.push(range_to_move.clone());
10448                    for fold in display_map.folds_in_range(
10449                        buffer.anchor_before(range_to_move.start)
10450                            ..buffer.anchor_after(range_to_move.end),
10451                    ) {
10452                        let mut start = fold.range.start.to_point(&buffer);
10453                        let mut end = fold.range.end.to_point(&buffer);
10454                        start.row += row_delta;
10455                        end.row += row_delta;
10456                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10457                    }
10458                }
10459            }
10460
10461            // If we didn't move line(s), preserve the existing selections
10462            new_selections.append(&mut contiguous_row_selections);
10463        }
10464
10465        self.transact(window, cx, |this, window, cx| {
10466            this.unfold_ranges(&unfold_ranges, true, true, cx);
10467            this.buffer.update(cx, |buffer, cx| {
10468                for (range, text) in edits {
10469                    buffer.edit([(range, text)], None, cx);
10470                }
10471            });
10472            this.fold_creases(refold_creases, true, window, cx);
10473            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10474                s.select(new_selections)
10475            });
10476        });
10477    }
10478
10479    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10480        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10481        let text_layout_details = &self.text_layout_details(window);
10482        self.transact(window, cx, |this, window, cx| {
10483            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10484                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10485                s.move_with(|display_map, selection| {
10486                    if !selection.is_empty() {
10487                        return;
10488                    }
10489
10490                    let mut head = selection.head();
10491                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10492                    if head.column() == display_map.line_len(head.row()) {
10493                        transpose_offset = display_map
10494                            .buffer_snapshot
10495                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10496                    }
10497
10498                    if transpose_offset == 0 {
10499                        return;
10500                    }
10501
10502                    *head.column_mut() += 1;
10503                    head = display_map.clip_point(head, Bias::Right);
10504                    let goal = SelectionGoal::HorizontalPosition(
10505                        display_map
10506                            .x_for_display_point(head, text_layout_details)
10507                            .into(),
10508                    );
10509                    selection.collapse_to(head, goal);
10510
10511                    let transpose_start = display_map
10512                        .buffer_snapshot
10513                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10514                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10515                        let transpose_end = display_map
10516                            .buffer_snapshot
10517                            .clip_offset(transpose_offset + 1, Bias::Right);
10518                        if let Some(ch) =
10519                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10520                        {
10521                            edits.push((transpose_start..transpose_offset, String::new()));
10522                            edits.push((transpose_end..transpose_end, ch.to_string()));
10523                        }
10524                    }
10525                });
10526                edits
10527            });
10528            this.buffer
10529                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10530            let selections = this.selections.all::<usize>(cx);
10531            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10532                s.select(selections);
10533            });
10534        });
10535    }
10536
10537    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10538        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10539        self.rewrap_impl(RewrapOptions::default(), cx)
10540    }
10541
10542    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10543        let buffer = self.buffer.read(cx).snapshot(cx);
10544        let selections = self.selections.all::<Point>(cx);
10545        let mut selections = selections.iter().peekable();
10546
10547        let mut edits = Vec::new();
10548        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10549
10550        while let Some(selection) = selections.next() {
10551            let mut start_row = selection.start.row;
10552            let mut end_row = selection.end.row;
10553
10554            // Skip selections that overlap with a range that has already been rewrapped.
10555            let selection_range = start_row..end_row;
10556            if rewrapped_row_ranges
10557                .iter()
10558                .any(|range| range.overlaps(&selection_range))
10559            {
10560                continue;
10561            }
10562
10563            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10564
10565            // Since not all lines in the selection may be at the same indent
10566            // level, choose the indent size that is the most common between all
10567            // of the lines.
10568            //
10569            // If there is a tie, we use the deepest indent.
10570            let (indent_size, indent_end) = {
10571                let mut indent_size_occurrences = HashMap::default();
10572                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10573
10574                for row in start_row..=end_row {
10575                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10576                    rows_by_indent_size.entry(indent).or_default().push(row);
10577                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10578                }
10579
10580                let indent_size = indent_size_occurrences
10581                    .into_iter()
10582                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10583                    .map(|(indent, _)| indent)
10584                    .unwrap_or_default();
10585                let row = rows_by_indent_size[&indent_size][0];
10586                let indent_end = Point::new(row, indent_size.len);
10587
10588                (indent_size, indent_end)
10589            };
10590
10591            let mut line_prefix = indent_size.chars().collect::<String>();
10592
10593            let mut inside_comment = false;
10594            if let Some(comment_prefix) =
10595                buffer
10596                    .language_scope_at(selection.head())
10597                    .and_then(|language| {
10598                        language
10599                            .line_comment_prefixes()
10600                            .iter()
10601                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10602                            .cloned()
10603                    })
10604            {
10605                line_prefix.push_str(&comment_prefix);
10606                inside_comment = true;
10607            }
10608
10609            let language_settings = buffer.language_settings_at(selection.head(), cx);
10610            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10611                RewrapBehavior::InComments => inside_comment,
10612                RewrapBehavior::InSelections => !selection.is_empty(),
10613                RewrapBehavior::Anywhere => true,
10614            };
10615
10616            let should_rewrap = options.override_language_settings
10617                || allow_rewrap_based_on_language
10618                || self.hard_wrap.is_some();
10619            if !should_rewrap {
10620                continue;
10621            }
10622
10623            if selection.is_empty() {
10624                'expand_upwards: while start_row > 0 {
10625                    let prev_row = start_row - 1;
10626                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10627                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10628                    {
10629                        start_row = prev_row;
10630                    } else {
10631                        break 'expand_upwards;
10632                    }
10633                }
10634
10635                'expand_downwards: while end_row < buffer.max_point().row {
10636                    let next_row = end_row + 1;
10637                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10638                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10639                    {
10640                        end_row = next_row;
10641                    } else {
10642                        break 'expand_downwards;
10643                    }
10644                }
10645            }
10646
10647            let start = Point::new(start_row, 0);
10648            let start_offset = start.to_offset(&buffer);
10649            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10650            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10651            let Some(lines_without_prefixes) = selection_text
10652                .lines()
10653                .map(|line| {
10654                    line.strip_prefix(&line_prefix)
10655                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10656                        .with_context(|| {
10657                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10658                        })
10659                })
10660                .collect::<Result<Vec<_>, _>>()
10661                .log_err()
10662            else {
10663                continue;
10664            };
10665
10666            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10667                buffer
10668                    .language_settings_at(Point::new(start_row, 0), cx)
10669                    .preferred_line_length as usize
10670            });
10671            let wrapped_text = wrap_with_prefix(
10672                line_prefix,
10673                lines_without_prefixes.join("\n"),
10674                wrap_column,
10675                tab_size,
10676                options.preserve_existing_whitespace,
10677            );
10678
10679            // TODO: should always use char-based diff while still supporting cursor behavior that
10680            // matches vim.
10681            let mut diff_options = DiffOptions::default();
10682            if options.override_language_settings {
10683                diff_options.max_word_diff_len = 0;
10684                diff_options.max_word_diff_line_count = 0;
10685            } else {
10686                diff_options.max_word_diff_len = usize::MAX;
10687                diff_options.max_word_diff_line_count = usize::MAX;
10688            }
10689
10690            for (old_range, new_text) in
10691                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10692            {
10693                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10694                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10695                edits.push((edit_start..edit_end, new_text));
10696            }
10697
10698            rewrapped_row_ranges.push(start_row..=end_row);
10699        }
10700
10701        self.buffer
10702            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10703    }
10704
10705    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10706        let mut text = String::new();
10707        let buffer = self.buffer.read(cx).snapshot(cx);
10708        let mut selections = self.selections.all::<Point>(cx);
10709        let mut clipboard_selections = Vec::with_capacity(selections.len());
10710        {
10711            let max_point = buffer.max_point();
10712            let mut is_first = true;
10713            for selection in &mut selections {
10714                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10715                if is_entire_line {
10716                    selection.start = Point::new(selection.start.row, 0);
10717                    if !selection.is_empty() && selection.end.column == 0 {
10718                        selection.end = cmp::min(max_point, selection.end);
10719                    } else {
10720                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10721                    }
10722                    selection.goal = SelectionGoal::None;
10723                }
10724                if is_first {
10725                    is_first = false;
10726                } else {
10727                    text += "\n";
10728                }
10729                let mut len = 0;
10730                for chunk in buffer.text_for_range(selection.start..selection.end) {
10731                    text.push_str(chunk);
10732                    len += chunk.len();
10733                }
10734                clipboard_selections.push(ClipboardSelection {
10735                    len,
10736                    is_entire_line,
10737                    first_line_indent: buffer
10738                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10739                        .len,
10740                });
10741            }
10742        }
10743
10744        self.transact(window, cx, |this, window, cx| {
10745            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10746                s.select(selections);
10747            });
10748            this.insert("", window, cx);
10749        });
10750        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10751    }
10752
10753    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10754        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10755        let item = self.cut_common(window, cx);
10756        cx.write_to_clipboard(item);
10757    }
10758
10759    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10760        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10761        self.change_selections(None, window, cx, |s| {
10762            s.move_with(|snapshot, sel| {
10763                if sel.is_empty() {
10764                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10765                }
10766            });
10767        });
10768        let item = self.cut_common(window, cx);
10769        cx.set_global(KillRing(item))
10770    }
10771
10772    pub fn kill_ring_yank(
10773        &mut self,
10774        _: &KillRingYank,
10775        window: &mut Window,
10776        cx: &mut Context<Self>,
10777    ) {
10778        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10779        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10780            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10781                (kill_ring.text().to_string(), kill_ring.metadata_json())
10782            } else {
10783                return;
10784            }
10785        } else {
10786            return;
10787        };
10788        self.do_paste(&text, metadata, false, window, cx);
10789    }
10790
10791    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10792        self.do_copy(true, cx);
10793    }
10794
10795    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10796        self.do_copy(false, cx);
10797    }
10798
10799    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10800        let selections = self.selections.all::<Point>(cx);
10801        let buffer = self.buffer.read(cx).read(cx);
10802        let mut text = String::new();
10803
10804        let mut clipboard_selections = Vec::with_capacity(selections.len());
10805        {
10806            let max_point = buffer.max_point();
10807            let mut is_first = true;
10808            for selection in &selections {
10809                let mut start = selection.start;
10810                let mut end = selection.end;
10811                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10812                if is_entire_line {
10813                    start = Point::new(start.row, 0);
10814                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10815                }
10816
10817                let mut trimmed_selections = Vec::new();
10818                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10819                    let row = MultiBufferRow(start.row);
10820                    let first_indent = buffer.indent_size_for_line(row);
10821                    if first_indent.len == 0 || start.column > first_indent.len {
10822                        trimmed_selections.push(start..end);
10823                    } else {
10824                        trimmed_selections.push(
10825                            Point::new(row.0, first_indent.len)
10826                                ..Point::new(row.0, buffer.line_len(row)),
10827                        );
10828                        for row in start.row + 1..=end.row {
10829                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10830                            if row == end.row {
10831                                line_len = end.column;
10832                            }
10833                            if line_len == 0 {
10834                                trimmed_selections
10835                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10836                                continue;
10837                            }
10838                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10839                            if row_indent_size.len >= first_indent.len {
10840                                trimmed_selections.push(
10841                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10842                                );
10843                            } else {
10844                                trimmed_selections.clear();
10845                                trimmed_selections.push(start..end);
10846                                break;
10847                            }
10848                        }
10849                    }
10850                } else {
10851                    trimmed_selections.push(start..end);
10852                }
10853
10854                for trimmed_range in trimmed_selections {
10855                    if is_first {
10856                        is_first = false;
10857                    } else {
10858                        text += "\n";
10859                    }
10860                    let mut len = 0;
10861                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10862                        text.push_str(chunk);
10863                        len += chunk.len();
10864                    }
10865                    clipboard_selections.push(ClipboardSelection {
10866                        len,
10867                        is_entire_line,
10868                        first_line_indent: buffer
10869                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10870                            .len,
10871                    });
10872                }
10873            }
10874        }
10875
10876        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10877            text,
10878            clipboard_selections,
10879        ));
10880    }
10881
10882    pub fn do_paste(
10883        &mut self,
10884        text: &String,
10885        clipboard_selections: Option<Vec<ClipboardSelection>>,
10886        handle_entire_lines: bool,
10887        window: &mut Window,
10888        cx: &mut Context<Self>,
10889    ) {
10890        if self.read_only(cx) {
10891            return;
10892        }
10893
10894        let clipboard_text = Cow::Borrowed(text);
10895
10896        self.transact(window, cx, |this, window, cx| {
10897            if let Some(mut clipboard_selections) = clipboard_selections {
10898                let old_selections = this.selections.all::<usize>(cx);
10899                let all_selections_were_entire_line =
10900                    clipboard_selections.iter().all(|s| s.is_entire_line);
10901                let first_selection_indent_column =
10902                    clipboard_selections.first().map(|s| s.first_line_indent);
10903                if clipboard_selections.len() != old_selections.len() {
10904                    clipboard_selections.drain(..);
10905                }
10906                let cursor_offset = this.selections.last::<usize>(cx).head();
10907                let mut auto_indent_on_paste = true;
10908
10909                this.buffer.update(cx, |buffer, cx| {
10910                    let snapshot = buffer.read(cx);
10911                    auto_indent_on_paste = snapshot
10912                        .language_settings_at(cursor_offset, cx)
10913                        .auto_indent_on_paste;
10914
10915                    let mut start_offset = 0;
10916                    let mut edits = Vec::new();
10917                    let mut original_indent_columns = Vec::new();
10918                    for (ix, selection) in old_selections.iter().enumerate() {
10919                        let to_insert;
10920                        let entire_line;
10921                        let original_indent_column;
10922                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10923                            let end_offset = start_offset + clipboard_selection.len;
10924                            to_insert = &clipboard_text[start_offset..end_offset];
10925                            entire_line = clipboard_selection.is_entire_line;
10926                            start_offset = end_offset + 1;
10927                            original_indent_column = Some(clipboard_selection.first_line_indent);
10928                        } else {
10929                            to_insert = clipboard_text.as_str();
10930                            entire_line = all_selections_were_entire_line;
10931                            original_indent_column = first_selection_indent_column
10932                        }
10933
10934                        // If the corresponding selection was empty when this slice of the
10935                        // clipboard text was written, then the entire line containing the
10936                        // selection was copied. If this selection is also currently empty,
10937                        // then paste the line before the current line of the buffer.
10938                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10939                            let column = selection.start.to_point(&snapshot).column as usize;
10940                            let line_start = selection.start - column;
10941                            line_start..line_start
10942                        } else {
10943                            selection.range()
10944                        };
10945
10946                        edits.push((range, to_insert));
10947                        original_indent_columns.push(original_indent_column);
10948                    }
10949                    drop(snapshot);
10950
10951                    buffer.edit(
10952                        edits,
10953                        if auto_indent_on_paste {
10954                            Some(AutoindentMode::Block {
10955                                original_indent_columns,
10956                            })
10957                        } else {
10958                            None
10959                        },
10960                        cx,
10961                    );
10962                });
10963
10964                let selections = this.selections.all::<usize>(cx);
10965                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10966                    s.select(selections)
10967                });
10968            } else {
10969                this.insert(&clipboard_text, window, cx);
10970            }
10971        });
10972    }
10973
10974    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10975        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10976        if let Some(item) = cx.read_from_clipboard() {
10977            let entries = item.entries();
10978
10979            match entries.first() {
10980                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10981                // of all the pasted entries.
10982                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10983                    .do_paste(
10984                        clipboard_string.text(),
10985                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10986                        true,
10987                        window,
10988                        cx,
10989                    ),
10990                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10991            }
10992        }
10993    }
10994
10995    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10996        if self.read_only(cx) {
10997            return;
10998        }
10999
11000        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11001
11002        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11003            if let Some((selections, _)) =
11004                self.selection_history.transaction(transaction_id).cloned()
11005            {
11006                self.change_selections(None, window, cx, |s| {
11007                    s.select_anchors(selections.to_vec());
11008                });
11009            } else {
11010                log::error!(
11011                    "No entry in selection_history found for undo. \
11012                     This may correspond to a bug where undo does not update the selection. \
11013                     If this is occurring, please add details to \
11014                     https://github.com/zed-industries/zed/issues/22692"
11015                );
11016            }
11017            self.request_autoscroll(Autoscroll::fit(), cx);
11018            self.unmark_text(window, cx);
11019            self.refresh_inline_completion(true, false, window, cx);
11020            cx.emit(EditorEvent::Edited { transaction_id });
11021            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11022        }
11023    }
11024
11025    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11026        if self.read_only(cx) {
11027            return;
11028        }
11029
11030        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11031
11032        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11033            if let Some((_, Some(selections))) =
11034                self.selection_history.transaction(transaction_id).cloned()
11035            {
11036                self.change_selections(None, window, cx, |s| {
11037                    s.select_anchors(selections.to_vec());
11038                });
11039            } else {
11040                log::error!(
11041                    "No entry in selection_history found for redo. \
11042                     This may correspond to a bug where undo does not update the selection. \
11043                     If this is occurring, please add details to \
11044                     https://github.com/zed-industries/zed/issues/22692"
11045                );
11046            }
11047            self.request_autoscroll(Autoscroll::fit(), cx);
11048            self.unmark_text(window, cx);
11049            self.refresh_inline_completion(true, false, window, cx);
11050            cx.emit(EditorEvent::Edited { transaction_id });
11051        }
11052    }
11053
11054    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11055        self.buffer
11056            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11057    }
11058
11059    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11060        self.buffer
11061            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11062    }
11063
11064    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11065        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11066        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11067            s.move_with(|map, selection| {
11068                let cursor = if selection.is_empty() {
11069                    movement::left(map, selection.start)
11070                } else {
11071                    selection.start
11072                };
11073                selection.collapse_to(cursor, SelectionGoal::None);
11074            });
11075        })
11076    }
11077
11078    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11079        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11080        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11081            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11082        })
11083    }
11084
11085    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11086        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11087        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11088            s.move_with(|map, selection| {
11089                let cursor = if selection.is_empty() {
11090                    movement::right(map, selection.end)
11091                } else {
11092                    selection.end
11093                };
11094                selection.collapse_to(cursor, SelectionGoal::None)
11095            });
11096        })
11097    }
11098
11099    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11100        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11101        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11102            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11103        })
11104    }
11105
11106    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11107        if self.take_rename(true, window, cx).is_some() {
11108            return;
11109        }
11110
11111        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11112            cx.propagate();
11113            return;
11114        }
11115
11116        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11117
11118        let text_layout_details = &self.text_layout_details(window);
11119        let selection_count = self.selections.count();
11120        let first_selection = self.selections.first_anchor();
11121
11122        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11123            s.move_with(|map, selection| {
11124                if !selection.is_empty() {
11125                    selection.goal = SelectionGoal::None;
11126                }
11127                let (cursor, goal) = movement::up(
11128                    map,
11129                    selection.start,
11130                    selection.goal,
11131                    false,
11132                    text_layout_details,
11133                );
11134                selection.collapse_to(cursor, goal);
11135            });
11136        });
11137
11138        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11139        {
11140            cx.propagate();
11141        }
11142    }
11143
11144    pub fn move_up_by_lines(
11145        &mut self,
11146        action: &MoveUpByLines,
11147        window: &mut Window,
11148        cx: &mut Context<Self>,
11149    ) {
11150        if self.take_rename(true, window, cx).is_some() {
11151            return;
11152        }
11153
11154        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11155            cx.propagate();
11156            return;
11157        }
11158
11159        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11160
11161        let text_layout_details = &self.text_layout_details(window);
11162
11163        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11164            s.move_with(|map, selection| {
11165                if !selection.is_empty() {
11166                    selection.goal = SelectionGoal::None;
11167                }
11168                let (cursor, goal) = movement::up_by_rows(
11169                    map,
11170                    selection.start,
11171                    action.lines,
11172                    selection.goal,
11173                    false,
11174                    text_layout_details,
11175                );
11176                selection.collapse_to(cursor, goal);
11177            });
11178        })
11179    }
11180
11181    pub fn move_down_by_lines(
11182        &mut self,
11183        action: &MoveDownByLines,
11184        window: &mut Window,
11185        cx: &mut Context<Self>,
11186    ) {
11187        if self.take_rename(true, window, cx).is_some() {
11188            return;
11189        }
11190
11191        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11192            cx.propagate();
11193            return;
11194        }
11195
11196        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11197
11198        let text_layout_details = &self.text_layout_details(window);
11199
11200        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11201            s.move_with(|map, selection| {
11202                if !selection.is_empty() {
11203                    selection.goal = SelectionGoal::None;
11204                }
11205                let (cursor, goal) = movement::down_by_rows(
11206                    map,
11207                    selection.start,
11208                    action.lines,
11209                    selection.goal,
11210                    false,
11211                    text_layout_details,
11212                );
11213                selection.collapse_to(cursor, goal);
11214            });
11215        })
11216    }
11217
11218    pub fn select_down_by_lines(
11219        &mut self,
11220        action: &SelectDownByLines,
11221        window: &mut Window,
11222        cx: &mut Context<Self>,
11223    ) {
11224        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11225        let text_layout_details = &self.text_layout_details(window);
11226        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11227            s.move_heads_with(|map, head, goal| {
11228                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11229            })
11230        })
11231    }
11232
11233    pub fn select_up_by_lines(
11234        &mut self,
11235        action: &SelectUpByLines,
11236        window: &mut Window,
11237        cx: &mut Context<Self>,
11238    ) {
11239        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11240        let text_layout_details = &self.text_layout_details(window);
11241        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11242            s.move_heads_with(|map, head, goal| {
11243                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11244            })
11245        })
11246    }
11247
11248    pub fn select_page_up(
11249        &mut self,
11250        _: &SelectPageUp,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253    ) {
11254        let Some(row_count) = self.visible_row_count() else {
11255            return;
11256        };
11257
11258        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11259
11260        let text_layout_details = &self.text_layout_details(window);
11261
11262        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11263            s.move_heads_with(|map, head, goal| {
11264                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11265            })
11266        })
11267    }
11268
11269    pub fn move_page_up(
11270        &mut self,
11271        action: &MovePageUp,
11272        window: &mut Window,
11273        cx: &mut Context<Self>,
11274    ) {
11275        if self.take_rename(true, window, cx).is_some() {
11276            return;
11277        }
11278
11279        if self
11280            .context_menu
11281            .borrow_mut()
11282            .as_mut()
11283            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11284            .unwrap_or(false)
11285        {
11286            return;
11287        }
11288
11289        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11290            cx.propagate();
11291            return;
11292        }
11293
11294        let Some(row_count) = self.visible_row_count() else {
11295            return;
11296        };
11297
11298        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11299
11300        let autoscroll = if action.center_cursor {
11301            Autoscroll::center()
11302        } else {
11303            Autoscroll::fit()
11304        };
11305
11306        let text_layout_details = &self.text_layout_details(window);
11307
11308        self.change_selections(Some(autoscroll), window, cx, |s| {
11309            s.move_with(|map, selection| {
11310                if !selection.is_empty() {
11311                    selection.goal = SelectionGoal::None;
11312                }
11313                let (cursor, goal) = movement::up_by_rows(
11314                    map,
11315                    selection.end,
11316                    row_count,
11317                    selection.goal,
11318                    false,
11319                    text_layout_details,
11320                );
11321                selection.collapse_to(cursor, goal);
11322            });
11323        });
11324    }
11325
11326    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11327        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11328        let text_layout_details = &self.text_layout_details(window);
11329        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11330            s.move_heads_with(|map, head, goal| {
11331                movement::up(map, head, goal, false, text_layout_details)
11332            })
11333        })
11334    }
11335
11336    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11337        self.take_rename(true, window, cx);
11338
11339        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11340            cx.propagate();
11341            return;
11342        }
11343
11344        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11345
11346        let text_layout_details = &self.text_layout_details(window);
11347        let selection_count = self.selections.count();
11348        let first_selection = self.selections.first_anchor();
11349
11350        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11351            s.move_with(|map, selection| {
11352                if !selection.is_empty() {
11353                    selection.goal = SelectionGoal::None;
11354                }
11355                let (cursor, goal) = movement::down(
11356                    map,
11357                    selection.end,
11358                    selection.goal,
11359                    false,
11360                    text_layout_details,
11361                );
11362                selection.collapse_to(cursor, goal);
11363            });
11364        });
11365
11366        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11367        {
11368            cx.propagate();
11369        }
11370    }
11371
11372    pub fn select_page_down(
11373        &mut self,
11374        _: &SelectPageDown,
11375        window: &mut Window,
11376        cx: &mut Context<Self>,
11377    ) {
11378        let Some(row_count) = self.visible_row_count() else {
11379            return;
11380        };
11381
11382        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11383
11384        let text_layout_details = &self.text_layout_details(window);
11385
11386        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11387            s.move_heads_with(|map, head, goal| {
11388                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11389            })
11390        })
11391    }
11392
11393    pub fn move_page_down(
11394        &mut self,
11395        action: &MovePageDown,
11396        window: &mut Window,
11397        cx: &mut Context<Self>,
11398    ) {
11399        if self.take_rename(true, window, cx).is_some() {
11400            return;
11401        }
11402
11403        if self
11404            .context_menu
11405            .borrow_mut()
11406            .as_mut()
11407            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11408            .unwrap_or(false)
11409        {
11410            return;
11411        }
11412
11413        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11414            cx.propagate();
11415            return;
11416        }
11417
11418        let Some(row_count) = self.visible_row_count() else {
11419            return;
11420        };
11421
11422        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11423
11424        let autoscroll = if action.center_cursor {
11425            Autoscroll::center()
11426        } else {
11427            Autoscroll::fit()
11428        };
11429
11430        let text_layout_details = &self.text_layout_details(window);
11431        self.change_selections(Some(autoscroll), window, cx, |s| {
11432            s.move_with(|map, selection| {
11433                if !selection.is_empty() {
11434                    selection.goal = SelectionGoal::None;
11435                }
11436                let (cursor, goal) = movement::down_by_rows(
11437                    map,
11438                    selection.end,
11439                    row_count,
11440                    selection.goal,
11441                    false,
11442                    text_layout_details,
11443                );
11444                selection.collapse_to(cursor, goal);
11445            });
11446        });
11447    }
11448
11449    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11450        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11451        let text_layout_details = &self.text_layout_details(window);
11452        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11453            s.move_heads_with(|map, head, goal| {
11454                movement::down(map, head, goal, false, text_layout_details)
11455            })
11456        });
11457    }
11458
11459    pub fn context_menu_first(
11460        &mut self,
11461        _: &ContextMenuFirst,
11462        _window: &mut Window,
11463        cx: &mut Context<Self>,
11464    ) {
11465        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11466            context_menu.select_first(self.completion_provider.as_deref(), cx);
11467        }
11468    }
11469
11470    pub fn context_menu_prev(
11471        &mut self,
11472        _: &ContextMenuPrevious,
11473        _window: &mut Window,
11474        cx: &mut Context<Self>,
11475    ) {
11476        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11477            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11478        }
11479    }
11480
11481    pub fn context_menu_next(
11482        &mut self,
11483        _: &ContextMenuNext,
11484        _window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11488            context_menu.select_next(self.completion_provider.as_deref(), cx);
11489        }
11490    }
11491
11492    pub fn context_menu_last(
11493        &mut self,
11494        _: &ContextMenuLast,
11495        _window: &mut Window,
11496        cx: &mut Context<Self>,
11497    ) {
11498        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11499            context_menu.select_last(self.completion_provider.as_deref(), cx);
11500        }
11501    }
11502
11503    pub fn move_to_previous_word_start(
11504        &mut self,
11505        _: &MoveToPreviousWordStart,
11506        window: &mut Window,
11507        cx: &mut Context<Self>,
11508    ) {
11509        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11510        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11511            s.move_cursors_with(|map, head, _| {
11512                (
11513                    movement::previous_word_start(map, head),
11514                    SelectionGoal::None,
11515                )
11516            });
11517        })
11518    }
11519
11520    pub fn move_to_previous_subword_start(
11521        &mut self,
11522        _: &MoveToPreviousSubwordStart,
11523        window: &mut Window,
11524        cx: &mut Context<Self>,
11525    ) {
11526        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11527        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11528            s.move_cursors_with(|map, head, _| {
11529                (
11530                    movement::previous_subword_start(map, head),
11531                    SelectionGoal::None,
11532                )
11533            });
11534        })
11535    }
11536
11537    pub fn select_to_previous_word_start(
11538        &mut self,
11539        _: &SelectToPreviousWordStart,
11540        window: &mut Window,
11541        cx: &mut Context<Self>,
11542    ) {
11543        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11544        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11545            s.move_heads_with(|map, head, _| {
11546                (
11547                    movement::previous_word_start(map, head),
11548                    SelectionGoal::None,
11549                )
11550            });
11551        })
11552    }
11553
11554    pub fn select_to_previous_subword_start(
11555        &mut self,
11556        _: &SelectToPreviousSubwordStart,
11557        window: &mut Window,
11558        cx: &mut Context<Self>,
11559    ) {
11560        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11561        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11562            s.move_heads_with(|map, head, _| {
11563                (
11564                    movement::previous_subword_start(map, head),
11565                    SelectionGoal::None,
11566                )
11567            });
11568        })
11569    }
11570
11571    pub fn delete_to_previous_word_start(
11572        &mut self,
11573        action: &DeleteToPreviousWordStart,
11574        window: &mut Window,
11575        cx: &mut Context<Self>,
11576    ) {
11577        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11578        self.transact(window, cx, |this, window, cx| {
11579            this.select_autoclose_pair(window, cx);
11580            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11581                s.move_with(|map, selection| {
11582                    if selection.is_empty() {
11583                        let cursor = if action.ignore_newlines {
11584                            movement::previous_word_start(map, selection.head())
11585                        } else {
11586                            movement::previous_word_start_or_newline(map, selection.head())
11587                        };
11588                        selection.set_head(cursor, SelectionGoal::None);
11589                    }
11590                });
11591            });
11592            this.insert("", window, cx);
11593        });
11594    }
11595
11596    pub fn delete_to_previous_subword_start(
11597        &mut self,
11598        _: &DeleteToPreviousSubwordStart,
11599        window: &mut Window,
11600        cx: &mut Context<Self>,
11601    ) {
11602        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11603        self.transact(window, cx, |this, window, cx| {
11604            this.select_autoclose_pair(window, cx);
11605            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11606                s.move_with(|map, selection| {
11607                    if selection.is_empty() {
11608                        let cursor = movement::previous_subword_start(map, selection.head());
11609                        selection.set_head(cursor, SelectionGoal::None);
11610                    }
11611                });
11612            });
11613            this.insert("", window, cx);
11614        });
11615    }
11616
11617    pub fn move_to_next_word_end(
11618        &mut self,
11619        _: &MoveToNextWordEnd,
11620        window: &mut Window,
11621        cx: &mut Context<Self>,
11622    ) {
11623        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11624        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11625            s.move_cursors_with(|map, head, _| {
11626                (movement::next_word_end(map, head), SelectionGoal::None)
11627            });
11628        })
11629    }
11630
11631    pub fn move_to_next_subword_end(
11632        &mut self,
11633        _: &MoveToNextSubwordEnd,
11634        window: &mut Window,
11635        cx: &mut Context<Self>,
11636    ) {
11637        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11638        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11639            s.move_cursors_with(|map, head, _| {
11640                (movement::next_subword_end(map, head), SelectionGoal::None)
11641            });
11642        })
11643    }
11644
11645    pub fn select_to_next_word_end(
11646        &mut self,
11647        _: &SelectToNextWordEnd,
11648        window: &mut Window,
11649        cx: &mut Context<Self>,
11650    ) {
11651        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11652        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11653            s.move_heads_with(|map, head, _| {
11654                (movement::next_word_end(map, head), SelectionGoal::None)
11655            });
11656        })
11657    }
11658
11659    pub fn select_to_next_subword_end(
11660        &mut self,
11661        _: &SelectToNextSubwordEnd,
11662        window: &mut Window,
11663        cx: &mut Context<Self>,
11664    ) {
11665        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11666        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11667            s.move_heads_with(|map, head, _| {
11668                (movement::next_subword_end(map, head), SelectionGoal::None)
11669            });
11670        })
11671    }
11672
11673    pub fn delete_to_next_word_end(
11674        &mut self,
11675        action: &DeleteToNextWordEnd,
11676        window: &mut Window,
11677        cx: &mut Context<Self>,
11678    ) {
11679        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11680        self.transact(window, cx, |this, window, cx| {
11681            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11682                s.move_with(|map, selection| {
11683                    if selection.is_empty() {
11684                        let cursor = if action.ignore_newlines {
11685                            movement::next_word_end(map, selection.head())
11686                        } else {
11687                            movement::next_word_end_or_newline(map, selection.head())
11688                        };
11689                        selection.set_head(cursor, SelectionGoal::None);
11690                    }
11691                });
11692            });
11693            this.insert("", window, cx);
11694        });
11695    }
11696
11697    pub fn delete_to_next_subword_end(
11698        &mut self,
11699        _: &DeleteToNextSubwordEnd,
11700        window: &mut Window,
11701        cx: &mut Context<Self>,
11702    ) {
11703        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11704        self.transact(window, cx, |this, window, cx| {
11705            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11706                s.move_with(|map, selection| {
11707                    if selection.is_empty() {
11708                        let cursor = movement::next_subword_end(map, selection.head());
11709                        selection.set_head(cursor, SelectionGoal::None);
11710                    }
11711                });
11712            });
11713            this.insert("", window, cx);
11714        });
11715    }
11716
11717    pub fn move_to_beginning_of_line(
11718        &mut self,
11719        action: &MoveToBeginningOfLine,
11720        window: &mut Window,
11721        cx: &mut Context<Self>,
11722    ) {
11723        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11724        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11725            s.move_cursors_with(|map, head, _| {
11726                (
11727                    movement::indented_line_beginning(
11728                        map,
11729                        head,
11730                        action.stop_at_soft_wraps,
11731                        action.stop_at_indent,
11732                    ),
11733                    SelectionGoal::None,
11734                )
11735            });
11736        })
11737    }
11738
11739    pub fn select_to_beginning_of_line(
11740        &mut self,
11741        action: &SelectToBeginningOfLine,
11742        window: &mut Window,
11743        cx: &mut Context<Self>,
11744    ) {
11745        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11746        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11747            s.move_heads_with(|map, head, _| {
11748                (
11749                    movement::indented_line_beginning(
11750                        map,
11751                        head,
11752                        action.stop_at_soft_wraps,
11753                        action.stop_at_indent,
11754                    ),
11755                    SelectionGoal::None,
11756                )
11757            });
11758        });
11759    }
11760
11761    pub fn delete_to_beginning_of_line(
11762        &mut self,
11763        action: &DeleteToBeginningOfLine,
11764        window: &mut Window,
11765        cx: &mut Context<Self>,
11766    ) {
11767        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11768        self.transact(window, cx, |this, window, cx| {
11769            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11770                s.move_with(|_, selection| {
11771                    selection.reversed = true;
11772                });
11773            });
11774
11775            this.select_to_beginning_of_line(
11776                &SelectToBeginningOfLine {
11777                    stop_at_soft_wraps: false,
11778                    stop_at_indent: action.stop_at_indent,
11779                },
11780                window,
11781                cx,
11782            );
11783            this.backspace(&Backspace, window, cx);
11784        });
11785    }
11786
11787    pub fn move_to_end_of_line(
11788        &mut self,
11789        action: &MoveToEndOfLine,
11790        window: &mut Window,
11791        cx: &mut Context<Self>,
11792    ) {
11793        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11794        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11795            s.move_cursors_with(|map, head, _| {
11796                (
11797                    movement::line_end(map, head, action.stop_at_soft_wraps),
11798                    SelectionGoal::None,
11799                )
11800            });
11801        })
11802    }
11803
11804    pub fn select_to_end_of_line(
11805        &mut self,
11806        action: &SelectToEndOfLine,
11807        window: &mut Window,
11808        cx: &mut Context<Self>,
11809    ) {
11810        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11811        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11812            s.move_heads_with(|map, head, _| {
11813                (
11814                    movement::line_end(map, head, action.stop_at_soft_wraps),
11815                    SelectionGoal::None,
11816                )
11817            });
11818        })
11819    }
11820
11821    pub fn delete_to_end_of_line(
11822        &mut self,
11823        _: &DeleteToEndOfLine,
11824        window: &mut Window,
11825        cx: &mut Context<Self>,
11826    ) {
11827        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11828        self.transact(window, cx, |this, window, cx| {
11829            this.select_to_end_of_line(
11830                &SelectToEndOfLine {
11831                    stop_at_soft_wraps: false,
11832                },
11833                window,
11834                cx,
11835            );
11836            this.delete(&Delete, window, cx);
11837        });
11838    }
11839
11840    pub fn cut_to_end_of_line(
11841        &mut self,
11842        _: &CutToEndOfLine,
11843        window: &mut Window,
11844        cx: &mut Context<Self>,
11845    ) {
11846        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11847        self.transact(window, cx, |this, window, cx| {
11848            this.select_to_end_of_line(
11849                &SelectToEndOfLine {
11850                    stop_at_soft_wraps: false,
11851                },
11852                window,
11853                cx,
11854            );
11855            this.cut(&Cut, window, cx);
11856        });
11857    }
11858
11859    pub fn move_to_start_of_paragraph(
11860        &mut self,
11861        _: &MoveToStartOfParagraph,
11862        window: &mut Window,
11863        cx: &mut Context<Self>,
11864    ) {
11865        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11866            cx.propagate();
11867            return;
11868        }
11869        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11870        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11871            s.move_with(|map, selection| {
11872                selection.collapse_to(
11873                    movement::start_of_paragraph(map, selection.head(), 1),
11874                    SelectionGoal::None,
11875                )
11876            });
11877        })
11878    }
11879
11880    pub fn move_to_end_of_paragraph(
11881        &mut self,
11882        _: &MoveToEndOfParagraph,
11883        window: &mut Window,
11884        cx: &mut Context<Self>,
11885    ) {
11886        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11887            cx.propagate();
11888            return;
11889        }
11890        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11891        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11892            s.move_with(|map, selection| {
11893                selection.collapse_to(
11894                    movement::end_of_paragraph(map, selection.head(), 1),
11895                    SelectionGoal::None,
11896                )
11897            });
11898        })
11899    }
11900
11901    pub fn select_to_start_of_paragraph(
11902        &mut self,
11903        _: &SelectToStartOfParagraph,
11904        window: &mut Window,
11905        cx: &mut Context<Self>,
11906    ) {
11907        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11908            cx.propagate();
11909            return;
11910        }
11911        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11912        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11913            s.move_heads_with(|map, head, _| {
11914                (
11915                    movement::start_of_paragraph(map, head, 1),
11916                    SelectionGoal::None,
11917                )
11918            });
11919        })
11920    }
11921
11922    pub fn select_to_end_of_paragraph(
11923        &mut self,
11924        _: &SelectToEndOfParagraph,
11925        window: &mut Window,
11926        cx: &mut Context<Self>,
11927    ) {
11928        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11929            cx.propagate();
11930            return;
11931        }
11932        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11933        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11934            s.move_heads_with(|map, head, _| {
11935                (
11936                    movement::end_of_paragraph(map, head, 1),
11937                    SelectionGoal::None,
11938                )
11939            });
11940        })
11941    }
11942
11943    pub fn move_to_start_of_excerpt(
11944        &mut self,
11945        _: &MoveToStartOfExcerpt,
11946        window: &mut Window,
11947        cx: &mut Context<Self>,
11948    ) {
11949        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11950            cx.propagate();
11951            return;
11952        }
11953        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11954        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11955            s.move_with(|map, selection| {
11956                selection.collapse_to(
11957                    movement::start_of_excerpt(
11958                        map,
11959                        selection.head(),
11960                        workspace::searchable::Direction::Prev,
11961                    ),
11962                    SelectionGoal::None,
11963                )
11964            });
11965        })
11966    }
11967
11968    pub fn move_to_start_of_next_excerpt(
11969        &mut self,
11970        _: &MoveToStartOfNextExcerpt,
11971        window: &mut Window,
11972        cx: &mut Context<Self>,
11973    ) {
11974        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11975            cx.propagate();
11976            return;
11977        }
11978
11979        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11980            s.move_with(|map, selection| {
11981                selection.collapse_to(
11982                    movement::start_of_excerpt(
11983                        map,
11984                        selection.head(),
11985                        workspace::searchable::Direction::Next,
11986                    ),
11987                    SelectionGoal::None,
11988                )
11989            });
11990        })
11991    }
11992
11993    pub fn move_to_end_of_excerpt(
11994        &mut self,
11995        _: &MoveToEndOfExcerpt,
11996        window: &mut Window,
11997        cx: &mut Context<Self>,
11998    ) {
11999        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12000            cx.propagate();
12001            return;
12002        }
12003        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12004        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12005            s.move_with(|map, selection| {
12006                selection.collapse_to(
12007                    movement::end_of_excerpt(
12008                        map,
12009                        selection.head(),
12010                        workspace::searchable::Direction::Next,
12011                    ),
12012                    SelectionGoal::None,
12013                )
12014            });
12015        })
12016    }
12017
12018    pub fn move_to_end_of_previous_excerpt(
12019        &mut self,
12020        _: &MoveToEndOfPreviousExcerpt,
12021        window: &mut Window,
12022        cx: &mut Context<Self>,
12023    ) {
12024        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12025            cx.propagate();
12026            return;
12027        }
12028        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12029        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12030            s.move_with(|map, selection| {
12031                selection.collapse_to(
12032                    movement::end_of_excerpt(
12033                        map,
12034                        selection.head(),
12035                        workspace::searchable::Direction::Prev,
12036                    ),
12037                    SelectionGoal::None,
12038                )
12039            });
12040        })
12041    }
12042
12043    pub fn select_to_start_of_excerpt(
12044        &mut self,
12045        _: &SelectToStartOfExcerpt,
12046        window: &mut Window,
12047        cx: &mut Context<Self>,
12048    ) {
12049        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12050            cx.propagate();
12051            return;
12052        }
12053        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12054        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12055            s.move_heads_with(|map, head, _| {
12056                (
12057                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12058                    SelectionGoal::None,
12059                )
12060            });
12061        })
12062    }
12063
12064    pub fn select_to_start_of_next_excerpt(
12065        &mut self,
12066        _: &SelectToStartOfNextExcerpt,
12067        window: &mut Window,
12068        cx: &mut Context<Self>,
12069    ) {
12070        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12071            cx.propagate();
12072            return;
12073        }
12074        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12075        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12076            s.move_heads_with(|map, head, _| {
12077                (
12078                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12079                    SelectionGoal::None,
12080                )
12081            });
12082        })
12083    }
12084
12085    pub fn select_to_end_of_excerpt(
12086        &mut self,
12087        _: &SelectToEndOfExcerpt,
12088        window: &mut Window,
12089        cx: &mut Context<Self>,
12090    ) {
12091        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12092            cx.propagate();
12093            return;
12094        }
12095        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12096        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12097            s.move_heads_with(|map, head, _| {
12098                (
12099                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12100                    SelectionGoal::None,
12101                )
12102            });
12103        })
12104    }
12105
12106    pub fn select_to_end_of_previous_excerpt(
12107        &mut self,
12108        _: &SelectToEndOfPreviousExcerpt,
12109        window: &mut Window,
12110        cx: &mut Context<Self>,
12111    ) {
12112        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12113            cx.propagate();
12114            return;
12115        }
12116        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12117        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12118            s.move_heads_with(|map, head, _| {
12119                (
12120                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12121                    SelectionGoal::None,
12122                )
12123            });
12124        })
12125    }
12126
12127    pub fn move_to_beginning(
12128        &mut self,
12129        _: &MoveToBeginning,
12130        window: &mut Window,
12131        cx: &mut Context<Self>,
12132    ) {
12133        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12134            cx.propagate();
12135            return;
12136        }
12137        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12138        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12139            s.select_ranges(vec![0..0]);
12140        });
12141    }
12142
12143    pub fn select_to_beginning(
12144        &mut self,
12145        _: &SelectToBeginning,
12146        window: &mut Window,
12147        cx: &mut Context<Self>,
12148    ) {
12149        let mut selection = self.selections.last::<Point>(cx);
12150        selection.set_head(Point::zero(), SelectionGoal::None);
12151        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12152        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12153            s.select(vec![selection]);
12154        });
12155    }
12156
12157    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12158        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12159            cx.propagate();
12160            return;
12161        }
12162        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12163        let cursor = self.buffer.read(cx).read(cx).len();
12164        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12165            s.select_ranges(vec![cursor..cursor])
12166        });
12167    }
12168
12169    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12170        self.nav_history = nav_history;
12171    }
12172
12173    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12174        self.nav_history.as_ref()
12175    }
12176
12177    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12178        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12179    }
12180
12181    fn push_to_nav_history(
12182        &mut self,
12183        cursor_anchor: Anchor,
12184        new_position: Option<Point>,
12185        is_deactivate: bool,
12186        cx: &mut Context<Self>,
12187    ) {
12188        if let Some(nav_history) = self.nav_history.as_mut() {
12189            let buffer = self.buffer.read(cx).read(cx);
12190            let cursor_position = cursor_anchor.to_point(&buffer);
12191            let scroll_state = self.scroll_manager.anchor();
12192            let scroll_top_row = scroll_state.top_row(&buffer);
12193            drop(buffer);
12194
12195            if let Some(new_position) = new_position {
12196                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12197                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12198                    return;
12199                }
12200            }
12201
12202            nav_history.push(
12203                Some(NavigationData {
12204                    cursor_anchor,
12205                    cursor_position,
12206                    scroll_anchor: scroll_state,
12207                    scroll_top_row,
12208                }),
12209                cx,
12210            );
12211            cx.emit(EditorEvent::PushedToNavHistory {
12212                anchor: cursor_anchor,
12213                is_deactivate,
12214            })
12215        }
12216    }
12217
12218    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12219        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12220        let buffer = self.buffer.read(cx).snapshot(cx);
12221        let mut selection = self.selections.first::<usize>(cx);
12222        selection.set_head(buffer.len(), SelectionGoal::None);
12223        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12224            s.select(vec![selection]);
12225        });
12226    }
12227
12228    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12229        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12230        let end = self.buffer.read(cx).read(cx).len();
12231        self.change_selections(None, window, cx, |s| {
12232            s.select_ranges(vec![0..end]);
12233        });
12234    }
12235
12236    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12237        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12238        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12239        let mut selections = self.selections.all::<Point>(cx);
12240        let max_point = display_map.buffer_snapshot.max_point();
12241        for selection in &mut selections {
12242            let rows = selection.spanned_rows(true, &display_map);
12243            selection.start = Point::new(rows.start.0, 0);
12244            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12245            selection.reversed = false;
12246        }
12247        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12248            s.select(selections);
12249        });
12250    }
12251
12252    pub fn split_selection_into_lines(
12253        &mut self,
12254        _: &SplitSelectionIntoLines,
12255        window: &mut Window,
12256        cx: &mut Context<Self>,
12257    ) {
12258        let selections = self
12259            .selections
12260            .all::<Point>(cx)
12261            .into_iter()
12262            .map(|selection| selection.start..selection.end)
12263            .collect::<Vec<_>>();
12264        self.unfold_ranges(&selections, true, true, cx);
12265
12266        let mut new_selection_ranges = Vec::new();
12267        {
12268            let buffer = self.buffer.read(cx).read(cx);
12269            for selection in selections {
12270                for row in selection.start.row..selection.end.row {
12271                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12272                    new_selection_ranges.push(cursor..cursor);
12273                }
12274
12275                let is_multiline_selection = selection.start.row != selection.end.row;
12276                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12277                // so this action feels more ergonomic when paired with other selection operations
12278                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12279                if !should_skip_last {
12280                    new_selection_ranges.push(selection.end..selection.end);
12281                }
12282            }
12283        }
12284        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12285            s.select_ranges(new_selection_ranges);
12286        });
12287    }
12288
12289    pub fn add_selection_above(
12290        &mut self,
12291        _: &AddSelectionAbove,
12292        window: &mut Window,
12293        cx: &mut Context<Self>,
12294    ) {
12295        self.add_selection(true, window, cx);
12296    }
12297
12298    pub fn add_selection_below(
12299        &mut self,
12300        _: &AddSelectionBelow,
12301        window: &mut Window,
12302        cx: &mut Context<Self>,
12303    ) {
12304        self.add_selection(false, window, cx);
12305    }
12306
12307    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12308        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12309
12310        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12311        let mut selections = self.selections.all::<Point>(cx);
12312        let text_layout_details = self.text_layout_details(window);
12313        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12314            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12315            let range = oldest_selection.display_range(&display_map).sorted();
12316
12317            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12318            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12319            let positions = start_x.min(end_x)..start_x.max(end_x);
12320
12321            selections.clear();
12322            let mut stack = Vec::new();
12323            for row in range.start.row().0..=range.end.row().0 {
12324                if let Some(selection) = self.selections.build_columnar_selection(
12325                    &display_map,
12326                    DisplayRow(row),
12327                    &positions,
12328                    oldest_selection.reversed,
12329                    &text_layout_details,
12330                ) {
12331                    stack.push(selection.id);
12332                    selections.push(selection);
12333                }
12334            }
12335
12336            if above {
12337                stack.reverse();
12338            }
12339
12340            AddSelectionsState { above, stack }
12341        });
12342
12343        let last_added_selection = *state.stack.last().unwrap();
12344        let mut new_selections = Vec::new();
12345        if above == state.above {
12346            let end_row = if above {
12347                DisplayRow(0)
12348            } else {
12349                display_map.max_point().row()
12350            };
12351
12352            'outer: for selection in selections {
12353                if selection.id == last_added_selection {
12354                    let range = selection.display_range(&display_map).sorted();
12355                    debug_assert_eq!(range.start.row(), range.end.row());
12356                    let mut row = range.start.row();
12357                    let positions =
12358                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12359                            px(start)..px(end)
12360                        } else {
12361                            let start_x =
12362                                display_map.x_for_display_point(range.start, &text_layout_details);
12363                            let end_x =
12364                                display_map.x_for_display_point(range.end, &text_layout_details);
12365                            start_x.min(end_x)..start_x.max(end_x)
12366                        };
12367
12368                    while row != end_row {
12369                        if above {
12370                            row.0 -= 1;
12371                        } else {
12372                            row.0 += 1;
12373                        }
12374
12375                        if let Some(new_selection) = self.selections.build_columnar_selection(
12376                            &display_map,
12377                            row,
12378                            &positions,
12379                            selection.reversed,
12380                            &text_layout_details,
12381                        ) {
12382                            state.stack.push(new_selection.id);
12383                            if above {
12384                                new_selections.push(new_selection);
12385                                new_selections.push(selection);
12386                            } else {
12387                                new_selections.push(selection);
12388                                new_selections.push(new_selection);
12389                            }
12390
12391                            continue 'outer;
12392                        }
12393                    }
12394                }
12395
12396                new_selections.push(selection);
12397            }
12398        } else {
12399            new_selections = selections;
12400            new_selections.retain(|s| s.id != last_added_selection);
12401            state.stack.pop();
12402        }
12403
12404        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12405            s.select(new_selections);
12406        });
12407        if state.stack.len() > 1 {
12408            self.add_selections_state = Some(state);
12409        }
12410    }
12411
12412    fn select_match_ranges(
12413        &mut self,
12414        range: Range<usize>,
12415        reversed: bool,
12416        replace_newest: bool,
12417        auto_scroll: Option<Autoscroll>,
12418        window: &mut Window,
12419        cx: &mut Context<Editor>,
12420    ) {
12421        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12422        self.change_selections(auto_scroll, window, cx, |s| {
12423            if replace_newest {
12424                s.delete(s.newest_anchor().id);
12425            }
12426            if reversed {
12427                s.insert_range(range.end..range.start);
12428            } else {
12429                s.insert_range(range);
12430            }
12431        });
12432    }
12433
12434    pub fn select_next_match_internal(
12435        &mut self,
12436        display_map: &DisplaySnapshot,
12437        replace_newest: bool,
12438        autoscroll: Option<Autoscroll>,
12439        window: &mut Window,
12440        cx: &mut Context<Self>,
12441    ) -> Result<()> {
12442        let buffer = &display_map.buffer_snapshot;
12443        let mut selections = self.selections.all::<usize>(cx);
12444        if let Some(mut select_next_state) = self.select_next_state.take() {
12445            let query = &select_next_state.query;
12446            if !select_next_state.done {
12447                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12448                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12449                let mut next_selected_range = None;
12450
12451                let bytes_after_last_selection =
12452                    buffer.bytes_in_range(last_selection.end..buffer.len());
12453                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12454                let query_matches = query
12455                    .stream_find_iter(bytes_after_last_selection)
12456                    .map(|result| (last_selection.end, result))
12457                    .chain(
12458                        query
12459                            .stream_find_iter(bytes_before_first_selection)
12460                            .map(|result| (0, result)),
12461                    );
12462
12463                for (start_offset, query_match) in query_matches {
12464                    let query_match = query_match.unwrap(); // can only fail due to I/O
12465                    let offset_range =
12466                        start_offset + query_match.start()..start_offset + query_match.end();
12467                    let display_range = offset_range.start.to_display_point(display_map)
12468                        ..offset_range.end.to_display_point(display_map);
12469
12470                    if !select_next_state.wordwise
12471                        || (!movement::is_inside_word(display_map, display_range.start)
12472                            && !movement::is_inside_word(display_map, display_range.end))
12473                    {
12474                        // TODO: This is n^2, because we might check all the selections
12475                        if !selections
12476                            .iter()
12477                            .any(|selection| selection.range().overlaps(&offset_range))
12478                        {
12479                            next_selected_range = Some(offset_range);
12480                            break;
12481                        }
12482                    }
12483                }
12484
12485                if let Some(next_selected_range) = next_selected_range {
12486                    self.select_match_ranges(
12487                        next_selected_range,
12488                        last_selection.reversed,
12489                        replace_newest,
12490                        autoscroll,
12491                        window,
12492                        cx,
12493                    );
12494                } else {
12495                    select_next_state.done = true;
12496                }
12497            }
12498
12499            self.select_next_state = Some(select_next_state);
12500        } else {
12501            let mut only_carets = true;
12502            let mut same_text_selected = true;
12503            let mut selected_text = None;
12504
12505            let mut selections_iter = selections.iter().peekable();
12506            while let Some(selection) = selections_iter.next() {
12507                if selection.start != selection.end {
12508                    only_carets = false;
12509                }
12510
12511                if same_text_selected {
12512                    if selected_text.is_none() {
12513                        selected_text =
12514                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12515                    }
12516
12517                    if let Some(next_selection) = selections_iter.peek() {
12518                        if next_selection.range().len() == selection.range().len() {
12519                            let next_selected_text = buffer
12520                                .text_for_range(next_selection.range())
12521                                .collect::<String>();
12522                            if Some(next_selected_text) != selected_text {
12523                                same_text_selected = false;
12524                                selected_text = None;
12525                            }
12526                        } else {
12527                            same_text_selected = false;
12528                            selected_text = None;
12529                        }
12530                    }
12531                }
12532            }
12533
12534            if only_carets {
12535                for selection in &mut selections {
12536                    let word_range = movement::surrounding_word(
12537                        display_map,
12538                        selection.start.to_display_point(display_map),
12539                    );
12540                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12541                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12542                    selection.goal = SelectionGoal::None;
12543                    selection.reversed = false;
12544                    self.select_match_ranges(
12545                        selection.start..selection.end,
12546                        selection.reversed,
12547                        replace_newest,
12548                        autoscroll,
12549                        window,
12550                        cx,
12551                    );
12552                }
12553
12554                if selections.len() == 1 {
12555                    let selection = selections
12556                        .last()
12557                        .expect("ensured that there's only one selection");
12558                    let query = buffer
12559                        .text_for_range(selection.start..selection.end)
12560                        .collect::<String>();
12561                    let is_empty = query.is_empty();
12562                    let select_state = SelectNextState {
12563                        query: AhoCorasick::new(&[query])?,
12564                        wordwise: true,
12565                        done: is_empty,
12566                    };
12567                    self.select_next_state = Some(select_state);
12568                } else {
12569                    self.select_next_state = None;
12570                }
12571            } else if let Some(selected_text) = selected_text {
12572                self.select_next_state = Some(SelectNextState {
12573                    query: AhoCorasick::new(&[selected_text])?,
12574                    wordwise: false,
12575                    done: false,
12576                });
12577                self.select_next_match_internal(
12578                    display_map,
12579                    replace_newest,
12580                    autoscroll,
12581                    window,
12582                    cx,
12583                )?;
12584            }
12585        }
12586        Ok(())
12587    }
12588
12589    pub fn select_all_matches(
12590        &mut self,
12591        _action: &SelectAllMatches,
12592        window: &mut Window,
12593        cx: &mut Context<Self>,
12594    ) -> Result<()> {
12595        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12596
12597        self.push_to_selection_history();
12598        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12599
12600        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12601        let Some(select_next_state) = self.select_next_state.as_mut() else {
12602            return Ok(());
12603        };
12604        if select_next_state.done {
12605            return Ok(());
12606        }
12607
12608        let mut new_selections = Vec::new();
12609
12610        let reversed = self.selections.oldest::<usize>(cx).reversed;
12611        let buffer = &display_map.buffer_snapshot;
12612        let query_matches = select_next_state
12613            .query
12614            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12615
12616        for query_match in query_matches.into_iter() {
12617            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12618            let offset_range = if reversed {
12619                query_match.end()..query_match.start()
12620            } else {
12621                query_match.start()..query_match.end()
12622            };
12623            let display_range = offset_range.start.to_display_point(&display_map)
12624                ..offset_range.end.to_display_point(&display_map);
12625
12626            if !select_next_state.wordwise
12627                || (!movement::is_inside_word(&display_map, display_range.start)
12628                    && !movement::is_inside_word(&display_map, display_range.end))
12629            {
12630                new_selections.push(offset_range.start..offset_range.end);
12631            }
12632        }
12633
12634        select_next_state.done = true;
12635        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12636        self.change_selections(None, window, cx, |selections| {
12637            selections.select_ranges(new_selections)
12638        });
12639
12640        Ok(())
12641    }
12642
12643    pub fn select_next(
12644        &mut self,
12645        action: &SelectNext,
12646        window: &mut Window,
12647        cx: &mut Context<Self>,
12648    ) -> Result<()> {
12649        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12650        self.push_to_selection_history();
12651        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12652        self.select_next_match_internal(
12653            &display_map,
12654            action.replace_newest,
12655            Some(Autoscroll::newest()),
12656            window,
12657            cx,
12658        )?;
12659        Ok(())
12660    }
12661
12662    pub fn select_previous(
12663        &mut self,
12664        action: &SelectPrevious,
12665        window: &mut Window,
12666        cx: &mut Context<Self>,
12667    ) -> Result<()> {
12668        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12669        self.push_to_selection_history();
12670        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12671        let buffer = &display_map.buffer_snapshot;
12672        let mut selections = self.selections.all::<usize>(cx);
12673        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12674            let query = &select_prev_state.query;
12675            if !select_prev_state.done {
12676                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12677                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12678                let mut next_selected_range = None;
12679                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12680                let bytes_before_last_selection =
12681                    buffer.reversed_bytes_in_range(0..last_selection.start);
12682                let bytes_after_first_selection =
12683                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12684                let query_matches = query
12685                    .stream_find_iter(bytes_before_last_selection)
12686                    .map(|result| (last_selection.start, result))
12687                    .chain(
12688                        query
12689                            .stream_find_iter(bytes_after_first_selection)
12690                            .map(|result| (buffer.len(), result)),
12691                    );
12692                for (end_offset, query_match) in query_matches {
12693                    let query_match = query_match.unwrap(); // can only fail due to I/O
12694                    let offset_range =
12695                        end_offset - query_match.end()..end_offset - query_match.start();
12696                    let display_range = offset_range.start.to_display_point(&display_map)
12697                        ..offset_range.end.to_display_point(&display_map);
12698
12699                    if !select_prev_state.wordwise
12700                        || (!movement::is_inside_word(&display_map, display_range.start)
12701                            && !movement::is_inside_word(&display_map, display_range.end))
12702                    {
12703                        next_selected_range = Some(offset_range);
12704                        break;
12705                    }
12706                }
12707
12708                if let Some(next_selected_range) = next_selected_range {
12709                    self.select_match_ranges(
12710                        next_selected_range,
12711                        last_selection.reversed,
12712                        action.replace_newest,
12713                        Some(Autoscroll::newest()),
12714                        window,
12715                        cx,
12716                    );
12717                } else {
12718                    select_prev_state.done = true;
12719                }
12720            }
12721
12722            self.select_prev_state = Some(select_prev_state);
12723        } else {
12724            let mut only_carets = true;
12725            let mut same_text_selected = true;
12726            let mut selected_text = None;
12727
12728            let mut selections_iter = selections.iter().peekable();
12729            while let Some(selection) = selections_iter.next() {
12730                if selection.start != selection.end {
12731                    only_carets = false;
12732                }
12733
12734                if same_text_selected {
12735                    if selected_text.is_none() {
12736                        selected_text =
12737                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12738                    }
12739
12740                    if let Some(next_selection) = selections_iter.peek() {
12741                        if next_selection.range().len() == selection.range().len() {
12742                            let next_selected_text = buffer
12743                                .text_for_range(next_selection.range())
12744                                .collect::<String>();
12745                            if Some(next_selected_text) != selected_text {
12746                                same_text_selected = false;
12747                                selected_text = None;
12748                            }
12749                        } else {
12750                            same_text_selected = false;
12751                            selected_text = None;
12752                        }
12753                    }
12754                }
12755            }
12756
12757            if only_carets {
12758                for selection in &mut selections {
12759                    let word_range = movement::surrounding_word(
12760                        &display_map,
12761                        selection.start.to_display_point(&display_map),
12762                    );
12763                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12764                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12765                    selection.goal = SelectionGoal::None;
12766                    selection.reversed = false;
12767                    self.select_match_ranges(
12768                        selection.start..selection.end,
12769                        selection.reversed,
12770                        action.replace_newest,
12771                        Some(Autoscroll::newest()),
12772                        window,
12773                        cx,
12774                    );
12775                }
12776                if selections.len() == 1 {
12777                    let selection = selections
12778                        .last()
12779                        .expect("ensured that there's only one selection");
12780                    let query = buffer
12781                        .text_for_range(selection.start..selection.end)
12782                        .collect::<String>();
12783                    let is_empty = query.is_empty();
12784                    let select_state = SelectNextState {
12785                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12786                        wordwise: true,
12787                        done: is_empty,
12788                    };
12789                    self.select_prev_state = Some(select_state);
12790                } else {
12791                    self.select_prev_state = None;
12792                }
12793            } else if let Some(selected_text) = selected_text {
12794                self.select_prev_state = Some(SelectNextState {
12795                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12796                    wordwise: false,
12797                    done: false,
12798                });
12799                self.select_previous(action, window, cx)?;
12800            }
12801        }
12802        Ok(())
12803    }
12804
12805    pub fn find_next_match(
12806        &mut self,
12807        _: &FindNextMatch,
12808        window: &mut Window,
12809        cx: &mut Context<Self>,
12810    ) -> Result<()> {
12811        let selections = self.selections.disjoint_anchors();
12812        match selections.first() {
12813            Some(first) if selections.len() >= 2 => {
12814                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12815                    s.select_ranges([first.range()]);
12816                });
12817            }
12818            _ => self.select_next(
12819                &SelectNext {
12820                    replace_newest: true,
12821                },
12822                window,
12823                cx,
12824            )?,
12825        }
12826        Ok(())
12827    }
12828
12829    pub fn find_previous_match(
12830        &mut self,
12831        _: &FindPreviousMatch,
12832        window: &mut Window,
12833        cx: &mut Context<Self>,
12834    ) -> Result<()> {
12835        let selections = self.selections.disjoint_anchors();
12836        match selections.last() {
12837            Some(last) if selections.len() >= 2 => {
12838                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12839                    s.select_ranges([last.range()]);
12840                });
12841            }
12842            _ => self.select_previous(
12843                &SelectPrevious {
12844                    replace_newest: true,
12845                },
12846                window,
12847                cx,
12848            )?,
12849        }
12850        Ok(())
12851    }
12852
12853    pub fn toggle_comments(
12854        &mut self,
12855        action: &ToggleComments,
12856        window: &mut Window,
12857        cx: &mut Context<Self>,
12858    ) {
12859        if self.read_only(cx) {
12860            return;
12861        }
12862        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12863        let text_layout_details = &self.text_layout_details(window);
12864        self.transact(window, cx, |this, window, cx| {
12865            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12866            let mut edits = Vec::new();
12867            let mut selection_edit_ranges = Vec::new();
12868            let mut last_toggled_row = None;
12869            let snapshot = this.buffer.read(cx).read(cx);
12870            let empty_str: Arc<str> = Arc::default();
12871            let mut suffixes_inserted = Vec::new();
12872            let ignore_indent = action.ignore_indent;
12873
12874            fn comment_prefix_range(
12875                snapshot: &MultiBufferSnapshot,
12876                row: MultiBufferRow,
12877                comment_prefix: &str,
12878                comment_prefix_whitespace: &str,
12879                ignore_indent: bool,
12880            ) -> Range<Point> {
12881                let indent_size = if ignore_indent {
12882                    0
12883                } else {
12884                    snapshot.indent_size_for_line(row).len
12885                };
12886
12887                let start = Point::new(row.0, indent_size);
12888
12889                let mut line_bytes = snapshot
12890                    .bytes_in_range(start..snapshot.max_point())
12891                    .flatten()
12892                    .copied();
12893
12894                // If this line currently begins with the line comment prefix, then record
12895                // the range containing the prefix.
12896                if line_bytes
12897                    .by_ref()
12898                    .take(comment_prefix.len())
12899                    .eq(comment_prefix.bytes())
12900                {
12901                    // Include any whitespace that matches the comment prefix.
12902                    let matching_whitespace_len = line_bytes
12903                        .zip(comment_prefix_whitespace.bytes())
12904                        .take_while(|(a, b)| a == b)
12905                        .count() as u32;
12906                    let end = Point::new(
12907                        start.row,
12908                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12909                    );
12910                    start..end
12911                } else {
12912                    start..start
12913                }
12914            }
12915
12916            fn comment_suffix_range(
12917                snapshot: &MultiBufferSnapshot,
12918                row: MultiBufferRow,
12919                comment_suffix: &str,
12920                comment_suffix_has_leading_space: bool,
12921            ) -> Range<Point> {
12922                let end = Point::new(row.0, snapshot.line_len(row));
12923                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12924
12925                let mut line_end_bytes = snapshot
12926                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12927                    .flatten()
12928                    .copied();
12929
12930                let leading_space_len = if suffix_start_column > 0
12931                    && line_end_bytes.next() == Some(b' ')
12932                    && comment_suffix_has_leading_space
12933                {
12934                    1
12935                } else {
12936                    0
12937                };
12938
12939                // If this line currently begins with the line comment prefix, then record
12940                // the range containing the prefix.
12941                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12942                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12943                    start..end
12944                } else {
12945                    end..end
12946                }
12947            }
12948
12949            // TODO: Handle selections that cross excerpts
12950            for selection in &mut selections {
12951                let start_column = snapshot
12952                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12953                    .len;
12954                let language = if let Some(language) =
12955                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12956                {
12957                    language
12958                } else {
12959                    continue;
12960                };
12961
12962                selection_edit_ranges.clear();
12963
12964                // If multiple selections contain a given row, avoid processing that
12965                // row more than once.
12966                let mut start_row = MultiBufferRow(selection.start.row);
12967                if last_toggled_row == Some(start_row) {
12968                    start_row = start_row.next_row();
12969                }
12970                let end_row =
12971                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12972                        MultiBufferRow(selection.end.row - 1)
12973                    } else {
12974                        MultiBufferRow(selection.end.row)
12975                    };
12976                last_toggled_row = Some(end_row);
12977
12978                if start_row > end_row {
12979                    continue;
12980                }
12981
12982                // If the language has line comments, toggle those.
12983                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12984
12985                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12986                if ignore_indent {
12987                    full_comment_prefixes = full_comment_prefixes
12988                        .into_iter()
12989                        .map(|s| Arc::from(s.trim_end()))
12990                        .collect();
12991                }
12992
12993                if !full_comment_prefixes.is_empty() {
12994                    let first_prefix = full_comment_prefixes
12995                        .first()
12996                        .expect("prefixes is non-empty");
12997                    let prefix_trimmed_lengths = full_comment_prefixes
12998                        .iter()
12999                        .map(|p| p.trim_end_matches(' ').len())
13000                        .collect::<SmallVec<[usize; 4]>>();
13001
13002                    let mut all_selection_lines_are_comments = true;
13003
13004                    for row in start_row.0..=end_row.0 {
13005                        let row = MultiBufferRow(row);
13006                        if start_row < end_row && snapshot.is_line_blank(row) {
13007                            continue;
13008                        }
13009
13010                        let prefix_range = full_comment_prefixes
13011                            .iter()
13012                            .zip(prefix_trimmed_lengths.iter().copied())
13013                            .map(|(prefix, trimmed_prefix_len)| {
13014                                comment_prefix_range(
13015                                    snapshot.deref(),
13016                                    row,
13017                                    &prefix[..trimmed_prefix_len],
13018                                    &prefix[trimmed_prefix_len..],
13019                                    ignore_indent,
13020                                )
13021                            })
13022                            .max_by_key(|range| range.end.column - range.start.column)
13023                            .expect("prefixes is non-empty");
13024
13025                        if prefix_range.is_empty() {
13026                            all_selection_lines_are_comments = false;
13027                        }
13028
13029                        selection_edit_ranges.push(prefix_range);
13030                    }
13031
13032                    if all_selection_lines_are_comments {
13033                        edits.extend(
13034                            selection_edit_ranges
13035                                .iter()
13036                                .cloned()
13037                                .map(|range| (range, empty_str.clone())),
13038                        );
13039                    } else {
13040                        let min_column = selection_edit_ranges
13041                            .iter()
13042                            .map(|range| range.start.column)
13043                            .min()
13044                            .unwrap_or(0);
13045                        edits.extend(selection_edit_ranges.iter().map(|range| {
13046                            let position = Point::new(range.start.row, min_column);
13047                            (position..position, first_prefix.clone())
13048                        }));
13049                    }
13050                } else if let Some((full_comment_prefix, comment_suffix)) =
13051                    language.block_comment_delimiters()
13052                {
13053                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13054                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13055                    let prefix_range = comment_prefix_range(
13056                        snapshot.deref(),
13057                        start_row,
13058                        comment_prefix,
13059                        comment_prefix_whitespace,
13060                        ignore_indent,
13061                    );
13062                    let suffix_range = comment_suffix_range(
13063                        snapshot.deref(),
13064                        end_row,
13065                        comment_suffix.trim_start_matches(' '),
13066                        comment_suffix.starts_with(' '),
13067                    );
13068
13069                    if prefix_range.is_empty() || suffix_range.is_empty() {
13070                        edits.push((
13071                            prefix_range.start..prefix_range.start,
13072                            full_comment_prefix.clone(),
13073                        ));
13074                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13075                        suffixes_inserted.push((end_row, comment_suffix.len()));
13076                    } else {
13077                        edits.push((prefix_range, empty_str.clone()));
13078                        edits.push((suffix_range, empty_str.clone()));
13079                    }
13080                } else {
13081                    continue;
13082                }
13083            }
13084
13085            drop(snapshot);
13086            this.buffer.update(cx, |buffer, cx| {
13087                buffer.edit(edits, None, cx);
13088            });
13089
13090            // Adjust selections so that they end before any comment suffixes that
13091            // were inserted.
13092            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13093            let mut selections = this.selections.all::<Point>(cx);
13094            let snapshot = this.buffer.read(cx).read(cx);
13095            for selection in &mut selections {
13096                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13097                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13098                        Ordering::Less => {
13099                            suffixes_inserted.next();
13100                            continue;
13101                        }
13102                        Ordering::Greater => break,
13103                        Ordering::Equal => {
13104                            if selection.end.column == snapshot.line_len(row) {
13105                                if selection.is_empty() {
13106                                    selection.start.column -= suffix_len as u32;
13107                                }
13108                                selection.end.column -= suffix_len as u32;
13109                            }
13110                            break;
13111                        }
13112                    }
13113                }
13114            }
13115
13116            drop(snapshot);
13117            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13118                s.select(selections)
13119            });
13120
13121            let selections = this.selections.all::<Point>(cx);
13122            let selections_on_single_row = selections.windows(2).all(|selections| {
13123                selections[0].start.row == selections[1].start.row
13124                    && selections[0].end.row == selections[1].end.row
13125                    && selections[0].start.row == selections[0].end.row
13126            });
13127            let selections_selecting = selections
13128                .iter()
13129                .any(|selection| selection.start != selection.end);
13130            let advance_downwards = action.advance_downwards
13131                && selections_on_single_row
13132                && !selections_selecting
13133                && !matches!(this.mode, EditorMode::SingleLine { .. });
13134
13135            if advance_downwards {
13136                let snapshot = this.buffer.read(cx).snapshot(cx);
13137
13138                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13139                    s.move_cursors_with(|display_snapshot, display_point, _| {
13140                        let mut point = display_point.to_point(display_snapshot);
13141                        point.row += 1;
13142                        point = snapshot.clip_point(point, Bias::Left);
13143                        let display_point = point.to_display_point(display_snapshot);
13144                        let goal = SelectionGoal::HorizontalPosition(
13145                            display_snapshot
13146                                .x_for_display_point(display_point, text_layout_details)
13147                                .into(),
13148                        );
13149                        (display_point, goal)
13150                    })
13151                });
13152            }
13153        });
13154    }
13155
13156    pub fn select_enclosing_symbol(
13157        &mut self,
13158        _: &SelectEnclosingSymbol,
13159        window: &mut Window,
13160        cx: &mut Context<Self>,
13161    ) {
13162        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13163
13164        let buffer = self.buffer.read(cx).snapshot(cx);
13165        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13166
13167        fn update_selection(
13168            selection: &Selection<usize>,
13169            buffer_snap: &MultiBufferSnapshot,
13170        ) -> Option<Selection<usize>> {
13171            let cursor = selection.head();
13172            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13173            for symbol in symbols.iter().rev() {
13174                let start = symbol.range.start.to_offset(buffer_snap);
13175                let end = symbol.range.end.to_offset(buffer_snap);
13176                let new_range = start..end;
13177                if start < selection.start || end > selection.end {
13178                    return Some(Selection {
13179                        id: selection.id,
13180                        start: new_range.start,
13181                        end: new_range.end,
13182                        goal: SelectionGoal::None,
13183                        reversed: selection.reversed,
13184                    });
13185                }
13186            }
13187            None
13188        }
13189
13190        let mut selected_larger_symbol = false;
13191        let new_selections = old_selections
13192            .iter()
13193            .map(|selection| match update_selection(selection, &buffer) {
13194                Some(new_selection) => {
13195                    if new_selection.range() != selection.range() {
13196                        selected_larger_symbol = true;
13197                    }
13198                    new_selection
13199                }
13200                None => selection.clone(),
13201            })
13202            .collect::<Vec<_>>();
13203
13204        if selected_larger_symbol {
13205            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13206                s.select(new_selections);
13207            });
13208        }
13209    }
13210
13211    pub fn select_larger_syntax_node(
13212        &mut self,
13213        _: &SelectLargerSyntaxNode,
13214        window: &mut Window,
13215        cx: &mut Context<Self>,
13216    ) {
13217        let Some(visible_row_count) = self.visible_row_count() else {
13218            return;
13219        };
13220        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13221        if old_selections.is_empty() {
13222            return;
13223        }
13224
13225        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13226
13227        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13228        let buffer = self.buffer.read(cx).snapshot(cx);
13229
13230        let mut selected_larger_node = false;
13231        let mut new_selections = old_selections
13232            .iter()
13233            .map(|selection| {
13234                let old_range = selection.start..selection.end;
13235
13236                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13237                    // manually select word at selection
13238                    if ["string_content", "inline"].contains(&node.kind()) {
13239                        let word_range = {
13240                            let display_point = buffer
13241                                .offset_to_point(old_range.start)
13242                                .to_display_point(&display_map);
13243                            let Range { start, end } =
13244                                movement::surrounding_word(&display_map, display_point);
13245                            start.to_point(&display_map).to_offset(&buffer)
13246                                ..end.to_point(&display_map).to_offset(&buffer)
13247                        };
13248                        // ignore if word is already selected
13249                        if !word_range.is_empty() && old_range != word_range {
13250                            let last_word_range = {
13251                                let display_point = buffer
13252                                    .offset_to_point(old_range.end)
13253                                    .to_display_point(&display_map);
13254                                let Range { start, end } =
13255                                    movement::surrounding_word(&display_map, display_point);
13256                                start.to_point(&display_map).to_offset(&buffer)
13257                                    ..end.to_point(&display_map).to_offset(&buffer)
13258                            };
13259                            // only select word if start and end point belongs to same word
13260                            if word_range == last_word_range {
13261                                selected_larger_node = true;
13262                                return Selection {
13263                                    id: selection.id,
13264                                    start: word_range.start,
13265                                    end: word_range.end,
13266                                    goal: SelectionGoal::None,
13267                                    reversed: selection.reversed,
13268                                };
13269                            }
13270                        }
13271                    }
13272                }
13273
13274                let mut new_range = old_range.clone();
13275                while let Some((_node, containing_range)) =
13276                    buffer.syntax_ancestor(new_range.clone())
13277                {
13278                    new_range = match containing_range {
13279                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13280                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13281                    };
13282                    if !display_map.intersects_fold(new_range.start)
13283                        && !display_map.intersects_fold(new_range.end)
13284                    {
13285                        break;
13286                    }
13287                }
13288
13289                selected_larger_node |= new_range != old_range;
13290                Selection {
13291                    id: selection.id,
13292                    start: new_range.start,
13293                    end: new_range.end,
13294                    goal: SelectionGoal::None,
13295                    reversed: selection.reversed,
13296                }
13297            })
13298            .collect::<Vec<_>>();
13299
13300        if !selected_larger_node {
13301            return; // don't put this call in the history
13302        }
13303
13304        // scroll based on transformation done to the last selection created by the user
13305        let (last_old, last_new) = old_selections
13306            .last()
13307            .zip(new_selections.last().cloned())
13308            .expect("old_selections isn't empty");
13309
13310        // revert selection
13311        let is_selection_reversed = {
13312            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13313            new_selections.last_mut().expect("checked above").reversed =
13314                should_newest_selection_be_reversed;
13315            should_newest_selection_be_reversed
13316        };
13317
13318        if selected_larger_node {
13319            self.select_syntax_node_history.disable_clearing = true;
13320            self.change_selections(None, window, cx, |s| {
13321                s.select(new_selections.clone());
13322            });
13323            self.select_syntax_node_history.disable_clearing = false;
13324        }
13325
13326        let start_row = last_new.start.to_display_point(&display_map).row().0;
13327        let end_row = last_new.end.to_display_point(&display_map).row().0;
13328        let selection_height = end_row - start_row + 1;
13329        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13330
13331        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13332        let scroll_behavior = if fits_on_the_screen {
13333            self.request_autoscroll(Autoscroll::fit(), cx);
13334            SelectSyntaxNodeScrollBehavior::FitSelection
13335        } else if is_selection_reversed {
13336            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13337            SelectSyntaxNodeScrollBehavior::CursorTop
13338        } else {
13339            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13340            SelectSyntaxNodeScrollBehavior::CursorBottom
13341        };
13342
13343        self.select_syntax_node_history.push((
13344            old_selections,
13345            scroll_behavior,
13346            is_selection_reversed,
13347        ));
13348    }
13349
13350    pub fn select_smaller_syntax_node(
13351        &mut self,
13352        _: &SelectSmallerSyntaxNode,
13353        window: &mut Window,
13354        cx: &mut Context<Self>,
13355    ) {
13356        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13357
13358        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13359            self.select_syntax_node_history.pop()
13360        {
13361            if let Some(selection) = selections.last_mut() {
13362                selection.reversed = is_selection_reversed;
13363            }
13364
13365            self.select_syntax_node_history.disable_clearing = true;
13366            self.change_selections(None, window, cx, |s| {
13367                s.select(selections.to_vec());
13368            });
13369            self.select_syntax_node_history.disable_clearing = false;
13370
13371            match scroll_behavior {
13372                SelectSyntaxNodeScrollBehavior::CursorTop => {
13373                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13374                }
13375                SelectSyntaxNodeScrollBehavior::FitSelection => {
13376                    self.request_autoscroll(Autoscroll::fit(), cx);
13377                }
13378                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13379                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13380                }
13381            }
13382        }
13383    }
13384
13385    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13386        if !EditorSettings::get_global(cx).gutter.runnables {
13387            self.clear_tasks();
13388            return Task::ready(());
13389        }
13390        let project = self.project.as_ref().map(Entity::downgrade);
13391        let task_sources = self.lsp_task_sources(cx);
13392        cx.spawn_in(window, async move |editor, cx| {
13393            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13394            let Some(project) = project.and_then(|p| p.upgrade()) else {
13395                return;
13396            };
13397            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13398                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13399            }) else {
13400                return;
13401            };
13402
13403            let hide_runnables = project
13404                .update(cx, |project, cx| {
13405                    // Do not display any test indicators in non-dev server remote projects.
13406                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13407                })
13408                .unwrap_or(true);
13409            if hide_runnables {
13410                return;
13411            }
13412            let new_rows =
13413                cx.background_spawn({
13414                    let snapshot = display_snapshot.clone();
13415                    async move {
13416                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13417                    }
13418                })
13419                    .await;
13420            let Ok(lsp_tasks) =
13421                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13422            else {
13423                return;
13424            };
13425            let lsp_tasks = lsp_tasks.await;
13426
13427            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13428                lsp_tasks
13429                    .into_iter()
13430                    .flat_map(|(kind, tasks)| {
13431                        tasks.into_iter().filter_map(move |(location, task)| {
13432                            Some((kind.clone(), location?, task))
13433                        })
13434                    })
13435                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13436                        let buffer = location.target.buffer;
13437                        let buffer_snapshot = buffer.read(cx).snapshot();
13438                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13439                            |(excerpt_id, snapshot, _)| {
13440                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13441                                    display_snapshot
13442                                        .buffer_snapshot
13443                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13444                                } else {
13445                                    None
13446                                }
13447                            },
13448                        );
13449                        if let Some(offset) = offset {
13450                            let task_buffer_range =
13451                                location.target.range.to_point(&buffer_snapshot);
13452                            let context_buffer_range =
13453                                task_buffer_range.to_offset(&buffer_snapshot);
13454                            let context_range = BufferOffset(context_buffer_range.start)
13455                                ..BufferOffset(context_buffer_range.end);
13456
13457                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13458                                .or_insert_with(|| RunnableTasks {
13459                                    templates: Vec::new(),
13460                                    offset,
13461                                    column: task_buffer_range.start.column,
13462                                    extra_variables: HashMap::default(),
13463                                    context_range,
13464                                })
13465                                .templates
13466                                .push((kind, task.original_task().clone()));
13467                        }
13468
13469                        acc
13470                    })
13471            }) else {
13472                return;
13473            };
13474
13475            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13476            editor
13477                .update(cx, |editor, _| {
13478                    editor.clear_tasks();
13479                    for (key, mut value) in rows {
13480                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13481                            value.templates.extend(lsp_tasks.templates);
13482                        }
13483
13484                        editor.insert_tasks(key, value);
13485                    }
13486                    for (key, value) in lsp_tasks_by_rows {
13487                        editor.insert_tasks(key, value);
13488                    }
13489                })
13490                .ok();
13491        })
13492    }
13493    fn fetch_runnable_ranges(
13494        snapshot: &DisplaySnapshot,
13495        range: Range<Anchor>,
13496    ) -> Vec<language::RunnableRange> {
13497        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13498    }
13499
13500    fn runnable_rows(
13501        project: Entity<Project>,
13502        snapshot: DisplaySnapshot,
13503        runnable_ranges: Vec<RunnableRange>,
13504        mut cx: AsyncWindowContext,
13505    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13506        runnable_ranges
13507            .into_iter()
13508            .filter_map(|mut runnable| {
13509                let tasks = cx
13510                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13511                    .ok()?;
13512                if tasks.is_empty() {
13513                    return None;
13514                }
13515
13516                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13517
13518                let row = snapshot
13519                    .buffer_snapshot
13520                    .buffer_line_for_row(MultiBufferRow(point.row))?
13521                    .1
13522                    .start
13523                    .row;
13524
13525                let context_range =
13526                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13527                Some((
13528                    (runnable.buffer_id, row),
13529                    RunnableTasks {
13530                        templates: tasks,
13531                        offset: snapshot
13532                            .buffer_snapshot
13533                            .anchor_before(runnable.run_range.start),
13534                        context_range,
13535                        column: point.column,
13536                        extra_variables: runnable.extra_captures,
13537                    },
13538                ))
13539            })
13540            .collect()
13541    }
13542
13543    fn templates_with_tags(
13544        project: &Entity<Project>,
13545        runnable: &mut Runnable,
13546        cx: &mut App,
13547    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13548        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13549            let (worktree_id, file) = project
13550                .buffer_for_id(runnable.buffer, cx)
13551                .and_then(|buffer| buffer.read(cx).file())
13552                .map(|file| (file.worktree_id(cx), file.clone()))
13553                .unzip();
13554
13555            (
13556                project.task_store().read(cx).task_inventory().cloned(),
13557                worktree_id,
13558                file,
13559            )
13560        });
13561
13562        let mut templates_with_tags = mem::take(&mut runnable.tags)
13563            .into_iter()
13564            .flat_map(|RunnableTag(tag)| {
13565                inventory
13566                    .as_ref()
13567                    .into_iter()
13568                    .flat_map(|inventory| {
13569                        inventory.read(cx).list_tasks(
13570                            file.clone(),
13571                            Some(runnable.language.clone()),
13572                            worktree_id,
13573                            cx,
13574                        )
13575                    })
13576                    .filter(move |(_, template)| {
13577                        template.tags.iter().any(|source_tag| source_tag == &tag)
13578                    })
13579            })
13580            .sorted_by_key(|(kind, _)| kind.to_owned())
13581            .collect::<Vec<_>>();
13582        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13583            // Strongest source wins; if we have worktree tag binding, prefer that to
13584            // global and language bindings;
13585            // if we have a global binding, prefer that to language binding.
13586            let first_mismatch = templates_with_tags
13587                .iter()
13588                .position(|(tag_source, _)| tag_source != leading_tag_source);
13589            if let Some(index) = first_mismatch {
13590                templates_with_tags.truncate(index);
13591            }
13592        }
13593
13594        templates_with_tags
13595    }
13596
13597    pub fn move_to_enclosing_bracket(
13598        &mut self,
13599        _: &MoveToEnclosingBracket,
13600        window: &mut Window,
13601        cx: &mut Context<Self>,
13602    ) {
13603        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13604        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13605            s.move_offsets_with(|snapshot, selection| {
13606                let Some(enclosing_bracket_ranges) =
13607                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13608                else {
13609                    return;
13610                };
13611
13612                let mut best_length = usize::MAX;
13613                let mut best_inside = false;
13614                let mut best_in_bracket_range = false;
13615                let mut best_destination = None;
13616                for (open, close) in enclosing_bracket_ranges {
13617                    let close = close.to_inclusive();
13618                    let length = close.end() - open.start;
13619                    let inside = selection.start >= open.end && selection.end <= *close.start();
13620                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13621                        || close.contains(&selection.head());
13622
13623                    // If best is next to a bracket and current isn't, skip
13624                    if !in_bracket_range && best_in_bracket_range {
13625                        continue;
13626                    }
13627
13628                    // Prefer smaller lengths unless best is inside and current isn't
13629                    if length > best_length && (best_inside || !inside) {
13630                        continue;
13631                    }
13632
13633                    best_length = length;
13634                    best_inside = inside;
13635                    best_in_bracket_range = in_bracket_range;
13636                    best_destination = Some(
13637                        if close.contains(&selection.start) && close.contains(&selection.end) {
13638                            if inside { open.end } else { open.start }
13639                        } else if inside {
13640                            *close.start()
13641                        } else {
13642                            *close.end()
13643                        },
13644                    );
13645                }
13646
13647                if let Some(destination) = best_destination {
13648                    selection.collapse_to(destination, SelectionGoal::None);
13649                }
13650            })
13651        });
13652    }
13653
13654    pub fn undo_selection(
13655        &mut self,
13656        _: &UndoSelection,
13657        window: &mut Window,
13658        cx: &mut Context<Self>,
13659    ) {
13660        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13661        self.end_selection(window, cx);
13662        self.selection_history.mode = SelectionHistoryMode::Undoing;
13663        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13664            self.change_selections(None, window, cx, |s| {
13665                s.select_anchors(entry.selections.to_vec())
13666            });
13667            self.select_next_state = entry.select_next_state;
13668            self.select_prev_state = entry.select_prev_state;
13669            self.add_selections_state = entry.add_selections_state;
13670            self.request_autoscroll(Autoscroll::newest(), cx);
13671        }
13672        self.selection_history.mode = SelectionHistoryMode::Normal;
13673    }
13674
13675    pub fn redo_selection(
13676        &mut self,
13677        _: &RedoSelection,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) {
13681        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13682        self.end_selection(window, cx);
13683        self.selection_history.mode = SelectionHistoryMode::Redoing;
13684        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13685            self.change_selections(None, window, cx, |s| {
13686                s.select_anchors(entry.selections.to_vec())
13687            });
13688            self.select_next_state = entry.select_next_state;
13689            self.select_prev_state = entry.select_prev_state;
13690            self.add_selections_state = entry.add_selections_state;
13691            self.request_autoscroll(Autoscroll::newest(), cx);
13692        }
13693        self.selection_history.mode = SelectionHistoryMode::Normal;
13694    }
13695
13696    pub fn expand_excerpts(
13697        &mut self,
13698        action: &ExpandExcerpts,
13699        _: &mut Window,
13700        cx: &mut Context<Self>,
13701    ) {
13702        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13703    }
13704
13705    pub fn expand_excerpts_down(
13706        &mut self,
13707        action: &ExpandExcerptsDown,
13708        _: &mut Window,
13709        cx: &mut Context<Self>,
13710    ) {
13711        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13712    }
13713
13714    pub fn expand_excerpts_up(
13715        &mut self,
13716        action: &ExpandExcerptsUp,
13717        _: &mut Window,
13718        cx: &mut Context<Self>,
13719    ) {
13720        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13721    }
13722
13723    pub fn expand_excerpts_for_direction(
13724        &mut self,
13725        lines: u32,
13726        direction: ExpandExcerptDirection,
13727
13728        cx: &mut Context<Self>,
13729    ) {
13730        let selections = self.selections.disjoint_anchors();
13731
13732        let lines = if lines == 0 {
13733            EditorSettings::get_global(cx).expand_excerpt_lines
13734        } else {
13735            lines
13736        };
13737
13738        self.buffer.update(cx, |buffer, cx| {
13739            let snapshot = buffer.snapshot(cx);
13740            let mut excerpt_ids = selections
13741                .iter()
13742                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13743                .collect::<Vec<_>>();
13744            excerpt_ids.sort();
13745            excerpt_ids.dedup();
13746            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13747        })
13748    }
13749
13750    pub fn expand_excerpt(
13751        &mut self,
13752        excerpt: ExcerptId,
13753        direction: ExpandExcerptDirection,
13754        window: &mut Window,
13755        cx: &mut Context<Self>,
13756    ) {
13757        let current_scroll_position = self.scroll_position(cx);
13758        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13759        let mut should_scroll_up = false;
13760
13761        if direction == ExpandExcerptDirection::Down {
13762            let multi_buffer = self.buffer.read(cx);
13763            let snapshot = multi_buffer.snapshot(cx);
13764            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13765                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13766                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13767                        let buffer_snapshot = buffer.read(cx).snapshot();
13768                        let excerpt_end_row =
13769                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13770                        let last_row = buffer_snapshot.max_point().row;
13771                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13772                        should_scroll_up = lines_below >= lines_to_expand;
13773                    }
13774                }
13775            }
13776        }
13777
13778        self.buffer.update(cx, |buffer, cx| {
13779            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13780        });
13781
13782        if should_scroll_up {
13783            let new_scroll_position =
13784                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13785            self.set_scroll_position(new_scroll_position, window, cx);
13786        }
13787    }
13788
13789    pub fn go_to_singleton_buffer_point(
13790        &mut self,
13791        point: Point,
13792        window: &mut Window,
13793        cx: &mut Context<Self>,
13794    ) {
13795        self.go_to_singleton_buffer_range(point..point, window, cx);
13796    }
13797
13798    pub fn go_to_singleton_buffer_range(
13799        &mut self,
13800        range: Range<Point>,
13801        window: &mut Window,
13802        cx: &mut Context<Self>,
13803    ) {
13804        let multibuffer = self.buffer().read(cx);
13805        let Some(buffer) = multibuffer.as_singleton() else {
13806            return;
13807        };
13808        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13809            return;
13810        };
13811        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13812            return;
13813        };
13814        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13815            s.select_anchor_ranges([start..end])
13816        });
13817    }
13818
13819    pub fn go_to_diagnostic(
13820        &mut self,
13821        _: &GoToDiagnostic,
13822        window: &mut Window,
13823        cx: &mut Context<Self>,
13824    ) {
13825        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13826        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13827    }
13828
13829    pub fn go_to_prev_diagnostic(
13830        &mut self,
13831        _: &GoToPreviousDiagnostic,
13832        window: &mut Window,
13833        cx: &mut Context<Self>,
13834    ) {
13835        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13836        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13837    }
13838
13839    pub fn go_to_diagnostic_impl(
13840        &mut self,
13841        direction: Direction,
13842        window: &mut Window,
13843        cx: &mut Context<Self>,
13844    ) {
13845        let buffer = self.buffer.read(cx).snapshot(cx);
13846        let selection = self.selections.newest::<usize>(cx);
13847
13848        let mut active_group_id = None;
13849        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13850            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13851                active_group_id = Some(active_group.group_id);
13852            }
13853        }
13854
13855        fn filtered(
13856            snapshot: EditorSnapshot,
13857            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13858        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13859            diagnostics
13860                .filter(|entry| entry.range.start != entry.range.end)
13861                .filter(|entry| !entry.diagnostic.is_unnecessary)
13862                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13863        }
13864
13865        let snapshot = self.snapshot(window, cx);
13866        let before = filtered(
13867            snapshot.clone(),
13868            buffer
13869                .diagnostics_in_range(0..selection.start)
13870                .filter(|entry| entry.range.start <= selection.start),
13871        );
13872        let after = filtered(
13873            snapshot,
13874            buffer
13875                .diagnostics_in_range(selection.start..buffer.len())
13876                .filter(|entry| entry.range.start >= selection.start),
13877        );
13878
13879        let mut found: Option<DiagnosticEntry<usize>> = None;
13880        if direction == Direction::Prev {
13881            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13882            {
13883                for diagnostic in prev_diagnostics.into_iter().rev() {
13884                    if diagnostic.range.start != selection.start
13885                        || active_group_id
13886                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13887                    {
13888                        found = Some(diagnostic);
13889                        break 'outer;
13890                    }
13891                }
13892            }
13893        } else {
13894            for diagnostic in after.chain(before) {
13895                if diagnostic.range.start != selection.start
13896                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13897                {
13898                    found = Some(diagnostic);
13899                    break;
13900                }
13901            }
13902        }
13903        let Some(next_diagnostic) = found else {
13904            return;
13905        };
13906
13907        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13908            return;
13909        };
13910        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13911            s.select_ranges(vec![
13912                next_diagnostic.range.start..next_diagnostic.range.start,
13913            ])
13914        });
13915        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13916        self.refresh_inline_completion(false, true, window, cx);
13917    }
13918
13919    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13920        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13921        let snapshot = self.snapshot(window, cx);
13922        let selection = self.selections.newest::<Point>(cx);
13923        self.go_to_hunk_before_or_after_position(
13924            &snapshot,
13925            selection.head(),
13926            Direction::Next,
13927            window,
13928            cx,
13929        );
13930    }
13931
13932    pub fn go_to_hunk_before_or_after_position(
13933        &mut self,
13934        snapshot: &EditorSnapshot,
13935        position: Point,
13936        direction: Direction,
13937        window: &mut Window,
13938        cx: &mut Context<Editor>,
13939    ) {
13940        let row = if direction == Direction::Next {
13941            self.hunk_after_position(snapshot, position)
13942                .map(|hunk| hunk.row_range.start)
13943        } else {
13944            self.hunk_before_position(snapshot, position)
13945        };
13946
13947        if let Some(row) = row {
13948            let destination = Point::new(row.0, 0);
13949            let autoscroll = Autoscroll::center();
13950
13951            self.unfold_ranges(&[destination..destination], false, false, cx);
13952            self.change_selections(Some(autoscroll), window, cx, |s| {
13953                s.select_ranges([destination..destination]);
13954            });
13955        }
13956    }
13957
13958    fn hunk_after_position(
13959        &mut self,
13960        snapshot: &EditorSnapshot,
13961        position: Point,
13962    ) -> Option<MultiBufferDiffHunk> {
13963        snapshot
13964            .buffer_snapshot
13965            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13966            .find(|hunk| hunk.row_range.start.0 > position.row)
13967            .or_else(|| {
13968                snapshot
13969                    .buffer_snapshot
13970                    .diff_hunks_in_range(Point::zero()..position)
13971                    .find(|hunk| hunk.row_range.end.0 < position.row)
13972            })
13973    }
13974
13975    fn go_to_prev_hunk(
13976        &mut self,
13977        _: &GoToPreviousHunk,
13978        window: &mut Window,
13979        cx: &mut Context<Self>,
13980    ) {
13981        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13982        let snapshot = self.snapshot(window, cx);
13983        let selection = self.selections.newest::<Point>(cx);
13984        self.go_to_hunk_before_or_after_position(
13985            &snapshot,
13986            selection.head(),
13987            Direction::Prev,
13988            window,
13989            cx,
13990        );
13991    }
13992
13993    fn hunk_before_position(
13994        &mut self,
13995        snapshot: &EditorSnapshot,
13996        position: Point,
13997    ) -> Option<MultiBufferRow> {
13998        snapshot
13999            .buffer_snapshot
14000            .diff_hunk_before(position)
14001            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14002    }
14003
14004    fn go_to_next_change(
14005        &mut self,
14006        _: &GoToNextChange,
14007        window: &mut Window,
14008        cx: &mut Context<Self>,
14009    ) {
14010        if let Some(selections) = self
14011            .change_list
14012            .next_change(1, Direction::Next)
14013            .map(|s| s.to_vec())
14014        {
14015            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14016                let map = s.display_map();
14017                s.select_display_ranges(selections.iter().map(|a| {
14018                    let point = a.to_display_point(&map);
14019                    point..point
14020                }))
14021            })
14022        }
14023    }
14024
14025    fn go_to_previous_change(
14026        &mut self,
14027        _: &GoToPreviousChange,
14028        window: &mut Window,
14029        cx: &mut Context<Self>,
14030    ) {
14031        if let Some(selections) = self
14032            .change_list
14033            .next_change(1, Direction::Prev)
14034            .map(|s| s.to_vec())
14035        {
14036            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14037                let map = s.display_map();
14038                s.select_display_ranges(selections.iter().map(|a| {
14039                    let point = a.to_display_point(&map);
14040                    point..point
14041                }))
14042            })
14043        }
14044    }
14045
14046    fn go_to_line<T: 'static>(
14047        &mut self,
14048        position: Anchor,
14049        highlight_color: Option<Hsla>,
14050        window: &mut Window,
14051        cx: &mut Context<Self>,
14052    ) {
14053        let snapshot = self.snapshot(window, cx).display_snapshot;
14054        let position = position.to_point(&snapshot.buffer_snapshot);
14055        let start = snapshot
14056            .buffer_snapshot
14057            .clip_point(Point::new(position.row, 0), Bias::Left);
14058        let end = start + Point::new(1, 0);
14059        let start = snapshot.buffer_snapshot.anchor_before(start);
14060        let end = snapshot.buffer_snapshot.anchor_before(end);
14061
14062        self.highlight_rows::<T>(
14063            start..end,
14064            highlight_color
14065                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14066            Default::default(),
14067            cx,
14068        );
14069
14070        if self.buffer.read(cx).is_singleton() {
14071            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14072        }
14073    }
14074
14075    pub fn go_to_definition(
14076        &mut self,
14077        _: &GoToDefinition,
14078        window: &mut Window,
14079        cx: &mut Context<Self>,
14080    ) -> Task<Result<Navigated>> {
14081        let definition =
14082            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14083        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14084        cx.spawn_in(window, async move |editor, cx| {
14085            if definition.await? == Navigated::Yes {
14086                return Ok(Navigated::Yes);
14087            }
14088            match fallback_strategy {
14089                GoToDefinitionFallback::None => Ok(Navigated::No),
14090                GoToDefinitionFallback::FindAllReferences => {
14091                    match editor.update_in(cx, |editor, window, cx| {
14092                        editor.find_all_references(&FindAllReferences, window, cx)
14093                    })? {
14094                        Some(references) => references.await,
14095                        None => Ok(Navigated::No),
14096                    }
14097                }
14098            }
14099        })
14100    }
14101
14102    pub fn go_to_declaration(
14103        &mut self,
14104        _: &GoToDeclaration,
14105        window: &mut Window,
14106        cx: &mut Context<Self>,
14107    ) -> Task<Result<Navigated>> {
14108        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14109    }
14110
14111    pub fn go_to_declaration_split(
14112        &mut self,
14113        _: &GoToDeclaration,
14114        window: &mut Window,
14115        cx: &mut Context<Self>,
14116    ) -> Task<Result<Navigated>> {
14117        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14118    }
14119
14120    pub fn go_to_implementation(
14121        &mut self,
14122        _: &GoToImplementation,
14123        window: &mut Window,
14124        cx: &mut Context<Self>,
14125    ) -> Task<Result<Navigated>> {
14126        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14127    }
14128
14129    pub fn go_to_implementation_split(
14130        &mut self,
14131        _: &GoToImplementationSplit,
14132        window: &mut Window,
14133        cx: &mut Context<Self>,
14134    ) -> Task<Result<Navigated>> {
14135        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14136    }
14137
14138    pub fn go_to_type_definition(
14139        &mut self,
14140        _: &GoToTypeDefinition,
14141        window: &mut Window,
14142        cx: &mut Context<Self>,
14143    ) -> Task<Result<Navigated>> {
14144        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14145    }
14146
14147    pub fn go_to_definition_split(
14148        &mut self,
14149        _: &GoToDefinitionSplit,
14150        window: &mut Window,
14151        cx: &mut Context<Self>,
14152    ) -> Task<Result<Navigated>> {
14153        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14154    }
14155
14156    pub fn go_to_type_definition_split(
14157        &mut self,
14158        _: &GoToTypeDefinitionSplit,
14159        window: &mut Window,
14160        cx: &mut Context<Self>,
14161    ) -> Task<Result<Navigated>> {
14162        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14163    }
14164
14165    fn go_to_definition_of_kind(
14166        &mut self,
14167        kind: GotoDefinitionKind,
14168        split: bool,
14169        window: &mut Window,
14170        cx: &mut Context<Self>,
14171    ) -> Task<Result<Navigated>> {
14172        let Some(provider) = self.semantics_provider.clone() else {
14173            return Task::ready(Ok(Navigated::No));
14174        };
14175        let head = self.selections.newest::<usize>(cx).head();
14176        let buffer = self.buffer.read(cx);
14177        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14178            text_anchor
14179        } else {
14180            return Task::ready(Ok(Navigated::No));
14181        };
14182
14183        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14184            return Task::ready(Ok(Navigated::No));
14185        };
14186
14187        cx.spawn_in(window, async move |editor, cx| {
14188            let definitions = definitions.await?;
14189            let navigated = editor
14190                .update_in(cx, |editor, window, cx| {
14191                    editor.navigate_to_hover_links(
14192                        Some(kind),
14193                        definitions
14194                            .into_iter()
14195                            .filter(|location| {
14196                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14197                            })
14198                            .map(HoverLink::Text)
14199                            .collect::<Vec<_>>(),
14200                        split,
14201                        window,
14202                        cx,
14203                    )
14204                })?
14205                .await?;
14206            anyhow::Ok(navigated)
14207        })
14208    }
14209
14210    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14211        let selection = self.selections.newest_anchor();
14212        let head = selection.head();
14213        let tail = selection.tail();
14214
14215        let Some((buffer, start_position)) =
14216            self.buffer.read(cx).text_anchor_for_position(head, cx)
14217        else {
14218            return;
14219        };
14220
14221        let end_position = if head != tail {
14222            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14223                return;
14224            };
14225            Some(pos)
14226        } else {
14227            None
14228        };
14229
14230        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14231            let url = if let Some(end_pos) = end_position {
14232                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14233            } else {
14234                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14235            };
14236
14237            if let Some(url) = url {
14238                editor.update(cx, |_, cx| {
14239                    cx.open_url(&url);
14240                })
14241            } else {
14242                Ok(())
14243            }
14244        });
14245
14246        url_finder.detach();
14247    }
14248
14249    pub fn open_selected_filename(
14250        &mut self,
14251        _: &OpenSelectedFilename,
14252        window: &mut Window,
14253        cx: &mut Context<Self>,
14254    ) {
14255        let Some(workspace) = self.workspace() else {
14256            return;
14257        };
14258
14259        let position = self.selections.newest_anchor().head();
14260
14261        let Some((buffer, buffer_position)) =
14262            self.buffer.read(cx).text_anchor_for_position(position, cx)
14263        else {
14264            return;
14265        };
14266
14267        let project = self.project.clone();
14268
14269        cx.spawn_in(window, async move |_, cx| {
14270            let result = find_file(&buffer, project, buffer_position, cx).await;
14271
14272            if let Some((_, path)) = result {
14273                workspace
14274                    .update_in(cx, |workspace, window, cx| {
14275                        workspace.open_resolved_path(path, window, cx)
14276                    })?
14277                    .await?;
14278            }
14279            anyhow::Ok(())
14280        })
14281        .detach();
14282    }
14283
14284    pub(crate) fn navigate_to_hover_links(
14285        &mut self,
14286        kind: Option<GotoDefinitionKind>,
14287        mut definitions: Vec<HoverLink>,
14288        split: bool,
14289        window: &mut Window,
14290        cx: &mut Context<Editor>,
14291    ) -> Task<Result<Navigated>> {
14292        // If there is one definition, just open it directly
14293        if definitions.len() == 1 {
14294            let definition = definitions.pop().unwrap();
14295
14296            enum TargetTaskResult {
14297                Location(Option<Location>),
14298                AlreadyNavigated,
14299            }
14300
14301            let target_task = match definition {
14302                HoverLink::Text(link) => {
14303                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14304                }
14305                HoverLink::InlayHint(lsp_location, server_id) => {
14306                    let computation =
14307                        self.compute_target_location(lsp_location, server_id, window, cx);
14308                    cx.background_spawn(async move {
14309                        let location = computation.await?;
14310                        Ok(TargetTaskResult::Location(location))
14311                    })
14312                }
14313                HoverLink::Url(url) => {
14314                    cx.open_url(&url);
14315                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14316                }
14317                HoverLink::File(path) => {
14318                    if let Some(workspace) = self.workspace() {
14319                        cx.spawn_in(window, async move |_, cx| {
14320                            workspace
14321                                .update_in(cx, |workspace, window, cx| {
14322                                    workspace.open_resolved_path(path, window, cx)
14323                                })?
14324                                .await
14325                                .map(|_| TargetTaskResult::AlreadyNavigated)
14326                        })
14327                    } else {
14328                        Task::ready(Ok(TargetTaskResult::Location(None)))
14329                    }
14330                }
14331            };
14332            cx.spawn_in(window, async move |editor, cx| {
14333                let target = match target_task.await.context("target resolution task")? {
14334                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14335                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14336                    TargetTaskResult::Location(Some(target)) => target,
14337                };
14338
14339                editor.update_in(cx, |editor, window, cx| {
14340                    let Some(workspace) = editor.workspace() else {
14341                        return Navigated::No;
14342                    };
14343                    let pane = workspace.read(cx).active_pane().clone();
14344
14345                    let range = target.range.to_point(target.buffer.read(cx));
14346                    let range = editor.range_for_match(&range);
14347                    let range = collapse_multiline_range(range);
14348
14349                    if !split
14350                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14351                    {
14352                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14353                    } else {
14354                        window.defer(cx, move |window, cx| {
14355                            let target_editor: Entity<Self> =
14356                                workspace.update(cx, |workspace, cx| {
14357                                    let pane = if split {
14358                                        workspace.adjacent_pane(window, cx)
14359                                    } else {
14360                                        workspace.active_pane().clone()
14361                                    };
14362
14363                                    workspace.open_project_item(
14364                                        pane,
14365                                        target.buffer.clone(),
14366                                        true,
14367                                        true,
14368                                        window,
14369                                        cx,
14370                                    )
14371                                });
14372                            target_editor.update(cx, |target_editor, cx| {
14373                                // When selecting a definition in a different buffer, disable the nav history
14374                                // to avoid creating a history entry at the previous cursor location.
14375                                pane.update(cx, |pane, _| pane.disable_history());
14376                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14377                                pane.update(cx, |pane, _| pane.enable_history());
14378                            });
14379                        });
14380                    }
14381                    Navigated::Yes
14382                })
14383            })
14384        } else if !definitions.is_empty() {
14385            cx.spawn_in(window, async move |editor, cx| {
14386                let (title, location_tasks, workspace) = editor
14387                    .update_in(cx, |editor, window, cx| {
14388                        let tab_kind = match kind {
14389                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14390                            _ => "Definitions",
14391                        };
14392                        let title = definitions
14393                            .iter()
14394                            .find_map(|definition| match definition {
14395                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14396                                    let buffer = origin.buffer.read(cx);
14397                                    format!(
14398                                        "{} for {}",
14399                                        tab_kind,
14400                                        buffer
14401                                            .text_for_range(origin.range.clone())
14402                                            .collect::<String>()
14403                                    )
14404                                }),
14405                                HoverLink::InlayHint(_, _) => None,
14406                                HoverLink::Url(_) => None,
14407                                HoverLink::File(_) => None,
14408                            })
14409                            .unwrap_or(tab_kind.to_string());
14410                        let location_tasks = definitions
14411                            .into_iter()
14412                            .map(|definition| match definition {
14413                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14414                                HoverLink::InlayHint(lsp_location, server_id) => editor
14415                                    .compute_target_location(lsp_location, server_id, window, cx),
14416                                HoverLink::Url(_) => Task::ready(Ok(None)),
14417                                HoverLink::File(_) => Task::ready(Ok(None)),
14418                            })
14419                            .collect::<Vec<_>>();
14420                        (title, location_tasks, editor.workspace().clone())
14421                    })
14422                    .context("location tasks preparation")?;
14423
14424                let locations = future::join_all(location_tasks)
14425                    .await
14426                    .into_iter()
14427                    .filter_map(|location| location.transpose())
14428                    .collect::<Result<_>>()
14429                    .context("location tasks")?;
14430
14431                let Some(workspace) = workspace else {
14432                    return Ok(Navigated::No);
14433                };
14434                let opened = workspace
14435                    .update_in(cx, |workspace, window, cx| {
14436                        Self::open_locations_in_multibuffer(
14437                            workspace,
14438                            locations,
14439                            title,
14440                            split,
14441                            MultibufferSelectionMode::First,
14442                            window,
14443                            cx,
14444                        )
14445                    })
14446                    .ok();
14447
14448                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14449            })
14450        } else {
14451            Task::ready(Ok(Navigated::No))
14452        }
14453    }
14454
14455    fn compute_target_location(
14456        &self,
14457        lsp_location: lsp::Location,
14458        server_id: LanguageServerId,
14459        window: &mut Window,
14460        cx: &mut Context<Self>,
14461    ) -> Task<anyhow::Result<Option<Location>>> {
14462        let Some(project) = self.project.clone() else {
14463            return Task::ready(Ok(None));
14464        };
14465
14466        cx.spawn_in(window, async move |editor, cx| {
14467            let location_task = editor.update(cx, |_, cx| {
14468                project.update(cx, |project, cx| {
14469                    let language_server_name = project
14470                        .language_server_statuses(cx)
14471                        .find(|(id, _)| server_id == *id)
14472                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14473                    language_server_name.map(|language_server_name| {
14474                        project.open_local_buffer_via_lsp(
14475                            lsp_location.uri.clone(),
14476                            server_id,
14477                            language_server_name,
14478                            cx,
14479                        )
14480                    })
14481                })
14482            })?;
14483            let location = match location_task {
14484                Some(task) => Some({
14485                    let target_buffer_handle = task.await.context("open local buffer")?;
14486                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14487                        let target_start = target_buffer
14488                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14489                        let target_end = target_buffer
14490                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14491                        target_buffer.anchor_after(target_start)
14492                            ..target_buffer.anchor_before(target_end)
14493                    })?;
14494                    Location {
14495                        buffer: target_buffer_handle,
14496                        range,
14497                    }
14498                }),
14499                None => None,
14500            };
14501            Ok(location)
14502        })
14503    }
14504
14505    pub fn find_all_references(
14506        &mut self,
14507        _: &FindAllReferences,
14508        window: &mut Window,
14509        cx: &mut Context<Self>,
14510    ) -> Option<Task<Result<Navigated>>> {
14511        let selection = self.selections.newest::<usize>(cx);
14512        let multi_buffer = self.buffer.read(cx);
14513        let head = selection.head();
14514
14515        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14516        let head_anchor = multi_buffer_snapshot.anchor_at(
14517            head,
14518            if head < selection.tail() {
14519                Bias::Right
14520            } else {
14521                Bias::Left
14522            },
14523        );
14524
14525        match self
14526            .find_all_references_task_sources
14527            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14528        {
14529            Ok(_) => {
14530                log::info!(
14531                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14532                );
14533                return None;
14534            }
14535            Err(i) => {
14536                self.find_all_references_task_sources.insert(i, head_anchor);
14537            }
14538        }
14539
14540        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14541        let workspace = self.workspace()?;
14542        let project = workspace.read(cx).project().clone();
14543        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14544        Some(cx.spawn_in(window, async move |editor, cx| {
14545            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14546                if let Ok(i) = editor
14547                    .find_all_references_task_sources
14548                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14549                {
14550                    editor.find_all_references_task_sources.remove(i);
14551                }
14552            });
14553
14554            let locations = references.await?;
14555            if locations.is_empty() {
14556                return anyhow::Ok(Navigated::No);
14557            }
14558
14559            workspace.update_in(cx, |workspace, window, cx| {
14560                let title = locations
14561                    .first()
14562                    .as_ref()
14563                    .map(|location| {
14564                        let buffer = location.buffer.read(cx);
14565                        format!(
14566                            "References to `{}`",
14567                            buffer
14568                                .text_for_range(location.range.clone())
14569                                .collect::<String>()
14570                        )
14571                    })
14572                    .unwrap();
14573                Self::open_locations_in_multibuffer(
14574                    workspace,
14575                    locations,
14576                    title,
14577                    false,
14578                    MultibufferSelectionMode::First,
14579                    window,
14580                    cx,
14581                );
14582                Navigated::Yes
14583            })
14584        }))
14585    }
14586
14587    /// Opens a multibuffer with the given project locations in it
14588    pub fn open_locations_in_multibuffer(
14589        workspace: &mut Workspace,
14590        mut locations: Vec<Location>,
14591        title: String,
14592        split: bool,
14593        multibuffer_selection_mode: MultibufferSelectionMode,
14594        window: &mut Window,
14595        cx: &mut Context<Workspace>,
14596    ) {
14597        // If there are multiple definitions, open them in a multibuffer
14598        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14599        let mut locations = locations.into_iter().peekable();
14600        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14601        let capability = workspace.project().read(cx).capability();
14602
14603        let excerpt_buffer = cx.new(|cx| {
14604            let mut multibuffer = MultiBuffer::new(capability);
14605            while let Some(location) = locations.next() {
14606                let buffer = location.buffer.read(cx);
14607                let mut ranges_for_buffer = Vec::new();
14608                let range = location.range.to_point(buffer);
14609                ranges_for_buffer.push(range.clone());
14610
14611                while let Some(next_location) = locations.peek() {
14612                    if next_location.buffer == location.buffer {
14613                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14614                        locations.next();
14615                    } else {
14616                        break;
14617                    }
14618                }
14619
14620                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14621                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14622                    PathKey::for_buffer(&location.buffer, cx),
14623                    location.buffer.clone(),
14624                    ranges_for_buffer,
14625                    DEFAULT_MULTIBUFFER_CONTEXT,
14626                    cx,
14627                );
14628                ranges.extend(new_ranges)
14629            }
14630
14631            multibuffer.with_title(title)
14632        });
14633
14634        let editor = cx.new(|cx| {
14635            Editor::for_multibuffer(
14636                excerpt_buffer,
14637                Some(workspace.project().clone()),
14638                window,
14639                cx,
14640            )
14641        });
14642        editor.update(cx, |editor, cx| {
14643            match multibuffer_selection_mode {
14644                MultibufferSelectionMode::First => {
14645                    if let Some(first_range) = ranges.first() {
14646                        editor.change_selections(None, window, cx, |selections| {
14647                            selections.clear_disjoint();
14648                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14649                        });
14650                    }
14651                    editor.highlight_background::<Self>(
14652                        &ranges,
14653                        |theme| theme.editor_highlighted_line_background,
14654                        cx,
14655                    );
14656                }
14657                MultibufferSelectionMode::All => {
14658                    editor.change_selections(None, window, cx, |selections| {
14659                        selections.clear_disjoint();
14660                        selections.select_anchor_ranges(ranges);
14661                    });
14662                }
14663            }
14664            editor.register_buffers_with_language_servers(cx);
14665        });
14666
14667        let item = Box::new(editor);
14668        let item_id = item.item_id();
14669
14670        if split {
14671            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14672        } else {
14673            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14674                let (preview_item_id, preview_item_idx) =
14675                    workspace.active_pane().update(cx, |pane, _| {
14676                        (pane.preview_item_id(), pane.preview_item_idx())
14677                    });
14678
14679                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14680
14681                if let Some(preview_item_id) = preview_item_id {
14682                    workspace.active_pane().update(cx, |pane, cx| {
14683                        pane.remove_item(preview_item_id, false, false, window, cx);
14684                    });
14685                }
14686            } else {
14687                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14688            }
14689        }
14690        workspace.active_pane().update(cx, |pane, cx| {
14691            pane.set_preview_item_id(Some(item_id), cx);
14692        });
14693    }
14694
14695    pub fn rename(
14696        &mut self,
14697        _: &Rename,
14698        window: &mut Window,
14699        cx: &mut Context<Self>,
14700    ) -> Option<Task<Result<()>>> {
14701        use language::ToOffset as _;
14702
14703        let provider = self.semantics_provider.clone()?;
14704        let selection = self.selections.newest_anchor().clone();
14705        let (cursor_buffer, cursor_buffer_position) = self
14706            .buffer
14707            .read(cx)
14708            .text_anchor_for_position(selection.head(), cx)?;
14709        let (tail_buffer, cursor_buffer_position_end) = self
14710            .buffer
14711            .read(cx)
14712            .text_anchor_for_position(selection.tail(), cx)?;
14713        if tail_buffer != cursor_buffer {
14714            return None;
14715        }
14716
14717        let snapshot = cursor_buffer.read(cx).snapshot();
14718        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14719        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14720        let prepare_rename = provider
14721            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14722            .unwrap_or_else(|| Task::ready(Ok(None)));
14723        drop(snapshot);
14724
14725        Some(cx.spawn_in(window, async move |this, cx| {
14726            let rename_range = if let Some(range) = prepare_rename.await? {
14727                Some(range)
14728            } else {
14729                this.update(cx, |this, cx| {
14730                    let buffer = this.buffer.read(cx).snapshot(cx);
14731                    let mut buffer_highlights = this
14732                        .document_highlights_for_position(selection.head(), &buffer)
14733                        .filter(|highlight| {
14734                            highlight.start.excerpt_id == selection.head().excerpt_id
14735                                && highlight.end.excerpt_id == selection.head().excerpt_id
14736                        });
14737                    buffer_highlights
14738                        .next()
14739                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14740                })?
14741            };
14742            if let Some(rename_range) = rename_range {
14743                this.update_in(cx, |this, window, cx| {
14744                    let snapshot = cursor_buffer.read(cx).snapshot();
14745                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14746                    let cursor_offset_in_rename_range =
14747                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14748                    let cursor_offset_in_rename_range_end =
14749                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14750
14751                    this.take_rename(false, window, cx);
14752                    let buffer = this.buffer.read(cx).read(cx);
14753                    let cursor_offset = selection.head().to_offset(&buffer);
14754                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14755                    let rename_end = rename_start + rename_buffer_range.len();
14756                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14757                    let mut old_highlight_id = None;
14758                    let old_name: Arc<str> = buffer
14759                        .chunks(rename_start..rename_end, true)
14760                        .map(|chunk| {
14761                            if old_highlight_id.is_none() {
14762                                old_highlight_id = chunk.syntax_highlight_id;
14763                            }
14764                            chunk.text
14765                        })
14766                        .collect::<String>()
14767                        .into();
14768
14769                    drop(buffer);
14770
14771                    // Position the selection in the rename editor so that it matches the current selection.
14772                    this.show_local_selections = false;
14773                    let rename_editor = cx.new(|cx| {
14774                        let mut editor = Editor::single_line(window, cx);
14775                        editor.buffer.update(cx, |buffer, cx| {
14776                            buffer.edit([(0..0, old_name.clone())], None, cx)
14777                        });
14778                        let rename_selection_range = match cursor_offset_in_rename_range
14779                            .cmp(&cursor_offset_in_rename_range_end)
14780                        {
14781                            Ordering::Equal => {
14782                                editor.select_all(&SelectAll, window, cx);
14783                                return editor;
14784                            }
14785                            Ordering::Less => {
14786                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14787                            }
14788                            Ordering::Greater => {
14789                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14790                            }
14791                        };
14792                        if rename_selection_range.end > old_name.len() {
14793                            editor.select_all(&SelectAll, window, cx);
14794                        } else {
14795                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14796                                s.select_ranges([rename_selection_range]);
14797                            });
14798                        }
14799                        editor
14800                    });
14801                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14802                        if e == &EditorEvent::Focused {
14803                            cx.emit(EditorEvent::FocusedIn)
14804                        }
14805                    })
14806                    .detach();
14807
14808                    let write_highlights =
14809                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14810                    let read_highlights =
14811                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14812                    let ranges = write_highlights
14813                        .iter()
14814                        .flat_map(|(_, ranges)| ranges.iter())
14815                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14816                        .cloned()
14817                        .collect();
14818
14819                    this.highlight_text::<Rename>(
14820                        ranges,
14821                        HighlightStyle {
14822                            fade_out: Some(0.6),
14823                            ..Default::default()
14824                        },
14825                        cx,
14826                    );
14827                    let rename_focus_handle = rename_editor.focus_handle(cx);
14828                    window.focus(&rename_focus_handle);
14829                    let block_id = this.insert_blocks(
14830                        [BlockProperties {
14831                            style: BlockStyle::Flex,
14832                            placement: BlockPlacement::Below(range.start),
14833                            height: Some(1),
14834                            render: Arc::new({
14835                                let rename_editor = rename_editor.clone();
14836                                move |cx: &mut BlockContext| {
14837                                    let mut text_style = cx.editor_style.text.clone();
14838                                    if let Some(highlight_style) = old_highlight_id
14839                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14840                                    {
14841                                        text_style = text_style.highlight(highlight_style);
14842                                    }
14843                                    div()
14844                                        .block_mouse_down()
14845                                        .pl(cx.anchor_x)
14846                                        .child(EditorElement::new(
14847                                            &rename_editor,
14848                                            EditorStyle {
14849                                                background: cx.theme().system().transparent,
14850                                                local_player: cx.editor_style.local_player,
14851                                                text: text_style,
14852                                                scrollbar_width: cx.editor_style.scrollbar_width,
14853                                                syntax: cx.editor_style.syntax.clone(),
14854                                                status: cx.editor_style.status.clone(),
14855                                                inlay_hints_style: HighlightStyle {
14856                                                    font_weight: Some(FontWeight::BOLD),
14857                                                    ..make_inlay_hints_style(cx.app)
14858                                                },
14859                                                inline_completion_styles: make_suggestion_styles(
14860                                                    cx.app,
14861                                                ),
14862                                                ..EditorStyle::default()
14863                                            },
14864                                        ))
14865                                        .into_any_element()
14866                                }
14867                            }),
14868                            priority: 0,
14869                            render_in_minimap: true,
14870                        }],
14871                        Some(Autoscroll::fit()),
14872                        cx,
14873                    )[0];
14874                    this.pending_rename = Some(RenameState {
14875                        range,
14876                        old_name,
14877                        editor: rename_editor,
14878                        block_id,
14879                    });
14880                })?;
14881            }
14882
14883            Ok(())
14884        }))
14885    }
14886
14887    pub fn confirm_rename(
14888        &mut self,
14889        _: &ConfirmRename,
14890        window: &mut Window,
14891        cx: &mut Context<Self>,
14892    ) -> Option<Task<Result<()>>> {
14893        let rename = self.take_rename(false, window, cx)?;
14894        let workspace = self.workspace()?.downgrade();
14895        let (buffer, start) = self
14896            .buffer
14897            .read(cx)
14898            .text_anchor_for_position(rename.range.start, cx)?;
14899        let (end_buffer, _) = self
14900            .buffer
14901            .read(cx)
14902            .text_anchor_for_position(rename.range.end, cx)?;
14903        if buffer != end_buffer {
14904            return None;
14905        }
14906
14907        let old_name = rename.old_name;
14908        let new_name = rename.editor.read(cx).text(cx);
14909
14910        let rename = self.semantics_provider.as_ref()?.perform_rename(
14911            &buffer,
14912            start,
14913            new_name.clone(),
14914            cx,
14915        )?;
14916
14917        Some(cx.spawn_in(window, async move |editor, cx| {
14918            let project_transaction = rename.await?;
14919            Self::open_project_transaction(
14920                &editor,
14921                workspace,
14922                project_transaction,
14923                format!("Rename: {}{}", old_name, new_name),
14924                cx,
14925            )
14926            .await?;
14927
14928            editor.update(cx, |editor, cx| {
14929                editor.refresh_document_highlights(cx);
14930            })?;
14931            Ok(())
14932        }))
14933    }
14934
14935    fn take_rename(
14936        &mut self,
14937        moving_cursor: bool,
14938        window: &mut Window,
14939        cx: &mut Context<Self>,
14940    ) -> Option<RenameState> {
14941        let rename = self.pending_rename.take()?;
14942        if rename.editor.focus_handle(cx).is_focused(window) {
14943            window.focus(&self.focus_handle);
14944        }
14945
14946        self.remove_blocks(
14947            [rename.block_id].into_iter().collect(),
14948            Some(Autoscroll::fit()),
14949            cx,
14950        );
14951        self.clear_highlights::<Rename>(cx);
14952        self.show_local_selections = true;
14953
14954        if moving_cursor {
14955            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14956                editor.selections.newest::<usize>(cx).head()
14957            });
14958
14959            // Update the selection to match the position of the selection inside
14960            // the rename editor.
14961            let snapshot = self.buffer.read(cx).read(cx);
14962            let rename_range = rename.range.to_offset(&snapshot);
14963            let cursor_in_editor = snapshot
14964                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14965                .min(rename_range.end);
14966            drop(snapshot);
14967
14968            self.change_selections(None, window, cx, |s| {
14969                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14970            });
14971        } else {
14972            self.refresh_document_highlights(cx);
14973        }
14974
14975        Some(rename)
14976    }
14977
14978    pub fn pending_rename(&self) -> Option<&RenameState> {
14979        self.pending_rename.as_ref()
14980    }
14981
14982    fn format(
14983        &mut self,
14984        _: &Format,
14985        window: &mut Window,
14986        cx: &mut Context<Self>,
14987    ) -> Option<Task<Result<()>>> {
14988        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14989
14990        let project = match &self.project {
14991            Some(project) => project.clone(),
14992            None => return None,
14993        };
14994
14995        Some(self.perform_format(
14996            project,
14997            FormatTrigger::Manual,
14998            FormatTarget::Buffers,
14999            window,
15000            cx,
15001        ))
15002    }
15003
15004    fn format_selections(
15005        &mut self,
15006        _: &FormatSelections,
15007        window: &mut Window,
15008        cx: &mut Context<Self>,
15009    ) -> Option<Task<Result<()>>> {
15010        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15011
15012        let project = match &self.project {
15013            Some(project) => project.clone(),
15014            None => return None,
15015        };
15016
15017        let ranges = self
15018            .selections
15019            .all_adjusted(cx)
15020            .into_iter()
15021            .map(|selection| selection.range())
15022            .collect_vec();
15023
15024        Some(self.perform_format(
15025            project,
15026            FormatTrigger::Manual,
15027            FormatTarget::Ranges(ranges),
15028            window,
15029            cx,
15030        ))
15031    }
15032
15033    fn perform_format(
15034        &mut self,
15035        project: Entity<Project>,
15036        trigger: FormatTrigger,
15037        target: FormatTarget,
15038        window: &mut Window,
15039        cx: &mut Context<Self>,
15040    ) -> Task<Result<()>> {
15041        let buffer = self.buffer.clone();
15042        let (buffers, target) = match target {
15043            FormatTarget::Buffers => {
15044                let mut buffers = buffer.read(cx).all_buffers();
15045                if trigger == FormatTrigger::Save {
15046                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15047                }
15048                (buffers, LspFormatTarget::Buffers)
15049            }
15050            FormatTarget::Ranges(selection_ranges) => {
15051                let multi_buffer = buffer.read(cx);
15052                let snapshot = multi_buffer.read(cx);
15053                let mut buffers = HashSet::default();
15054                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15055                    BTreeMap::new();
15056                for selection_range in selection_ranges {
15057                    for (buffer, buffer_range, _) in
15058                        snapshot.range_to_buffer_ranges(selection_range)
15059                    {
15060                        let buffer_id = buffer.remote_id();
15061                        let start = buffer.anchor_before(buffer_range.start);
15062                        let end = buffer.anchor_after(buffer_range.end);
15063                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15064                        buffer_id_to_ranges
15065                            .entry(buffer_id)
15066                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15067                            .or_insert_with(|| vec![start..end]);
15068                    }
15069                }
15070                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15071            }
15072        };
15073
15074        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15075        let selections_prev = transaction_id_prev
15076            .and_then(|transaction_id_prev| {
15077                // default to selections as they were after the last edit, if we have them,
15078                // instead of how they are now.
15079                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15080                // will take you back to where you made the last edit, instead of staying where you scrolled
15081                self.selection_history
15082                    .transaction(transaction_id_prev)
15083                    .map(|t| t.0.clone())
15084            })
15085            .unwrap_or_else(|| {
15086                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15087                self.selections.disjoint_anchors()
15088            });
15089
15090        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15091        let format = project.update(cx, |project, cx| {
15092            project.format(buffers, target, true, trigger, cx)
15093        });
15094
15095        cx.spawn_in(window, async move |editor, cx| {
15096            let transaction = futures::select_biased! {
15097                transaction = format.log_err().fuse() => transaction,
15098                () = timeout => {
15099                    log::warn!("timed out waiting for formatting");
15100                    None
15101                }
15102            };
15103
15104            buffer
15105                .update(cx, |buffer, cx| {
15106                    if let Some(transaction) = transaction {
15107                        if !buffer.is_singleton() {
15108                            buffer.push_transaction(&transaction.0, cx);
15109                        }
15110                    }
15111                    cx.notify();
15112                })
15113                .ok();
15114
15115            if let Some(transaction_id_now) =
15116                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15117            {
15118                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15119                if has_new_transaction {
15120                    _ = editor.update(cx, |editor, _| {
15121                        editor
15122                            .selection_history
15123                            .insert_transaction(transaction_id_now, selections_prev);
15124                    });
15125                }
15126            }
15127
15128            Ok(())
15129        })
15130    }
15131
15132    fn organize_imports(
15133        &mut self,
15134        _: &OrganizeImports,
15135        window: &mut Window,
15136        cx: &mut Context<Self>,
15137    ) -> Option<Task<Result<()>>> {
15138        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15139        let project = match &self.project {
15140            Some(project) => project.clone(),
15141            None => return None,
15142        };
15143        Some(self.perform_code_action_kind(
15144            project,
15145            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15146            window,
15147            cx,
15148        ))
15149    }
15150
15151    fn perform_code_action_kind(
15152        &mut self,
15153        project: Entity<Project>,
15154        kind: CodeActionKind,
15155        window: &mut Window,
15156        cx: &mut Context<Self>,
15157    ) -> Task<Result<()>> {
15158        let buffer = self.buffer.clone();
15159        let buffers = buffer.read(cx).all_buffers();
15160        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15161        let apply_action = project.update(cx, |project, cx| {
15162            project.apply_code_action_kind(buffers, kind, true, cx)
15163        });
15164        cx.spawn_in(window, async move |_, cx| {
15165            let transaction = futures::select_biased! {
15166                () = timeout => {
15167                    log::warn!("timed out waiting for executing code action");
15168                    None
15169                }
15170                transaction = apply_action.log_err().fuse() => transaction,
15171            };
15172            buffer
15173                .update(cx, |buffer, cx| {
15174                    // check if we need this
15175                    if let Some(transaction) = transaction {
15176                        if !buffer.is_singleton() {
15177                            buffer.push_transaction(&transaction.0, cx);
15178                        }
15179                    }
15180                    cx.notify();
15181                })
15182                .ok();
15183            Ok(())
15184        })
15185    }
15186
15187    fn restart_language_server(
15188        &mut self,
15189        _: &RestartLanguageServer,
15190        _: &mut Window,
15191        cx: &mut Context<Self>,
15192    ) {
15193        if let Some(project) = self.project.clone() {
15194            self.buffer.update(cx, |multi_buffer, cx| {
15195                project.update(cx, |project, cx| {
15196                    project.restart_language_servers_for_buffers(
15197                        multi_buffer.all_buffers().into_iter().collect(),
15198                        cx,
15199                    );
15200                });
15201            })
15202        }
15203    }
15204
15205    fn stop_language_server(
15206        &mut self,
15207        _: &StopLanguageServer,
15208        _: &mut Window,
15209        cx: &mut Context<Self>,
15210    ) {
15211        if let Some(project) = self.project.clone() {
15212            self.buffer.update(cx, |multi_buffer, cx| {
15213                project.update(cx, |project, cx| {
15214                    project.stop_language_servers_for_buffers(
15215                        multi_buffer.all_buffers().into_iter().collect(),
15216                        cx,
15217                    );
15218                    cx.emit(project::Event::RefreshInlayHints);
15219                });
15220            });
15221        }
15222    }
15223
15224    fn cancel_language_server_work(
15225        workspace: &mut Workspace,
15226        _: &actions::CancelLanguageServerWork,
15227        _: &mut Window,
15228        cx: &mut Context<Workspace>,
15229    ) {
15230        let project = workspace.project();
15231        let buffers = workspace
15232            .active_item(cx)
15233            .and_then(|item| item.act_as::<Editor>(cx))
15234            .map_or(HashSet::default(), |editor| {
15235                editor.read(cx).buffer.read(cx).all_buffers()
15236            });
15237        project.update(cx, |project, cx| {
15238            project.cancel_language_server_work_for_buffers(buffers, cx);
15239        });
15240    }
15241
15242    fn show_character_palette(
15243        &mut self,
15244        _: &ShowCharacterPalette,
15245        window: &mut Window,
15246        _: &mut Context<Self>,
15247    ) {
15248        window.show_character_palette();
15249    }
15250
15251    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15252        if self.mode.is_minimap() {
15253            return;
15254        }
15255
15256        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15257            let buffer = self.buffer.read(cx).snapshot(cx);
15258            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15259            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15260            let is_valid = buffer
15261                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15262                .any(|entry| {
15263                    entry.diagnostic.is_primary
15264                        && !entry.range.is_empty()
15265                        && entry.range.start == primary_range_start
15266                        && entry.diagnostic.message == active_diagnostics.active_message
15267                });
15268
15269            if !is_valid {
15270                self.dismiss_diagnostics(cx);
15271            }
15272        }
15273    }
15274
15275    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15276        match &self.active_diagnostics {
15277            ActiveDiagnostic::Group(group) => Some(group),
15278            _ => None,
15279        }
15280    }
15281
15282    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15283        self.dismiss_diagnostics(cx);
15284        self.active_diagnostics = ActiveDiagnostic::All;
15285    }
15286
15287    fn activate_diagnostics(
15288        &mut self,
15289        buffer_id: BufferId,
15290        diagnostic: DiagnosticEntry<usize>,
15291        window: &mut Window,
15292        cx: &mut Context<Self>,
15293    ) {
15294        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15295            return;
15296        }
15297        self.dismiss_diagnostics(cx);
15298        let snapshot = self.snapshot(window, cx);
15299        let buffer = self.buffer.read(cx).snapshot(cx);
15300        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15301            return;
15302        };
15303
15304        let diagnostic_group = buffer
15305            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15306            .collect::<Vec<_>>();
15307
15308        let blocks =
15309            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15310
15311        let blocks = self.display_map.update(cx, |display_map, cx| {
15312            display_map.insert_blocks(blocks, cx).into_iter().collect()
15313        });
15314        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15315            active_range: buffer.anchor_before(diagnostic.range.start)
15316                ..buffer.anchor_after(diagnostic.range.end),
15317            active_message: diagnostic.diagnostic.message.clone(),
15318            group_id: diagnostic.diagnostic.group_id,
15319            blocks,
15320        });
15321        cx.notify();
15322    }
15323
15324    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15325        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15326            return;
15327        };
15328
15329        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15330        if let ActiveDiagnostic::Group(group) = prev {
15331            self.display_map.update(cx, |display_map, cx| {
15332                display_map.remove_blocks(group.blocks, cx);
15333            });
15334            cx.notify();
15335        }
15336    }
15337
15338    /// Disable inline diagnostics rendering for this editor.
15339    pub fn disable_inline_diagnostics(&mut self) {
15340        self.inline_diagnostics_enabled = false;
15341        self.inline_diagnostics_update = Task::ready(());
15342        self.inline_diagnostics.clear();
15343    }
15344
15345    pub fn diagnostics_enabled(&self) -> bool {
15346        self.mode.is_full()
15347    }
15348
15349    pub fn inline_diagnostics_enabled(&self) -> bool {
15350        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15351    }
15352
15353    pub fn show_inline_diagnostics(&self) -> bool {
15354        self.show_inline_diagnostics
15355    }
15356
15357    pub fn toggle_inline_diagnostics(
15358        &mut self,
15359        _: &ToggleInlineDiagnostics,
15360        window: &mut Window,
15361        cx: &mut Context<Editor>,
15362    ) {
15363        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15364        self.refresh_inline_diagnostics(false, window, cx);
15365    }
15366
15367    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15368        self.diagnostics_max_severity = severity;
15369        self.display_map.update(cx, |display_map, _| {
15370            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15371        });
15372    }
15373
15374    pub fn toggle_diagnostics(
15375        &mut self,
15376        _: &ToggleDiagnostics,
15377        window: &mut Window,
15378        cx: &mut Context<Editor>,
15379    ) {
15380        if !self.diagnostics_enabled() {
15381            return;
15382        }
15383
15384        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15385            EditorSettings::get_global(cx)
15386                .diagnostics_max_severity
15387                .filter(|severity| severity != &DiagnosticSeverity::Off)
15388                .unwrap_or(DiagnosticSeverity::Hint)
15389        } else {
15390            DiagnosticSeverity::Off
15391        };
15392        self.set_max_diagnostics_severity(new_severity, cx);
15393        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15394            self.active_diagnostics = ActiveDiagnostic::None;
15395            self.inline_diagnostics_update = Task::ready(());
15396            self.inline_diagnostics.clear();
15397        } else {
15398            self.refresh_inline_diagnostics(false, window, cx);
15399        }
15400
15401        cx.notify();
15402    }
15403
15404    pub fn toggle_minimap(
15405        &mut self,
15406        _: &ToggleMinimap,
15407        window: &mut Window,
15408        cx: &mut Context<Editor>,
15409    ) {
15410        if self.supports_minimap(cx) {
15411            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15412        }
15413    }
15414
15415    fn refresh_inline_diagnostics(
15416        &mut self,
15417        debounce: bool,
15418        window: &mut Window,
15419        cx: &mut Context<Self>,
15420    ) {
15421        let max_severity = ProjectSettings::get_global(cx)
15422            .diagnostics
15423            .inline
15424            .max_severity
15425            .unwrap_or(self.diagnostics_max_severity);
15426
15427        if self.mode.is_minimap()
15428            || !self.inline_diagnostics_enabled()
15429            || !self.show_inline_diagnostics
15430            || max_severity == DiagnosticSeverity::Off
15431        {
15432            self.inline_diagnostics_update = Task::ready(());
15433            self.inline_diagnostics.clear();
15434            return;
15435        }
15436
15437        let debounce_ms = ProjectSettings::get_global(cx)
15438            .diagnostics
15439            .inline
15440            .update_debounce_ms;
15441        let debounce = if debounce && debounce_ms > 0 {
15442            Some(Duration::from_millis(debounce_ms))
15443        } else {
15444            None
15445        };
15446        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15447            let editor = editor.upgrade().unwrap();
15448
15449            if let Some(debounce) = debounce {
15450                cx.background_executor().timer(debounce).await;
15451            }
15452            let Some(snapshot) = editor
15453                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15454                .ok()
15455            else {
15456                return;
15457            };
15458
15459            let new_inline_diagnostics = cx
15460                .background_spawn(async move {
15461                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15462                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15463                        let message = diagnostic_entry
15464                            .diagnostic
15465                            .message
15466                            .split_once('\n')
15467                            .map(|(line, _)| line)
15468                            .map(SharedString::new)
15469                            .unwrap_or_else(|| {
15470                                SharedString::from(diagnostic_entry.diagnostic.message)
15471                            });
15472                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15473                        let (Ok(i) | Err(i)) = inline_diagnostics
15474                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15475                        inline_diagnostics.insert(
15476                            i,
15477                            (
15478                                start_anchor,
15479                                InlineDiagnostic {
15480                                    message,
15481                                    group_id: diagnostic_entry.diagnostic.group_id,
15482                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15483                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15484                                    severity: diagnostic_entry.diagnostic.severity,
15485                                },
15486                            ),
15487                        );
15488                    }
15489                    inline_diagnostics
15490                })
15491                .await;
15492
15493            editor
15494                .update(cx, |editor, cx| {
15495                    editor.inline_diagnostics = new_inline_diagnostics;
15496                    cx.notify();
15497                })
15498                .ok();
15499        });
15500    }
15501
15502    pub fn set_selections_from_remote(
15503        &mut self,
15504        selections: Vec<Selection<Anchor>>,
15505        pending_selection: Option<Selection<Anchor>>,
15506        window: &mut Window,
15507        cx: &mut Context<Self>,
15508    ) {
15509        let old_cursor_position = self.selections.newest_anchor().head();
15510        self.selections.change_with(cx, |s| {
15511            s.select_anchors(selections);
15512            if let Some(pending_selection) = pending_selection {
15513                s.set_pending(pending_selection, SelectMode::Character);
15514            } else {
15515                s.clear_pending();
15516            }
15517        });
15518        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15519    }
15520
15521    fn push_to_selection_history(&mut self) {
15522        self.selection_history.push(SelectionHistoryEntry {
15523            selections: self.selections.disjoint_anchors(),
15524            select_next_state: self.select_next_state.clone(),
15525            select_prev_state: self.select_prev_state.clone(),
15526            add_selections_state: self.add_selections_state.clone(),
15527        });
15528    }
15529
15530    pub fn transact(
15531        &mut self,
15532        window: &mut Window,
15533        cx: &mut Context<Self>,
15534        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15535    ) -> Option<TransactionId> {
15536        self.start_transaction_at(Instant::now(), window, cx);
15537        update(self, window, cx);
15538        self.end_transaction_at(Instant::now(), cx)
15539    }
15540
15541    pub fn start_transaction_at(
15542        &mut self,
15543        now: Instant,
15544        window: &mut Window,
15545        cx: &mut Context<Self>,
15546    ) {
15547        self.end_selection(window, cx);
15548        if let Some(tx_id) = self
15549            .buffer
15550            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15551        {
15552            self.selection_history
15553                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15554            cx.emit(EditorEvent::TransactionBegun {
15555                transaction_id: tx_id,
15556            })
15557        }
15558    }
15559
15560    pub fn end_transaction_at(
15561        &mut self,
15562        now: Instant,
15563        cx: &mut Context<Self>,
15564    ) -> Option<TransactionId> {
15565        if let Some(transaction_id) = self
15566            .buffer
15567            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15568        {
15569            if let Some((_, end_selections)) =
15570                self.selection_history.transaction_mut(transaction_id)
15571            {
15572                *end_selections = Some(self.selections.disjoint_anchors());
15573            } else {
15574                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15575            }
15576
15577            cx.emit(EditorEvent::Edited { transaction_id });
15578            Some(transaction_id)
15579        } else {
15580            None
15581        }
15582    }
15583
15584    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15585        if self.selection_mark_mode {
15586            self.change_selections(None, window, cx, |s| {
15587                s.move_with(|_, sel| {
15588                    sel.collapse_to(sel.head(), SelectionGoal::None);
15589                });
15590            })
15591        }
15592        self.selection_mark_mode = true;
15593        cx.notify();
15594    }
15595
15596    pub fn swap_selection_ends(
15597        &mut self,
15598        _: &actions::SwapSelectionEnds,
15599        window: &mut Window,
15600        cx: &mut Context<Self>,
15601    ) {
15602        self.change_selections(None, window, cx, |s| {
15603            s.move_with(|_, sel| {
15604                if sel.start != sel.end {
15605                    sel.reversed = !sel.reversed
15606                }
15607            });
15608        });
15609        self.request_autoscroll(Autoscroll::newest(), cx);
15610        cx.notify();
15611    }
15612
15613    pub fn toggle_fold(
15614        &mut self,
15615        _: &actions::ToggleFold,
15616        window: &mut Window,
15617        cx: &mut Context<Self>,
15618    ) {
15619        if self.is_singleton(cx) {
15620            let selection = self.selections.newest::<Point>(cx);
15621
15622            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15623            let range = if selection.is_empty() {
15624                let point = selection.head().to_display_point(&display_map);
15625                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15626                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15627                    .to_point(&display_map);
15628                start..end
15629            } else {
15630                selection.range()
15631            };
15632            if display_map.folds_in_range(range).next().is_some() {
15633                self.unfold_lines(&Default::default(), window, cx)
15634            } else {
15635                self.fold(&Default::default(), window, cx)
15636            }
15637        } else {
15638            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15639            let buffer_ids: HashSet<_> = self
15640                .selections
15641                .disjoint_anchor_ranges()
15642                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15643                .collect();
15644
15645            let should_unfold = buffer_ids
15646                .iter()
15647                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15648
15649            for buffer_id in buffer_ids {
15650                if should_unfold {
15651                    self.unfold_buffer(buffer_id, cx);
15652                } else {
15653                    self.fold_buffer(buffer_id, cx);
15654                }
15655            }
15656        }
15657    }
15658
15659    pub fn toggle_fold_recursive(
15660        &mut self,
15661        _: &actions::ToggleFoldRecursive,
15662        window: &mut Window,
15663        cx: &mut Context<Self>,
15664    ) {
15665        let selection = self.selections.newest::<Point>(cx);
15666
15667        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15668        let range = if selection.is_empty() {
15669            let point = selection.head().to_display_point(&display_map);
15670            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15671            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15672                .to_point(&display_map);
15673            start..end
15674        } else {
15675            selection.range()
15676        };
15677        if display_map.folds_in_range(range).next().is_some() {
15678            self.unfold_recursive(&Default::default(), window, cx)
15679        } else {
15680            self.fold_recursive(&Default::default(), window, cx)
15681        }
15682    }
15683
15684    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15685        if self.is_singleton(cx) {
15686            let mut to_fold = Vec::new();
15687            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15688            let selections = self.selections.all_adjusted(cx);
15689
15690            for selection in selections {
15691                let range = selection.range().sorted();
15692                let buffer_start_row = range.start.row;
15693
15694                if range.start.row != range.end.row {
15695                    let mut found = false;
15696                    let mut row = range.start.row;
15697                    while row <= range.end.row {
15698                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15699                        {
15700                            found = true;
15701                            row = crease.range().end.row + 1;
15702                            to_fold.push(crease);
15703                        } else {
15704                            row += 1
15705                        }
15706                    }
15707                    if found {
15708                        continue;
15709                    }
15710                }
15711
15712                for row in (0..=range.start.row).rev() {
15713                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15714                        if crease.range().end.row >= buffer_start_row {
15715                            to_fold.push(crease);
15716                            if row <= range.start.row {
15717                                break;
15718                            }
15719                        }
15720                    }
15721                }
15722            }
15723
15724            self.fold_creases(to_fold, true, window, cx);
15725        } else {
15726            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15727            let buffer_ids = self
15728                .selections
15729                .disjoint_anchor_ranges()
15730                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15731                .collect::<HashSet<_>>();
15732            for buffer_id in buffer_ids {
15733                self.fold_buffer(buffer_id, cx);
15734            }
15735        }
15736    }
15737
15738    fn fold_at_level(
15739        &mut self,
15740        fold_at: &FoldAtLevel,
15741        window: &mut Window,
15742        cx: &mut Context<Self>,
15743    ) {
15744        if !self.buffer.read(cx).is_singleton() {
15745            return;
15746        }
15747
15748        let fold_at_level = fold_at.0;
15749        let snapshot = self.buffer.read(cx).snapshot(cx);
15750        let mut to_fold = Vec::new();
15751        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15752
15753        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15754            while start_row < end_row {
15755                match self
15756                    .snapshot(window, cx)
15757                    .crease_for_buffer_row(MultiBufferRow(start_row))
15758                {
15759                    Some(crease) => {
15760                        let nested_start_row = crease.range().start.row + 1;
15761                        let nested_end_row = crease.range().end.row;
15762
15763                        if current_level < fold_at_level {
15764                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15765                        } else if current_level == fold_at_level {
15766                            to_fold.push(crease);
15767                        }
15768
15769                        start_row = nested_end_row + 1;
15770                    }
15771                    None => start_row += 1,
15772                }
15773            }
15774        }
15775
15776        self.fold_creases(to_fold, true, window, cx);
15777    }
15778
15779    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15780        if self.buffer.read(cx).is_singleton() {
15781            let mut fold_ranges = Vec::new();
15782            let snapshot = self.buffer.read(cx).snapshot(cx);
15783
15784            for row in 0..snapshot.max_row().0 {
15785                if let Some(foldable_range) = self
15786                    .snapshot(window, cx)
15787                    .crease_for_buffer_row(MultiBufferRow(row))
15788                {
15789                    fold_ranges.push(foldable_range);
15790                }
15791            }
15792
15793            self.fold_creases(fold_ranges, true, window, cx);
15794        } else {
15795            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15796                editor
15797                    .update_in(cx, |editor, _, cx| {
15798                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15799                            editor.fold_buffer(buffer_id, cx);
15800                        }
15801                    })
15802                    .ok();
15803            });
15804        }
15805    }
15806
15807    pub fn fold_function_bodies(
15808        &mut self,
15809        _: &actions::FoldFunctionBodies,
15810        window: &mut Window,
15811        cx: &mut Context<Self>,
15812    ) {
15813        let snapshot = self.buffer.read(cx).snapshot(cx);
15814
15815        let ranges = snapshot
15816            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15817            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15818            .collect::<Vec<_>>();
15819
15820        let creases = ranges
15821            .into_iter()
15822            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15823            .collect();
15824
15825        self.fold_creases(creases, true, window, cx);
15826    }
15827
15828    pub fn fold_recursive(
15829        &mut self,
15830        _: &actions::FoldRecursive,
15831        window: &mut Window,
15832        cx: &mut Context<Self>,
15833    ) {
15834        let mut to_fold = Vec::new();
15835        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15836        let selections = self.selections.all_adjusted(cx);
15837
15838        for selection in selections {
15839            let range = selection.range().sorted();
15840            let buffer_start_row = range.start.row;
15841
15842            if range.start.row != range.end.row {
15843                let mut found = false;
15844                for row in range.start.row..=range.end.row {
15845                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15846                        found = true;
15847                        to_fold.push(crease);
15848                    }
15849                }
15850                if found {
15851                    continue;
15852                }
15853            }
15854
15855            for row in (0..=range.start.row).rev() {
15856                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15857                    if crease.range().end.row >= buffer_start_row {
15858                        to_fold.push(crease);
15859                    } else {
15860                        break;
15861                    }
15862                }
15863            }
15864        }
15865
15866        self.fold_creases(to_fold, true, window, cx);
15867    }
15868
15869    pub fn fold_at(
15870        &mut self,
15871        buffer_row: MultiBufferRow,
15872        window: &mut Window,
15873        cx: &mut Context<Self>,
15874    ) {
15875        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15876
15877        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15878            let autoscroll = self
15879                .selections
15880                .all::<Point>(cx)
15881                .iter()
15882                .any(|selection| crease.range().overlaps(&selection.range()));
15883
15884            self.fold_creases(vec![crease], autoscroll, window, cx);
15885        }
15886    }
15887
15888    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15889        if self.is_singleton(cx) {
15890            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15891            let buffer = &display_map.buffer_snapshot;
15892            let selections = self.selections.all::<Point>(cx);
15893            let ranges = selections
15894                .iter()
15895                .map(|s| {
15896                    let range = s.display_range(&display_map).sorted();
15897                    let mut start = range.start.to_point(&display_map);
15898                    let mut end = range.end.to_point(&display_map);
15899                    start.column = 0;
15900                    end.column = buffer.line_len(MultiBufferRow(end.row));
15901                    start..end
15902                })
15903                .collect::<Vec<_>>();
15904
15905            self.unfold_ranges(&ranges, true, true, cx);
15906        } else {
15907            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15908            let buffer_ids = self
15909                .selections
15910                .disjoint_anchor_ranges()
15911                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15912                .collect::<HashSet<_>>();
15913            for buffer_id in buffer_ids {
15914                self.unfold_buffer(buffer_id, cx);
15915            }
15916        }
15917    }
15918
15919    pub fn unfold_recursive(
15920        &mut self,
15921        _: &UnfoldRecursive,
15922        _window: &mut Window,
15923        cx: &mut Context<Self>,
15924    ) {
15925        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15926        let selections = self.selections.all::<Point>(cx);
15927        let ranges = selections
15928            .iter()
15929            .map(|s| {
15930                let mut range = s.display_range(&display_map).sorted();
15931                *range.start.column_mut() = 0;
15932                *range.end.column_mut() = display_map.line_len(range.end.row());
15933                let start = range.start.to_point(&display_map);
15934                let end = range.end.to_point(&display_map);
15935                start..end
15936            })
15937            .collect::<Vec<_>>();
15938
15939        self.unfold_ranges(&ranges, true, true, cx);
15940    }
15941
15942    pub fn unfold_at(
15943        &mut self,
15944        buffer_row: MultiBufferRow,
15945        _window: &mut Window,
15946        cx: &mut Context<Self>,
15947    ) {
15948        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15949
15950        let intersection_range = Point::new(buffer_row.0, 0)
15951            ..Point::new(
15952                buffer_row.0,
15953                display_map.buffer_snapshot.line_len(buffer_row),
15954            );
15955
15956        let autoscroll = self
15957            .selections
15958            .all::<Point>(cx)
15959            .iter()
15960            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15961
15962        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15963    }
15964
15965    pub fn unfold_all(
15966        &mut self,
15967        _: &actions::UnfoldAll,
15968        _window: &mut Window,
15969        cx: &mut Context<Self>,
15970    ) {
15971        if self.buffer.read(cx).is_singleton() {
15972            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15973            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15974        } else {
15975            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15976                editor
15977                    .update(cx, |editor, cx| {
15978                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15979                            editor.unfold_buffer(buffer_id, cx);
15980                        }
15981                    })
15982                    .ok();
15983            });
15984        }
15985    }
15986
15987    pub fn fold_selected_ranges(
15988        &mut self,
15989        _: &FoldSelectedRanges,
15990        window: &mut Window,
15991        cx: &mut Context<Self>,
15992    ) {
15993        let selections = self.selections.all_adjusted(cx);
15994        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15995        let ranges = selections
15996            .into_iter()
15997            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15998            .collect::<Vec<_>>();
15999        self.fold_creases(ranges, true, window, cx);
16000    }
16001
16002    pub fn fold_ranges<T: ToOffset + Clone>(
16003        &mut self,
16004        ranges: Vec<Range<T>>,
16005        auto_scroll: bool,
16006        window: &mut Window,
16007        cx: &mut Context<Self>,
16008    ) {
16009        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16010        let ranges = ranges
16011            .into_iter()
16012            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16013            .collect::<Vec<_>>();
16014        self.fold_creases(ranges, auto_scroll, window, cx);
16015    }
16016
16017    pub fn fold_creases<T: ToOffset + Clone>(
16018        &mut self,
16019        creases: Vec<Crease<T>>,
16020        auto_scroll: bool,
16021        _window: &mut Window,
16022        cx: &mut Context<Self>,
16023    ) {
16024        if creases.is_empty() {
16025            return;
16026        }
16027
16028        let mut buffers_affected = HashSet::default();
16029        let multi_buffer = self.buffer().read(cx);
16030        for crease in &creases {
16031            if let Some((_, buffer, _)) =
16032                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16033            {
16034                buffers_affected.insert(buffer.read(cx).remote_id());
16035            };
16036        }
16037
16038        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16039
16040        if auto_scroll {
16041            self.request_autoscroll(Autoscroll::fit(), cx);
16042        }
16043
16044        cx.notify();
16045
16046        self.scrollbar_marker_state.dirty = true;
16047        self.folds_did_change(cx);
16048    }
16049
16050    /// Removes any folds whose ranges intersect any of the given ranges.
16051    pub fn unfold_ranges<T: ToOffset + Clone>(
16052        &mut self,
16053        ranges: &[Range<T>],
16054        inclusive: bool,
16055        auto_scroll: bool,
16056        cx: &mut Context<Self>,
16057    ) {
16058        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16059            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16060        });
16061        self.folds_did_change(cx);
16062    }
16063
16064    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16065        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16066            return;
16067        }
16068        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16069        self.display_map.update(cx, |display_map, cx| {
16070            display_map.fold_buffers([buffer_id], cx)
16071        });
16072        cx.emit(EditorEvent::BufferFoldToggled {
16073            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16074            folded: true,
16075        });
16076        cx.notify();
16077    }
16078
16079    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16080        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16081            return;
16082        }
16083        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16084        self.display_map.update(cx, |display_map, cx| {
16085            display_map.unfold_buffers([buffer_id], cx);
16086        });
16087        cx.emit(EditorEvent::BufferFoldToggled {
16088            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16089            folded: false,
16090        });
16091        cx.notify();
16092    }
16093
16094    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16095        self.display_map.read(cx).is_buffer_folded(buffer)
16096    }
16097
16098    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16099        self.display_map.read(cx).folded_buffers()
16100    }
16101
16102    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16103        self.display_map.update(cx, |display_map, cx| {
16104            display_map.disable_header_for_buffer(buffer_id, cx);
16105        });
16106        cx.notify();
16107    }
16108
16109    /// Removes any folds with the given ranges.
16110    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16111        &mut self,
16112        ranges: &[Range<T>],
16113        type_id: TypeId,
16114        auto_scroll: bool,
16115        cx: &mut Context<Self>,
16116    ) {
16117        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16118            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16119        });
16120        self.folds_did_change(cx);
16121    }
16122
16123    fn remove_folds_with<T: ToOffset + Clone>(
16124        &mut self,
16125        ranges: &[Range<T>],
16126        auto_scroll: bool,
16127        cx: &mut Context<Self>,
16128        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16129    ) {
16130        if ranges.is_empty() {
16131            return;
16132        }
16133
16134        let mut buffers_affected = HashSet::default();
16135        let multi_buffer = self.buffer().read(cx);
16136        for range in ranges {
16137            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16138                buffers_affected.insert(buffer.read(cx).remote_id());
16139            };
16140        }
16141
16142        self.display_map.update(cx, update);
16143
16144        if auto_scroll {
16145            self.request_autoscroll(Autoscroll::fit(), cx);
16146        }
16147
16148        cx.notify();
16149        self.scrollbar_marker_state.dirty = true;
16150        self.active_indent_guides_state.dirty = true;
16151    }
16152
16153    pub fn update_fold_widths(
16154        &mut self,
16155        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16156        cx: &mut Context<Self>,
16157    ) -> bool {
16158        self.display_map
16159            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16160    }
16161
16162    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16163        self.display_map.read(cx).fold_placeholder.clone()
16164    }
16165
16166    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16167        self.buffer.update(cx, |buffer, cx| {
16168            buffer.set_all_diff_hunks_expanded(cx);
16169        });
16170    }
16171
16172    pub fn expand_all_diff_hunks(
16173        &mut self,
16174        _: &ExpandAllDiffHunks,
16175        _window: &mut Window,
16176        cx: &mut Context<Self>,
16177    ) {
16178        self.buffer.update(cx, |buffer, cx| {
16179            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16180        });
16181    }
16182
16183    pub fn toggle_selected_diff_hunks(
16184        &mut self,
16185        _: &ToggleSelectedDiffHunks,
16186        _window: &mut Window,
16187        cx: &mut Context<Self>,
16188    ) {
16189        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16190        self.toggle_diff_hunks_in_ranges(ranges, cx);
16191    }
16192
16193    pub fn diff_hunks_in_ranges<'a>(
16194        &'a self,
16195        ranges: &'a [Range<Anchor>],
16196        buffer: &'a MultiBufferSnapshot,
16197    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16198        ranges.iter().flat_map(move |range| {
16199            let end_excerpt_id = range.end.excerpt_id;
16200            let range = range.to_point(buffer);
16201            let mut peek_end = range.end;
16202            if range.end.row < buffer.max_row().0 {
16203                peek_end = Point::new(range.end.row + 1, 0);
16204            }
16205            buffer
16206                .diff_hunks_in_range(range.start..peek_end)
16207                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16208        })
16209    }
16210
16211    pub fn has_stageable_diff_hunks_in_ranges(
16212        &self,
16213        ranges: &[Range<Anchor>],
16214        snapshot: &MultiBufferSnapshot,
16215    ) -> bool {
16216        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16217        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16218    }
16219
16220    pub fn toggle_staged_selected_diff_hunks(
16221        &mut self,
16222        _: &::git::ToggleStaged,
16223        _: &mut Window,
16224        cx: &mut Context<Self>,
16225    ) {
16226        let snapshot = self.buffer.read(cx).snapshot(cx);
16227        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16228        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16229        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16230    }
16231
16232    pub fn set_render_diff_hunk_controls(
16233        &mut self,
16234        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16235        cx: &mut Context<Self>,
16236    ) {
16237        self.render_diff_hunk_controls = render_diff_hunk_controls;
16238        cx.notify();
16239    }
16240
16241    pub fn stage_and_next(
16242        &mut self,
16243        _: &::git::StageAndNext,
16244        window: &mut Window,
16245        cx: &mut Context<Self>,
16246    ) {
16247        self.do_stage_or_unstage_and_next(true, window, cx);
16248    }
16249
16250    pub fn unstage_and_next(
16251        &mut self,
16252        _: &::git::UnstageAndNext,
16253        window: &mut Window,
16254        cx: &mut Context<Self>,
16255    ) {
16256        self.do_stage_or_unstage_and_next(false, window, cx);
16257    }
16258
16259    pub fn stage_or_unstage_diff_hunks(
16260        &mut self,
16261        stage: bool,
16262        ranges: Vec<Range<Anchor>>,
16263        cx: &mut Context<Self>,
16264    ) {
16265        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16266        cx.spawn(async move |this, cx| {
16267            task.await?;
16268            this.update(cx, |this, cx| {
16269                let snapshot = this.buffer.read(cx).snapshot(cx);
16270                let chunk_by = this
16271                    .diff_hunks_in_ranges(&ranges, &snapshot)
16272                    .chunk_by(|hunk| hunk.buffer_id);
16273                for (buffer_id, hunks) in &chunk_by {
16274                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16275                }
16276            })
16277        })
16278        .detach_and_log_err(cx);
16279    }
16280
16281    fn save_buffers_for_ranges_if_needed(
16282        &mut self,
16283        ranges: &[Range<Anchor>],
16284        cx: &mut Context<Editor>,
16285    ) -> Task<Result<()>> {
16286        let multibuffer = self.buffer.read(cx);
16287        let snapshot = multibuffer.read(cx);
16288        let buffer_ids: HashSet<_> = ranges
16289            .iter()
16290            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16291            .collect();
16292        drop(snapshot);
16293
16294        let mut buffers = HashSet::default();
16295        for buffer_id in buffer_ids {
16296            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16297                let buffer = buffer_entity.read(cx);
16298                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16299                {
16300                    buffers.insert(buffer_entity);
16301                }
16302            }
16303        }
16304
16305        if let Some(project) = &self.project {
16306            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16307        } else {
16308            Task::ready(Ok(()))
16309        }
16310    }
16311
16312    fn do_stage_or_unstage_and_next(
16313        &mut self,
16314        stage: bool,
16315        window: &mut Window,
16316        cx: &mut Context<Self>,
16317    ) {
16318        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16319
16320        if ranges.iter().any(|range| range.start != range.end) {
16321            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16322            return;
16323        }
16324
16325        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16326        let snapshot = self.snapshot(window, cx);
16327        let position = self.selections.newest::<Point>(cx).head();
16328        let mut row = snapshot
16329            .buffer_snapshot
16330            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16331            .find(|hunk| hunk.row_range.start.0 > position.row)
16332            .map(|hunk| hunk.row_range.start);
16333
16334        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16335        // Outside of the project diff editor, wrap around to the beginning.
16336        if !all_diff_hunks_expanded {
16337            row = row.or_else(|| {
16338                snapshot
16339                    .buffer_snapshot
16340                    .diff_hunks_in_range(Point::zero()..position)
16341                    .find(|hunk| hunk.row_range.end.0 < position.row)
16342                    .map(|hunk| hunk.row_range.start)
16343            });
16344        }
16345
16346        if let Some(row) = row {
16347            let destination = Point::new(row.0, 0);
16348            let autoscroll = Autoscroll::center();
16349
16350            self.unfold_ranges(&[destination..destination], false, false, cx);
16351            self.change_selections(Some(autoscroll), window, cx, |s| {
16352                s.select_ranges([destination..destination]);
16353            });
16354        }
16355    }
16356
16357    fn do_stage_or_unstage(
16358        &self,
16359        stage: bool,
16360        buffer_id: BufferId,
16361        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16362        cx: &mut App,
16363    ) -> Option<()> {
16364        let project = self.project.as_ref()?;
16365        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16366        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16367        let buffer_snapshot = buffer.read(cx).snapshot();
16368        let file_exists = buffer_snapshot
16369            .file()
16370            .is_some_and(|file| file.disk_state().exists());
16371        diff.update(cx, |diff, cx| {
16372            diff.stage_or_unstage_hunks(
16373                stage,
16374                &hunks
16375                    .map(|hunk| buffer_diff::DiffHunk {
16376                        buffer_range: hunk.buffer_range,
16377                        diff_base_byte_range: hunk.diff_base_byte_range,
16378                        secondary_status: hunk.secondary_status,
16379                        range: Point::zero()..Point::zero(), // unused
16380                    })
16381                    .collect::<Vec<_>>(),
16382                &buffer_snapshot,
16383                file_exists,
16384                cx,
16385            )
16386        });
16387        None
16388    }
16389
16390    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16391        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16392        self.buffer
16393            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16394    }
16395
16396    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16397        self.buffer.update(cx, |buffer, cx| {
16398            let ranges = vec![Anchor::min()..Anchor::max()];
16399            if !buffer.all_diff_hunks_expanded()
16400                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16401            {
16402                buffer.collapse_diff_hunks(ranges, cx);
16403                true
16404            } else {
16405                false
16406            }
16407        })
16408    }
16409
16410    fn toggle_diff_hunks_in_ranges(
16411        &mut self,
16412        ranges: Vec<Range<Anchor>>,
16413        cx: &mut Context<Editor>,
16414    ) {
16415        self.buffer.update(cx, |buffer, cx| {
16416            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16417            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16418        })
16419    }
16420
16421    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16422        self.buffer.update(cx, |buffer, cx| {
16423            let snapshot = buffer.snapshot(cx);
16424            let excerpt_id = range.end.excerpt_id;
16425            let point_range = range.to_point(&snapshot);
16426            let expand = !buffer.single_hunk_is_expanded(range, cx);
16427            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16428        })
16429    }
16430
16431    pub(crate) fn apply_all_diff_hunks(
16432        &mut self,
16433        _: &ApplyAllDiffHunks,
16434        window: &mut Window,
16435        cx: &mut Context<Self>,
16436    ) {
16437        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16438
16439        let buffers = self.buffer.read(cx).all_buffers();
16440        for branch_buffer in buffers {
16441            branch_buffer.update(cx, |branch_buffer, cx| {
16442                branch_buffer.merge_into_base(Vec::new(), cx);
16443            });
16444        }
16445
16446        if let Some(project) = self.project.clone() {
16447            self.save(true, project, window, cx).detach_and_log_err(cx);
16448        }
16449    }
16450
16451    pub(crate) fn apply_selected_diff_hunks(
16452        &mut self,
16453        _: &ApplyDiffHunk,
16454        window: &mut Window,
16455        cx: &mut Context<Self>,
16456    ) {
16457        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16458        let snapshot = self.snapshot(window, cx);
16459        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16460        let mut ranges_by_buffer = HashMap::default();
16461        self.transact(window, cx, |editor, _window, cx| {
16462            for hunk in hunks {
16463                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16464                    ranges_by_buffer
16465                        .entry(buffer.clone())
16466                        .or_insert_with(Vec::new)
16467                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16468                }
16469            }
16470
16471            for (buffer, ranges) in ranges_by_buffer {
16472                buffer.update(cx, |buffer, cx| {
16473                    buffer.merge_into_base(ranges, cx);
16474                });
16475            }
16476        });
16477
16478        if let Some(project) = self.project.clone() {
16479            self.save(true, project, window, cx).detach_and_log_err(cx);
16480        }
16481    }
16482
16483    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16484        if hovered != self.gutter_hovered {
16485            self.gutter_hovered = hovered;
16486            cx.notify();
16487        }
16488    }
16489
16490    pub fn insert_blocks(
16491        &mut self,
16492        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16493        autoscroll: Option<Autoscroll>,
16494        cx: &mut Context<Self>,
16495    ) -> Vec<CustomBlockId> {
16496        let blocks = self
16497            .display_map
16498            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16499        if let Some(autoscroll) = autoscroll {
16500            self.request_autoscroll(autoscroll, cx);
16501        }
16502        cx.notify();
16503        blocks
16504    }
16505
16506    pub fn resize_blocks(
16507        &mut self,
16508        heights: HashMap<CustomBlockId, u32>,
16509        autoscroll: Option<Autoscroll>,
16510        cx: &mut Context<Self>,
16511    ) {
16512        self.display_map
16513            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16514        if let Some(autoscroll) = autoscroll {
16515            self.request_autoscroll(autoscroll, cx);
16516        }
16517        cx.notify();
16518    }
16519
16520    pub fn replace_blocks(
16521        &mut self,
16522        renderers: HashMap<CustomBlockId, RenderBlock>,
16523        autoscroll: Option<Autoscroll>,
16524        cx: &mut Context<Self>,
16525    ) {
16526        self.display_map
16527            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16528        if let Some(autoscroll) = autoscroll {
16529            self.request_autoscroll(autoscroll, cx);
16530        }
16531        cx.notify();
16532    }
16533
16534    pub fn remove_blocks(
16535        &mut self,
16536        block_ids: HashSet<CustomBlockId>,
16537        autoscroll: Option<Autoscroll>,
16538        cx: &mut Context<Self>,
16539    ) {
16540        self.display_map.update(cx, |display_map, cx| {
16541            display_map.remove_blocks(block_ids, cx)
16542        });
16543        if let Some(autoscroll) = autoscroll {
16544            self.request_autoscroll(autoscroll, cx);
16545        }
16546        cx.notify();
16547    }
16548
16549    pub fn row_for_block(
16550        &self,
16551        block_id: CustomBlockId,
16552        cx: &mut Context<Self>,
16553    ) -> Option<DisplayRow> {
16554        self.display_map
16555            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16556    }
16557
16558    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16559        self.focused_block = Some(focused_block);
16560    }
16561
16562    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16563        self.focused_block.take()
16564    }
16565
16566    pub fn insert_creases(
16567        &mut self,
16568        creases: impl IntoIterator<Item = Crease<Anchor>>,
16569        cx: &mut Context<Self>,
16570    ) -> Vec<CreaseId> {
16571        self.display_map
16572            .update(cx, |map, cx| map.insert_creases(creases, cx))
16573    }
16574
16575    pub fn remove_creases(
16576        &mut self,
16577        ids: impl IntoIterator<Item = CreaseId>,
16578        cx: &mut Context<Self>,
16579    ) -> Vec<(CreaseId, Range<Anchor>)> {
16580        self.display_map
16581            .update(cx, |map, cx| map.remove_creases(ids, cx))
16582    }
16583
16584    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16585        self.display_map
16586            .update(cx, |map, cx| map.snapshot(cx))
16587            .longest_row()
16588    }
16589
16590    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16591        self.display_map
16592            .update(cx, |map, cx| map.snapshot(cx))
16593            .max_point()
16594    }
16595
16596    pub fn text(&self, cx: &App) -> String {
16597        self.buffer.read(cx).read(cx).text()
16598    }
16599
16600    pub fn is_empty(&self, cx: &App) -> bool {
16601        self.buffer.read(cx).read(cx).is_empty()
16602    }
16603
16604    pub fn text_option(&self, cx: &App) -> Option<String> {
16605        let text = self.text(cx);
16606        let text = text.trim();
16607
16608        if text.is_empty() {
16609            return None;
16610        }
16611
16612        Some(text.to_string())
16613    }
16614
16615    pub fn set_text(
16616        &mut self,
16617        text: impl Into<Arc<str>>,
16618        window: &mut Window,
16619        cx: &mut Context<Self>,
16620    ) {
16621        self.transact(window, cx, |this, _, cx| {
16622            this.buffer
16623                .read(cx)
16624                .as_singleton()
16625                .expect("you can only call set_text on editors for singleton buffers")
16626                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16627        });
16628    }
16629
16630    pub fn display_text(&self, cx: &mut App) -> String {
16631        self.display_map
16632            .update(cx, |map, cx| map.snapshot(cx))
16633            .text()
16634    }
16635
16636    fn create_minimap(
16637        &self,
16638        minimap_settings: MinimapSettings,
16639        window: &mut Window,
16640        cx: &mut Context<Self>,
16641    ) -> Option<Entity<Self>> {
16642        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16643            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16644    }
16645
16646    fn initialize_new_minimap(
16647        &self,
16648        minimap_settings: MinimapSettings,
16649        window: &mut Window,
16650        cx: &mut Context<Self>,
16651    ) -> Entity<Self> {
16652        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16653
16654        let mut minimap = Editor::new_internal(
16655            EditorMode::Minimap {
16656                parent: cx.weak_entity(),
16657            },
16658            self.buffer.clone(),
16659            self.project.clone(),
16660            Some(self.display_map.clone()),
16661            window,
16662            cx,
16663        );
16664        minimap.scroll_manager.clone_state(&self.scroll_manager);
16665        minimap.set_text_style_refinement(TextStyleRefinement {
16666            font_size: Some(MINIMAP_FONT_SIZE),
16667            font_weight: Some(MINIMAP_FONT_WEIGHT),
16668            ..Default::default()
16669        });
16670        minimap.update_minimap_configuration(minimap_settings, cx);
16671        cx.new(|_| minimap)
16672    }
16673
16674    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16675        let current_line_highlight = minimap_settings
16676            .current_line_highlight
16677            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16678        self.set_current_line_highlight(Some(current_line_highlight));
16679    }
16680
16681    pub fn minimap(&self) -> Option<&Entity<Self>> {
16682        self.minimap
16683            .as_ref()
16684            .filter(|_| self.minimap_visibility.visible())
16685    }
16686
16687    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16688        let mut wrap_guides = smallvec::smallvec![];
16689
16690        if self.show_wrap_guides == Some(false) {
16691            return wrap_guides;
16692        }
16693
16694        let settings = self.buffer.read(cx).language_settings(cx);
16695        if settings.show_wrap_guides {
16696            match self.soft_wrap_mode(cx) {
16697                SoftWrap::Column(soft_wrap) => {
16698                    wrap_guides.push((soft_wrap as usize, true));
16699                }
16700                SoftWrap::Bounded(soft_wrap) => {
16701                    wrap_guides.push((soft_wrap as usize, true));
16702                }
16703                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16704            }
16705            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16706        }
16707
16708        wrap_guides
16709    }
16710
16711    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16712        let settings = self.buffer.read(cx).language_settings(cx);
16713        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16714        match mode {
16715            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16716                SoftWrap::None
16717            }
16718            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16719            language_settings::SoftWrap::PreferredLineLength => {
16720                SoftWrap::Column(settings.preferred_line_length)
16721            }
16722            language_settings::SoftWrap::Bounded => {
16723                SoftWrap::Bounded(settings.preferred_line_length)
16724            }
16725        }
16726    }
16727
16728    pub fn set_soft_wrap_mode(
16729        &mut self,
16730        mode: language_settings::SoftWrap,
16731
16732        cx: &mut Context<Self>,
16733    ) {
16734        self.soft_wrap_mode_override = Some(mode);
16735        cx.notify();
16736    }
16737
16738    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16739        self.hard_wrap = hard_wrap;
16740        cx.notify();
16741    }
16742
16743    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16744        self.text_style_refinement = Some(style);
16745    }
16746
16747    /// called by the Element so we know what style we were most recently rendered with.
16748    pub(crate) fn set_style(
16749        &mut self,
16750        style: EditorStyle,
16751        window: &mut Window,
16752        cx: &mut Context<Self>,
16753    ) {
16754        // We intentionally do not inform the display map about the minimap style
16755        // so that wrapping is not recalculated and stays consistent for the editor
16756        // and its linked minimap.
16757        if !self.mode.is_minimap() {
16758            let rem_size = window.rem_size();
16759            self.display_map.update(cx, |map, cx| {
16760                map.set_font(
16761                    style.text.font(),
16762                    style.text.font_size.to_pixels(rem_size),
16763                    cx,
16764                )
16765            });
16766        }
16767        self.style = Some(style);
16768    }
16769
16770    pub fn style(&self) -> Option<&EditorStyle> {
16771        self.style.as_ref()
16772    }
16773
16774    // Called by the element. This method is not designed to be called outside of the editor
16775    // element's layout code because it does not notify when rewrapping is computed synchronously.
16776    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16777        self.display_map
16778            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16779    }
16780
16781    pub fn set_soft_wrap(&mut self) {
16782        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16783    }
16784
16785    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16786        if self.soft_wrap_mode_override.is_some() {
16787            self.soft_wrap_mode_override.take();
16788        } else {
16789            let soft_wrap = match self.soft_wrap_mode(cx) {
16790                SoftWrap::GitDiff => return,
16791                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16792                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16793                    language_settings::SoftWrap::None
16794                }
16795            };
16796            self.soft_wrap_mode_override = Some(soft_wrap);
16797        }
16798        cx.notify();
16799    }
16800
16801    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16802        let Some(workspace) = self.workspace() else {
16803            return;
16804        };
16805        let fs = workspace.read(cx).app_state().fs.clone();
16806        let current_show = TabBarSettings::get_global(cx).show;
16807        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16808            setting.show = Some(!current_show);
16809        });
16810    }
16811
16812    pub fn toggle_indent_guides(
16813        &mut self,
16814        _: &ToggleIndentGuides,
16815        _: &mut Window,
16816        cx: &mut Context<Self>,
16817    ) {
16818        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16819            self.buffer
16820                .read(cx)
16821                .language_settings(cx)
16822                .indent_guides
16823                .enabled
16824        });
16825        self.show_indent_guides = Some(!currently_enabled);
16826        cx.notify();
16827    }
16828
16829    fn should_show_indent_guides(&self) -> Option<bool> {
16830        self.show_indent_guides
16831    }
16832
16833    pub fn toggle_line_numbers(
16834        &mut self,
16835        _: &ToggleLineNumbers,
16836        _: &mut Window,
16837        cx: &mut Context<Self>,
16838    ) {
16839        let mut editor_settings = EditorSettings::get_global(cx).clone();
16840        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16841        EditorSettings::override_global(editor_settings, cx);
16842    }
16843
16844    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16845        if let Some(show_line_numbers) = self.show_line_numbers {
16846            return show_line_numbers;
16847        }
16848        EditorSettings::get_global(cx).gutter.line_numbers
16849    }
16850
16851    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16852        self.use_relative_line_numbers
16853            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16854    }
16855
16856    pub fn toggle_relative_line_numbers(
16857        &mut self,
16858        _: &ToggleRelativeLineNumbers,
16859        _: &mut Window,
16860        cx: &mut Context<Self>,
16861    ) {
16862        let is_relative = self.should_use_relative_line_numbers(cx);
16863        self.set_relative_line_number(Some(!is_relative), cx)
16864    }
16865
16866    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16867        self.use_relative_line_numbers = is_relative;
16868        cx.notify();
16869    }
16870
16871    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16872        self.show_gutter = show_gutter;
16873        cx.notify();
16874    }
16875
16876    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16877        self.show_scrollbars = show_scrollbars;
16878        cx.notify();
16879    }
16880
16881    pub fn set_minimap_visibility(
16882        &mut self,
16883        minimap_visibility: MinimapVisibility,
16884        window: &mut Window,
16885        cx: &mut Context<Self>,
16886    ) {
16887        if self.minimap_visibility != minimap_visibility {
16888            if minimap_visibility.visible() && self.minimap.is_none() {
16889                let minimap_settings = EditorSettings::get_global(cx).minimap;
16890                self.minimap =
16891                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16892            }
16893            self.minimap_visibility = minimap_visibility;
16894            cx.notify();
16895        }
16896    }
16897
16898    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16899        self.set_show_scrollbars(false, cx);
16900        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16901    }
16902
16903    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16904        self.show_line_numbers = Some(show_line_numbers);
16905        cx.notify();
16906    }
16907
16908    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16909        self.disable_expand_excerpt_buttons = true;
16910        cx.notify();
16911    }
16912
16913    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16914        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16915        cx.notify();
16916    }
16917
16918    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16919        self.show_code_actions = Some(show_code_actions);
16920        cx.notify();
16921    }
16922
16923    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16924        self.show_runnables = Some(show_runnables);
16925        cx.notify();
16926    }
16927
16928    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16929        self.show_breakpoints = Some(show_breakpoints);
16930        cx.notify();
16931    }
16932
16933    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16934        if self.display_map.read(cx).masked != masked {
16935            self.display_map.update(cx, |map, _| map.masked = masked);
16936        }
16937        cx.notify()
16938    }
16939
16940    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16941        self.show_wrap_guides = Some(show_wrap_guides);
16942        cx.notify();
16943    }
16944
16945    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16946        self.show_indent_guides = Some(show_indent_guides);
16947        cx.notify();
16948    }
16949
16950    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16951        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16952            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16953                if let Some(dir) = file.abs_path(cx).parent() {
16954                    return Some(dir.to_owned());
16955                }
16956            }
16957
16958            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16959                return Some(project_path.path.to_path_buf());
16960            }
16961        }
16962
16963        None
16964    }
16965
16966    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16967        self.active_excerpt(cx)?
16968            .1
16969            .read(cx)
16970            .file()
16971            .and_then(|f| f.as_local())
16972    }
16973
16974    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16975        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16976            let buffer = buffer.read(cx);
16977            if let Some(project_path) = buffer.project_path(cx) {
16978                let project = self.project.as_ref()?.read(cx);
16979                project.absolute_path(&project_path, cx)
16980            } else {
16981                buffer
16982                    .file()
16983                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16984            }
16985        })
16986    }
16987
16988    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16989        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16990            let project_path = buffer.read(cx).project_path(cx)?;
16991            let project = self.project.as_ref()?.read(cx);
16992            let entry = project.entry_for_path(&project_path, cx)?;
16993            let path = entry.path.to_path_buf();
16994            Some(path)
16995        })
16996    }
16997
16998    pub fn reveal_in_finder(
16999        &mut self,
17000        _: &RevealInFileManager,
17001        _window: &mut Window,
17002        cx: &mut Context<Self>,
17003    ) {
17004        if let Some(target) = self.target_file(cx) {
17005            cx.reveal_path(&target.abs_path(cx));
17006        }
17007    }
17008
17009    pub fn copy_path(
17010        &mut self,
17011        _: &zed_actions::workspace::CopyPath,
17012        _window: &mut Window,
17013        cx: &mut Context<Self>,
17014    ) {
17015        if let Some(path) = self.target_file_abs_path(cx) {
17016            if let Some(path) = path.to_str() {
17017                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17018            }
17019        }
17020    }
17021
17022    pub fn copy_relative_path(
17023        &mut self,
17024        _: &zed_actions::workspace::CopyRelativePath,
17025        _window: &mut Window,
17026        cx: &mut Context<Self>,
17027    ) {
17028        if let Some(path) = self.target_file_path(cx) {
17029            if let Some(path) = path.to_str() {
17030                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17031            }
17032        }
17033    }
17034
17035    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17036        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17037            buffer.read(cx).project_path(cx)
17038        } else {
17039            None
17040        }
17041    }
17042
17043    // Returns true if the editor handled a go-to-line request
17044    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17045        maybe!({
17046            let breakpoint_store = self.breakpoint_store.as_ref()?;
17047
17048            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17049            else {
17050                self.clear_row_highlights::<ActiveDebugLine>();
17051                return None;
17052            };
17053
17054            let position = active_stack_frame.position;
17055            let buffer_id = position.buffer_id?;
17056            let snapshot = self
17057                .project
17058                .as_ref()?
17059                .read(cx)
17060                .buffer_for_id(buffer_id, cx)?
17061                .read(cx)
17062                .snapshot();
17063
17064            let mut handled = false;
17065            for (id, ExcerptRange { context, .. }) in
17066                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17067            {
17068                if context.start.cmp(&position, &snapshot).is_ge()
17069                    || context.end.cmp(&position, &snapshot).is_lt()
17070                {
17071                    continue;
17072                }
17073                let snapshot = self.buffer.read(cx).snapshot(cx);
17074                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17075
17076                handled = true;
17077                self.clear_row_highlights::<ActiveDebugLine>();
17078
17079                self.go_to_line::<ActiveDebugLine>(
17080                    multibuffer_anchor,
17081                    Some(cx.theme().colors().editor_debugger_active_line_background),
17082                    window,
17083                    cx,
17084                );
17085
17086                cx.notify();
17087            }
17088
17089            handled.then_some(())
17090        })
17091        .is_some()
17092    }
17093
17094    pub fn copy_file_name_without_extension(
17095        &mut self,
17096        _: &CopyFileNameWithoutExtension,
17097        _: &mut Window,
17098        cx: &mut Context<Self>,
17099    ) {
17100        if let Some(file) = self.target_file(cx) {
17101            if let Some(file_stem) = file.path().file_stem() {
17102                if let Some(name) = file_stem.to_str() {
17103                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17104                }
17105            }
17106        }
17107    }
17108
17109    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17110        if let Some(file) = self.target_file(cx) {
17111            if let Some(file_name) = file.path().file_name() {
17112                if let Some(name) = file_name.to_str() {
17113                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17114                }
17115            }
17116        }
17117    }
17118
17119    pub fn toggle_git_blame(
17120        &mut self,
17121        _: &::git::Blame,
17122        window: &mut Window,
17123        cx: &mut Context<Self>,
17124    ) {
17125        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17126
17127        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17128            self.start_git_blame(true, window, cx);
17129        }
17130
17131        cx.notify();
17132    }
17133
17134    pub fn toggle_git_blame_inline(
17135        &mut self,
17136        _: &ToggleGitBlameInline,
17137        window: &mut Window,
17138        cx: &mut Context<Self>,
17139    ) {
17140        self.toggle_git_blame_inline_internal(true, window, cx);
17141        cx.notify();
17142    }
17143
17144    pub fn open_git_blame_commit(
17145        &mut self,
17146        _: &OpenGitBlameCommit,
17147        window: &mut Window,
17148        cx: &mut Context<Self>,
17149    ) {
17150        self.open_git_blame_commit_internal(window, cx);
17151    }
17152
17153    fn open_git_blame_commit_internal(
17154        &mut self,
17155        window: &mut Window,
17156        cx: &mut Context<Self>,
17157    ) -> Option<()> {
17158        let blame = self.blame.as_ref()?;
17159        let snapshot = self.snapshot(window, cx);
17160        let cursor = self.selections.newest::<Point>(cx).head();
17161        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17162        let blame_entry = blame
17163            .update(cx, |blame, cx| {
17164                blame
17165                    .blame_for_rows(
17166                        &[RowInfo {
17167                            buffer_id: Some(buffer.remote_id()),
17168                            buffer_row: Some(point.row),
17169                            ..Default::default()
17170                        }],
17171                        cx,
17172                    )
17173                    .next()
17174            })
17175            .flatten()?;
17176        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17177        let repo = blame.read(cx).repository(cx)?;
17178        let workspace = self.workspace()?.downgrade();
17179        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17180        None
17181    }
17182
17183    pub fn git_blame_inline_enabled(&self) -> bool {
17184        self.git_blame_inline_enabled
17185    }
17186
17187    pub fn toggle_selection_menu(
17188        &mut self,
17189        _: &ToggleSelectionMenu,
17190        _: &mut Window,
17191        cx: &mut Context<Self>,
17192    ) {
17193        self.show_selection_menu = self
17194            .show_selection_menu
17195            .map(|show_selections_menu| !show_selections_menu)
17196            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17197
17198        cx.notify();
17199    }
17200
17201    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17202        self.show_selection_menu
17203            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17204    }
17205
17206    fn start_git_blame(
17207        &mut self,
17208        user_triggered: bool,
17209        window: &mut Window,
17210        cx: &mut Context<Self>,
17211    ) {
17212        if let Some(project) = self.project.as_ref() {
17213            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17214                return;
17215            };
17216
17217            if buffer.read(cx).file().is_none() {
17218                return;
17219            }
17220
17221            let focused = self.focus_handle(cx).contains_focused(window, cx);
17222
17223            let project = project.clone();
17224            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17225            self.blame_subscription =
17226                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17227            self.blame = Some(blame);
17228        }
17229    }
17230
17231    fn toggle_git_blame_inline_internal(
17232        &mut self,
17233        user_triggered: bool,
17234        window: &mut Window,
17235        cx: &mut Context<Self>,
17236    ) {
17237        if self.git_blame_inline_enabled {
17238            self.git_blame_inline_enabled = false;
17239            self.show_git_blame_inline = false;
17240            self.show_git_blame_inline_delay_task.take();
17241        } else {
17242            self.git_blame_inline_enabled = true;
17243            self.start_git_blame_inline(user_triggered, window, cx);
17244        }
17245
17246        cx.notify();
17247    }
17248
17249    fn start_git_blame_inline(
17250        &mut self,
17251        user_triggered: bool,
17252        window: &mut Window,
17253        cx: &mut Context<Self>,
17254    ) {
17255        self.start_git_blame(user_triggered, window, cx);
17256
17257        if ProjectSettings::get_global(cx)
17258            .git
17259            .inline_blame_delay()
17260            .is_some()
17261        {
17262            self.start_inline_blame_timer(window, cx);
17263        } else {
17264            self.show_git_blame_inline = true
17265        }
17266    }
17267
17268    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17269        self.blame.as_ref()
17270    }
17271
17272    pub fn show_git_blame_gutter(&self) -> bool {
17273        self.show_git_blame_gutter
17274    }
17275
17276    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17277        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17278    }
17279
17280    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17281        self.show_git_blame_inline
17282            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17283            && !self.newest_selection_head_on_empty_line(cx)
17284            && self.has_blame_entries(cx)
17285    }
17286
17287    fn has_blame_entries(&self, cx: &App) -> bool {
17288        self.blame()
17289            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17290    }
17291
17292    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17293        let cursor_anchor = self.selections.newest_anchor().head();
17294
17295        let snapshot = self.buffer.read(cx).snapshot(cx);
17296        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17297
17298        snapshot.line_len(buffer_row) == 0
17299    }
17300
17301    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17302        let buffer_and_selection = maybe!({
17303            let selection = self.selections.newest::<Point>(cx);
17304            let selection_range = selection.range();
17305
17306            let multi_buffer = self.buffer().read(cx);
17307            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17308            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17309
17310            let (buffer, range, _) = if selection.reversed {
17311                buffer_ranges.first()
17312            } else {
17313                buffer_ranges.last()
17314            }?;
17315
17316            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17317                ..text::ToPoint::to_point(&range.end, &buffer).row;
17318            Some((
17319                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17320                selection,
17321            ))
17322        });
17323
17324        let Some((buffer, selection)) = buffer_and_selection else {
17325            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17326        };
17327
17328        let Some(project) = self.project.as_ref() else {
17329            return Task::ready(Err(anyhow!("editor does not have project")));
17330        };
17331
17332        project.update(cx, |project, cx| {
17333            project.get_permalink_to_line(&buffer, selection, cx)
17334        })
17335    }
17336
17337    pub fn copy_permalink_to_line(
17338        &mut self,
17339        _: &CopyPermalinkToLine,
17340        window: &mut Window,
17341        cx: &mut Context<Self>,
17342    ) {
17343        let permalink_task = self.get_permalink_to_line(cx);
17344        let workspace = self.workspace();
17345
17346        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17347            Ok(permalink) => {
17348                cx.update(|_, cx| {
17349                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17350                })
17351                .ok();
17352            }
17353            Err(err) => {
17354                let message = format!("Failed to copy permalink: {err}");
17355
17356                anyhow::Result::<()>::Err(err).log_err();
17357
17358                if let Some(workspace) = workspace {
17359                    workspace
17360                        .update_in(cx, |workspace, _, cx| {
17361                            struct CopyPermalinkToLine;
17362
17363                            workspace.show_toast(
17364                                Toast::new(
17365                                    NotificationId::unique::<CopyPermalinkToLine>(),
17366                                    message,
17367                                ),
17368                                cx,
17369                            )
17370                        })
17371                        .ok();
17372                }
17373            }
17374        })
17375        .detach();
17376    }
17377
17378    pub fn copy_file_location(
17379        &mut self,
17380        _: &CopyFileLocation,
17381        _: &mut Window,
17382        cx: &mut Context<Self>,
17383    ) {
17384        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17385        if let Some(file) = self.target_file(cx) {
17386            if let Some(path) = file.path().to_str() {
17387                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17388            }
17389        }
17390    }
17391
17392    pub fn open_permalink_to_line(
17393        &mut self,
17394        _: &OpenPermalinkToLine,
17395        window: &mut Window,
17396        cx: &mut Context<Self>,
17397    ) {
17398        let permalink_task = self.get_permalink_to_line(cx);
17399        let workspace = self.workspace();
17400
17401        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17402            Ok(permalink) => {
17403                cx.update(|_, cx| {
17404                    cx.open_url(permalink.as_ref());
17405                })
17406                .ok();
17407            }
17408            Err(err) => {
17409                let message = format!("Failed to open permalink: {err}");
17410
17411                anyhow::Result::<()>::Err(err).log_err();
17412
17413                if let Some(workspace) = workspace {
17414                    workspace
17415                        .update(cx, |workspace, cx| {
17416                            struct OpenPermalinkToLine;
17417
17418                            workspace.show_toast(
17419                                Toast::new(
17420                                    NotificationId::unique::<OpenPermalinkToLine>(),
17421                                    message,
17422                                ),
17423                                cx,
17424                            )
17425                        })
17426                        .ok();
17427                }
17428            }
17429        })
17430        .detach();
17431    }
17432
17433    pub fn insert_uuid_v4(
17434        &mut self,
17435        _: &InsertUuidV4,
17436        window: &mut Window,
17437        cx: &mut Context<Self>,
17438    ) {
17439        self.insert_uuid(UuidVersion::V4, window, cx);
17440    }
17441
17442    pub fn insert_uuid_v7(
17443        &mut self,
17444        _: &InsertUuidV7,
17445        window: &mut Window,
17446        cx: &mut Context<Self>,
17447    ) {
17448        self.insert_uuid(UuidVersion::V7, window, cx);
17449    }
17450
17451    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17452        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17453        self.transact(window, cx, |this, window, cx| {
17454            let edits = this
17455                .selections
17456                .all::<Point>(cx)
17457                .into_iter()
17458                .map(|selection| {
17459                    let uuid = match version {
17460                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17461                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17462                    };
17463
17464                    (selection.range(), uuid.to_string())
17465                });
17466            this.edit(edits, cx);
17467            this.refresh_inline_completion(true, false, window, cx);
17468        });
17469    }
17470
17471    pub fn open_selections_in_multibuffer(
17472        &mut self,
17473        _: &OpenSelectionsInMultibuffer,
17474        window: &mut Window,
17475        cx: &mut Context<Self>,
17476    ) {
17477        let multibuffer = self.buffer.read(cx);
17478
17479        let Some(buffer) = multibuffer.as_singleton() else {
17480            return;
17481        };
17482
17483        let Some(workspace) = self.workspace() else {
17484            return;
17485        };
17486
17487        let locations = self
17488            .selections
17489            .disjoint_anchors()
17490            .iter()
17491            .map(|range| Location {
17492                buffer: buffer.clone(),
17493                range: range.start.text_anchor..range.end.text_anchor,
17494            })
17495            .collect::<Vec<_>>();
17496
17497        let title = multibuffer.title(cx).to_string();
17498
17499        cx.spawn_in(window, async move |_, cx| {
17500            workspace.update_in(cx, |workspace, window, cx| {
17501                Self::open_locations_in_multibuffer(
17502                    workspace,
17503                    locations,
17504                    format!("Selections for '{title}'"),
17505                    false,
17506                    MultibufferSelectionMode::All,
17507                    window,
17508                    cx,
17509                );
17510            })
17511        })
17512        .detach();
17513    }
17514
17515    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17516    /// last highlight added will be used.
17517    ///
17518    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17519    pub fn highlight_rows<T: 'static>(
17520        &mut self,
17521        range: Range<Anchor>,
17522        color: Hsla,
17523        options: RowHighlightOptions,
17524        cx: &mut Context<Self>,
17525    ) {
17526        let snapshot = self.buffer().read(cx).snapshot(cx);
17527        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17528        let ix = row_highlights.binary_search_by(|highlight| {
17529            Ordering::Equal
17530                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17531                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17532        });
17533
17534        if let Err(mut ix) = ix {
17535            let index = post_inc(&mut self.highlight_order);
17536
17537            // If this range intersects with the preceding highlight, then merge it with
17538            // the preceding highlight. Otherwise insert a new highlight.
17539            let mut merged = false;
17540            if ix > 0 {
17541                let prev_highlight = &mut row_highlights[ix - 1];
17542                if prev_highlight
17543                    .range
17544                    .end
17545                    .cmp(&range.start, &snapshot)
17546                    .is_ge()
17547                {
17548                    ix -= 1;
17549                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17550                        prev_highlight.range.end = range.end;
17551                    }
17552                    merged = true;
17553                    prev_highlight.index = index;
17554                    prev_highlight.color = color;
17555                    prev_highlight.options = options;
17556                }
17557            }
17558
17559            if !merged {
17560                row_highlights.insert(
17561                    ix,
17562                    RowHighlight {
17563                        range: range.clone(),
17564                        index,
17565                        color,
17566                        options,
17567                        type_id: TypeId::of::<T>(),
17568                    },
17569                );
17570            }
17571
17572            // If any of the following highlights intersect with this one, merge them.
17573            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17574                let highlight = &row_highlights[ix];
17575                if next_highlight
17576                    .range
17577                    .start
17578                    .cmp(&highlight.range.end, &snapshot)
17579                    .is_le()
17580                {
17581                    if next_highlight
17582                        .range
17583                        .end
17584                        .cmp(&highlight.range.end, &snapshot)
17585                        .is_gt()
17586                    {
17587                        row_highlights[ix].range.end = next_highlight.range.end;
17588                    }
17589                    row_highlights.remove(ix + 1);
17590                } else {
17591                    break;
17592                }
17593            }
17594        }
17595    }
17596
17597    /// Remove any highlighted row ranges of the given type that intersect the
17598    /// given ranges.
17599    pub fn remove_highlighted_rows<T: 'static>(
17600        &mut self,
17601        ranges_to_remove: Vec<Range<Anchor>>,
17602        cx: &mut Context<Self>,
17603    ) {
17604        let snapshot = self.buffer().read(cx).snapshot(cx);
17605        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17606        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17607        row_highlights.retain(|highlight| {
17608            while let Some(range_to_remove) = ranges_to_remove.peek() {
17609                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17610                    Ordering::Less | Ordering::Equal => {
17611                        ranges_to_remove.next();
17612                    }
17613                    Ordering::Greater => {
17614                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17615                            Ordering::Less | Ordering::Equal => {
17616                                return false;
17617                            }
17618                            Ordering::Greater => break,
17619                        }
17620                    }
17621                }
17622            }
17623
17624            true
17625        })
17626    }
17627
17628    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17629    pub fn clear_row_highlights<T: 'static>(&mut self) {
17630        self.highlighted_rows.remove(&TypeId::of::<T>());
17631    }
17632
17633    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17634    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17635        self.highlighted_rows
17636            .get(&TypeId::of::<T>())
17637            .map_or(&[] as &[_], |vec| vec.as_slice())
17638            .iter()
17639            .map(|highlight| (highlight.range.clone(), highlight.color))
17640    }
17641
17642    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17643    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17644    /// Allows to ignore certain kinds of highlights.
17645    pub fn highlighted_display_rows(
17646        &self,
17647        window: &mut Window,
17648        cx: &mut App,
17649    ) -> BTreeMap<DisplayRow, LineHighlight> {
17650        let snapshot = self.snapshot(window, cx);
17651        let mut used_highlight_orders = HashMap::default();
17652        self.highlighted_rows
17653            .iter()
17654            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17655            .fold(
17656                BTreeMap::<DisplayRow, LineHighlight>::new(),
17657                |mut unique_rows, highlight| {
17658                    let start = highlight.range.start.to_display_point(&snapshot);
17659                    let end = highlight.range.end.to_display_point(&snapshot);
17660                    let start_row = start.row().0;
17661                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17662                        && end.column() == 0
17663                    {
17664                        end.row().0.saturating_sub(1)
17665                    } else {
17666                        end.row().0
17667                    };
17668                    for row in start_row..=end_row {
17669                        let used_index =
17670                            used_highlight_orders.entry(row).or_insert(highlight.index);
17671                        if highlight.index >= *used_index {
17672                            *used_index = highlight.index;
17673                            unique_rows.insert(
17674                                DisplayRow(row),
17675                                LineHighlight {
17676                                    include_gutter: highlight.options.include_gutter,
17677                                    border: None,
17678                                    background: highlight.color.into(),
17679                                    type_id: Some(highlight.type_id),
17680                                },
17681                            );
17682                        }
17683                    }
17684                    unique_rows
17685                },
17686            )
17687    }
17688
17689    pub fn highlighted_display_row_for_autoscroll(
17690        &self,
17691        snapshot: &DisplaySnapshot,
17692    ) -> Option<DisplayRow> {
17693        self.highlighted_rows
17694            .values()
17695            .flat_map(|highlighted_rows| highlighted_rows.iter())
17696            .filter_map(|highlight| {
17697                if highlight.options.autoscroll {
17698                    Some(highlight.range.start.to_display_point(snapshot).row())
17699                } else {
17700                    None
17701                }
17702            })
17703            .min()
17704    }
17705
17706    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17707        self.highlight_background::<SearchWithinRange>(
17708            ranges,
17709            |colors| colors.editor_document_highlight_read_background,
17710            cx,
17711        )
17712    }
17713
17714    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17715        self.breadcrumb_header = Some(new_header);
17716    }
17717
17718    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17719        self.clear_background_highlights::<SearchWithinRange>(cx);
17720    }
17721
17722    pub fn highlight_background<T: 'static>(
17723        &mut self,
17724        ranges: &[Range<Anchor>],
17725        color_fetcher: fn(&ThemeColors) -> Hsla,
17726        cx: &mut Context<Self>,
17727    ) {
17728        self.background_highlights
17729            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17730        self.scrollbar_marker_state.dirty = true;
17731        cx.notify();
17732    }
17733
17734    pub fn clear_background_highlights<T: 'static>(
17735        &mut self,
17736        cx: &mut Context<Self>,
17737    ) -> Option<BackgroundHighlight> {
17738        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17739        if !text_highlights.1.is_empty() {
17740            self.scrollbar_marker_state.dirty = true;
17741            cx.notify();
17742        }
17743        Some(text_highlights)
17744    }
17745
17746    pub fn highlight_gutter<T: 'static>(
17747        &mut self,
17748        ranges: &[Range<Anchor>],
17749        color_fetcher: fn(&App) -> Hsla,
17750        cx: &mut Context<Self>,
17751    ) {
17752        self.gutter_highlights
17753            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17754        cx.notify();
17755    }
17756
17757    pub fn clear_gutter_highlights<T: 'static>(
17758        &mut self,
17759        cx: &mut Context<Self>,
17760    ) -> Option<GutterHighlight> {
17761        cx.notify();
17762        self.gutter_highlights.remove(&TypeId::of::<T>())
17763    }
17764
17765    #[cfg(feature = "test-support")]
17766    pub fn all_text_background_highlights(
17767        &self,
17768        window: &mut Window,
17769        cx: &mut Context<Self>,
17770    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17771        let snapshot = self.snapshot(window, cx);
17772        let buffer = &snapshot.buffer_snapshot;
17773        let start = buffer.anchor_before(0);
17774        let end = buffer.anchor_after(buffer.len());
17775        let theme = cx.theme().colors();
17776        self.background_highlights_in_range(start..end, &snapshot, theme)
17777    }
17778
17779    #[cfg(feature = "test-support")]
17780    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17781        let snapshot = self.buffer().read(cx).snapshot(cx);
17782
17783        let highlights = self
17784            .background_highlights
17785            .get(&TypeId::of::<items::BufferSearchHighlights>());
17786
17787        if let Some((_color, ranges)) = highlights {
17788            ranges
17789                .iter()
17790                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17791                .collect_vec()
17792        } else {
17793            vec![]
17794        }
17795    }
17796
17797    fn document_highlights_for_position<'a>(
17798        &'a self,
17799        position: Anchor,
17800        buffer: &'a MultiBufferSnapshot,
17801    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17802        let read_highlights = self
17803            .background_highlights
17804            .get(&TypeId::of::<DocumentHighlightRead>())
17805            .map(|h| &h.1);
17806        let write_highlights = self
17807            .background_highlights
17808            .get(&TypeId::of::<DocumentHighlightWrite>())
17809            .map(|h| &h.1);
17810        let left_position = position.bias_left(buffer);
17811        let right_position = position.bias_right(buffer);
17812        read_highlights
17813            .into_iter()
17814            .chain(write_highlights)
17815            .flat_map(move |ranges| {
17816                let start_ix = match ranges.binary_search_by(|probe| {
17817                    let cmp = probe.end.cmp(&left_position, buffer);
17818                    if cmp.is_ge() {
17819                        Ordering::Greater
17820                    } else {
17821                        Ordering::Less
17822                    }
17823                }) {
17824                    Ok(i) | Err(i) => i,
17825                };
17826
17827                ranges[start_ix..]
17828                    .iter()
17829                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17830            })
17831    }
17832
17833    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17834        self.background_highlights
17835            .get(&TypeId::of::<T>())
17836            .map_or(false, |(_, highlights)| !highlights.is_empty())
17837    }
17838
17839    pub fn background_highlights_in_range(
17840        &self,
17841        search_range: Range<Anchor>,
17842        display_snapshot: &DisplaySnapshot,
17843        theme: &ThemeColors,
17844    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17845        let mut results = Vec::new();
17846        for (color_fetcher, ranges) in self.background_highlights.values() {
17847            let color = color_fetcher(theme);
17848            let start_ix = match ranges.binary_search_by(|probe| {
17849                let cmp = probe
17850                    .end
17851                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17852                if cmp.is_gt() {
17853                    Ordering::Greater
17854                } else {
17855                    Ordering::Less
17856                }
17857            }) {
17858                Ok(i) | Err(i) => i,
17859            };
17860            for range in &ranges[start_ix..] {
17861                if range
17862                    .start
17863                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17864                    .is_ge()
17865                {
17866                    break;
17867                }
17868
17869                let start = range.start.to_display_point(display_snapshot);
17870                let end = range.end.to_display_point(display_snapshot);
17871                results.push((start..end, color))
17872            }
17873        }
17874        results
17875    }
17876
17877    pub fn background_highlight_row_ranges<T: 'static>(
17878        &self,
17879        search_range: Range<Anchor>,
17880        display_snapshot: &DisplaySnapshot,
17881        count: usize,
17882    ) -> Vec<RangeInclusive<DisplayPoint>> {
17883        let mut results = Vec::new();
17884        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17885            return vec![];
17886        };
17887
17888        let start_ix = match ranges.binary_search_by(|probe| {
17889            let cmp = probe
17890                .end
17891                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17892            if cmp.is_gt() {
17893                Ordering::Greater
17894            } else {
17895                Ordering::Less
17896            }
17897        }) {
17898            Ok(i) | Err(i) => i,
17899        };
17900        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17901            if let (Some(start_display), Some(end_display)) = (start, end) {
17902                results.push(
17903                    start_display.to_display_point(display_snapshot)
17904                        ..=end_display.to_display_point(display_snapshot),
17905                );
17906            }
17907        };
17908        let mut start_row: Option<Point> = None;
17909        let mut end_row: Option<Point> = None;
17910        if ranges.len() > count {
17911            return Vec::new();
17912        }
17913        for range in &ranges[start_ix..] {
17914            if range
17915                .start
17916                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17917                .is_ge()
17918            {
17919                break;
17920            }
17921            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17922            if let Some(current_row) = &end_row {
17923                if end.row == current_row.row {
17924                    continue;
17925                }
17926            }
17927            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17928            if start_row.is_none() {
17929                assert_eq!(end_row, None);
17930                start_row = Some(start);
17931                end_row = Some(end);
17932                continue;
17933            }
17934            if let Some(current_end) = end_row.as_mut() {
17935                if start.row > current_end.row + 1 {
17936                    push_region(start_row, end_row);
17937                    start_row = Some(start);
17938                    end_row = Some(end);
17939                } else {
17940                    // Merge two hunks.
17941                    *current_end = end;
17942                }
17943            } else {
17944                unreachable!();
17945            }
17946        }
17947        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17948        push_region(start_row, end_row);
17949        results
17950    }
17951
17952    pub fn gutter_highlights_in_range(
17953        &self,
17954        search_range: Range<Anchor>,
17955        display_snapshot: &DisplaySnapshot,
17956        cx: &App,
17957    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17958        let mut results = Vec::new();
17959        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17960            let color = color_fetcher(cx);
17961            let start_ix = match ranges.binary_search_by(|probe| {
17962                let cmp = probe
17963                    .end
17964                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17965                if cmp.is_gt() {
17966                    Ordering::Greater
17967                } else {
17968                    Ordering::Less
17969                }
17970            }) {
17971                Ok(i) | Err(i) => i,
17972            };
17973            for range in &ranges[start_ix..] {
17974                if range
17975                    .start
17976                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17977                    .is_ge()
17978                {
17979                    break;
17980                }
17981
17982                let start = range.start.to_display_point(display_snapshot);
17983                let end = range.end.to_display_point(display_snapshot);
17984                results.push((start..end, color))
17985            }
17986        }
17987        results
17988    }
17989
17990    /// Get the text ranges corresponding to the redaction query
17991    pub fn redacted_ranges(
17992        &self,
17993        search_range: Range<Anchor>,
17994        display_snapshot: &DisplaySnapshot,
17995        cx: &App,
17996    ) -> Vec<Range<DisplayPoint>> {
17997        display_snapshot
17998            .buffer_snapshot
17999            .redacted_ranges(search_range, |file| {
18000                if let Some(file) = file {
18001                    file.is_private()
18002                        && EditorSettings::get(
18003                            Some(SettingsLocation {
18004                                worktree_id: file.worktree_id(cx),
18005                                path: file.path().as_ref(),
18006                            }),
18007                            cx,
18008                        )
18009                        .redact_private_values
18010                } else {
18011                    false
18012                }
18013            })
18014            .map(|range| {
18015                range.start.to_display_point(display_snapshot)
18016                    ..range.end.to_display_point(display_snapshot)
18017            })
18018            .collect()
18019    }
18020
18021    pub fn highlight_text<T: 'static>(
18022        &mut self,
18023        ranges: Vec<Range<Anchor>>,
18024        style: HighlightStyle,
18025        cx: &mut Context<Self>,
18026    ) {
18027        self.display_map.update(cx, |map, _| {
18028            map.highlight_text(TypeId::of::<T>(), ranges, style)
18029        });
18030        cx.notify();
18031    }
18032
18033    pub(crate) fn highlight_inlays<T: 'static>(
18034        &mut self,
18035        highlights: Vec<InlayHighlight>,
18036        style: HighlightStyle,
18037        cx: &mut Context<Self>,
18038    ) {
18039        self.display_map.update(cx, |map, _| {
18040            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18041        });
18042        cx.notify();
18043    }
18044
18045    pub fn text_highlights<'a, T: 'static>(
18046        &'a self,
18047        cx: &'a App,
18048    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18049        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18050    }
18051
18052    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18053        let cleared = self
18054            .display_map
18055            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18056        if cleared {
18057            cx.notify();
18058        }
18059    }
18060
18061    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18062        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18063            && self.focus_handle.is_focused(window)
18064    }
18065
18066    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18067        self.show_cursor_when_unfocused = is_enabled;
18068        cx.notify();
18069    }
18070
18071    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18072        cx.notify();
18073    }
18074
18075    fn on_debug_session_event(
18076        &mut self,
18077        _session: Entity<Session>,
18078        event: &SessionEvent,
18079        cx: &mut Context<Self>,
18080    ) {
18081        match event {
18082            SessionEvent::InvalidateInlineValue => {
18083                self.refresh_inline_values(cx);
18084            }
18085            _ => {}
18086        }
18087    }
18088
18089    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18090        let Some(project) = self.project.clone() else {
18091            return;
18092        };
18093
18094        if !self.inline_value_cache.enabled {
18095            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18096            self.splice_inlays(&inlays, Vec::new(), cx);
18097            return;
18098        }
18099
18100        let current_execution_position = self
18101            .highlighted_rows
18102            .get(&TypeId::of::<ActiveDebugLine>())
18103            .and_then(|lines| lines.last().map(|line| line.range.start));
18104
18105        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18106            let inline_values = editor
18107                .update(cx, |editor, cx| {
18108                    let Some(current_execution_position) = current_execution_position else {
18109                        return Some(Task::ready(Ok(Vec::new())));
18110                    };
18111
18112                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18113                        let snapshot = buffer.snapshot(cx);
18114
18115                        let excerpt = snapshot.excerpt_containing(
18116                            current_execution_position..current_execution_position,
18117                        )?;
18118
18119                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18120                    })?;
18121
18122                    let range =
18123                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18124
18125                    project.inline_values(buffer, range, cx)
18126                })
18127                .ok()
18128                .flatten()?
18129                .await
18130                .context("refreshing debugger inlays")
18131                .log_err()?;
18132
18133            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18134
18135            for (buffer_id, inline_value) in inline_values
18136                .into_iter()
18137                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18138            {
18139                buffer_inline_values
18140                    .entry(buffer_id)
18141                    .or_default()
18142                    .push(inline_value);
18143            }
18144
18145            editor
18146                .update(cx, |editor, cx| {
18147                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18148                    let mut new_inlays = Vec::default();
18149
18150                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18151                        let buffer_id = buffer_snapshot.remote_id();
18152                        buffer_inline_values
18153                            .get(&buffer_id)
18154                            .into_iter()
18155                            .flatten()
18156                            .for_each(|hint| {
18157                                let inlay = Inlay::debugger_hint(
18158                                    post_inc(&mut editor.next_inlay_id),
18159                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18160                                    hint.text(),
18161                                );
18162
18163                                new_inlays.push(inlay);
18164                            });
18165                    }
18166
18167                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18168                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18169
18170                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18171                })
18172                .ok()?;
18173            Some(())
18174        });
18175    }
18176
18177    fn on_buffer_event(
18178        &mut self,
18179        multibuffer: &Entity<MultiBuffer>,
18180        event: &multi_buffer::Event,
18181        window: &mut Window,
18182        cx: &mut Context<Self>,
18183    ) {
18184        match event {
18185            multi_buffer::Event::Edited {
18186                singleton_buffer_edited,
18187                edited_buffer: buffer_edited,
18188            } => {
18189                self.scrollbar_marker_state.dirty = true;
18190                self.active_indent_guides_state.dirty = true;
18191                self.refresh_active_diagnostics(cx);
18192                self.refresh_code_actions(window, cx);
18193                self.refresh_selected_text_highlights(true, window, cx);
18194                refresh_matching_bracket_highlights(self, window, cx);
18195                if self.has_active_inline_completion() {
18196                    self.update_visible_inline_completion(window, cx);
18197                }
18198                if let Some(buffer) = buffer_edited {
18199                    let buffer_id = buffer.read(cx).remote_id();
18200                    if !self.registered_buffers.contains_key(&buffer_id) {
18201                        if let Some(project) = self.project.as_ref() {
18202                            project.update(cx, |project, cx| {
18203                                self.registered_buffers.insert(
18204                                    buffer_id,
18205                                    project.register_buffer_with_language_servers(&buffer, cx),
18206                                );
18207                            })
18208                        }
18209                    }
18210                }
18211                cx.emit(EditorEvent::BufferEdited);
18212                cx.emit(SearchEvent::MatchesInvalidated);
18213                if *singleton_buffer_edited {
18214                    if let Some(project) = &self.project {
18215                        #[allow(clippy::mutable_key_type)]
18216                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18217                            multibuffer
18218                                .all_buffers()
18219                                .into_iter()
18220                                .filter_map(|buffer| {
18221                                    buffer.update(cx, |buffer, cx| {
18222                                        let language = buffer.language()?;
18223                                        let should_discard = project.update(cx, |project, cx| {
18224                                            project.is_local()
18225                                                && !project.has_language_servers_for(buffer, cx)
18226                                        });
18227                                        should_discard.not().then_some(language.clone())
18228                                    })
18229                                })
18230                                .collect::<HashSet<_>>()
18231                        });
18232                        if !languages_affected.is_empty() {
18233                            self.refresh_inlay_hints(
18234                                InlayHintRefreshReason::BufferEdited(languages_affected),
18235                                cx,
18236                            );
18237                        }
18238                    }
18239                }
18240
18241                let Some(project) = &self.project else { return };
18242                let (telemetry, is_via_ssh) = {
18243                    let project = project.read(cx);
18244                    let telemetry = project.client().telemetry().clone();
18245                    let is_via_ssh = project.is_via_ssh();
18246                    (telemetry, is_via_ssh)
18247                };
18248                refresh_linked_ranges(self, window, cx);
18249                telemetry.log_edit_event("editor", is_via_ssh);
18250            }
18251            multi_buffer::Event::ExcerptsAdded {
18252                buffer,
18253                predecessor,
18254                excerpts,
18255            } => {
18256                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18257                let buffer_id = buffer.read(cx).remote_id();
18258                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18259                    if let Some(project) = &self.project {
18260                        update_uncommitted_diff_for_buffer(
18261                            cx.entity(),
18262                            project,
18263                            [buffer.clone()],
18264                            self.buffer.clone(),
18265                            cx,
18266                        )
18267                        .detach();
18268                    }
18269                }
18270                cx.emit(EditorEvent::ExcerptsAdded {
18271                    buffer: buffer.clone(),
18272                    predecessor: *predecessor,
18273                    excerpts: excerpts.clone(),
18274                });
18275                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18276            }
18277            multi_buffer::Event::ExcerptsRemoved {
18278                ids,
18279                removed_buffer_ids,
18280            } => {
18281                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18282                let buffer = self.buffer.read(cx);
18283                self.registered_buffers
18284                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18285                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18286                cx.emit(EditorEvent::ExcerptsRemoved {
18287                    ids: ids.clone(),
18288                    removed_buffer_ids: removed_buffer_ids.clone(),
18289                })
18290            }
18291            multi_buffer::Event::ExcerptsEdited {
18292                excerpt_ids,
18293                buffer_ids,
18294            } => {
18295                self.display_map.update(cx, |map, cx| {
18296                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18297                });
18298                cx.emit(EditorEvent::ExcerptsEdited {
18299                    ids: excerpt_ids.clone(),
18300                })
18301            }
18302            multi_buffer::Event::ExcerptsExpanded { ids } => {
18303                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18304                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18305            }
18306            multi_buffer::Event::Reparsed(buffer_id) => {
18307                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18308                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18309
18310                cx.emit(EditorEvent::Reparsed(*buffer_id));
18311            }
18312            multi_buffer::Event::DiffHunksToggled => {
18313                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18314            }
18315            multi_buffer::Event::LanguageChanged(buffer_id) => {
18316                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18317                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18318                cx.emit(EditorEvent::Reparsed(*buffer_id));
18319                cx.notify();
18320            }
18321            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18322            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18323            multi_buffer::Event::FileHandleChanged
18324            | multi_buffer::Event::Reloaded
18325            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18326            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18327            multi_buffer::Event::DiagnosticsUpdated => {
18328                self.refresh_active_diagnostics(cx);
18329                self.refresh_inline_diagnostics(true, window, cx);
18330                self.scrollbar_marker_state.dirty = true;
18331                cx.notify();
18332            }
18333            _ => {}
18334        };
18335    }
18336
18337    pub fn start_temporary_diff_override(&mut self) {
18338        self.load_diff_task.take();
18339        self.temporary_diff_override = true;
18340    }
18341
18342    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18343        self.temporary_diff_override = false;
18344        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18345        self.buffer.update(cx, |buffer, cx| {
18346            buffer.set_all_diff_hunks_collapsed(cx);
18347        });
18348
18349        if let Some(project) = self.project.clone() {
18350            self.load_diff_task = Some(
18351                update_uncommitted_diff_for_buffer(
18352                    cx.entity(),
18353                    &project,
18354                    self.buffer.read(cx).all_buffers(),
18355                    self.buffer.clone(),
18356                    cx,
18357                )
18358                .shared(),
18359            );
18360        }
18361    }
18362
18363    fn on_display_map_changed(
18364        &mut self,
18365        _: Entity<DisplayMap>,
18366        _: &mut Window,
18367        cx: &mut Context<Self>,
18368    ) {
18369        cx.notify();
18370    }
18371
18372    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18373        let new_severity = if self.diagnostics_enabled() {
18374            EditorSettings::get_global(cx)
18375                .diagnostics_max_severity
18376                .unwrap_or(DiagnosticSeverity::Hint)
18377        } else {
18378            DiagnosticSeverity::Off
18379        };
18380        self.set_max_diagnostics_severity(new_severity, cx);
18381        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18382        self.update_edit_prediction_settings(cx);
18383        self.refresh_inline_completion(true, false, window, cx);
18384        self.refresh_inlay_hints(
18385            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18386                self.selections.newest_anchor().head(),
18387                &self.buffer.read(cx).snapshot(cx),
18388                cx,
18389            )),
18390            cx,
18391        );
18392
18393        let old_cursor_shape = self.cursor_shape;
18394
18395        {
18396            let editor_settings = EditorSettings::get_global(cx);
18397            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18398            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18399            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18400            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18401        }
18402
18403        if old_cursor_shape != self.cursor_shape {
18404            cx.emit(EditorEvent::CursorShapeChanged);
18405        }
18406
18407        let project_settings = ProjectSettings::get_global(cx);
18408        self.serialize_dirty_buffers =
18409            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18410
18411        if self.mode.is_full() {
18412            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18413            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18414            if self.show_inline_diagnostics != show_inline_diagnostics {
18415                self.show_inline_diagnostics = show_inline_diagnostics;
18416                self.refresh_inline_diagnostics(false, window, cx);
18417            }
18418
18419            if self.git_blame_inline_enabled != inline_blame_enabled {
18420                self.toggle_git_blame_inline_internal(false, window, cx);
18421            }
18422
18423            let minimap_settings = EditorSettings::get_global(cx).minimap;
18424            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18425                self.set_minimap_visibility(
18426                    self.minimap_visibility.toggle_visibility(),
18427                    window,
18428                    cx,
18429                );
18430            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18431                minimap_entity.update(cx, |minimap_editor, cx| {
18432                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18433                })
18434            }
18435        }
18436
18437        cx.notify();
18438    }
18439
18440    pub fn set_searchable(&mut self, searchable: bool) {
18441        self.searchable = searchable;
18442    }
18443
18444    pub fn searchable(&self) -> bool {
18445        self.searchable
18446    }
18447
18448    fn open_proposed_changes_editor(
18449        &mut self,
18450        _: &OpenProposedChangesEditor,
18451        window: &mut Window,
18452        cx: &mut Context<Self>,
18453    ) {
18454        let Some(workspace) = self.workspace() else {
18455            cx.propagate();
18456            return;
18457        };
18458
18459        let selections = self.selections.all::<usize>(cx);
18460        let multi_buffer = self.buffer.read(cx);
18461        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18462        let mut new_selections_by_buffer = HashMap::default();
18463        for selection in selections {
18464            for (buffer, range, _) in
18465                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18466            {
18467                let mut range = range.to_point(buffer);
18468                range.start.column = 0;
18469                range.end.column = buffer.line_len(range.end.row);
18470                new_selections_by_buffer
18471                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18472                    .or_insert(Vec::new())
18473                    .push(range)
18474            }
18475        }
18476
18477        let proposed_changes_buffers = new_selections_by_buffer
18478            .into_iter()
18479            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18480            .collect::<Vec<_>>();
18481        let proposed_changes_editor = cx.new(|cx| {
18482            ProposedChangesEditor::new(
18483                "Proposed changes",
18484                proposed_changes_buffers,
18485                self.project.clone(),
18486                window,
18487                cx,
18488            )
18489        });
18490
18491        window.defer(cx, move |window, cx| {
18492            workspace.update(cx, |workspace, cx| {
18493                workspace.active_pane().update(cx, |pane, cx| {
18494                    pane.add_item(
18495                        Box::new(proposed_changes_editor),
18496                        true,
18497                        true,
18498                        None,
18499                        window,
18500                        cx,
18501                    );
18502                });
18503            });
18504        });
18505    }
18506
18507    pub fn open_excerpts_in_split(
18508        &mut self,
18509        _: &OpenExcerptsSplit,
18510        window: &mut Window,
18511        cx: &mut Context<Self>,
18512    ) {
18513        self.open_excerpts_common(None, true, window, cx)
18514    }
18515
18516    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18517        self.open_excerpts_common(None, false, window, cx)
18518    }
18519
18520    fn open_excerpts_common(
18521        &mut self,
18522        jump_data: Option<JumpData>,
18523        split: bool,
18524        window: &mut Window,
18525        cx: &mut Context<Self>,
18526    ) {
18527        let Some(workspace) = self.workspace() else {
18528            cx.propagate();
18529            return;
18530        };
18531
18532        if self.buffer.read(cx).is_singleton() {
18533            cx.propagate();
18534            return;
18535        }
18536
18537        let mut new_selections_by_buffer = HashMap::default();
18538        match &jump_data {
18539            Some(JumpData::MultiBufferPoint {
18540                excerpt_id,
18541                position,
18542                anchor,
18543                line_offset_from_top,
18544            }) => {
18545                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18546                if let Some(buffer) = multi_buffer_snapshot
18547                    .buffer_id_for_excerpt(*excerpt_id)
18548                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18549                {
18550                    let buffer_snapshot = buffer.read(cx).snapshot();
18551                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18552                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18553                    } else {
18554                        buffer_snapshot.clip_point(*position, Bias::Left)
18555                    };
18556                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18557                    new_selections_by_buffer.insert(
18558                        buffer,
18559                        (
18560                            vec![jump_to_offset..jump_to_offset],
18561                            Some(*line_offset_from_top),
18562                        ),
18563                    );
18564                }
18565            }
18566            Some(JumpData::MultiBufferRow {
18567                row,
18568                line_offset_from_top,
18569            }) => {
18570                let point = MultiBufferPoint::new(row.0, 0);
18571                if let Some((buffer, buffer_point, _)) =
18572                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18573                {
18574                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18575                    new_selections_by_buffer
18576                        .entry(buffer)
18577                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18578                        .0
18579                        .push(buffer_offset..buffer_offset)
18580                }
18581            }
18582            None => {
18583                let selections = self.selections.all::<usize>(cx);
18584                let multi_buffer = self.buffer.read(cx);
18585                for selection in selections {
18586                    for (snapshot, range, _, anchor) in multi_buffer
18587                        .snapshot(cx)
18588                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18589                    {
18590                        if let Some(anchor) = anchor {
18591                            // selection is in a deleted hunk
18592                            let Some(buffer_id) = anchor.buffer_id else {
18593                                continue;
18594                            };
18595                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18596                                continue;
18597                            };
18598                            let offset = text::ToOffset::to_offset(
18599                                &anchor.text_anchor,
18600                                &buffer_handle.read(cx).snapshot(),
18601                            );
18602                            let range = offset..offset;
18603                            new_selections_by_buffer
18604                                .entry(buffer_handle)
18605                                .or_insert((Vec::new(), None))
18606                                .0
18607                                .push(range)
18608                        } else {
18609                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18610                            else {
18611                                continue;
18612                            };
18613                            new_selections_by_buffer
18614                                .entry(buffer_handle)
18615                                .or_insert((Vec::new(), None))
18616                                .0
18617                                .push(range)
18618                        }
18619                    }
18620                }
18621            }
18622        }
18623
18624        new_selections_by_buffer
18625            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18626
18627        if new_selections_by_buffer.is_empty() {
18628            return;
18629        }
18630
18631        // We defer the pane interaction because we ourselves are a workspace item
18632        // and activating a new item causes the pane to call a method on us reentrantly,
18633        // which panics if we're on the stack.
18634        window.defer(cx, move |window, cx| {
18635            workspace.update(cx, |workspace, cx| {
18636                let pane = if split {
18637                    workspace.adjacent_pane(window, cx)
18638                } else {
18639                    workspace.active_pane().clone()
18640                };
18641
18642                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18643                    let editor = buffer
18644                        .read(cx)
18645                        .file()
18646                        .is_none()
18647                        .then(|| {
18648                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18649                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18650                            // Instead, we try to activate the existing editor in the pane first.
18651                            let (editor, pane_item_index) =
18652                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18653                                    let editor = item.downcast::<Editor>()?;
18654                                    let singleton_buffer =
18655                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18656                                    if singleton_buffer == buffer {
18657                                        Some((editor, i))
18658                                    } else {
18659                                        None
18660                                    }
18661                                })?;
18662                            pane.update(cx, |pane, cx| {
18663                                pane.activate_item(pane_item_index, true, true, window, cx)
18664                            });
18665                            Some(editor)
18666                        })
18667                        .flatten()
18668                        .unwrap_or_else(|| {
18669                            workspace.open_project_item::<Self>(
18670                                pane.clone(),
18671                                buffer,
18672                                true,
18673                                true,
18674                                window,
18675                                cx,
18676                            )
18677                        });
18678
18679                    editor.update(cx, |editor, cx| {
18680                        let autoscroll = match scroll_offset {
18681                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18682                            None => Autoscroll::newest(),
18683                        };
18684                        let nav_history = editor.nav_history.take();
18685                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18686                            s.select_ranges(ranges);
18687                        });
18688                        editor.nav_history = nav_history;
18689                    });
18690                }
18691            })
18692        });
18693    }
18694
18695    // For now, don't allow opening excerpts in buffers that aren't backed by
18696    // regular project files.
18697    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18698        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18699    }
18700
18701    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18702        let snapshot = self.buffer.read(cx).read(cx);
18703        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18704        Some(
18705            ranges
18706                .iter()
18707                .map(move |range| {
18708                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18709                })
18710                .collect(),
18711        )
18712    }
18713
18714    fn selection_replacement_ranges(
18715        &self,
18716        range: Range<OffsetUtf16>,
18717        cx: &mut App,
18718    ) -> Vec<Range<OffsetUtf16>> {
18719        let selections = self.selections.all::<OffsetUtf16>(cx);
18720        let newest_selection = selections
18721            .iter()
18722            .max_by_key(|selection| selection.id)
18723            .unwrap();
18724        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18725        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18726        let snapshot = self.buffer.read(cx).read(cx);
18727        selections
18728            .into_iter()
18729            .map(|mut selection| {
18730                selection.start.0 =
18731                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18732                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18733                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18734                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18735            })
18736            .collect()
18737    }
18738
18739    fn report_editor_event(
18740        &self,
18741        event_type: &'static str,
18742        file_extension: Option<String>,
18743        cx: &App,
18744    ) {
18745        if cfg!(any(test, feature = "test-support")) {
18746            return;
18747        }
18748
18749        let Some(project) = &self.project else { return };
18750
18751        // If None, we are in a file without an extension
18752        let file = self
18753            .buffer
18754            .read(cx)
18755            .as_singleton()
18756            .and_then(|b| b.read(cx).file());
18757        let file_extension = file_extension.or(file
18758            .as_ref()
18759            .and_then(|file| Path::new(file.file_name(cx)).extension())
18760            .and_then(|e| e.to_str())
18761            .map(|a| a.to_string()));
18762
18763        let vim_mode = vim_enabled(cx);
18764
18765        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18766        let copilot_enabled = edit_predictions_provider
18767            == language::language_settings::EditPredictionProvider::Copilot;
18768        let copilot_enabled_for_language = self
18769            .buffer
18770            .read(cx)
18771            .language_settings(cx)
18772            .show_edit_predictions;
18773
18774        let project = project.read(cx);
18775        telemetry::event!(
18776            event_type,
18777            file_extension,
18778            vim_mode,
18779            copilot_enabled,
18780            copilot_enabled_for_language,
18781            edit_predictions_provider,
18782            is_via_ssh = project.is_via_ssh(),
18783        );
18784    }
18785
18786    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18787    /// with each line being an array of {text, highlight} objects.
18788    fn copy_highlight_json(
18789        &mut self,
18790        _: &CopyHighlightJson,
18791        window: &mut Window,
18792        cx: &mut Context<Self>,
18793    ) {
18794        #[derive(Serialize)]
18795        struct Chunk<'a> {
18796            text: String,
18797            highlight: Option<&'a str>,
18798        }
18799
18800        let snapshot = self.buffer.read(cx).snapshot(cx);
18801        let range = self
18802            .selected_text_range(false, window, cx)
18803            .and_then(|selection| {
18804                if selection.range.is_empty() {
18805                    None
18806                } else {
18807                    Some(selection.range)
18808                }
18809            })
18810            .unwrap_or_else(|| 0..snapshot.len());
18811
18812        let chunks = snapshot.chunks(range, true);
18813        let mut lines = Vec::new();
18814        let mut line: VecDeque<Chunk> = VecDeque::new();
18815
18816        let Some(style) = self.style.as_ref() else {
18817            return;
18818        };
18819
18820        for chunk in chunks {
18821            let highlight = chunk
18822                .syntax_highlight_id
18823                .and_then(|id| id.name(&style.syntax));
18824            let mut chunk_lines = chunk.text.split('\n').peekable();
18825            while let Some(text) = chunk_lines.next() {
18826                let mut merged_with_last_token = false;
18827                if let Some(last_token) = line.back_mut() {
18828                    if last_token.highlight == highlight {
18829                        last_token.text.push_str(text);
18830                        merged_with_last_token = true;
18831                    }
18832                }
18833
18834                if !merged_with_last_token {
18835                    line.push_back(Chunk {
18836                        text: text.into(),
18837                        highlight,
18838                    });
18839                }
18840
18841                if chunk_lines.peek().is_some() {
18842                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18843                        line.pop_front();
18844                    }
18845                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18846                        line.pop_back();
18847                    }
18848
18849                    lines.push(mem::take(&mut line));
18850                }
18851            }
18852        }
18853
18854        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18855            return;
18856        };
18857        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18858    }
18859
18860    pub fn open_context_menu(
18861        &mut self,
18862        _: &OpenContextMenu,
18863        window: &mut Window,
18864        cx: &mut Context<Self>,
18865    ) {
18866        self.request_autoscroll(Autoscroll::newest(), cx);
18867        let position = self.selections.newest_display(cx).start;
18868        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18869    }
18870
18871    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18872        &self.inlay_hint_cache
18873    }
18874
18875    pub fn replay_insert_event(
18876        &mut self,
18877        text: &str,
18878        relative_utf16_range: Option<Range<isize>>,
18879        window: &mut Window,
18880        cx: &mut Context<Self>,
18881    ) {
18882        if !self.input_enabled {
18883            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18884            return;
18885        }
18886        if let Some(relative_utf16_range) = relative_utf16_range {
18887            let selections = self.selections.all::<OffsetUtf16>(cx);
18888            self.change_selections(None, window, cx, |s| {
18889                let new_ranges = selections.into_iter().map(|range| {
18890                    let start = OffsetUtf16(
18891                        range
18892                            .head()
18893                            .0
18894                            .saturating_add_signed(relative_utf16_range.start),
18895                    );
18896                    let end = OffsetUtf16(
18897                        range
18898                            .head()
18899                            .0
18900                            .saturating_add_signed(relative_utf16_range.end),
18901                    );
18902                    start..end
18903                });
18904                s.select_ranges(new_ranges);
18905            });
18906        }
18907
18908        self.handle_input(text, window, cx);
18909    }
18910
18911    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18912        let Some(provider) = self.semantics_provider.as_ref() else {
18913            return false;
18914        };
18915
18916        let mut supports = false;
18917        self.buffer().update(cx, |this, cx| {
18918            this.for_each_buffer(|buffer| {
18919                supports |= provider.supports_inlay_hints(buffer, cx);
18920            });
18921        });
18922
18923        supports
18924    }
18925
18926    pub fn is_focused(&self, window: &Window) -> bool {
18927        self.focus_handle.is_focused(window)
18928    }
18929
18930    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18931        cx.emit(EditorEvent::Focused);
18932
18933        if let Some(descendant) = self
18934            .last_focused_descendant
18935            .take()
18936            .and_then(|descendant| descendant.upgrade())
18937        {
18938            window.focus(&descendant);
18939        } else {
18940            if let Some(blame) = self.blame.as_ref() {
18941                blame.update(cx, GitBlame::focus)
18942            }
18943
18944            self.blink_manager.update(cx, BlinkManager::enable);
18945            self.show_cursor_names(window, cx);
18946            self.buffer.update(cx, |buffer, cx| {
18947                buffer.finalize_last_transaction(cx);
18948                if self.leader_id.is_none() {
18949                    buffer.set_active_selections(
18950                        &self.selections.disjoint_anchors(),
18951                        self.selections.line_mode,
18952                        self.cursor_shape,
18953                        cx,
18954                    );
18955                }
18956            });
18957        }
18958    }
18959
18960    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18961        cx.emit(EditorEvent::FocusedIn)
18962    }
18963
18964    fn handle_focus_out(
18965        &mut self,
18966        event: FocusOutEvent,
18967        _window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) {
18970        if event.blurred != self.focus_handle {
18971            self.last_focused_descendant = Some(event.blurred);
18972        }
18973        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18974    }
18975
18976    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18977        self.blink_manager.update(cx, BlinkManager::disable);
18978        self.buffer
18979            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18980
18981        if let Some(blame) = self.blame.as_ref() {
18982            blame.update(cx, GitBlame::blur)
18983        }
18984        if !self.hover_state.focused(window, cx) {
18985            hide_hover(self, cx);
18986        }
18987        if !self
18988            .context_menu
18989            .borrow()
18990            .as_ref()
18991            .is_some_and(|context_menu| context_menu.focused(window, cx))
18992        {
18993            self.hide_context_menu(window, cx);
18994        }
18995        self.discard_inline_completion(false, cx);
18996        cx.emit(EditorEvent::Blurred);
18997        cx.notify();
18998    }
18999
19000    pub fn register_action<A: Action>(
19001        &mut self,
19002        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19003    ) -> Subscription {
19004        let id = self.next_editor_action_id.post_inc();
19005        let listener = Arc::new(listener);
19006        self.editor_actions.borrow_mut().insert(
19007            id,
19008            Box::new(move |window, _| {
19009                let listener = listener.clone();
19010                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19011                    let action = action.downcast_ref().unwrap();
19012                    if phase == DispatchPhase::Bubble {
19013                        listener(action, window, cx)
19014                    }
19015                })
19016            }),
19017        );
19018
19019        let editor_actions = self.editor_actions.clone();
19020        Subscription::new(move || {
19021            editor_actions.borrow_mut().remove(&id);
19022        })
19023    }
19024
19025    pub fn file_header_size(&self) -> u32 {
19026        FILE_HEADER_HEIGHT
19027    }
19028
19029    pub fn restore(
19030        &mut self,
19031        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19032        window: &mut Window,
19033        cx: &mut Context<Self>,
19034    ) {
19035        let workspace = self.workspace();
19036        let project = self.project.as_ref();
19037        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19038            let mut tasks = Vec::new();
19039            for (buffer_id, changes) in revert_changes {
19040                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19041                    buffer.update(cx, |buffer, cx| {
19042                        buffer.edit(
19043                            changes
19044                                .into_iter()
19045                                .map(|(range, text)| (range, text.to_string())),
19046                            None,
19047                            cx,
19048                        );
19049                    });
19050
19051                    if let Some(project) =
19052                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19053                    {
19054                        project.update(cx, |project, cx| {
19055                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19056                        })
19057                    }
19058                }
19059            }
19060            tasks
19061        });
19062        cx.spawn_in(window, async move |_, cx| {
19063            for (buffer, task) in save_tasks {
19064                let result = task.await;
19065                if result.is_err() {
19066                    let Some(path) = buffer
19067                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19068                        .ok()
19069                    else {
19070                        continue;
19071                    };
19072                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19073                        let Some(task) = cx
19074                            .update_window_entity(&workspace, |workspace, window, cx| {
19075                                workspace
19076                                    .open_path_preview(path, None, false, false, false, window, cx)
19077                            })
19078                            .ok()
19079                        else {
19080                            continue;
19081                        };
19082                        task.await.log_err();
19083                    }
19084                }
19085            }
19086        })
19087        .detach();
19088        self.change_selections(None, window, cx, |selections| selections.refresh());
19089    }
19090
19091    pub fn to_pixel_point(
19092        &self,
19093        source: multi_buffer::Anchor,
19094        editor_snapshot: &EditorSnapshot,
19095        window: &mut Window,
19096    ) -> Option<gpui::Point<Pixels>> {
19097        let source_point = source.to_display_point(editor_snapshot);
19098        self.display_to_pixel_point(source_point, editor_snapshot, window)
19099    }
19100
19101    pub fn display_to_pixel_point(
19102        &self,
19103        source: DisplayPoint,
19104        editor_snapshot: &EditorSnapshot,
19105        window: &mut Window,
19106    ) -> Option<gpui::Point<Pixels>> {
19107        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19108        let text_layout_details = self.text_layout_details(window);
19109        let scroll_top = text_layout_details
19110            .scroll_anchor
19111            .scroll_position(editor_snapshot)
19112            .y;
19113
19114        if source.row().as_f32() < scroll_top.floor() {
19115            return None;
19116        }
19117        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19118        let source_y = line_height * (source.row().as_f32() - scroll_top);
19119        Some(gpui::Point::new(source_x, source_y))
19120    }
19121
19122    pub fn has_visible_completions_menu(&self) -> bool {
19123        !self.edit_prediction_preview_is_active()
19124            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19125                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19126            })
19127    }
19128
19129    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19130        if self.mode.is_minimap() {
19131            return;
19132        }
19133        self.addons
19134            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19135    }
19136
19137    pub fn unregister_addon<T: Addon>(&mut self) {
19138        self.addons.remove(&std::any::TypeId::of::<T>());
19139    }
19140
19141    pub fn addon<T: Addon>(&self) -> Option<&T> {
19142        let type_id = std::any::TypeId::of::<T>();
19143        self.addons
19144            .get(&type_id)
19145            .and_then(|item| item.to_any().downcast_ref::<T>())
19146    }
19147
19148    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19149        let type_id = std::any::TypeId::of::<T>();
19150        self.addons
19151            .get_mut(&type_id)
19152            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19153    }
19154
19155    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19156        let text_layout_details = self.text_layout_details(window);
19157        let style = &text_layout_details.editor_style;
19158        let font_id = window.text_system().resolve_font(&style.text.font());
19159        let font_size = style.text.font_size.to_pixels(window.rem_size());
19160        let line_height = style.text.line_height_in_pixels(window.rem_size());
19161        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19162
19163        gpui::Size::new(em_width, line_height)
19164    }
19165
19166    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19167        self.load_diff_task.clone()
19168    }
19169
19170    fn read_metadata_from_db(
19171        &mut self,
19172        item_id: u64,
19173        workspace_id: WorkspaceId,
19174        window: &mut Window,
19175        cx: &mut Context<Editor>,
19176    ) {
19177        if self.is_singleton(cx)
19178            && !self.mode.is_minimap()
19179            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19180        {
19181            let buffer_snapshot = OnceCell::new();
19182
19183            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19184                if !folds.is_empty() {
19185                    let snapshot =
19186                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19187                    self.fold_ranges(
19188                        folds
19189                            .into_iter()
19190                            .map(|(start, end)| {
19191                                snapshot.clip_offset(start, Bias::Left)
19192                                    ..snapshot.clip_offset(end, Bias::Right)
19193                            })
19194                            .collect(),
19195                        false,
19196                        window,
19197                        cx,
19198                    );
19199                }
19200            }
19201
19202            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19203                if !selections.is_empty() {
19204                    let snapshot =
19205                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19206                    self.change_selections(None, window, cx, |s| {
19207                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19208                            snapshot.clip_offset(start, Bias::Left)
19209                                ..snapshot.clip_offset(end, Bias::Right)
19210                        }));
19211                    });
19212                }
19213            };
19214        }
19215
19216        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19217    }
19218}
19219
19220fn vim_enabled(cx: &App) -> bool {
19221    cx.global::<SettingsStore>()
19222        .raw_user_settings()
19223        .get("vim_mode")
19224        == Some(&serde_json::Value::Bool(true))
19225}
19226
19227// Consider user intent and default settings
19228fn choose_completion_range(
19229    completion: &Completion,
19230    intent: CompletionIntent,
19231    buffer: &Entity<Buffer>,
19232    cx: &mut Context<Editor>,
19233) -> Range<usize> {
19234    fn should_replace(
19235        completion: &Completion,
19236        insert_range: &Range<text::Anchor>,
19237        intent: CompletionIntent,
19238        completion_mode_setting: LspInsertMode,
19239        buffer: &Buffer,
19240    ) -> bool {
19241        // specific actions take precedence over settings
19242        match intent {
19243            CompletionIntent::CompleteWithInsert => return false,
19244            CompletionIntent::CompleteWithReplace => return true,
19245            CompletionIntent::Complete | CompletionIntent::Compose => {}
19246        }
19247
19248        match completion_mode_setting {
19249            LspInsertMode::Insert => false,
19250            LspInsertMode::Replace => true,
19251            LspInsertMode::ReplaceSubsequence => {
19252                let mut text_to_replace = buffer.chars_for_range(
19253                    buffer.anchor_before(completion.replace_range.start)
19254                        ..buffer.anchor_after(completion.replace_range.end),
19255                );
19256                let mut completion_text = completion.new_text.chars();
19257
19258                // is `text_to_replace` a subsequence of `completion_text`
19259                text_to_replace
19260                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19261            }
19262            LspInsertMode::ReplaceSuffix => {
19263                let range_after_cursor = insert_range.end..completion.replace_range.end;
19264
19265                let text_after_cursor = buffer
19266                    .text_for_range(
19267                        buffer.anchor_before(range_after_cursor.start)
19268                            ..buffer.anchor_after(range_after_cursor.end),
19269                    )
19270                    .collect::<String>();
19271                completion.new_text.ends_with(&text_after_cursor)
19272            }
19273        }
19274    }
19275
19276    let buffer = buffer.read(cx);
19277
19278    if let CompletionSource::Lsp {
19279        insert_range: Some(insert_range),
19280        ..
19281    } = &completion.source
19282    {
19283        let completion_mode_setting =
19284            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19285                .completions
19286                .lsp_insert_mode;
19287
19288        if !should_replace(
19289            completion,
19290            &insert_range,
19291            intent,
19292            completion_mode_setting,
19293            buffer,
19294        ) {
19295            return insert_range.to_offset(buffer);
19296        }
19297    }
19298
19299    completion.replace_range.to_offset(buffer)
19300}
19301
19302fn insert_extra_newline_brackets(
19303    buffer: &MultiBufferSnapshot,
19304    range: Range<usize>,
19305    language: &language::LanguageScope,
19306) -> bool {
19307    let leading_whitespace_len = buffer
19308        .reversed_chars_at(range.start)
19309        .take_while(|c| c.is_whitespace() && *c != '\n')
19310        .map(|c| c.len_utf8())
19311        .sum::<usize>();
19312    let trailing_whitespace_len = buffer
19313        .chars_at(range.end)
19314        .take_while(|c| c.is_whitespace() && *c != '\n')
19315        .map(|c| c.len_utf8())
19316        .sum::<usize>();
19317    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19318
19319    language.brackets().any(|(pair, enabled)| {
19320        let pair_start = pair.start.trim_end();
19321        let pair_end = pair.end.trim_start();
19322
19323        enabled
19324            && pair.newline
19325            && buffer.contains_str_at(range.end, pair_end)
19326            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19327    })
19328}
19329
19330fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19331    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19332        [(buffer, range, _)] => (*buffer, range.clone()),
19333        _ => return false,
19334    };
19335    let pair = {
19336        let mut result: Option<BracketMatch> = None;
19337
19338        for pair in buffer
19339            .all_bracket_ranges(range.clone())
19340            .filter(move |pair| {
19341                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19342            })
19343        {
19344            let len = pair.close_range.end - pair.open_range.start;
19345
19346            if let Some(existing) = &result {
19347                let existing_len = existing.close_range.end - existing.open_range.start;
19348                if len > existing_len {
19349                    continue;
19350                }
19351            }
19352
19353            result = Some(pair);
19354        }
19355
19356        result
19357    };
19358    let Some(pair) = pair else {
19359        return false;
19360    };
19361    pair.newline_only
19362        && buffer
19363            .chars_for_range(pair.open_range.end..range.start)
19364            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19365            .all(|c| c.is_whitespace() && c != '\n')
19366}
19367
19368fn update_uncommitted_diff_for_buffer(
19369    editor: Entity<Editor>,
19370    project: &Entity<Project>,
19371    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19372    buffer: Entity<MultiBuffer>,
19373    cx: &mut App,
19374) -> Task<()> {
19375    let mut tasks = Vec::new();
19376    project.update(cx, |project, cx| {
19377        for buffer in buffers {
19378            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19379                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19380            }
19381        }
19382    });
19383    cx.spawn(async move |cx| {
19384        let diffs = future::join_all(tasks).await;
19385        if editor
19386            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19387            .unwrap_or(false)
19388        {
19389            return;
19390        }
19391
19392        buffer
19393            .update(cx, |buffer, cx| {
19394                for diff in diffs.into_iter().flatten() {
19395                    buffer.add_diff(diff, cx);
19396                }
19397            })
19398            .ok();
19399    })
19400}
19401
19402fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19403    let tab_size = tab_size.get() as usize;
19404    let mut width = offset;
19405
19406    for ch in text.chars() {
19407        width += if ch == '\t' {
19408            tab_size - (width % tab_size)
19409        } else {
19410            1
19411        };
19412    }
19413
19414    width - offset
19415}
19416
19417#[cfg(test)]
19418mod tests {
19419    use super::*;
19420
19421    #[test]
19422    fn test_string_size_with_expanded_tabs() {
19423        let nz = |val| NonZeroU32::new(val).unwrap();
19424        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19425        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19426        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19427        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19428        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19429        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19430        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19431        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19432    }
19433}
19434
19435/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19436struct WordBreakingTokenizer<'a> {
19437    input: &'a str,
19438}
19439
19440impl<'a> WordBreakingTokenizer<'a> {
19441    fn new(input: &'a str) -> Self {
19442        Self { input }
19443    }
19444}
19445
19446fn is_char_ideographic(ch: char) -> bool {
19447    use unicode_script::Script::*;
19448    use unicode_script::UnicodeScript;
19449    matches!(ch.script(), Han | Tangut | Yi)
19450}
19451
19452fn is_grapheme_ideographic(text: &str) -> bool {
19453    text.chars().any(is_char_ideographic)
19454}
19455
19456fn is_grapheme_whitespace(text: &str) -> bool {
19457    text.chars().any(|x| x.is_whitespace())
19458}
19459
19460fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19461    text.chars().next().map_or(false, |ch| {
19462        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19463    })
19464}
19465
19466#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19467enum WordBreakToken<'a> {
19468    Word { token: &'a str, grapheme_len: usize },
19469    InlineWhitespace { token: &'a str, grapheme_len: usize },
19470    Newline,
19471}
19472
19473impl<'a> Iterator for WordBreakingTokenizer<'a> {
19474    /// Yields a span, the count of graphemes in the token, and whether it was
19475    /// whitespace. Note that it also breaks at word boundaries.
19476    type Item = WordBreakToken<'a>;
19477
19478    fn next(&mut self) -> Option<Self::Item> {
19479        use unicode_segmentation::UnicodeSegmentation;
19480        if self.input.is_empty() {
19481            return None;
19482        }
19483
19484        let mut iter = self.input.graphemes(true).peekable();
19485        let mut offset = 0;
19486        let mut grapheme_len = 0;
19487        if let Some(first_grapheme) = iter.next() {
19488            let is_newline = first_grapheme == "\n";
19489            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19490            offset += first_grapheme.len();
19491            grapheme_len += 1;
19492            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19493                if let Some(grapheme) = iter.peek().copied() {
19494                    if should_stay_with_preceding_ideograph(grapheme) {
19495                        offset += grapheme.len();
19496                        grapheme_len += 1;
19497                    }
19498                }
19499            } else {
19500                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19501                let mut next_word_bound = words.peek().copied();
19502                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19503                    next_word_bound = words.next();
19504                }
19505                while let Some(grapheme) = iter.peek().copied() {
19506                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19507                        break;
19508                    };
19509                    if is_grapheme_whitespace(grapheme) != is_whitespace
19510                        || (grapheme == "\n") != is_newline
19511                    {
19512                        break;
19513                    };
19514                    offset += grapheme.len();
19515                    grapheme_len += 1;
19516                    iter.next();
19517                }
19518            }
19519            let token = &self.input[..offset];
19520            self.input = &self.input[offset..];
19521            if token == "\n" {
19522                Some(WordBreakToken::Newline)
19523            } else if is_whitespace {
19524                Some(WordBreakToken::InlineWhitespace {
19525                    token,
19526                    grapheme_len,
19527                })
19528            } else {
19529                Some(WordBreakToken::Word {
19530                    token,
19531                    grapheme_len,
19532                })
19533            }
19534        } else {
19535            None
19536        }
19537    }
19538}
19539
19540#[test]
19541fn test_word_breaking_tokenizer() {
19542    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19543        ("", &[]),
19544        ("  ", &[whitespace("  ", 2)]),
19545        ("Ʒ", &[word("Ʒ", 1)]),
19546        ("Ǽ", &[word("Ǽ", 1)]),
19547        ("", &[word("", 1)]),
19548        ("⋑⋑", &[word("⋑⋑", 2)]),
19549        (
19550            "原理,进而",
19551            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19552        ),
19553        (
19554            "hello world",
19555            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19556        ),
19557        (
19558            "hello, world",
19559            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19560        ),
19561        (
19562            "  hello world",
19563            &[
19564                whitespace("  ", 2),
19565                word("hello", 5),
19566                whitespace(" ", 1),
19567                word("world", 5),
19568            ],
19569        ),
19570        (
19571            "这是什么 \n 钢笔",
19572            &[
19573                word("", 1),
19574                word("", 1),
19575                word("", 1),
19576                word("", 1),
19577                whitespace(" ", 1),
19578                newline(),
19579                whitespace(" ", 1),
19580                word("", 1),
19581                word("", 1),
19582            ],
19583        ),
19584        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19585    ];
19586
19587    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19588        WordBreakToken::Word {
19589            token,
19590            grapheme_len,
19591        }
19592    }
19593
19594    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19595        WordBreakToken::InlineWhitespace {
19596            token,
19597            grapheme_len,
19598        }
19599    }
19600
19601    fn newline() -> WordBreakToken<'static> {
19602        WordBreakToken::Newline
19603    }
19604
19605    for (input, result) in tests {
19606        assert_eq!(
19607            WordBreakingTokenizer::new(input)
19608                .collect::<Vec<_>>()
19609                .as_slice(),
19610            *result,
19611        );
19612    }
19613}
19614
19615fn wrap_with_prefix(
19616    line_prefix: String,
19617    unwrapped_text: String,
19618    wrap_column: usize,
19619    tab_size: NonZeroU32,
19620    preserve_existing_whitespace: bool,
19621) -> String {
19622    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19623    let mut wrapped_text = String::new();
19624    let mut current_line = line_prefix.clone();
19625
19626    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19627    let mut current_line_len = line_prefix_len;
19628    let mut in_whitespace = false;
19629    for token in tokenizer {
19630        let have_preceding_whitespace = in_whitespace;
19631        match token {
19632            WordBreakToken::Word {
19633                token,
19634                grapheme_len,
19635            } => {
19636                in_whitespace = false;
19637                if current_line_len + grapheme_len > wrap_column
19638                    && current_line_len != line_prefix_len
19639                {
19640                    wrapped_text.push_str(current_line.trim_end());
19641                    wrapped_text.push('\n');
19642                    current_line.truncate(line_prefix.len());
19643                    current_line_len = line_prefix_len;
19644                }
19645                current_line.push_str(token);
19646                current_line_len += grapheme_len;
19647            }
19648            WordBreakToken::InlineWhitespace {
19649                mut token,
19650                mut grapheme_len,
19651            } => {
19652                in_whitespace = true;
19653                if have_preceding_whitespace && !preserve_existing_whitespace {
19654                    continue;
19655                }
19656                if !preserve_existing_whitespace {
19657                    token = " ";
19658                    grapheme_len = 1;
19659                }
19660                if current_line_len + grapheme_len > wrap_column {
19661                    wrapped_text.push_str(current_line.trim_end());
19662                    wrapped_text.push('\n');
19663                    current_line.truncate(line_prefix.len());
19664                    current_line_len = line_prefix_len;
19665                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19666                    current_line.push_str(token);
19667                    current_line_len += grapheme_len;
19668                }
19669            }
19670            WordBreakToken::Newline => {
19671                in_whitespace = true;
19672                if preserve_existing_whitespace {
19673                    wrapped_text.push_str(current_line.trim_end());
19674                    wrapped_text.push('\n');
19675                    current_line.truncate(line_prefix.len());
19676                    current_line_len = line_prefix_len;
19677                } else if have_preceding_whitespace {
19678                    continue;
19679                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19680                {
19681                    wrapped_text.push_str(current_line.trim_end());
19682                    wrapped_text.push('\n');
19683                    current_line.truncate(line_prefix.len());
19684                    current_line_len = line_prefix_len;
19685                } else if current_line_len != line_prefix_len {
19686                    current_line.push(' ');
19687                    current_line_len += 1;
19688                }
19689            }
19690        }
19691    }
19692
19693    if !current_line.is_empty() {
19694        wrapped_text.push_str(&current_line);
19695    }
19696    wrapped_text
19697}
19698
19699#[test]
19700fn test_wrap_with_prefix() {
19701    assert_eq!(
19702        wrap_with_prefix(
19703            "# ".to_string(),
19704            "abcdefg".to_string(),
19705            4,
19706            NonZeroU32::new(4).unwrap(),
19707            false,
19708        ),
19709        "# abcdefg"
19710    );
19711    assert_eq!(
19712        wrap_with_prefix(
19713            "".to_string(),
19714            "\thello world".to_string(),
19715            8,
19716            NonZeroU32::new(4).unwrap(),
19717            false,
19718        ),
19719        "hello\nworld"
19720    );
19721    assert_eq!(
19722        wrap_with_prefix(
19723            "// ".to_string(),
19724            "xx \nyy zz aa bb cc".to_string(),
19725            12,
19726            NonZeroU32::new(4).unwrap(),
19727            false,
19728        ),
19729        "// xx yy zz\n// aa bb cc"
19730    );
19731    assert_eq!(
19732        wrap_with_prefix(
19733            String::new(),
19734            "这是什么 \n 钢笔".to_string(),
19735            3,
19736            NonZeroU32::new(4).unwrap(),
19737            false,
19738        ),
19739        "这是什\n么 钢\n"
19740    );
19741}
19742
19743pub trait CollaborationHub {
19744    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19745    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19746    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19747}
19748
19749impl CollaborationHub for Entity<Project> {
19750    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19751        self.read(cx).collaborators()
19752    }
19753
19754    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19755        self.read(cx).user_store().read(cx).participant_indices()
19756    }
19757
19758    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19759        let this = self.read(cx);
19760        let user_ids = this.collaborators().values().map(|c| c.user_id);
19761        this.user_store().read_with(cx, |user_store, cx| {
19762            user_store.participant_names(user_ids, cx)
19763        })
19764    }
19765}
19766
19767pub trait SemanticsProvider {
19768    fn hover(
19769        &self,
19770        buffer: &Entity<Buffer>,
19771        position: text::Anchor,
19772        cx: &mut App,
19773    ) -> Option<Task<Vec<project::Hover>>>;
19774
19775    fn inline_values(
19776        &self,
19777        buffer_handle: Entity<Buffer>,
19778        range: Range<text::Anchor>,
19779        cx: &mut App,
19780    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19781
19782    fn inlay_hints(
19783        &self,
19784        buffer_handle: Entity<Buffer>,
19785        range: Range<text::Anchor>,
19786        cx: &mut App,
19787    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19788
19789    fn resolve_inlay_hint(
19790        &self,
19791        hint: InlayHint,
19792        buffer_handle: Entity<Buffer>,
19793        server_id: LanguageServerId,
19794        cx: &mut App,
19795    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19796
19797    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19798
19799    fn document_highlights(
19800        &self,
19801        buffer: &Entity<Buffer>,
19802        position: text::Anchor,
19803        cx: &mut App,
19804    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19805
19806    fn definitions(
19807        &self,
19808        buffer: &Entity<Buffer>,
19809        position: text::Anchor,
19810        kind: GotoDefinitionKind,
19811        cx: &mut App,
19812    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19813
19814    fn range_for_rename(
19815        &self,
19816        buffer: &Entity<Buffer>,
19817        position: text::Anchor,
19818        cx: &mut App,
19819    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19820
19821    fn perform_rename(
19822        &self,
19823        buffer: &Entity<Buffer>,
19824        position: text::Anchor,
19825        new_name: String,
19826        cx: &mut App,
19827    ) -> Option<Task<Result<ProjectTransaction>>>;
19828}
19829
19830pub trait CompletionProvider {
19831    fn completions(
19832        &self,
19833        excerpt_id: ExcerptId,
19834        buffer: &Entity<Buffer>,
19835        buffer_position: text::Anchor,
19836        trigger: CompletionContext,
19837        window: &mut Window,
19838        cx: &mut Context<Editor>,
19839    ) -> Task<Result<Option<Vec<Completion>>>>;
19840
19841    fn resolve_completions(
19842        &self,
19843        buffer: Entity<Buffer>,
19844        completion_indices: Vec<usize>,
19845        completions: Rc<RefCell<Box<[Completion]>>>,
19846        cx: &mut Context<Editor>,
19847    ) -> Task<Result<bool>>;
19848
19849    fn apply_additional_edits_for_completion(
19850        &self,
19851        _buffer: Entity<Buffer>,
19852        _completions: Rc<RefCell<Box<[Completion]>>>,
19853        _completion_index: usize,
19854        _push_to_history: bool,
19855        _cx: &mut Context<Editor>,
19856    ) -> Task<Result<Option<language::Transaction>>> {
19857        Task::ready(Ok(None))
19858    }
19859
19860    fn is_completion_trigger(
19861        &self,
19862        buffer: &Entity<Buffer>,
19863        position: language::Anchor,
19864        text: &str,
19865        trigger_in_words: bool,
19866        cx: &mut Context<Editor>,
19867    ) -> bool;
19868
19869    fn sort_completions(&self) -> bool {
19870        true
19871    }
19872
19873    fn filter_completions(&self) -> bool {
19874        true
19875    }
19876}
19877
19878pub trait CodeActionProvider {
19879    fn id(&self) -> Arc<str>;
19880
19881    fn code_actions(
19882        &self,
19883        buffer: &Entity<Buffer>,
19884        range: Range<text::Anchor>,
19885        window: &mut Window,
19886        cx: &mut App,
19887    ) -> Task<Result<Vec<CodeAction>>>;
19888
19889    fn apply_code_action(
19890        &self,
19891        buffer_handle: Entity<Buffer>,
19892        action: CodeAction,
19893        excerpt_id: ExcerptId,
19894        push_to_history: bool,
19895        window: &mut Window,
19896        cx: &mut App,
19897    ) -> Task<Result<ProjectTransaction>>;
19898}
19899
19900impl CodeActionProvider for Entity<Project> {
19901    fn id(&self) -> Arc<str> {
19902        "project".into()
19903    }
19904
19905    fn code_actions(
19906        &self,
19907        buffer: &Entity<Buffer>,
19908        range: Range<text::Anchor>,
19909        _window: &mut Window,
19910        cx: &mut App,
19911    ) -> Task<Result<Vec<CodeAction>>> {
19912        self.update(cx, |project, cx| {
19913            let code_lens = project.code_lens(buffer, range.clone(), cx);
19914            let code_actions = project.code_actions(buffer, range, None, cx);
19915            cx.background_spawn(async move {
19916                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19917                Ok(code_lens
19918                    .context("code lens fetch")?
19919                    .into_iter()
19920                    .chain(code_actions.context("code action fetch")?)
19921                    .collect())
19922            })
19923        })
19924    }
19925
19926    fn apply_code_action(
19927        &self,
19928        buffer_handle: Entity<Buffer>,
19929        action: CodeAction,
19930        _excerpt_id: ExcerptId,
19931        push_to_history: bool,
19932        _window: &mut Window,
19933        cx: &mut App,
19934    ) -> Task<Result<ProjectTransaction>> {
19935        self.update(cx, |project, cx| {
19936            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19937        })
19938    }
19939}
19940
19941fn snippet_completions(
19942    project: &Project,
19943    buffer: &Entity<Buffer>,
19944    buffer_position: text::Anchor,
19945    cx: &mut App,
19946) -> Task<Result<Vec<Completion>>> {
19947    let languages = buffer.read(cx).languages_at(buffer_position);
19948    let snippet_store = project.snippets().read(cx);
19949
19950    let scopes: Vec<_> = languages
19951        .iter()
19952        .filter_map(|language| {
19953            let language_name = language.lsp_id();
19954            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19955
19956            if snippets.is_empty() {
19957                None
19958            } else {
19959                Some((language.default_scope(), snippets))
19960            }
19961        })
19962        .collect();
19963
19964    if scopes.is_empty() {
19965        return Task::ready(Ok(vec![]));
19966    }
19967
19968    let snapshot = buffer.read(cx).text_snapshot();
19969    let chars: String = snapshot
19970        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19971        .collect();
19972    let executor = cx.background_executor().clone();
19973
19974    cx.background_spawn(async move {
19975        let mut all_results: Vec<Completion> = Vec::new();
19976        for (scope, snippets) in scopes.into_iter() {
19977            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19978            let mut last_word = chars
19979                .chars()
19980                .take_while(|c| classifier.is_word(*c))
19981                .collect::<String>();
19982            last_word = last_word.chars().rev().collect();
19983
19984            if last_word.is_empty() {
19985                return Ok(vec![]);
19986            }
19987
19988            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19989            let to_lsp = |point: &text::Anchor| {
19990                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19991                point_to_lsp(end)
19992            };
19993            let lsp_end = to_lsp(&buffer_position);
19994
19995            let candidates = snippets
19996                .iter()
19997                .enumerate()
19998                .flat_map(|(ix, snippet)| {
19999                    snippet
20000                        .prefix
20001                        .iter()
20002                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20003                })
20004                .collect::<Vec<StringMatchCandidate>>();
20005
20006            let mut matches = fuzzy::match_strings(
20007                &candidates,
20008                &last_word,
20009                last_word.chars().any(|c| c.is_uppercase()),
20010                100,
20011                &Default::default(),
20012                executor.clone(),
20013            )
20014            .await;
20015
20016            // Remove all candidates where the query's start does not match the start of any word in the candidate
20017            if let Some(query_start) = last_word.chars().next() {
20018                matches.retain(|string_match| {
20019                    split_words(&string_match.string).any(|word| {
20020                        // Check that the first codepoint of the word as lowercase matches the first
20021                        // codepoint of the query as lowercase
20022                        word.chars()
20023                            .flat_map(|codepoint| codepoint.to_lowercase())
20024                            .zip(query_start.to_lowercase())
20025                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20026                    })
20027                });
20028            }
20029
20030            let matched_strings = matches
20031                .into_iter()
20032                .map(|m| m.string)
20033                .collect::<HashSet<_>>();
20034
20035            let mut result: Vec<Completion> = snippets
20036                .iter()
20037                .filter_map(|snippet| {
20038                    let matching_prefix = snippet
20039                        .prefix
20040                        .iter()
20041                        .find(|prefix| matched_strings.contains(*prefix))?;
20042                    let start = as_offset - last_word.len();
20043                    let start = snapshot.anchor_before(start);
20044                    let range = start..buffer_position;
20045                    let lsp_start = to_lsp(&start);
20046                    let lsp_range = lsp::Range {
20047                        start: lsp_start,
20048                        end: lsp_end,
20049                    };
20050                    Some(Completion {
20051                        replace_range: range,
20052                        new_text: snippet.body.clone(),
20053                        source: CompletionSource::Lsp {
20054                            insert_range: None,
20055                            server_id: LanguageServerId(usize::MAX),
20056                            resolved: true,
20057                            lsp_completion: Box::new(lsp::CompletionItem {
20058                                label: snippet.prefix.first().unwrap().clone(),
20059                                kind: Some(CompletionItemKind::SNIPPET),
20060                                label_details: snippet.description.as_ref().map(|description| {
20061                                    lsp::CompletionItemLabelDetails {
20062                                        detail: Some(description.clone()),
20063                                        description: None,
20064                                    }
20065                                }),
20066                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20067                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20068                                    lsp::InsertReplaceEdit {
20069                                        new_text: snippet.body.clone(),
20070                                        insert: lsp_range,
20071                                        replace: lsp_range,
20072                                    },
20073                                )),
20074                                filter_text: Some(snippet.body.clone()),
20075                                sort_text: Some(char::MAX.to_string()),
20076                                ..lsp::CompletionItem::default()
20077                            }),
20078                            lsp_defaults: None,
20079                        },
20080                        label: CodeLabel {
20081                            text: matching_prefix.clone(),
20082                            runs: Vec::new(),
20083                            filter_range: 0..matching_prefix.len(),
20084                        },
20085                        icon_path: None,
20086                        documentation: Some(
20087                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20088                                single_line: snippet.name.clone().into(),
20089                                plain_text: snippet
20090                                    .description
20091                                    .clone()
20092                                    .map(|description| description.into()),
20093                            },
20094                        ),
20095                        insert_text_mode: None,
20096                        confirm: None,
20097                    })
20098                })
20099                .collect();
20100
20101            all_results.append(&mut result);
20102        }
20103
20104        Ok(all_results)
20105    })
20106}
20107
20108impl CompletionProvider for Entity<Project> {
20109    fn completions(
20110        &self,
20111        _excerpt_id: ExcerptId,
20112        buffer: &Entity<Buffer>,
20113        buffer_position: text::Anchor,
20114        options: CompletionContext,
20115        _window: &mut Window,
20116        cx: &mut Context<Editor>,
20117    ) -> Task<Result<Option<Vec<Completion>>>> {
20118        self.update(cx, |project, cx| {
20119            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20120            let project_completions = project.completions(buffer, buffer_position, options, cx);
20121            cx.background_spawn(async move {
20122                let snippets_completions = snippets.await?;
20123                match project_completions.await? {
20124                    Some(mut completions) => {
20125                        completions.extend(snippets_completions);
20126                        Ok(Some(completions))
20127                    }
20128                    None => {
20129                        if snippets_completions.is_empty() {
20130                            Ok(None)
20131                        } else {
20132                            Ok(Some(snippets_completions))
20133                        }
20134                    }
20135                }
20136            })
20137        })
20138    }
20139
20140    fn resolve_completions(
20141        &self,
20142        buffer: Entity<Buffer>,
20143        completion_indices: Vec<usize>,
20144        completions: Rc<RefCell<Box<[Completion]>>>,
20145        cx: &mut Context<Editor>,
20146    ) -> Task<Result<bool>> {
20147        self.update(cx, |project, cx| {
20148            project.lsp_store().update(cx, |lsp_store, cx| {
20149                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20150            })
20151        })
20152    }
20153
20154    fn apply_additional_edits_for_completion(
20155        &self,
20156        buffer: Entity<Buffer>,
20157        completions: Rc<RefCell<Box<[Completion]>>>,
20158        completion_index: usize,
20159        push_to_history: bool,
20160        cx: &mut Context<Editor>,
20161    ) -> Task<Result<Option<language::Transaction>>> {
20162        self.update(cx, |project, cx| {
20163            project.lsp_store().update(cx, |lsp_store, cx| {
20164                lsp_store.apply_additional_edits_for_completion(
20165                    buffer,
20166                    completions,
20167                    completion_index,
20168                    push_to_history,
20169                    cx,
20170                )
20171            })
20172        })
20173    }
20174
20175    fn is_completion_trigger(
20176        &self,
20177        buffer: &Entity<Buffer>,
20178        position: language::Anchor,
20179        text: &str,
20180        trigger_in_words: bool,
20181        cx: &mut Context<Editor>,
20182    ) -> bool {
20183        let mut chars = text.chars();
20184        let char = if let Some(char) = chars.next() {
20185            char
20186        } else {
20187            return false;
20188        };
20189        if chars.next().is_some() {
20190            return false;
20191        }
20192
20193        let buffer = buffer.read(cx);
20194        let snapshot = buffer.snapshot();
20195        if !snapshot.settings_at(position, cx).show_completions_on_input {
20196            return false;
20197        }
20198        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20199        if trigger_in_words && classifier.is_word(char) {
20200            return true;
20201        }
20202
20203        buffer.completion_triggers().contains(text)
20204    }
20205}
20206
20207impl SemanticsProvider for Entity<Project> {
20208    fn hover(
20209        &self,
20210        buffer: &Entity<Buffer>,
20211        position: text::Anchor,
20212        cx: &mut App,
20213    ) -> Option<Task<Vec<project::Hover>>> {
20214        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20215    }
20216
20217    fn document_highlights(
20218        &self,
20219        buffer: &Entity<Buffer>,
20220        position: text::Anchor,
20221        cx: &mut App,
20222    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20223        Some(self.update(cx, |project, cx| {
20224            project.document_highlights(buffer, position, cx)
20225        }))
20226    }
20227
20228    fn definitions(
20229        &self,
20230        buffer: &Entity<Buffer>,
20231        position: text::Anchor,
20232        kind: GotoDefinitionKind,
20233        cx: &mut App,
20234    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20235        Some(self.update(cx, |project, cx| match kind {
20236            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20237            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20238            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20239            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20240        }))
20241    }
20242
20243    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20244        // TODO: make this work for remote projects
20245        self.update(cx, |project, cx| {
20246            if project
20247                .active_debug_session(cx)
20248                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20249            {
20250                return true;
20251            }
20252
20253            buffer.update(cx, |buffer, cx| {
20254                project.any_language_server_supports_inlay_hints(buffer, cx)
20255            })
20256        })
20257    }
20258
20259    fn inline_values(
20260        &self,
20261        buffer_handle: Entity<Buffer>,
20262
20263        range: Range<text::Anchor>,
20264        cx: &mut App,
20265    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20266        self.update(cx, |project, cx| {
20267            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20268
20269            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20270        })
20271    }
20272
20273    fn inlay_hints(
20274        &self,
20275        buffer_handle: Entity<Buffer>,
20276        range: Range<text::Anchor>,
20277        cx: &mut App,
20278    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20279        Some(self.update(cx, |project, cx| {
20280            project.inlay_hints(buffer_handle, range, cx)
20281        }))
20282    }
20283
20284    fn resolve_inlay_hint(
20285        &self,
20286        hint: InlayHint,
20287        buffer_handle: Entity<Buffer>,
20288        server_id: LanguageServerId,
20289        cx: &mut App,
20290    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20291        Some(self.update(cx, |project, cx| {
20292            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20293        }))
20294    }
20295
20296    fn range_for_rename(
20297        &self,
20298        buffer: &Entity<Buffer>,
20299        position: text::Anchor,
20300        cx: &mut App,
20301    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20302        Some(self.update(cx, |project, cx| {
20303            let buffer = buffer.clone();
20304            let task = project.prepare_rename(buffer.clone(), position, cx);
20305            cx.spawn(async move |_, cx| {
20306                Ok(match task.await? {
20307                    PrepareRenameResponse::Success(range) => Some(range),
20308                    PrepareRenameResponse::InvalidPosition => None,
20309                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20310                        // Fallback on using TreeSitter info to determine identifier range
20311                        buffer.update(cx, |buffer, _| {
20312                            let snapshot = buffer.snapshot();
20313                            let (range, kind) = snapshot.surrounding_word(position);
20314                            if kind != Some(CharKind::Word) {
20315                                return None;
20316                            }
20317                            Some(
20318                                snapshot.anchor_before(range.start)
20319                                    ..snapshot.anchor_after(range.end),
20320                            )
20321                        })?
20322                    }
20323                })
20324            })
20325        }))
20326    }
20327
20328    fn perform_rename(
20329        &self,
20330        buffer: &Entity<Buffer>,
20331        position: text::Anchor,
20332        new_name: String,
20333        cx: &mut App,
20334    ) -> Option<Task<Result<ProjectTransaction>>> {
20335        Some(self.update(cx, |project, cx| {
20336            project.perform_rename(buffer.clone(), position, new_name, cx)
20337        }))
20338    }
20339}
20340
20341fn inlay_hint_settings(
20342    location: Anchor,
20343    snapshot: &MultiBufferSnapshot,
20344    cx: &mut Context<Editor>,
20345) -> InlayHintSettings {
20346    let file = snapshot.file_at(location);
20347    let language = snapshot.language_at(location).map(|l| l.name());
20348    language_settings(language, file, cx).inlay_hints
20349}
20350
20351fn consume_contiguous_rows(
20352    contiguous_row_selections: &mut Vec<Selection<Point>>,
20353    selection: &Selection<Point>,
20354    display_map: &DisplaySnapshot,
20355    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20356) -> (MultiBufferRow, MultiBufferRow) {
20357    contiguous_row_selections.push(selection.clone());
20358    let start_row = MultiBufferRow(selection.start.row);
20359    let mut end_row = ending_row(selection, display_map);
20360
20361    while let Some(next_selection) = selections.peek() {
20362        if next_selection.start.row <= end_row.0 {
20363            end_row = ending_row(next_selection, display_map);
20364            contiguous_row_selections.push(selections.next().unwrap().clone());
20365        } else {
20366            break;
20367        }
20368    }
20369    (start_row, end_row)
20370}
20371
20372fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20373    if next_selection.end.column > 0 || next_selection.is_empty() {
20374        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20375    } else {
20376        MultiBufferRow(next_selection.end.row)
20377    }
20378}
20379
20380impl EditorSnapshot {
20381    pub fn remote_selections_in_range<'a>(
20382        &'a self,
20383        range: &'a Range<Anchor>,
20384        collaboration_hub: &dyn CollaborationHub,
20385        cx: &'a App,
20386    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20387        let participant_names = collaboration_hub.user_names(cx);
20388        let participant_indices = collaboration_hub.user_participant_indices(cx);
20389        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20390        let collaborators_by_replica_id = collaborators_by_peer_id
20391            .values()
20392            .map(|collaborator| (collaborator.replica_id, collaborator))
20393            .collect::<HashMap<_, _>>();
20394        self.buffer_snapshot
20395            .selections_in_range(range, false)
20396            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20397                if replica_id == AGENT_REPLICA_ID {
20398                    Some(RemoteSelection {
20399                        replica_id,
20400                        selection,
20401                        cursor_shape,
20402                        line_mode,
20403                        collaborator_id: CollaboratorId::Agent,
20404                        user_name: Some("Agent".into()),
20405                        color: cx.theme().players().agent(),
20406                    })
20407                } else {
20408                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20409                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20410                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20411                    Some(RemoteSelection {
20412                        replica_id,
20413                        selection,
20414                        cursor_shape,
20415                        line_mode,
20416                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20417                        user_name,
20418                        color: if let Some(index) = participant_index {
20419                            cx.theme().players().color_for_participant(index.0)
20420                        } else {
20421                            cx.theme().players().absent()
20422                        },
20423                    })
20424                }
20425            })
20426    }
20427
20428    pub fn hunks_for_ranges(
20429        &self,
20430        ranges: impl IntoIterator<Item = Range<Point>>,
20431    ) -> Vec<MultiBufferDiffHunk> {
20432        let mut hunks = Vec::new();
20433        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20434            HashMap::default();
20435        for query_range in ranges {
20436            let query_rows =
20437                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20438            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20439                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20440            ) {
20441                // Include deleted hunks that are adjacent to the query range, because
20442                // otherwise they would be missed.
20443                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20444                if hunk.status().is_deleted() {
20445                    intersects_range |= hunk.row_range.start == query_rows.end;
20446                    intersects_range |= hunk.row_range.end == query_rows.start;
20447                }
20448                if intersects_range {
20449                    if !processed_buffer_rows
20450                        .entry(hunk.buffer_id)
20451                        .or_default()
20452                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20453                    {
20454                        continue;
20455                    }
20456                    hunks.push(hunk);
20457                }
20458            }
20459        }
20460
20461        hunks
20462    }
20463
20464    fn display_diff_hunks_for_rows<'a>(
20465        &'a self,
20466        display_rows: Range<DisplayRow>,
20467        folded_buffers: &'a HashSet<BufferId>,
20468    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20469        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20470        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20471
20472        self.buffer_snapshot
20473            .diff_hunks_in_range(buffer_start..buffer_end)
20474            .filter_map(|hunk| {
20475                if folded_buffers.contains(&hunk.buffer_id) {
20476                    return None;
20477                }
20478
20479                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20480                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20481
20482                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20483                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20484
20485                let display_hunk = if hunk_display_start.column() != 0 {
20486                    DisplayDiffHunk::Folded {
20487                        display_row: hunk_display_start.row(),
20488                    }
20489                } else {
20490                    let mut end_row = hunk_display_end.row();
20491                    if hunk_display_end.column() > 0 {
20492                        end_row.0 += 1;
20493                    }
20494                    let is_created_file = hunk.is_created_file();
20495                    DisplayDiffHunk::Unfolded {
20496                        status: hunk.status(),
20497                        diff_base_byte_range: hunk.diff_base_byte_range,
20498                        display_row_range: hunk_display_start.row()..end_row,
20499                        multi_buffer_range: Anchor::range_in_buffer(
20500                            hunk.excerpt_id,
20501                            hunk.buffer_id,
20502                            hunk.buffer_range,
20503                        ),
20504                        is_created_file,
20505                    }
20506                };
20507
20508                Some(display_hunk)
20509            })
20510    }
20511
20512    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20513        self.display_snapshot.buffer_snapshot.language_at(position)
20514    }
20515
20516    pub fn is_focused(&self) -> bool {
20517        self.is_focused
20518    }
20519
20520    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20521        self.placeholder_text.as_ref()
20522    }
20523
20524    pub fn scroll_position(&self) -> gpui::Point<f32> {
20525        self.scroll_anchor.scroll_position(&self.display_snapshot)
20526    }
20527
20528    fn gutter_dimensions(
20529        &self,
20530        font_id: FontId,
20531        font_size: Pixels,
20532        max_line_number_width: Pixels,
20533        cx: &App,
20534    ) -> Option<GutterDimensions> {
20535        if !self.show_gutter {
20536            return None;
20537        }
20538
20539        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20540        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20541
20542        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20543            matches!(
20544                ProjectSettings::get_global(cx).git.git_gutter,
20545                Some(GitGutterSetting::TrackedFiles)
20546            )
20547        });
20548        let gutter_settings = EditorSettings::get_global(cx).gutter;
20549        let show_line_numbers = self
20550            .show_line_numbers
20551            .unwrap_or(gutter_settings.line_numbers);
20552        let line_gutter_width = if show_line_numbers {
20553            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20554            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20555            max_line_number_width.max(min_width_for_number_on_gutter)
20556        } else {
20557            0.0.into()
20558        };
20559
20560        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20561        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20562
20563        let git_blame_entries_width =
20564            self.git_blame_gutter_max_author_length
20565                .map(|max_author_length| {
20566                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20567                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20568
20569                    /// The number of characters to dedicate to gaps and margins.
20570                    const SPACING_WIDTH: usize = 4;
20571
20572                    let max_char_count = max_author_length.min(renderer.max_author_length())
20573                        + ::git::SHORT_SHA_LENGTH
20574                        + MAX_RELATIVE_TIMESTAMP.len()
20575                        + SPACING_WIDTH;
20576
20577                    em_advance * max_char_count
20578                });
20579
20580        let is_singleton = self.buffer_snapshot.is_singleton();
20581
20582        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20583        left_padding += if !is_singleton {
20584            em_width * 4.0
20585        } else if show_runnables || show_breakpoints {
20586            em_width * 3.0
20587        } else if show_git_gutter && show_line_numbers {
20588            em_width * 2.0
20589        } else if show_git_gutter || show_line_numbers {
20590            em_width
20591        } else {
20592            px(0.)
20593        };
20594
20595        let shows_folds = is_singleton && gutter_settings.folds;
20596
20597        let right_padding = if shows_folds && show_line_numbers {
20598            em_width * 4.0
20599        } else if shows_folds || (!is_singleton && show_line_numbers) {
20600            em_width * 3.0
20601        } else if show_line_numbers {
20602            em_width
20603        } else {
20604            px(0.)
20605        };
20606
20607        Some(GutterDimensions {
20608            left_padding,
20609            right_padding,
20610            width: line_gutter_width + left_padding + right_padding,
20611            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20612            git_blame_entries_width,
20613        })
20614    }
20615
20616    pub fn render_crease_toggle(
20617        &self,
20618        buffer_row: MultiBufferRow,
20619        row_contains_cursor: bool,
20620        editor: Entity<Editor>,
20621        window: &mut Window,
20622        cx: &mut App,
20623    ) -> Option<AnyElement> {
20624        let folded = self.is_line_folded(buffer_row);
20625        let mut is_foldable = false;
20626
20627        if let Some(crease) = self
20628            .crease_snapshot
20629            .query_row(buffer_row, &self.buffer_snapshot)
20630        {
20631            is_foldable = true;
20632            match crease {
20633                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20634                    if let Some(render_toggle) = render_toggle {
20635                        let toggle_callback =
20636                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20637                                if folded {
20638                                    editor.update(cx, |editor, cx| {
20639                                        editor.fold_at(buffer_row, window, cx)
20640                                    });
20641                                } else {
20642                                    editor.update(cx, |editor, cx| {
20643                                        editor.unfold_at(buffer_row, window, cx)
20644                                    });
20645                                }
20646                            });
20647                        return Some((render_toggle)(
20648                            buffer_row,
20649                            folded,
20650                            toggle_callback,
20651                            window,
20652                            cx,
20653                        ));
20654                    }
20655                }
20656            }
20657        }
20658
20659        is_foldable |= self.starts_indent(buffer_row);
20660
20661        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20662            Some(
20663                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20664                    .toggle_state(folded)
20665                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20666                        if folded {
20667                            this.unfold_at(buffer_row, window, cx);
20668                        } else {
20669                            this.fold_at(buffer_row, window, cx);
20670                        }
20671                    }))
20672                    .into_any_element(),
20673            )
20674        } else {
20675            None
20676        }
20677    }
20678
20679    pub fn render_crease_trailer(
20680        &self,
20681        buffer_row: MultiBufferRow,
20682        window: &mut Window,
20683        cx: &mut App,
20684    ) -> Option<AnyElement> {
20685        let folded = self.is_line_folded(buffer_row);
20686        if let Crease::Inline { render_trailer, .. } = self
20687            .crease_snapshot
20688            .query_row(buffer_row, &self.buffer_snapshot)?
20689        {
20690            let render_trailer = render_trailer.as_ref()?;
20691            Some(render_trailer(buffer_row, folded, window, cx))
20692        } else {
20693            None
20694        }
20695    }
20696}
20697
20698impl Deref for EditorSnapshot {
20699    type Target = DisplaySnapshot;
20700
20701    fn deref(&self) -> &Self::Target {
20702        &self.display_snapshot
20703    }
20704}
20705
20706#[derive(Clone, Debug, PartialEq, Eq)]
20707pub enum EditorEvent {
20708    InputIgnored {
20709        text: Arc<str>,
20710    },
20711    InputHandled {
20712        utf16_range_to_replace: Option<Range<isize>>,
20713        text: Arc<str>,
20714    },
20715    ExcerptsAdded {
20716        buffer: Entity<Buffer>,
20717        predecessor: ExcerptId,
20718        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20719    },
20720    ExcerptsRemoved {
20721        ids: Vec<ExcerptId>,
20722        removed_buffer_ids: Vec<BufferId>,
20723    },
20724    BufferFoldToggled {
20725        ids: Vec<ExcerptId>,
20726        folded: bool,
20727    },
20728    ExcerptsEdited {
20729        ids: Vec<ExcerptId>,
20730    },
20731    ExcerptsExpanded {
20732        ids: Vec<ExcerptId>,
20733    },
20734    BufferEdited,
20735    Edited {
20736        transaction_id: clock::Lamport,
20737    },
20738    Reparsed(BufferId),
20739    Focused,
20740    FocusedIn,
20741    Blurred,
20742    DirtyChanged,
20743    Saved,
20744    TitleChanged,
20745    DiffBaseChanged,
20746    SelectionsChanged {
20747        local: bool,
20748    },
20749    ScrollPositionChanged {
20750        local: bool,
20751        autoscroll: bool,
20752    },
20753    Closed,
20754    TransactionUndone {
20755        transaction_id: clock::Lamport,
20756    },
20757    TransactionBegun {
20758        transaction_id: clock::Lamport,
20759    },
20760    Reloaded,
20761    CursorShapeChanged,
20762    PushedToNavHistory {
20763        anchor: Anchor,
20764        is_deactivate: bool,
20765    },
20766}
20767
20768impl EventEmitter<EditorEvent> for Editor {}
20769
20770impl Focusable for Editor {
20771    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20772        self.focus_handle.clone()
20773    }
20774}
20775
20776impl Render for Editor {
20777    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20778        let settings = ThemeSettings::get_global(cx);
20779
20780        let mut text_style = match self.mode {
20781            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20782                color: cx.theme().colors().editor_foreground,
20783                font_family: settings.ui_font.family.clone(),
20784                font_features: settings.ui_font.features.clone(),
20785                font_fallbacks: settings.ui_font.fallbacks.clone(),
20786                font_size: rems(0.875).into(),
20787                font_weight: settings.ui_font.weight,
20788                line_height: relative(settings.buffer_line_height.value()),
20789                ..Default::default()
20790            },
20791            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20792                color: cx.theme().colors().editor_foreground,
20793                font_family: settings.buffer_font.family.clone(),
20794                font_features: settings.buffer_font.features.clone(),
20795                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20796                font_size: settings.buffer_font_size(cx).into(),
20797                font_weight: settings.buffer_font.weight,
20798                line_height: relative(settings.buffer_line_height.value()),
20799                ..Default::default()
20800            },
20801        };
20802        if let Some(text_style_refinement) = &self.text_style_refinement {
20803            text_style.refine(text_style_refinement)
20804        }
20805
20806        let background = match self.mode {
20807            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20808            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20809            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20810            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20811        };
20812
20813        EditorElement::new(
20814            &cx.entity(),
20815            EditorStyle {
20816                background,
20817                local_player: cx.theme().players().local(),
20818                text: text_style,
20819                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20820                syntax: cx.theme().syntax().clone(),
20821                status: cx.theme().status().clone(),
20822                inlay_hints_style: make_inlay_hints_style(cx),
20823                inline_completion_styles: make_suggestion_styles(cx),
20824                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20825                show_underlines: !self.mode.is_minimap(),
20826            },
20827        )
20828    }
20829}
20830
20831impl EntityInputHandler for Editor {
20832    fn text_for_range(
20833        &mut self,
20834        range_utf16: Range<usize>,
20835        adjusted_range: &mut Option<Range<usize>>,
20836        _: &mut Window,
20837        cx: &mut Context<Self>,
20838    ) -> Option<String> {
20839        let snapshot = self.buffer.read(cx).read(cx);
20840        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20841        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20842        if (start.0..end.0) != range_utf16 {
20843            adjusted_range.replace(start.0..end.0);
20844        }
20845        Some(snapshot.text_for_range(start..end).collect())
20846    }
20847
20848    fn selected_text_range(
20849        &mut self,
20850        ignore_disabled_input: bool,
20851        _: &mut Window,
20852        cx: &mut Context<Self>,
20853    ) -> Option<UTF16Selection> {
20854        // Prevent the IME menu from appearing when holding down an alphabetic key
20855        // while input is disabled.
20856        if !ignore_disabled_input && !self.input_enabled {
20857            return None;
20858        }
20859
20860        let selection = self.selections.newest::<OffsetUtf16>(cx);
20861        let range = selection.range();
20862
20863        Some(UTF16Selection {
20864            range: range.start.0..range.end.0,
20865            reversed: selection.reversed,
20866        })
20867    }
20868
20869    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20870        let snapshot = self.buffer.read(cx).read(cx);
20871        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20872        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20873    }
20874
20875    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20876        self.clear_highlights::<InputComposition>(cx);
20877        self.ime_transaction.take();
20878    }
20879
20880    fn replace_text_in_range(
20881        &mut self,
20882        range_utf16: Option<Range<usize>>,
20883        text: &str,
20884        window: &mut Window,
20885        cx: &mut Context<Self>,
20886    ) {
20887        if !self.input_enabled {
20888            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20889            return;
20890        }
20891
20892        self.transact(window, cx, |this, window, cx| {
20893            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20894                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20895                Some(this.selection_replacement_ranges(range_utf16, cx))
20896            } else {
20897                this.marked_text_ranges(cx)
20898            };
20899
20900            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20901                let newest_selection_id = this.selections.newest_anchor().id;
20902                this.selections
20903                    .all::<OffsetUtf16>(cx)
20904                    .iter()
20905                    .zip(ranges_to_replace.iter())
20906                    .find_map(|(selection, range)| {
20907                        if selection.id == newest_selection_id {
20908                            Some(
20909                                (range.start.0 as isize - selection.head().0 as isize)
20910                                    ..(range.end.0 as isize - selection.head().0 as isize),
20911                            )
20912                        } else {
20913                            None
20914                        }
20915                    })
20916            });
20917
20918            cx.emit(EditorEvent::InputHandled {
20919                utf16_range_to_replace: range_to_replace,
20920                text: text.into(),
20921            });
20922
20923            if let Some(new_selected_ranges) = new_selected_ranges {
20924                this.change_selections(None, window, cx, |selections| {
20925                    selections.select_ranges(new_selected_ranges)
20926                });
20927                this.backspace(&Default::default(), window, cx);
20928            }
20929
20930            this.handle_input(text, window, cx);
20931        });
20932
20933        if let Some(transaction) = self.ime_transaction {
20934            self.buffer.update(cx, |buffer, cx| {
20935                buffer.group_until_transaction(transaction, cx);
20936            });
20937        }
20938
20939        self.unmark_text(window, cx);
20940    }
20941
20942    fn replace_and_mark_text_in_range(
20943        &mut self,
20944        range_utf16: Option<Range<usize>>,
20945        text: &str,
20946        new_selected_range_utf16: Option<Range<usize>>,
20947        window: &mut Window,
20948        cx: &mut Context<Self>,
20949    ) {
20950        if !self.input_enabled {
20951            return;
20952        }
20953
20954        let transaction = self.transact(window, cx, |this, window, cx| {
20955            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20956                let snapshot = this.buffer.read(cx).read(cx);
20957                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20958                    for marked_range in &mut marked_ranges {
20959                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20960                        marked_range.start.0 += relative_range_utf16.start;
20961                        marked_range.start =
20962                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20963                        marked_range.end =
20964                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20965                    }
20966                }
20967                Some(marked_ranges)
20968            } else if let Some(range_utf16) = range_utf16 {
20969                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20970                Some(this.selection_replacement_ranges(range_utf16, cx))
20971            } else {
20972                None
20973            };
20974
20975            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20976                let newest_selection_id = this.selections.newest_anchor().id;
20977                this.selections
20978                    .all::<OffsetUtf16>(cx)
20979                    .iter()
20980                    .zip(ranges_to_replace.iter())
20981                    .find_map(|(selection, range)| {
20982                        if selection.id == newest_selection_id {
20983                            Some(
20984                                (range.start.0 as isize - selection.head().0 as isize)
20985                                    ..(range.end.0 as isize - selection.head().0 as isize),
20986                            )
20987                        } else {
20988                            None
20989                        }
20990                    })
20991            });
20992
20993            cx.emit(EditorEvent::InputHandled {
20994                utf16_range_to_replace: range_to_replace,
20995                text: text.into(),
20996            });
20997
20998            if let Some(ranges) = ranges_to_replace {
20999                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21000            }
21001
21002            let marked_ranges = {
21003                let snapshot = this.buffer.read(cx).read(cx);
21004                this.selections
21005                    .disjoint_anchors()
21006                    .iter()
21007                    .map(|selection| {
21008                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21009                    })
21010                    .collect::<Vec<_>>()
21011            };
21012
21013            if text.is_empty() {
21014                this.unmark_text(window, cx);
21015            } else {
21016                this.highlight_text::<InputComposition>(
21017                    marked_ranges.clone(),
21018                    HighlightStyle {
21019                        underline: Some(UnderlineStyle {
21020                            thickness: px(1.),
21021                            color: None,
21022                            wavy: false,
21023                        }),
21024                        ..Default::default()
21025                    },
21026                    cx,
21027                );
21028            }
21029
21030            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21031            let use_autoclose = this.use_autoclose;
21032            let use_auto_surround = this.use_auto_surround;
21033            this.set_use_autoclose(false);
21034            this.set_use_auto_surround(false);
21035            this.handle_input(text, window, cx);
21036            this.set_use_autoclose(use_autoclose);
21037            this.set_use_auto_surround(use_auto_surround);
21038
21039            if let Some(new_selected_range) = new_selected_range_utf16 {
21040                let snapshot = this.buffer.read(cx).read(cx);
21041                let new_selected_ranges = marked_ranges
21042                    .into_iter()
21043                    .map(|marked_range| {
21044                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21045                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21046                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21047                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21048                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21049                    })
21050                    .collect::<Vec<_>>();
21051
21052                drop(snapshot);
21053                this.change_selections(None, window, cx, |selections| {
21054                    selections.select_ranges(new_selected_ranges)
21055                });
21056            }
21057        });
21058
21059        self.ime_transaction = self.ime_transaction.or(transaction);
21060        if let Some(transaction) = self.ime_transaction {
21061            self.buffer.update(cx, |buffer, cx| {
21062                buffer.group_until_transaction(transaction, cx);
21063            });
21064        }
21065
21066        if self.text_highlights::<InputComposition>(cx).is_none() {
21067            self.ime_transaction.take();
21068        }
21069    }
21070
21071    fn bounds_for_range(
21072        &mut self,
21073        range_utf16: Range<usize>,
21074        element_bounds: gpui::Bounds<Pixels>,
21075        window: &mut Window,
21076        cx: &mut Context<Self>,
21077    ) -> Option<gpui::Bounds<Pixels>> {
21078        let text_layout_details = self.text_layout_details(window);
21079        let gpui::Size {
21080            width: em_width,
21081            height: line_height,
21082        } = self.character_size(window);
21083
21084        let snapshot = self.snapshot(window, cx);
21085        let scroll_position = snapshot.scroll_position();
21086        let scroll_left = scroll_position.x * em_width;
21087
21088        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21089        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21090            + self.gutter_dimensions.width
21091            + self.gutter_dimensions.margin;
21092        let y = line_height * (start.row().as_f32() - scroll_position.y);
21093
21094        Some(Bounds {
21095            origin: element_bounds.origin + point(x, y),
21096            size: size(em_width, line_height),
21097        })
21098    }
21099
21100    fn character_index_for_point(
21101        &mut self,
21102        point: gpui::Point<Pixels>,
21103        _window: &mut Window,
21104        _cx: &mut Context<Self>,
21105    ) -> Option<usize> {
21106        let position_map = self.last_position_map.as_ref()?;
21107        if !position_map.text_hitbox.contains(&point) {
21108            return None;
21109        }
21110        let display_point = position_map.point_for_position(point).previous_valid;
21111        let anchor = position_map
21112            .snapshot
21113            .display_point_to_anchor(display_point, Bias::Left);
21114        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21115        Some(utf16_offset.0)
21116    }
21117}
21118
21119trait SelectionExt {
21120    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21121    fn spanned_rows(
21122        &self,
21123        include_end_if_at_line_start: bool,
21124        map: &DisplaySnapshot,
21125    ) -> Range<MultiBufferRow>;
21126}
21127
21128impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21129    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21130        let start = self
21131            .start
21132            .to_point(&map.buffer_snapshot)
21133            .to_display_point(map);
21134        let end = self
21135            .end
21136            .to_point(&map.buffer_snapshot)
21137            .to_display_point(map);
21138        if self.reversed {
21139            end..start
21140        } else {
21141            start..end
21142        }
21143    }
21144
21145    fn spanned_rows(
21146        &self,
21147        include_end_if_at_line_start: bool,
21148        map: &DisplaySnapshot,
21149    ) -> Range<MultiBufferRow> {
21150        let start = self.start.to_point(&map.buffer_snapshot);
21151        let mut end = self.end.to_point(&map.buffer_snapshot);
21152        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21153            end.row -= 1;
21154        }
21155
21156        let buffer_start = map.prev_line_boundary(start).0;
21157        let buffer_end = map.next_line_boundary(end).0;
21158        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21159    }
21160}
21161
21162impl<T: InvalidationRegion> InvalidationStack<T> {
21163    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21164    where
21165        S: Clone + ToOffset,
21166    {
21167        while let Some(region) = self.last() {
21168            let all_selections_inside_invalidation_ranges =
21169                if selections.len() == region.ranges().len() {
21170                    selections
21171                        .iter()
21172                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21173                        .all(|(selection, invalidation_range)| {
21174                            let head = selection.head().to_offset(buffer);
21175                            invalidation_range.start <= head && invalidation_range.end >= head
21176                        })
21177                } else {
21178                    false
21179                };
21180
21181            if all_selections_inside_invalidation_ranges {
21182                break;
21183            } else {
21184                self.pop();
21185            }
21186        }
21187    }
21188}
21189
21190impl<T> Default for InvalidationStack<T> {
21191    fn default() -> Self {
21192        Self(Default::default())
21193    }
21194}
21195
21196impl<T> Deref for InvalidationStack<T> {
21197    type Target = Vec<T>;
21198
21199    fn deref(&self) -> &Self::Target {
21200        &self.0
21201    }
21202}
21203
21204impl<T> DerefMut for InvalidationStack<T> {
21205    fn deref_mut(&mut self) -> &mut Self::Target {
21206        &mut self.0
21207    }
21208}
21209
21210impl InvalidationRegion for SnippetState {
21211    fn ranges(&self) -> &[Range<Anchor>] {
21212        &self.ranges[self.active_index]
21213    }
21214}
21215
21216fn inline_completion_edit_text(
21217    current_snapshot: &BufferSnapshot,
21218    edits: &[(Range<Anchor>, String)],
21219    edit_preview: &EditPreview,
21220    include_deletions: bool,
21221    cx: &App,
21222) -> HighlightedText {
21223    let edits = edits
21224        .iter()
21225        .map(|(anchor, text)| {
21226            (
21227                anchor.start.text_anchor..anchor.end.text_anchor,
21228                text.clone(),
21229            )
21230        })
21231        .collect::<Vec<_>>();
21232
21233    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21234}
21235
21236pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21237    match severity {
21238        lsp::DiagnosticSeverity::ERROR => colors.error,
21239        lsp::DiagnosticSeverity::WARNING => colors.warning,
21240        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21241        lsp::DiagnosticSeverity::HINT => colors.info,
21242        _ => colors.ignored,
21243    }
21244}
21245
21246pub fn styled_runs_for_code_label<'a>(
21247    label: &'a CodeLabel,
21248    syntax_theme: &'a theme::SyntaxTheme,
21249) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21250    let fade_out = HighlightStyle {
21251        fade_out: Some(0.35),
21252        ..Default::default()
21253    };
21254
21255    let mut prev_end = label.filter_range.end;
21256    label
21257        .runs
21258        .iter()
21259        .enumerate()
21260        .flat_map(move |(ix, (range, highlight_id))| {
21261            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21262                style
21263            } else {
21264                return Default::default();
21265            };
21266            let mut muted_style = style;
21267            muted_style.highlight(fade_out);
21268
21269            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21270            if range.start >= label.filter_range.end {
21271                if range.start > prev_end {
21272                    runs.push((prev_end..range.start, fade_out));
21273                }
21274                runs.push((range.clone(), muted_style));
21275            } else if range.end <= label.filter_range.end {
21276                runs.push((range.clone(), style));
21277            } else {
21278                runs.push((range.start..label.filter_range.end, style));
21279                runs.push((label.filter_range.end..range.end, muted_style));
21280            }
21281            prev_end = cmp::max(prev_end, range.end);
21282
21283            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21284                runs.push((prev_end..label.text.len(), fade_out));
21285            }
21286
21287            runs
21288        })
21289}
21290
21291pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21292    let mut prev_index = 0;
21293    let mut prev_codepoint: Option<char> = None;
21294    text.char_indices()
21295        .chain([(text.len(), '\0')])
21296        .filter_map(move |(index, codepoint)| {
21297            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21298            let is_boundary = index == text.len()
21299                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21300                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21301            if is_boundary {
21302                let chunk = &text[prev_index..index];
21303                prev_index = index;
21304                Some(chunk)
21305            } else {
21306                None
21307            }
21308        })
21309}
21310
21311pub trait RangeToAnchorExt: Sized {
21312    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21313
21314    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21315        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21316        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21317    }
21318}
21319
21320impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21321    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21322        let start_offset = self.start.to_offset(snapshot);
21323        let end_offset = self.end.to_offset(snapshot);
21324        if start_offset == end_offset {
21325            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21326        } else {
21327            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21328        }
21329    }
21330}
21331
21332pub trait RowExt {
21333    fn as_f32(&self) -> f32;
21334
21335    fn next_row(&self) -> Self;
21336
21337    fn previous_row(&self) -> Self;
21338
21339    fn minus(&self, other: Self) -> u32;
21340}
21341
21342impl RowExt for DisplayRow {
21343    fn as_f32(&self) -> f32 {
21344        self.0 as f32
21345    }
21346
21347    fn next_row(&self) -> Self {
21348        Self(self.0 + 1)
21349    }
21350
21351    fn previous_row(&self) -> Self {
21352        Self(self.0.saturating_sub(1))
21353    }
21354
21355    fn minus(&self, other: Self) -> u32 {
21356        self.0 - other.0
21357    }
21358}
21359
21360impl RowExt for MultiBufferRow {
21361    fn as_f32(&self) -> f32 {
21362        self.0 as f32
21363    }
21364
21365    fn next_row(&self) -> Self {
21366        Self(self.0 + 1)
21367    }
21368
21369    fn previous_row(&self) -> Self {
21370        Self(self.0.saturating_sub(1))
21371    }
21372
21373    fn minus(&self, other: Self) -> u32 {
21374        self.0 - other.0
21375    }
21376}
21377
21378trait RowRangeExt {
21379    type Row;
21380
21381    fn len(&self) -> usize;
21382
21383    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21384}
21385
21386impl RowRangeExt for Range<MultiBufferRow> {
21387    type Row = MultiBufferRow;
21388
21389    fn len(&self) -> usize {
21390        (self.end.0 - self.start.0) as usize
21391    }
21392
21393    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21394        (self.start.0..self.end.0).map(MultiBufferRow)
21395    }
21396}
21397
21398impl RowRangeExt for Range<DisplayRow> {
21399    type Row = DisplayRow;
21400
21401    fn len(&self) -> usize {
21402        (self.end.0 - self.start.0) as usize
21403    }
21404
21405    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21406        (self.start.0..self.end.0).map(DisplayRow)
21407    }
21408}
21409
21410/// If select range has more than one line, we
21411/// just point the cursor to range.start.
21412fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21413    if range.start.row == range.end.row {
21414        range
21415    } else {
21416        range.start..range.start
21417    }
21418}
21419pub struct KillRing(ClipboardItem);
21420impl Global for KillRing {}
21421
21422const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21423
21424enum BreakpointPromptEditAction {
21425    Log,
21426    Condition,
21427    HitCondition,
21428}
21429
21430struct BreakpointPromptEditor {
21431    pub(crate) prompt: Entity<Editor>,
21432    editor: WeakEntity<Editor>,
21433    breakpoint_anchor: Anchor,
21434    breakpoint: Breakpoint,
21435    edit_action: BreakpointPromptEditAction,
21436    block_ids: HashSet<CustomBlockId>,
21437    editor_margins: Arc<Mutex<EditorMargins>>,
21438    _subscriptions: Vec<Subscription>,
21439}
21440
21441impl BreakpointPromptEditor {
21442    const MAX_LINES: u8 = 4;
21443
21444    fn new(
21445        editor: WeakEntity<Editor>,
21446        breakpoint_anchor: Anchor,
21447        breakpoint: Breakpoint,
21448        edit_action: BreakpointPromptEditAction,
21449        window: &mut Window,
21450        cx: &mut Context<Self>,
21451    ) -> Self {
21452        let base_text = match edit_action {
21453            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21454            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21455            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21456        }
21457        .map(|msg| msg.to_string())
21458        .unwrap_or_default();
21459
21460        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21461        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21462
21463        let prompt = cx.new(|cx| {
21464            let mut prompt = Editor::new(
21465                EditorMode::AutoHeight {
21466                    max_lines: Self::MAX_LINES as usize,
21467                },
21468                buffer,
21469                None,
21470                window,
21471                cx,
21472            );
21473            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21474            prompt.set_show_cursor_when_unfocused(false, cx);
21475            prompt.set_placeholder_text(
21476                match edit_action {
21477                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21478                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21479                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21480                },
21481                cx,
21482            );
21483
21484            prompt
21485        });
21486
21487        Self {
21488            prompt,
21489            editor,
21490            breakpoint_anchor,
21491            breakpoint,
21492            edit_action,
21493            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21494            block_ids: Default::default(),
21495            _subscriptions: vec![],
21496        }
21497    }
21498
21499    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21500        self.block_ids.extend(block_ids)
21501    }
21502
21503    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21504        if let Some(editor) = self.editor.upgrade() {
21505            let message = self
21506                .prompt
21507                .read(cx)
21508                .buffer
21509                .read(cx)
21510                .as_singleton()
21511                .expect("A multi buffer in breakpoint prompt isn't possible")
21512                .read(cx)
21513                .as_rope()
21514                .to_string();
21515
21516            editor.update(cx, |editor, cx| {
21517                editor.edit_breakpoint_at_anchor(
21518                    self.breakpoint_anchor,
21519                    self.breakpoint.clone(),
21520                    match self.edit_action {
21521                        BreakpointPromptEditAction::Log => {
21522                            BreakpointEditAction::EditLogMessage(message.into())
21523                        }
21524                        BreakpointPromptEditAction::Condition => {
21525                            BreakpointEditAction::EditCondition(message.into())
21526                        }
21527                        BreakpointPromptEditAction::HitCondition => {
21528                            BreakpointEditAction::EditHitCondition(message.into())
21529                        }
21530                    },
21531                    cx,
21532                );
21533
21534                editor.remove_blocks(self.block_ids.clone(), None, cx);
21535                cx.focus_self(window);
21536            });
21537        }
21538    }
21539
21540    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21541        self.editor
21542            .update(cx, |editor, cx| {
21543                editor.remove_blocks(self.block_ids.clone(), None, cx);
21544                window.focus(&editor.focus_handle);
21545            })
21546            .log_err();
21547    }
21548
21549    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21550        let settings = ThemeSettings::get_global(cx);
21551        let text_style = TextStyle {
21552            color: if self.prompt.read(cx).read_only(cx) {
21553                cx.theme().colors().text_disabled
21554            } else {
21555                cx.theme().colors().text
21556            },
21557            font_family: settings.buffer_font.family.clone(),
21558            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21559            font_size: settings.buffer_font_size(cx).into(),
21560            font_weight: settings.buffer_font.weight,
21561            line_height: relative(settings.buffer_line_height.value()),
21562            ..Default::default()
21563        };
21564        EditorElement::new(
21565            &self.prompt,
21566            EditorStyle {
21567                background: cx.theme().colors().editor_background,
21568                local_player: cx.theme().players().local(),
21569                text: text_style,
21570                ..Default::default()
21571            },
21572        )
21573    }
21574}
21575
21576impl Render for BreakpointPromptEditor {
21577    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21578        let editor_margins = *self.editor_margins.lock();
21579        let gutter_dimensions = editor_margins.gutter;
21580        h_flex()
21581            .key_context("Editor")
21582            .bg(cx.theme().colors().editor_background)
21583            .border_y_1()
21584            .border_color(cx.theme().status().info_border)
21585            .size_full()
21586            .py(window.line_height() / 2.5)
21587            .on_action(cx.listener(Self::confirm))
21588            .on_action(cx.listener(Self::cancel))
21589            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21590            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21591    }
21592}
21593
21594impl Focusable for BreakpointPromptEditor {
21595    fn focus_handle(&self, cx: &App) -> FocusHandle {
21596        self.prompt.focus_handle(cx)
21597    }
21598}
21599
21600fn all_edits_insertions_or_deletions(
21601    edits: &Vec<(Range<Anchor>, String)>,
21602    snapshot: &MultiBufferSnapshot,
21603) -> bool {
21604    let mut all_insertions = true;
21605    let mut all_deletions = true;
21606
21607    for (range, new_text) in edits.iter() {
21608        let range_is_empty = range.to_offset(&snapshot).is_empty();
21609        let text_is_empty = new_text.is_empty();
21610
21611        if range_is_empty != text_is_empty {
21612            if range_is_empty {
21613                all_deletions = false;
21614            } else {
21615                all_insertions = false;
21616            }
21617        } else {
21618            return false;
21619        }
21620
21621        if !all_insertions && !all_deletions {
21622            return false;
21623        }
21624    }
21625    all_insertions || all_deletions
21626}
21627
21628struct MissingEditPredictionKeybindingTooltip;
21629
21630impl Render for MissingEditPredictionKeybindingTooltip {
21631    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21632        ui::tooltip_container(window, cx, |container, _, cx| {
21633            container
21634                .flex_shrink_0()
21635                .max_w_80()
21636                .min_h(rems_from_px(124.))
21637                .justify_between()
21638                .child(
21639                    v_flex()
21640                        .flex_1()
21641                        .text_ui_sm(cx)
21642                        .child(Label::new("Conflict with Accept Keybinding"))
21643                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21644                )
21645                .child(
21646                    h_flex()
21647                        .pb_1()
21648                        .gap_1()
21649                        .items_end()
21650                        .w_full()
21651                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21652                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21653                        }))
21654                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21655                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21656                        })),
21657                )
21658        })
21659    }
21660}
21661
21662#[derive(Debug, Clone, Copy, PartialEq)]
21663pub struct LineHighlight {
21664    pub background: Background,
21665    pub border: Option<gpui::Hsla>,
21666    pub include_gutter: bool,
21667    pub type_id: Option<TypeId>,
21668}
21669
21670fn render_diff_hunk_controls(
21671    row: u32,
21672    status: &DiffHunkStatus,
21673    hunk_range: Range<Anchor>,
21674    is_created_file: bool,
21675    line_height: Pixels,
21676    editor: &Entity<Editor>,
21677    _window: &mut Window,
21678    cx: &mut App,
21679) -> AnyElement {
21680    h_flex()
21681        .h(line_height)
21682        .mr_1()
21683        .gap_1()
21684        .px_0p5()
21685        .pb_1()
21686        .border_x_1()
21687        .border_b_1()
21688        .border_color(cx.theme().colors().border_variant)
21689        .rounded_b_lg()
21690        .bg(cx.theme().colors().editor_background)
21691        .gap_1()
21692        .occlude()
21693        .shadow_md()
21694        .child(if status.has_secondary_hunk() {
21695            Button::new(("stage", row as u64), "Stage")
21696                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21697                .tooltip({
21698                    let focus_handle = editor.focus_handle(cx);
21699                    move |window, cx| {
21700                        Tooltip::for_action_in(
21701                            "Stage Hunk",
21702                            &::git::ToggleStaged,
21703                            &focus_handle,
21704                            window,
21705                            cx,
21706                        )
21707                    }
21708                })
21709                .on_click({
21710                    let editor = editor.clone();
21711                    move |_event, _window, cx| {
21712                        editor.update(cx, |editor, cx| {
21713                            editor.stage_or_unstage_diff_hunks(
21714                                true,
21715                                vec![hunk_range.start..hunk_range.start],
21716                                cx,
21717                            );
21718                        });
21719                    }
21720                })
21721        } else {
21722            Button::new(("unstage", row as u64), "Unstage")
21723                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21724                .tooltip({
21725                    let focus_handle = editor.focus_handle(cx);
21726                    move |window, cx| {
21727                        Tooltip::for_action_in(
21728                            "Unstage Hunk",
21729                            &::git::ToggleStaged,
21730                            &focus_handle,
21731                            window,
21732                            cx,
21733                        )
21734                    }
21735                })
21736                .on_click({
21737                    let editor = editor.clone();
21738                    move |_event, _window, cx| {
21739                        editor.update(cx, |editor, cx| {
21740                            editor.stage_or_unstage_diff_hunks(
21741                                false,
21742                                vec![hunk_range.start..hunk_range.start],
21743                                cx,
21744                            );
21745                        });
21746                    }
21747                })
21748        })
21749        .child(
21750            Button::new(("restore", row as u64), "Restore")
21751                .tooltip({
21752                    let focus_handle = editor.focus_handle(cx);
21753                    move |window, cx| {
21754                        Tooltip::for_action_in(
21755                            "Restore Hunk",
21756                            &::git::Restore,
21757                            &focus_handle,
21758                            window,
21759                            cx,
21760                        )
21761                    }
21762                })
21763                .on_click({
21764                    let editor = editor.clone();
21765                    move |_event, window, cx| {
21766                        editor.update(cx, |editor, cx| {
21767                            let snapshot = editor.snapshot(window, cx);
21768                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21769                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21770                        });
21771                    }
21772                })
21773                .disabled(is_created_file),
21774        )
21775        .when(
21776            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21777            |el| {
21778                el.child(
21779                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21780                        .shape(IconButtonShape::Square)
21781                        .icon_size(IconSize::Small)
21782                        // .disabled(!has_multiple_hunks)
21783                        .tooltip({
21784                            let focus_handle = editor.focus_handle(cx);
21785                            move |window, cx| {
21786                                Tooltip::for_action_in(
21787                                    "Next Hunk",
21788                                    &GoToHunk,
21789                                    &focus_handle,
21790                                    window,
21791                                    cx,
21792                                )
21793                            }
21794                        })
21795                        .on_click({
21796                            let editor = editor.clone();
21797                            move |_event, window, cx| {
21798                                editor.update(cx, |editor, cx| {
21799                                    let snapshot = editor.snapshot(window, cx);
21800                                    let position =
21801                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21802                                    editor.go_to_hunk_before_or_after_position(
21803                                        &snapshot,
21804                                        position,
21805                                        Direction::Next,
21806                                        window,
21807                                        cx,
21808                                    );
21809                                    editor.expand_selected_diff_hunks(cx);
21810                                });
21811                            }
21812                        }),
21813                )
21814                .child(
21815                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21816                        .shape(IconButtonShape::Square)
21817                        .icon_size(IconSize::Small)
21818                        // .disabled(!has_multiple_hunks)
21819                        .tooltip({
21820                            let focus_handle = editor.focus_handle(cx);
21821                            move |window, cx| {
21822                                Tooltip::for_action_in(
21823                                    "Previous Hunk",
21824                                    &GoToPreviousHunk,
21825                                    &focus_handle,
21826                                    window,
21827                                    cx,
21828                                )
21829                            }
21830                        })
21831                        .on_click({
21832                            let editor = editor.clone();
21833                            move |_event, window, cx| {
21834                                editor.update(cx, |editor, cx| {
21835                                    let snapshot = editor.snapshot(window, cx);
21836                                    let point =
21837                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21838                                    editor.go_to_hunk_before_or_after_position(
21839                                        &snapshot,
21840                                        point,
21841                                        Direction::Prev,
21842                                        window,
21843                                        cx,
21844                                    );
21845                                    editor.expand_selected_diff_hunks(cx);
21846                                });
21847                            }
21848                        }),
21849                )
21850            },
21851        )
21852        .into_any_element()
21853}