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) =
 3968                                    delimiters.iter().find_map(|delimiter| {
 3969                                        let trimmed = delimiter.trim_end();
 3970                                        if comment_candidate.starts_with(trimmed) {
 3971                                            Some((delimiter, trimmed.len()))
 3972                                        } else {
 3973                                            None
 3974                                        }
 3975                                    })?;
 3976                                let cursor_is_placed_after_comment_marker =
 3977                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3978                                if cursor_is_placed_after_comment_marker {
 3979                                    Some(delimiter.clone())
 3980                                } else {
 3981                                    None
 3982                                }
 3983                            });
 3984
 3985                            let mut indent_on_newline = IndentSize::spaces(0);
 3986                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3987
 3988                            let doc_delimiter = maybe!({
 3989                                if !selection_is_empty {
 3990                                    return None;
 3991                                }
 3992
 3993                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3994                                    return None;
 3995                                }
 3996
 3997                                let DocumentationConfig {
 3998                                    start: start_tag,
 3999                                    end: end_tag,
 4000                                    prefix: delimiter,
 4001                                    tab_size: len,
 4002                                } = language.documentation()?;
 4003
 4004                                let (snapshot, range) =
 4005                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4006
 4007                                let num_of_whitespaces = snapshot
 4008                                    .chars_for_range(range.clone())
 4009                                    .take_while(|c| c.is_whitespace())
 4010                                    .count();
 4011
 4012                                let cursor_is_after_start_tag = {
 4013                                    let start_tag_len = start_tag.len();
 4014                                    let start_tag_line = snapshot
 4015                                        .chars_for_range(range.clone())
 4016                                        .skip(num_of_whitespaces)
 4017                                        .take(start_tag_len)
 4018                                        .collect::<String>();
 4019                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4020                                        num_of_whitespaces + start_tag_len
 4021                                            <= start_point.column as usize
 4022                                    } else {
 4023                                        false
 4024                                    }
 4025                                };
 4026
 4027                                let cursor_is_after_delimiter = {
 4028                                    let delimiter_trim = delimiter.trim_end();
 4029                                    let delimiter_line = snapshot
 4030                                        .chars_for_range(range.clone())
 4031                                        .skip(num_of_whitespaces)
 4032                                        .take(delimiter_trim.len())
 4033                                        .collect::<String>();
 4034                                    if delimiter_line.starts_with(delimiter_trim) {
 4035                                        num_of_whitespaces + delimiter_trim.len()
 4036                                            <= start_point.column as usize
 4037                                    } else {
 4038                                        false
 4039                                    }
 4040                                };
 4041
 4042                                let cursor_is_before_end_tag_if_exists = {
 4043                                    let num_of_whitespaces_rev = snapshot
 4044                                        .reversed_chars_for_range(range.clone())
 4045                                        .take_while(|c| c.is_whitespace())
 4046                                        .count();
 4047                                    let mut line_iter = snapshot
 4048                                        .reversed_chars_for_range(range)
 4049                                        .skip(num_of_whitespaces_rev);
 4050                                    let end_tag_exists = end_tag
 4051                                        .chars()
 4052                                        .rev()
 4053                                        .all(|char| line_iter.next() == Some(char));
 4054                                    if end_tag_exists {
 4055                                        let max_point = snapshot.line_len(start_point.row) as usize;
 4056                                        let ordering = (num_of_whitespaces_rev
 4057                                            + end_tag.len()
 4058                                            + start_point.column as usize)
 4059                                            .cmp(&max_point);
 4060                                        let cursor_is_before_end_tag =
 4061                                            ordering != Ordering::Greater;
 4062                                        if cursor_is_after_start_tag {
 4063                                            if cursor_is_before_end_tag {
 4064                                                insert_extra_newline = true;
 4065                                            }
 4066                                            let cursor_is_at_start_of_end_tag =
 4067                                                ordering == Ordering::Equal;
 4068                                            if cursor_is_at_start_of_end_tag {
 4069                                                indent_on_extra_newline.len = (*len).into();
 4070                                            }
 4071                                        }
 4072                                        cursor_is_before_end_tag
 4073                                    } else {
 4074                                        true
 4075                                    }
 4076                                };
 4077
 4078                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4079                                    && cursor_is_before_end_tag_if_exists
 4080                                {
 4081                                    if cursor_is_after_start_tag {
 4082                                        indent_on_newline.len = (*len).into();
 4083                                    }
 4084                                    Some(delimiter.clone())
 4085                                } else {
 4086                                    None
 4087                                }
 4088                            });
 4089
 4090                            (
 4091                                comment_delimiter,
 4092                                doc_delimiter,
 4093                                insert_extra_newline,
 4094                                indent_on_newline,
 4095                                indent_on_extra_newline,
 4096                            )
 4097                        } else {
 4098                            (
 4099                                None,
 4100                                None,
 4101                                false,
 4102                                IndentSize::default(),
 4103                                IndentSize::default(),
 4104                            )
 4105                        };
 4106
 4107                        let prevent_auto_indent = doc_delimiter.is_some();
 4108                        let delimiter = comment_delimiter.or(doc_delimiter);
 4109
 4110                        let capacity_for_delimiter =
 4111                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4112                        let mut new_text = String::with_capacity(
 4113                            1 + capacity_for_delimiter
 4114                                + existing_indent.len as usize
 4115                                + indent_on_newline.len as usize
 4116                                + indent_on_extra_newline.len as usize,
 4117                        );
 4118                        new_text.push('\n');
 4119                        new_text.extend(existing_indent.chars());
 4120                        new_text.extend(indent_on_newline.chars());
 4121
 4122                        if let Some(delimiter) = &delimiter {
 4123                            new_text.push_str(delimiter);
 4124                        }
 4125
 4126                        if insert_extra_newline {
 4127                            new_text.push('\n');
 4128                            new_text.extend(existing_indent.chars());
 4129                            new_text.extend(indent_on_extra_newline.chars());
 4130                        }
 4131
 4132                        let anchor = buffer.anchor_after(end);
 4133                        let new_selection = selection.map(|_| anchor);
 4134                        (
 4135                            ((start..end, new_text), prevent_auto_indent),
 4136                            (insert_extra_newline, new_selection),
 4137                        )
 4138                    })
 4139                    .unzip()
 4140            };
 4141
 4142            let mut auto_indent_edits = Vec::new();
 4143            let mut edits = Vec::new();
 4144            for (edit, prevent_auto_indent) in edits_with_flags {
 4145                if prevent_auto_indent {
 4146                    edits.push(edit);
 4147                } else {
 4148                    auto_indent_edits.push(edit);
 4149                }
 4150            }
 4151            if !edits.is_empty() {
 4152                this.edit(edits, cx);
 4153            }
 4154            if !auto_indent_edits.is_empty() {
 4155                this.edit_with_autoindent(auto_indent_edits, cx);
 4156            }
 4157
 4158            let buffer = this.buffer.read(cx).snapshot(cx);
 4159            let new_selections = selection_info
 4160                .into_iter()
 4161                .map(|(extra_newline_inserted, new_selection)| {
 4162                    let mut cursor = new_selection.end.to_point(&buffer);
 4163                    if extra_newline_inserted {
 4164                        cursor.row -= 1;
 4165                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4166                    }
 4167                    new_selection.map(|_| cursor)
 4168                })
 4169                .collect();
 4170
 4171            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4172                s.select(new_selections)
 4173            });
 4174            this.refresh_inline_completion(true, false, window, cx);
 4175        });
 4176    }
 4177
 4178    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4179        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4180
 4181        let buffer = self.buffer.read(cx);
 4182        let snapshot = buffer.snapshot(cx);
 4183
 4184        let mut edits = Vec::new();
 4185        let mut rows = Vec::new();
 4186
 4187        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4188            let cursor = selection.head();
 4189            let row = cursor.row;
 4190
 4191            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4192
 4193            let newline = "\n".to_string();
 4194            edits.push((start_of_line..start_of_line, newline));
 4195
 4196            rows.push(row + rows_inserted as u32);
 4197        }
 4198
 4199        self.transact(window, cx, |editor, window, cx| {
 4200            editor.edit(edits, cx);
 4201
 4202            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4203                let mut index = 0;
 4204                s.move_cursors_with(|map, _, _| {
 4205                    let row = rows[index];
 4206                    index += 1;
 4207
 4208                    let point = Point::new(row, 0);
 4209                    let boundary = map.next_line_boundary(point).1;
 4210                    let clipped = map.clip_point(boundary, Bias::Left);
 4211
 4212                    (clipped, SelectionGoal::None)
 4213                });
 4214            });
 4215
 4216            let mut indent_edits = Vec::new();
 4217            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4218            for row in rows {
 4219                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4220                for (row, indent) in indents {
 4221                    if indent.len == 0 {
 4222                        continue;
 4223                    }
 4224
 4225                    let text = match indent.kind {
 4226                        IndentKind::Space => " ".repeat(indent.len as usize),
 4227                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4228                    };
 4229                    let point = Point::new(row.0, 0);
 4230                    indent_edits.push((point..point, text));
 4231                }
 4232            }
 4233            editor.edit(indent_edits, cx);
 4234        });
 4235    }
 4236
 4237    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4238        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4239
 4240        let buffer = self.buffer.read(cx);
 4241        let snapshot = buffer.snapshot(cx);
 4242
 4243        let mut edits = Vec::new();
 4244        let mut rows = Vec::new();
 4245        let mut rows_inserted = 0;
 4246
 4247        for selection in self.selections.all_adjusted(cx) {
 4248            let cursor = selection.head();
 4249            let row = cursor.row;
 4250
 4251            let point = Point::new(row + 1, 0);
 4252            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4253
 4254            let newline = "\n".to_string();
 4255            edits.push((start_of_line..start_of_line, newline));
 4256
 4257            rows_inserted += 1;
 4258            rows.push(row + rows_inserted);
 4259        }
 4260
 4261        self.transact(window, cx, |editor, window, cx| {
 4262            editor.edit(edits, cx);
 4263
 4264            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4265                let mut index = 0;
 4266                s.move_cursors_with(|map, _, _| {
 4267                    let row = rows[index];
 4268                    index += 1;
 4269
 4270                    let point = Point::new(row, 0);
 4271                    let boundary = map.next_line_boundary(point).1;
 4272                    let clipped = map.clip_point(boundary, Bias::Left);
 4273
 4274                    (clipped, SelectionGoal::None)
 4275                });
 4276            });
 4277
 4278            let mut indent_edits = Vec::new();
 4279            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4280            for row in rows {
 4281                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4282                for (row, indent) in indents {
 4283                    if indent.len == 0 {
 4284                        continue;
 4285                    }
 4286
 4287                    let text = match indent.kind {
 4288                        IndentKind::Space => " ".repeat(indent.len as usize),
 4289                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4290                    };
 4291                    let point = Point::new(row.0, 0);
 4292                    indent_edits.push((point..point, text));
 4293                }
 4294            }
 4295            editor.edit(indent_edits, cx);
 4296        });
 4297    }
 4298
 4299    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4300        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4301            original_indent_columns: Vec::new(),
 4302        });
 4303        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4304    }
 4305
 4306    fn insert_with_autoindent_mode(
 4307        &mut self,
 4308        text: &str,
 4309        autoindent_mode: Option<AutoindentMode>,
 4310        window: &mut Window,
 4311        cx: &mut Context<Self>,
 4312    ) {
 4313        if self.read_only(cx) {
 4314            return;
 4315        }
 4316
 4317        let text: Arc<str> = text.into();
 4318        self.transact(window, cx, |this, window, cx| {
 4319            let old_selections = this.selections.all_adjusted(cx);
 4320            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4321                let anchors = {
 4322                    let snapshot = buffer.read(cx);
 4323                    old_selections
 4324                        .iter()
 4325                        .map(|s| {
 4326                            let anchor = snapshot.anchor_after(s.head());
 4327                            s.map(|_| anchor)
 4328                        })
 4329                        .collect::<Vec<_>>()
 4330                };
 4331                buffer.edit(
 4332                    old_selections
 4333                        .iter()
 4334                        .map(|s| (s.start..s.end, text.clone())),
 4335                    autoindent_mode,
 4336                    cx,
 4337                );
 4338                anchors
 4339            });
 4340
 4341            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4342                s.select_anchors(selection_anchors);
 4343            });
 4344
 4345            cx.notify();
 4346        });
 4347    }
 4348
 4349    fn trigger_completion_on_input(
 4350        &mut self,
 4351        text: &str,
 4352        trigger_in_words: bool,
 4353        window: &mut Window,
 4354        cx: &mut Context<Self>,
 4355    ) {
 4356        let ignore_completion_provider = self
 4357            .context_menu
 4358            .borrow()
 4359            .as_ref()
 4360            .map(|menu| match menu {
 4361                CodeContextMenu::Completions(completions_menu) => {
 4362                    completions_menu.ignore_completion_provider
 4363                }
 4364                CodeContextMenu::CodeActions(_) => false,
 4365            })
 4366            .unwrap_or(false);
 4367
 4368        if ignore_completion_provider {
 4369            self.show_word_completions(&ShowWordCompletions, window, cx);
 4370        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4371            self.show_completions(
 4372                &ShowCompletions {
 4373                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4374                },
 4375                window,
 4376                cx,
 4377            );
 4378        } else {
 4379            self.hide_context_menu(window, cx);
 4380        }
 4381    }
 4382
 4383    fn is_completion_trigger(
 4384        &self,
 4385        text: &str,
 4386        trigger_in_words: bool,
 4387        cx: &mut Context<Self>,
 4388    ) -> bool {
 4389        let position = self.selections.newest_anchor().head();
 4390        let multibuffer = self.buffer.read(cx);
 4391        let Some(buffer) = position
 4392            .buffer_id
 4393            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4394        else {
 4395            return false;
 4396        };
 4397
 4398        if let Some(completion_provider) = &self.completion_provider {
 4399            completion_provider.is_completion_trigger(
 4400                &buffer,
 4401                position.text_anchor,
 4402                text,
 4403                trigger_in_words,
 4404                cx,
 4405            )
 4406        } else {
 4407            false
 4408        }
 4409    }
 4410
 4411    /// If any empty selections is touching the start of its innermost containing autoclose
 4412    /// region, expand it to select the brackets.
 4413    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4414        let selections = self.selections.all::<usize>(cx);
 4415        let buffer = self.buffer.read(cx).read(cx);
 4416        let new_selections = self
 4417            .selections_with_autoclose_regions(selections, &buffer)
 4418            .map(|(mut selection, region)| {
 4419                if !selection.is_empty() {
 4420                    return selection;
 4421                }
 4422
 4423                if let Some(region) = region {
 4424                    let mut range = region.range.to_offset(&buffer);
 4425                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4426                        range.start -= region.pair.start.len();
 4427                        if buffer.contains_str_at(range.start, &region.pair.start)
 4428                            && buffer.contains_str_at(range.end, &region.pair.end)
 4429                        {
 4430                            range.end += region.pair.end.len();
 4431                            selection.start = range.start;
 4432                            selection.end = range.end;
 4433
 4434                            return selection;
 4435                        }
 4436                    }
 4437                }
 4438
 4439                let always_treat_brackets_as_autoclosed = buffer
 4440                    .language_settings_at(selection.start, cx)
 4441                    .always_treat_brackets_as_autoclosed;
 4442
 4443                if !always_treat_brackets_as_autoclosed {
 4444                    return selection;
 4445                }
 4446
 4447                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4448                    for (pair, enabled) in scope.brackets() {
 4449                        if !enabled || !pair.close {
 4450                            continue;
 4451                        }
 4452
 4453                        if buffer.contains_str_at(selection.start, &pair.end) {
 4454                            let pair_start_len = pair.start.len();
 4455                            if buffer.contains_str_at(
 4456                                selection.start.saturating_sub(pair_start_len),
 4457                                &pair.start,
 4458                            ) {
 4459                                selection.start -= pair_start_len;
 4460                                selection.end += pair.end.len();
 4461
 4462                                return selection;
 4463                            }
 4464                        }
 4465                    }
 4466                }
 4467
 4468                selection
 4469            })
 4470            .collect();
 4471
 4472        drop(buffer);
 4473        self.change_selections(None, window, cx, |selections| {
 4474            selections.select(new_selections)
 4475        });
 4476    }
 4477
 4478    /// Iterate the given selections, and for each one, find the smallest surrounding
 4479    /// autoclose region. This uses the ordering of the selections and the autoclose
 4480    /// regions to avoid repeated comparisons.
 4481    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4482        &'a self,
 4483        selections: impl IntoIterator<Item = Selection<D>>,
 4484        buffer: &'a MultiBufferSnapshot,
 4485    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4486        let mut i = 0;
 4487        let mut regions = self.autoclose_regions.as_slice();
 4488        selections.into_iter().map(move |selection| {
 4489            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4490
 4491            let mut enclosing = None;
 4492            while let Some(pair_state) = regions.get(i) {
 4493                if pair_state.range.end.to_offset(buffer) < range.start {
 4494                    regions = &regions[i + 1..];
 4495                    i = 0;
 4496                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4497                    break;
 4498                } else {
 4499                    if pair_state.selection_id == selection.id {
 4500                        enclosing = Some(pair_state);
 4501                    }
 4502                    i += 1;
 4503                }
 4504            }
 4505
 4506            (selection, enclosing)
 4507        })
 4508    }
 4509
 4510    /// Remove any autoclose regions that no longer contain their selection.
 4511    fn invalidate_autoclose_regions(
 4512        &mut self,
 4513        mut selections: &[Selection<Anchor>],
 4514        buffer: &MultiBufferSnapshot,
 4515    ) {
 4516        self.autoclose_regions.retain(|state| {
 4517            let mut i = 0;
 4518            while let Some(selection) = selections.get(i) {
 4519                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4520                    selections = &selections[1..];
 4521                    continue;
 4522                }
 4523                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4524                    break;
 4525                }
 4526                if selection.id == state.selection_id {
 4527                    return true;
 4528                } else {
 4529                    i += 1;
 4530                }
 4531            }
 4532            false
 4533        });
 4534    }
 4535
 4536    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4537        let offset = position.to_offset(buffer);
 4538        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4539        if offset > word_range.start && kind == Some(CharKind::Word) {
 4540            Some(
 4541                buffer
 4542                    .text_for_range(word_range.start..offset)
 4543                    .collect::<String>(),
 4544            )
 4545        } else {
 4546            None
 4547        }
 4548    }
 4549
 4550    pub fn toggle_inline_values(
 4551        &mut self,
 4552        _: &ToggleInlineValues,
 4553        _: &mut Window,
 4554        cx: &mut Context<Self>,
 4555    ) {
 4556        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4557
 4558        self.refresh_inline_values(cx);
 4559    }
 4560
 4561    pub fn toggle_inlay_hints(
 4562        &mut self,
 4563        _: &ToggleInlayHints,
 4564        _: &mut Window,
 4565        cx: &mut Context<Self>,
 4566    ) {
 4567        self.refresh_inlay_hints(
 4568            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4569            cx,
 4570        );
 4571    }
 4572
 4573    pub fn inlay_hints_enabled(&self) -> bool {
 4574        self.inlay_hint_cache.enabled
 4575    }
 4576
 4577    pub fn inline_values_enabled(&self) -> bool {
 4578        self.inline_value_cache.enabled
 4579    }
 4580
 4581    #[cfg(any(test, feature = "test-support"))]
 4582    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4583        self.display_map
 4584            .read(cx)
 4585            .current_inlays()
 4586            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4587            .cloned()
 4588            .collect()
 4589    }
 4590
 4591    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4592        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4593            return;
 4594        }
 4595
 4596        let reason_description = reason.description();
 4597        let ignore_debounce = matches!(
 4598            reason,
 4599            InlayHintRefreshReason::SettingsChange(_)
 4600                | InlayHintRefreshReason::Toggle(_)
 4601                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4602                | InlayHintRefreshReason::ModifiersChanged(_)
 4603        );
 4604        let (invalidate_cache, required_languages) = match reason {
 4605            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4606                match self.inlay_hint_cache.modifiers_override(enabled) {
 4607                    Some(enabled) => {
 4608                        if enabled {
 4609                            (InvalidationStrategy::RefreshRequested, None)
 4610                        } else {
 4611                            self.splice_inlays(
 4612                                &self
 4613                                    .visible_inlay_hints(cx)
 4614                                    .iter()
 4615                                    .map(|inlay| inlay.id)
 4616                                    .collect::<Vec<InlayId>>(),
 4617                                Vec::new(),
 4618                                cx,
 4619                            );
 4620                            return;
 4621                        }
 4622                    }
 4623                    None => return,
 4624                }
 4625            }
 4626            InlayHintRefreshReason::Toggle(enabled) => {
 4627                if self.inlay_hint_cache.toggle(enabled) {
 4628                    if enabled {
 4629                        (InvalidationStrategy::RefreshRequested, None)
 4630                    } else {
 4631                        self.splice_inlays(
 4632                            &self
 4633                                .visible_inlay_hints(cx)
 4634                                .iter()
 4635                                .map(|inlay| inlay.id)
 4636                                .collect::<Vec<InlayId>>(),
 4637                            Vec::new(),
 4638                            cx,
 4639                        );
 4640                        return;
 4641                    }
 4642                } else {
 4643                    return;
 4644                }
 4645            }
 4646            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4647                match self.inlay_hint_cache.update_settings(
 4648                    &self.buffer,
 4649                    new_settings,
 4650                    self.visible_inlay_hints(cx),
 4651                    cx,
 4652                ) {
 4653                    ControlFlow::Break(Some(InlaySplice {
 4654                        to_remove,
 4655                        to_insert,
 4656                    })) => {
 4657                        self.splice_inlays(&to_remove, to_insert, cx);
 4658                        return;
 4659                    }
 4660                    ControlFlow::Break(None) => return,
 4661                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4662                }
 4663            }
 4664            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4665                if let Some(InlaySplice {
 4666                    to_remove,
 4667                    to_insert,
 4668                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4669                {
 4670                    self.splice_inlays(&to_remove, to_insert, cx);
 4671                }
 4672                self.display_map.update(cx, |display_map, _| {
 4673                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4674                });
 4675                return;
 4676            }
 4677            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4678            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4679                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4680            }
 4681            InlayHintRefreshReason::RefreshRequested => {
 4682                (InvalidationStrategy::RefreshRequested, None)
 4683            }
 4684        };
 4685
 4686        if let Some(InlaySplice {
 4687            to_remove,
 4688            to_insert,
 4689        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4690            reason_description,
 4691            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4692            invalidate_cache,
 4693            ignore_debounce,
 4694            cx,
 4695        ) {
 4696            self.splice_inlays(&to_remove, to_insert, cx);
 4697        }
 4698    }
 4699
 4700    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4701        self.display_map
 4702            .read(cx)
 4703            .current_inlays()
 4704            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4705            .cloned()
 4706            .collect()
 4707    }
 4708
 4709    pub fn excerpts_for_inlay_hints_query(
 4710        &self,
 4711        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4712        cx: &mut Context<Editor>,
 4713    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4714        let Some(project) = self.project.as_ref() else {
 4715            return HashMap::default();
 4716        };
 4717        let project = project.read(cx);
 4718        let multi_buffer = self.buffer().read(cx);
 4719        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4720        let multi_buffer_visible_start = self
 4721            .scroll_manager
 4722            .anchor()
 4723            .anchor
 4724            .to_point(&multi_buffer_snapshot);
 4725        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4726            multi_buffer_visible_start
 4727                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4728            Bias::Left,
 4729        );
 4730        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4731        multi_buffer_snapshot
 4732            .range_to_buffer_ranges(multi_buffer_visible_range)
 4733            .into_iter()
 4734            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4735            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4736                let buffer_file = project::File::from_dyn(buffer.file())?;
 4737                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4738                let worktree_entry = buffer_worktree
 4739                    .read(cx)
 4740                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4741                if worktree_entry.is_ignored {
 4742                    return None;
 4743                }
 4744
 4745                let language = buffer.language()?;
 4746                if let Some(restrict_to_languages) = restrict_to_languages {
 4747                    if !restrict_to_languages.contains(language) {
 4748                        return None;
 4749                    }
 4750                }
 4751                Some((
 4752                    excerpt_id,
 4753                    (
 4754                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4755                        buffer.version().clone(),
 4756                        excerpt_visible_range,
 4757                    ),
 4758                ))
 4759            })
 4760            .collect()
 4761    }
 4762
 4763    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4764        TextLayoutDetails {
 4765            text_system: window.text_system().clone(),
 4766            editor_style: self.style.clone().unwrap(),
 4767            rem_size: window.rem_size(),
 4768            scroll_anchor: self.scroll_manager.anchor(),
 4769            visible_rows: self.visible_line_count(),
 4770            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4771        }
 4772    }
 4773
 4774    pub fn splice_inlays(
 4775        &self,
 4776        to_remove: &[InlayId],
 4777        to_insert: Vec<Inlay>,
 4778        cx: &mut Context<Self>,
 4779    ) {
 4780        self.display_map.update(cx, |display_map, cx| {
 4781            display_map.splice_inlays(to_remove, to_insert, cx)
 4782        });
 4783        cx.notify();
 4784    }
 4785
 4786    fn trigger_on_type_formatting(
 4787        &self,
 4788        input: String,
 4789        window: &mut Window,
 4790        cx: &mut Context<Self>,
 4791    ) -> Option<Task<Result<()>>> {
 4792        if input.len() != 1 {
 4793            return None;
 4794        }
 4795
 4796        let project = self.project.as_ref()?;
 4797        let position = self.selections.newest_anchor().head();
 4798        let (buffer, buffer_position) = self
 4799            .buffer
 4800            .read(cx)
 4801            .text_anchor_for_position(position, cx)?;
 4802
 4803        let settings = language_settings::language_settings(
 4804            buffer
 4805                .read(cx)
 4806                .language_at(buffer_position)
 4807                .map(|l| l.name()),
 4808            buffer.read(cx).file(),
 4809            cx,
 4810        );
 4811        if !settings.use_on_type_format {
 4812            return None;
 4813        }
 4814
 4815        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4816        // hence we do LSP request & edit on host side only — add formats to host's history.
 4817        let push_to_lsp_host_history = true;
 4818        // If this is not the host, append its history with new edits.
 4819        let push_to_client_history = project.read(cx).is_via_collab();
 4820
 4821        let on_type_formatting = project.update(cx, |project, cx| {
 4822            project.on_type_format(
 4823                buffer.clone(),
 4824                buffer_position,
 4825                input,
 4826                push_to_lsp_host_history,
 4827                cx,
 4828            )
 4829        });
 4830        Some(cx.spawn_in(window, async move |editor, cx| {
 4831            if let Some(transaction) = on_type_formatting.await? {
 4832                if push_to_client_history {
 4833                    buffer
 4834                        .update(cx, |buffer, _| {
 4835                            buffer.push_transaction(transaction, Instant::now());
 4836                            buffer.finalize_last_transaction();
 4837                        })
 4838                        .ok();
 4839                }
 4840                editor.update(cx, |editor, cx| {
 4841                    editor.refresh_document_highlights(cx);
 4842                })?;
 4843            }
 4844            Ok(())
 4845        }))
 4846    }
 4847
 4848    pub fn show_word_completions(
 4849        &mut self,
 4850        _: &ShowWordCompletions,
 4851        window: &mut Window,
 4852        cx: &mut Context<Self>,
 4853    ) {
 4854        self.open_completions_menu(true, None, window, cx);
 4855    }
 4856
 4857    pub fn show_completions(
 4858        &mut self,
 4859        options: &ShowCompletions,
 4860        window: &mut Window,
 4861        cx: &mut Context<Self>,
 4862    ) {
 4863        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4864    }
 4865
 4866    fn open_completions_menu(
 4867        &mut self,
 4868        ignore_completion_provider: bool,
 4869        trigger: Option<&str>,
 4870        window: &mut Window,
 4871        cx: &mut Context<Self>,
 4872    ) {
 4873        if self.pending_rename.is_some() {
 4874            return;
 4875        }
 4876        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4877            return;
 4878        }
 4879
 4880        let position = self.selections.newest_anchor().head();
 4881        if position.diff_base_anchor.is_some() {
 4882            return;
 4883        }
 4884        let (buffer, buffer_position) =
 4885            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4886                output
 4887            } else {
 4888                return;
 4889            };
 4890        let buffer_snapshot = buffer.read(cx).snapshot();
 4891        let show_completion_documentation = buffer_snapshot
 4892            .settings_at(buffer_position, cx)
 4893            .show_completion_documentation;
 4894
 4895        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4896
 4897        let trigger_kind = match trigger {
 4898            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4899                CompletionTriggerKind::TRIGGER_CHARACTER
 4900            }
 4901            _ => CompletionTriggerKind::INVOKED,
 4902        };
 4903        let completion_context = CompletionContext {
 4904            trigger_character: trigger.and_then(|trigger| {
 4905                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4906                    Some(String::from(trigger))
 4907                } else {
 4908                    None
 4909                }
 4910            }),
 4911            trigger_kind,
 4912        };
 4913
 4914        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4915        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4916            let word_to_exclude = buffer_snapshot
 4917                .text_for_range(old_range.clone())
 4918                .collect::<String>();
 4919            (
 4920                buffer_snapshot.anchor_before(old_range.start)
 4921                    ..buffer_snapshot.anchor_after(old_range.end),
 4922                Some(word_to_exclude),
 4923            )
 4924        } else {
 4925            (buffer_position..buffer_position, None)
 4926        };
 4927
 4928        let completion_settings = language_settings(
 4929            buffer_snapshot
 4930                .language_at(buffer_position)
 4931                .map(|language| language.name()),
 4932            buffer_snapshot.file(),
 4933            cx,
 4934        )
 4935        .completions;
 4936
 4937        // The document can be large, so stay in reasonable bounds when searching for words,
 4938        // otherwise completion pop-up might be slow to appear.
 4939        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4940        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4941        let min_word_search = buffer_snapshot.clip_point(
 4942            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4943            Bias::Left,
 4944        );
 4945        let max_word_search = buffer_snapshot.clip_point(
 4946            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4947            Bias::Right,
 4948        );
 4949        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4950            ..buffer_snapshot.point_to_offset(max_word_search);
 4951
 4952        let provider = self
 4953            .completion_provider
 4954            .as_ref()
 4955            .filter(|_| !ignore_completion_provider);
 4956        let skip_digits = query
 4957            .as_ref()
 4958            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4959
 4960        let (mut words, provided_completions) = match provider {
 4961            Some(provider) => {
 4962                let completions = provider.completions(
 4963                    position.excerpt_id,
 4964                    &buffer,
 4965                    buffer_position,
 4966                    completion_context,
 4967                    window,
 4968                    cx,
 4969                );
 4970
 4971                let words = match completion_settings.words {
 4972                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4973                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4974                        .background_spawn(async move {
 4975                            buffer_snapshot.words_in_range(WordsQuery {
 4976                                fuzzy_contents: None,
 4977                                range: word_search_range,
 4978                                skip_digits,
 4979                            })
 4980                        }),
 4981                };
 4982
 4983                (words, completions)
 4984            }
 4985            None => (
 4986                cx.background_spawn(async move {
 4987                    buffer_snapshot.words_in_range(WordsQuery {
 4988                        fuzzy_contents: None,
 4989                        range: word_search_range,
 4990                        skip_digits,
 4991                    })
 4992                }),
 4993                Task::ready(Ok(None)),
 4994            ),
 4995        };
 4996
 4997        let sort_completions = provider
 4998            .as_ref()
 4999            .map_or(false, |provider| provider.sort_completions());
 5000
 5001        let filter_completions = provider
 5002            .as_ref()
 5003            .map_or(true, |provider| provider.filter_completions());
 5004
 5005        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5006
 5007        let id = post_inc(&mut self.next_completion_id);
 5008        let task = cx.spawn_in(window, async move |editor, cx| {
 5009            async move {
 5010                editor.update(cx, |this, _| {
 5011                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5012                })?;
 5013
 5014                let mut completions = Vec::new();
 5015                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5016                    completions.extend(provided_completions);
 5017                    if completion_settings.words == WordsCompletionMode::Fallback {
 5018                        words = Task::ready(BTreeMap::default());
 5019                    }
 5020                }
 5021
 5022                let mut words = words.await;
 5023                if let Some(word_to_exclude) = &word_to_exclude {
 5024                    words.remove(word_to_exclude);
 5025                }
 5026                for lsp_completion in &completions {
 5027                    words.remove(&lsp_completion.new_text);
 5028                }
 5029                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5030                    replace_range: old_range.clone(),
 5031                    new_text: word.clone(),
 5032                    label: CodeLabel::plain(word, None),
 5033                    icon_path: None,
 5034                    documentation: None,
 5035                    source: CompletionSource::BufferWord {
 5036                        word_range,
 5037                        resolved: false,
 5038                    },
 5039                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5040                    confirm: None,
 5041                }));
 5042
 5043                let menu = if completions.is_empty() {
 5044                    None
 5045                } else {
 5046                    let mut menu = CompletionsMenu::new(
 5047                        id,
 5048                        sort_completions,
 5049                        show_completion_documentation,
 5050                        ignore_completion_provider,
 5051                        position,
 5052                        buffer.clone(),
 5053                        completions.into(),
 5054                        snippet_sort_order,
 5055                    );
 5056
 5057                    menu.filter(
 5058                        if filter_completions {
 5059                            query.as_deref()
 5060                        } else {
 5061                            None
 5062                        },
 5063                        cx.background_executor().clone(),
 5064                    )
 5065                    .await;
 5066
 5067                    menu.visible().then_some(menu)
 5068                };
 5069
 5070                editor.update_in(cx, |editor, window, cx| {
 5071                    match editor.context_menu.borrow().as_ref() {
 5072                        None => {}
 5073                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5074                            if prev_menu.id > id {
 5075                                return;
 5076                            }
 5077                        }
 5078                        _ => return,
 5079                    }
 5080
 5081                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5082                        let mut menu = menu.unwrap();
 5083                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5084
 5085                        *editor.context_menu.borrow_mut() =
 5086                            Some(CodeContextMenu::Completions(menu));
 5087
 5088                        if editor.show_edit_predictions_in_menu() {
 5089                            editor.update_visible_inline_completion(window, cx);
 5090                        } else {
 5091                            editor.discard_inline_completion(false, cx);
 5092                        }
 5093
 5094                        cx.notify();
 5095                    } else if editor.completion_tasks.len() <= 1 {
 5096                        // If there are no more completion tasks and the last menu was
 5097                        // empty, we should hide it.
 5098                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5099                        // If it was already hidden and we don't show inline
 5100                        // completions in the menu, we should also show the
 5101                        // inline-completion when available.
 5102                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5103                            editor.update_visible_inline_completion(window, cx);
 5104                        }
 5105                    }
 5106                })?;
 5107
 5108                anyhow::Ok(())
 5109            }
 5110            .log_err()
 5111            .await
 5112        });
 5113
 5114        self.completion_tasks.push((id, task));
 5115    }
 5116
 5117    #[cfg(feature = "test-support")]
 5118    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5119        let menu = self.context_menu.borrow();
 5120        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5121            let completions = menu.completions.borrow();
 5122            Some(completions.to_vec())
 5123        } else {
 5124            None
 5125        }
 5126    }
 5127
 5128    pub fn confirm_completion(
 5129        &mut self,
 5130        action: &ConfirmCompletion,
 5131        window: &mut Window,
 5132        cx: &mut Context<Self>,
 5133    ) -> Option<Task<Result<()>>> {
 5134        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5135        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5136    }
 5137
 5138    pub fn confirm_completion_insert(
 5139        &mut self,
 5140        _: &ConfirmCompletionInsert,
 5141        window: &mut Window,
 5142        cx: &mut Context<Self>,
 5143    ) -> Option<Task<Result<()>>> {
 5144        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5145        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5146    }
 5147
 5148    pub fn confirm_completion_replace(
 5149        &mut self,
 5150        _: &ConfirmCompletionReplace,
 5151        window: &mut Window,
 5152        cx: &mut Context<Self>,
 5153    ) -> Option<Task<Result<()>>> {
 5154        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5155        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5156    }
 5157
 5158    pub fn compose_completion(
 5159        &mut self,
 5160        action: &ComposeCompletion,
 5161        window: &mut Window,
 5162        cx: &mut Context<Self>,
 5163    ) -> Option<Task<Result<()>>> {
 5164        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5165        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5166    }
 5167
 5168    fn do_completion(
 5169        &mut self,
 5170        item_ix: Option<usize>,
 5171        intent: CompletionIntent,
 5172        window: &mut Window,
 5173        cx: &mut Context<Editor>,
 5174    ) -> Option<Task<Result<()>>> {
 5175        use language::ToOffset as _;
 5176
 5177        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5178        else {
 5179            return None;
 5180        };
 5181
 5182        let candidate_id = {
 5183            let entries = completions_menu.entries.borrow();
 5184            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5185            if self.show_edit_predictions_in_menu() {
 5186                self.discard_inline_completion(true, cx);
 5187            }
 5188            mat.candidate_id
 5189        };
 5190
 5191        let buffer_handle = completions_menu.buffer;
 5192        let completion = completions_menu
 5193            .completions
 5194            .borrow()
 5195            .get(candidate_id)?
 5196            .clone();
 5197        cx.stop_propagation();
 5198
 5199        let snapshot = self.buffer.read(cx).snapshot(cx);
 5200        let newest_anchor = self.selections.newest_anchor();
 5201
 5202        let snippet;
 5203        let new_text;
 5204        if completion.is_snippet() {
 5205            let mut snippet_source = completion.new_text.clone();
 5206            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5207                if scope.prefers_label_for_snippet_in_completion() {
 5208                    if let Some(label) = completion.label() {
 5209                        if matches!(
 5210                            completion.kind(),
 5211                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5212                        ) {
 5213                            snippet_source = label;
 5214                        }
 5215                    }
 5216                }
 5217            }
 5218            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5219            new_text = snippet.as_ref().unwrap().text.clone();
 5220        } else {
 5221            snippet = None;
 5222            new_text = completion.new_text.clone();
 5223        };
 5224
 5225        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5226        let buffer = buffer_handle.read(cx);
 5227        let replace_range_multibuffer = {
 5228            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5229            let multibuffer_anchor = snapshot
 5230                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5231                .unwrap()
 5232                ..snapshot
 5233                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5234                    .unwrap();
 5235            multibuffer_anchor.start.to_offset(&snapshot)
 5236                ..multibuffer_anchor.end.to_offset(&snapshot)
 5237        };
 5238        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5239            return None;
 5240        }
 5241
 5242        let old_text = buffer
 5243            .text_for_range(replace_range.clone())
 5244            .collect::<String>();
 5245        let lookbehind = newest_anchor
 5246            .start
 5247            .text_anchor
 5248            .to_offset(buffer)
 5249            .saturating_sub(replace_range.start);
 5250        let lookahead = replace_range
 5251            .end
 5252            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5253        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5254        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5255
 5256        let selections = self.selections.all::<usize>(cx);
 5257        let mut ranges = Vec::new();
 5258        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5259
 5260        for selection in &selections {
 5261            let range = if selection.id == newest_anchor.id {
 5262                replace_range_multibuffer.clone()
 5263            } else {
 5264                let mut range = selection.range();
 5265
 5266                // if prefix is present, don't duplicate it
 5267                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5268                    range.start = range.start.saturating_sub(lookbehind);
 5269
 5270                    // if suffix is also present, mimic the newest cursor and replace it
 5271                    if selection.id != newest_anchor.id
 5272                        && snapshot.contains_str_at(range.end, suffix)
 5273                    {
 5274                        range.end += lookahead;
 5275                    }
 5276                }
 5277                range
 5278            };
 5279
 5280            ranges.push(range.clone());
 5281
 5282            if !self.linked_edit_ranges.is_empty() {
 5283                let start_anchor = snapshot.anchor_before(range.start);
 5284                let end_anchor = snapshot.anchor_after(range.end);
 5285                if let Some(ranges) = self
 5286                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5287                {
 5288                    for (buffer, edits) in ranges {
 5289                        linked_edits
 5290                            .entry(buffer.clone())
 5291                            .or_default()
 5292                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5293                    }
 5294                }
 5295            }
 5296        }
 5297
 5298        cx.emit(EditorEvent::InputHandled {
 5299            utf16_range_to_replace: None,
 5300            text: new_text.clone().into(),
 5301        });
 5302
 5303        self.transact(window, cx, |this, window, cx| {
 5304            if let Some(mut snippet) = snippet {
 5305                snippet.text = new_text.to_string();
 5306                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5307            } else {
 5308                this.buffer.update(cx, |buffer, cx| {
 5309                    let auto_indent = match completion.insert_text_mode {
 5310                        Some(InsertTextMode::AS_IS) => None,
 5311                        _ => this.autoindent_mode.clone(),
 5312                    };
 5313                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5314                    buffer.edit(edits, auto_indent, cx);
 5315                });
 5316            }
 5317            for (buffer, edits) in linked_edits {
 5318                buffer.update(cx, |buffer, cx| {
 5319                    let snapshot = buffer.snapshot();
 5320                    let edits = edits
 5321                        .into_iter()
 5322                        .map(|(range, text)| {
 5323                            use text::ToPoint as TP;
 5324                            let end_point = TP::to_point(&range.end, &snapshot);
 5325                            let start_point = TP::to_point(&range.start, &snapshot);
 5326                            (start_point..end_point, text)
 5327                        })
 5328                        .sorted_by_key(|(range, _)| range.start);
 5329                    buffer.edit(edits, None, cx);
 5330                })
 5331            }
 5332
 5333            this.refresh_inline_completion(true, false, window, cx);
 5334        });
 5335
 5336        let show_new_completions_on_confirm = completion
 5337            .confirm
 5338            .as_ref()
 5339            .map_or(false, |confirm| confirm(intent, window, cx));
 5340        if show_new_completions_on_confirm {
 5341            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5342        }
 5343
 5344        let provider = self.completion_provider.as_ref()?;
 5345        drop(completion);
 5346        let apply_edits = provider.apply_additional_edits_for_completion(
 5347            buffer_handle,
 5348            completions_menu.completions.clone(),
 5349            candidate_id,
 5350            true,
 5351            cx,
 5352        );
 5353
 5354        let editor_settings = EditorSettings::get_global(cx);
 5355        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5356            // After the code completion is finished, users often want to know what signatures are needed.
 5357            // so we should automatically call signature_help
 5358            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5359        }
 5360
 5361        Some(cx.foreground_executor().spawn(async move {
 5362            apply_edits.await?;
 5363            Ok(())
 5364        }))
 5365    }
 5366
 5367    pub fn toggle_code_actions(
 5368        &mut self,
 5369        action: &ToggleCodeActions,
 5370        window: &mut Window,
 5371        cx: &mut Context<Self>,
 5372    ) {
 5373        let quick_launch = action.quick_launch;
 5374        let mut context_menu = self.context_menu.borrow_mut();
 5375        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5376            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5377                // Toggle if we're selecting the same one
 5378                *context_menu = None;
 5379                cx.notify();
 5380                return;
 5381            } else {
 5382                // Otherwise, clear it and start a new one
 5383                *context_menu = None;
 5384                cx.notify();
 5385            }
 5386        }
 5387        drop(context_menu);
 5388        let snapshot = self.snapshot(window, cx);
 5389        let deployed_from_indicator = action.deployed_from_indicator;
 5390        let mut task = self.code_actions_task.take();
 5391        let action = action.clone();
 5392        cx.spawn_in(window, async move |editor, cx| {
 5393            while let Some(prev_task) = task {
 5394                prev_task.await.log_err();
 5395                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5396            }
 5397
 5398            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5399                if editor.focus_handle.is_focused(window) {
 5400                    let multibuffer_point = action
 5401                        .deployed_from_indicator
 5402                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5403                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5404                    let (buffer, buffer_row) = snapshot
 5405                        .buffer_snapshot
 5406                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5407                        .and_then(|(buffer_snapshot, range)| {
 5408                            editor
 5409                                .buffer
 5410                                .read(cx)
 5411                                .buffer(buffer_snapshot.remote_id())
 5412                                .map(|buffer| (buffer, range.start.row))
 5413                        })?;
 5414                    let (_, code_actions) = editor
 5415                        .available_code_actions
 5416                        .clone()
 5417                        .and_then(|(location, code_actions)| {
 5418                            let snapshot = location.buffer.read(cx).snapshot();
 5419                            let point_range = location.range.to_point(&snapshot);
 5420                            let point_range = point_range.start.row..=point_range.end.row;
 5421                            if point_range.contains(&buffer_row) {
 5422                                Some((location, code_actions))
 5423                            } else {
 5424                                None
 5425                            }
 5426                        })
 5427                        .unzip();
 5428                    let buffer_id = buffer.read(cx).remote_id();
 5429                    let tasks = editor
 5430                        .tasks
 5431                        .get(&(buffer_id, buffer_row))
 5432                        .map(|t| Arc::new(t.to_owned()));
 5433                    if tasks.is_none() && code_actions.is_none() {
 5434                        return None;
 5435                    }
 5436
 5437                    editor.completion_tasks.clear();
 5438                    editor.discard_inline_completion(false, cx);
 5439                    let task_context =
 5440                        tasks
 5441                            .as_ref()
 5442                            .zip(editor.project.clone())
 5443                            .map(|(tasks, project)| {
 5444                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5445                            });
 5446
 5447                    Some(cx.spawn_in(window, async move |editor, cx| {
 5448                        let task_context = match task_context {
 5449                            Some(task_context) => task_context.await,
 5450                            None => None,
 5451                        };
 5452                        let resolved_tasks =
 5453                            tasks
 5454                                .zip(task_context.clone())
 5455                                .map(|(tasks, task_context)| ResolvedTasks {
 5456                                    templates: tasks.resolve(&task_context).collect(),
 5457                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5458                                        multibuffer_point.row,
 5459                                        tasks.column,
 5460                                    )),
 5461                                });
 5462                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5463                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5464                                maybe!({
 5465                                    let project = editor.project.as_ref()?;
 5466                                    let dap_store = project.read(cx).dap_store();
 5467                                    let mut scenarios = vec![];
 5468                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5469                                    let buffer = buffer.read(cx);
 5470                                    let language = buffer.language()?;
 5471                                    let file = buffer.file();
 5472                                    let debug_adapter =
 5473                                        language_settings(language.name().into(), file, cx)
 5474                                            .debuggers
 5475                                            .first()
 5476                                            .map(SharedString::from)
 5477                                            .or_else(|| {
 5478                                                language
 5479                                                    .config()
 5480                                                    .debuggers
 5481                                                    .first()
 5482                                                    .map(SharedString::from)
 5483                                            })?;
 5484
 5485                                    dap_store.update(cx, |dap_store, cx| {
 5486                                        for (_, task) in &resolved_tasks.templates {
 5487                                            if let Some(scenario) = dap_store
 5488                                                .debug_scenario_for_build_task(
 5489                                                    task.original_task().clone(),
 5490                                                    debug_adapter.clone().into(),
 5491                                                    task.display_label().to_owned().into(),
 5492                                                    cx,
 5493                                                )
 5494                                            {
 5495                                                scenarios.push(scenario);
 5496                                            }
 5497                                        }
 5498                                    });
 5499                                    Some(scenarios)
 5500                                })
 5501                                .unwrap_or_default()
 5502                            } else {
 5503                                vec![]
 5504                            }
 5505                        })?;
 5506                        let spawn_straight_away = quick_launch
 5507                            && resolved_tasks
 5508                                .as_ref()
 5509                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5510                            && code_actions
 5511                                .as_ref()
 5512                                .map_or(true, |actions| actions.is_empty())
 5513                            && debug_scenarios.is_empty();
 5514                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5515                            *editor.context_menu.borrow_mut() =
 5516                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5517                                    buffer,
 5518                                    actions: CodeActionContents::new(
 5519                                        resolved_tasks,
 5520                                        code_actions,
 5521                                        debug_scenarios,
 5522                                        task_context.unwrap_or_default(),
 5523                                    ),
 5524                                    selected_item: Default::default(),
 5525                                    scroll_handle: UniformListScrollHandle::default(),
 5526                                    deployed_from_indicator,
 5527                                }));
 5528                            if spawn_straight_away {
 5529                                if let Some(task) = editor.confirm_code_action(
 5530                                    &ConfirmCodeAction { item_ix: Some(0) },
 5531                                    window,
 5532                                    cx,
 5533                                ) {
 5534                                    cx.notify();
 5535                                    return task;
 5536                                }
 5537                            }
 5538                            cx.notify();
 5539                            Task::ready(Ok(()))
 5540                        }) {
 5541                            task.await
 5542                        } else {
 5543                            Ok(())
 5544                        }
 5545                    }))
 5546                } else {
 5547                    Some(Task::ready(Ok(())))
 5548                }
 5549            })?;
 5550            if let Some(task) = spawned_test_task {
 5551                task.await?;
 5552            }
 5553
 5554            Ok::<_, anyhow::Error>(())
 5555        })
 5556        .detach_and_log_err(cx);
 5557    }
 5558
 5559    pub fn confirm_code_action(
 5560        &mut self,
 5561        action: &ConfirmCodeAction,
 5562        window: &mut Window,
 5563        cx: &mut Context<Self>,
 5564    ) -> Option<Task<Result<()>>> {
 5565        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5566
 5567        let actions_menu =
 5568            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5569                menu
 5570            } else {
 5571                return None;
 5572            };
 5573
 5574        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5575        let action = actions_menu.actions.get(action_ix)?;
 5576        let title = action.label();
 5577        let buffer = actions_menu.buffer;
 5578        let workspace = self.workspace()?;
 5579
 5580        match action {
 5581            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5582                workspace.update(cx, |workspace, cx| {
 5583                    workspace.schedule_resolved_task(
 5584                        task_source_kind,
 5585                        resolved_task,
 5586                        false,
 5587                        window,
 5588                        cx,
 5589                    );
 5590
 5591                    Some(Task::ready(Ok(())))
 5592                })
 5593            }
 5594            CodeActionsItem::CodeAction {
 5595                excerpt_id,
 5596                action,
 5597                provider,
 5598            } => {
 5599                let apply_code_action =
 5600                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5601                let workspace = workspace.downgrade();
 5602                Some(cx.spawn_in(window, async move |editor, cx| {
 5603                    let project_transaction = apply_code_action.await?;
 5604                    Self::open_project_transaction(
 5605                        &editor,
 5606                        workspace,
 5607                        project_transaction,
 5608                        title,
 5609                        cx,
 5610                    )
 5611                    .await
 5612                }))
 5613            }
 5614            CodeActionsItem::DebugScenario(scenario) => {
 5615                let context = actions_menu.actions.context.clone();
 5616
 5617                workspace.update(cx, |workspace, cx| {
 5618                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5619                });
 5620                Some(Task::ready(Ok(())))
 5621            }
 5622        }
 5623    }
 5624
 5625    pub async fn open_project_transaction(
 5626        this: &WeakEntity<Editor>,
 5627        workspace: WeakEntity<Workspace>,
 5628        transaction: ProjectTransaction,
 5629        title: String,
 5630        cx: &mut AsyncWindowContext,
 5631    ) -> Result<()> {
 5632        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5633        cx.update(|_, cx| {
 5634            entries.sort_unstable_by_key(|(buffer, _)| {
 5635                buffer.read(cx).file().map(|f| f.path().clone())
 5636            });
 5637        })?;
 5638
 5639        // If the project transaction's edits are all contained within this editor, then
 5640        // avoid opening a new editor to display them.
 5641
 5642        if let Some((buffer, transaction)) = entries.first() {
 5643            if entries.len() == 1 {
 5644                let excerpt = this.update(cx, |editor, cx| {
 5645                    editor
 5646                        .buffer()
 5647                        .read(cx)
 5648                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5649                })?;
 5650                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5651                    if excerpted_buffer == *buffer {
 5652                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5653                            let excerpt_range = excerpt_range.to_offset(buffer);
 5654                            buffer
 5655                                .edited_ranges_for_transaction::<usize>(transaction)
 5656                                .all(|range| {
 5657                                    excerpt_range.start <= range.start
 5658                                        && excerpt_range.end >= range.end
 5659                                })
 5660                        })?;
 5661
 5662                        if all_edits_within_excerpt {
 5663                            return Ok(());
 5664                        }
 5665                    }
 5666                }
 5667            }
 5668        } else {
 5669            return Ok(());
 5670        }
 5671
 5672        let mut ranges_to_highlight = Vec::new();
 5673        let excerpt_buffer = cx.new(|cx| {
 5674            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5675            for (buffer_handle, transaction) in &entries {
 5676                let edited_ranges = buffer_handle
 5677                    .read(cx)
 5678                    .edited_ranges_for_transaction::<Point>(transaction)
 5679                    .collect::<Vec<_>>();
 5680                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5681                    PathKey::for_buffer(buffer_handle, cx),
 5682                    buffer_handle.clone(),
 5683                    edited_ranges,
 5684                    DEFAULT_MULTIBUFFER_CONTEXT,
 5685                    cx,
 5686                );
 5687
 5688                ranges_to_highlight.extend(ranges);
 5689            }
 5690            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5691            multibuffer
 5692        })?;
 5693
 5694        workspace.update_in(cx, |workspace, window, cx| {
 5695            let project = workspace.project().clone();
 5696            let editor =
 5697                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5698            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5699            editor.update(cx, |editor, cx| {
 5700                editor.highlight_background::<Self>(
 5701                    &ranges_to_highlight,
 5702                    |theme| theme.editor_highlighted_line_background,
 5703                    cx,
 5704                );
 5705            });
 5706        })?;
 5707
 5708        Ok(())
 5709    }
 5710
 5711    pub fn clear_code_action_providers(&mut self) {
 5712        self.code_action_providers.clear();
 5713        self.available_code_actions.take();
 5714    }
 5715
 5716    pub fn add_code_action_provider(
 5717        &mut self,
 5718        provider: Rc<dyn CodeActionProvider>,
 5719        window: &mut Window,
 5720        cx: &mut Context<Self>,
 5721    ) {
 5722        if self
 5723            .code_action_providers
 5724            .iter()
 5725            .any(|existing_provider| existing_provider.id() == provider.id())
 5726        {
 5727            return;
 5728        }
 5729
 5730        self.code_action_providers.push(provider);
 5731        self.refresh_code_actions(window, cx);
 5732    }
 5733
 5734    pub fn remove_code_action_provider(
 5735        &mut self,
 5736        id: Arc<str>,
 5737        window: &mut Window,
 5738        cx: &mut Context<Self>,
 5739    ) {
 5740        self.code_action_providers
 5741            .retain(|provider| provider.id() != id);
 5742        self.refresh_code_actions(window, cx);
 5743    }
 5744
 5745    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5746        let newest_selection = self.selections.newest_anchor().clone();
 5747        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5748        let buffer = self.buffer.read(cx);
 5749        if newest_selection.head().diff_base_anchor.is_some() {
 5750            return None;
 5751        }
 5752        let (start_buffer, start) =
 5753            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5754        let (end_buffer, end) =
 5755            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5756        if start_buffer != end_buffer {
 5757            return None;
 5758        }
 5759
 5760        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5761            cx.background_executor()
 5762                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5763                .await;
 5764
 5765            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5766                let providers = this.code_action_providers.clone();
 5767                let tasks = this
 5768                    .code_action_providers
 5769                    .iter()
 5770                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5771                    .collect::<Vec<_>>();
 5772                (providers, tasks)
 5773            })?;
 5774
 5775            let mut actions = Vec::new();
 5776            for (provider, provider_actions) in
 5777                providers.into_iter().zip(future::join_all(tasks).await)
 5778            {
 5779                if let Some(provider_actions) = provider_actions.log_err() {
 5780                    actions.extend(provider_actions.into_iter().map(|action| {
 5781                        AvailableCodeAction {
 5782                            excerpt_id: newest_selection.start.excerpt_id,
 5783                            action,
 5784                            provider: provider.clone(),
 5785                        }
 5786                    }));
 5787                }
 5788            }
 5789
 5790            this.update(cx, |this, cx| {
 5791                this.available_code_actions = if actions.is_empty() {
 5792                    None
 5793                } else {
 5794                    Some((
 5795                        Location {
 5796                            buffer: start_buffer,
 5797                            range: start..end,
 5798                        },
 5799                        actions.into(),
 5800                    ))
 5801                };
 5802                cx.notify();
 5803            })
 5804        }));
 5805        None
 5806    }
 5807
 5808    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5809        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5810            self.show_git_blame_inline = false;
 5811
 5812            self.show_git_blame_inline_delay_task =
 5813                Some(cx.spawn_in(window, async move |this, cx| {
 5814                    cx.background_executor().timer(delay).await;
 5815
 5816                    this.update(cx, |this, cx| {
 5817                        this.show_git_blame_inline = true;
 5818                        cx.notify();
 5819                    })
 5820                    .log_err();
 5821                }));
 5822        }
 5823    }
 5824
 5825    fn show_blame_popover(
 5826        &mut self,
 5827        blame_entry: &BlameEntry,
 5828        position: gpui::Point<Pixels>,
 5829        cx: &mut Context<Self>,
 5830    ) {
 5831        if let Some(state) = &mut self.inline_blame_popover {
 5832            state.hide_task.take();
 5833            cx.notify();
 5834        } else {
 5835            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5836            let show_task = cx.spawn(async move |editor, cx| {
 5837                cx.background_executor()
 5838                    .timer(std::time::Duration::from_millis(delay))
 5839                    .await;
 5840                editor
 5841                    .update(cx, |editor, cx| {
 5842                        if let Some(state) = &mut editor.inline_blame_popover {
 5843                            state.show_task = None;
 5844                            cx.notify();
 5845                        }
 5846                    })
 5847                    .ok();
 5848            });
 5849            let Some(blame) = self.blame.as_ref() else {
 5850                return;
 5851            };
 5852            let blame = blame.read(cx);
 5853            let details = blame.details_for_entry(&blame_entry);
 5854            let markdown = cx.new(|cx| {
 5855                Markdown::new(
 5856                    details
 5857                        .as_ref()
 5858                        .map(|message| message.message.clone())
 5859                        .unwrap_or_default(),
 5860                    None,
 5861                    None,
 5862                    cx,
 5863                )
 5864            });
 5865            self.inline_blame_popover = Some(InlineBlamePopover {
 5866                position,
 5867                show_task: Some(show_task),
 5868                hide_task: None,
 5869                popover_bounds: None,
 5870                popover_state: InlineBlamePopoverState {
 5871                    scroll_handle: ScrollHandle::new(),
 5872                    commit_message: details,
 5873                    markdown,
 5874                },
 5875            });
 5876        }
 5877    }
 5878
 5879    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5880        if let Some(state) = &mut self.inline_blame_popover {
 5881            if state.show_task.is_some() {
 5882                self.inline_blame_popover.take();
 5883                cx.notify();
 5884            } else {
 5885                let hide_task = cx.spawn(async move |editor, cx| {
 5886                    cx.background_executor()
 5887                        .timer(std::time::Duration::from_millis(100))
 5888                        .await;
 5889                    editor
 5890                        .update(cx, |editor, cx| {
 5891                            editor.inline_blame_popover.take();
 5892                            cx.notify();
 5893                        })
 5894                        .ok();
 5895                });
 5896                state.hide_task = Some(hide_task);
 5897            }
 5898        }
 5899    }
 5900
 5901    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5902        if self.pending_rename.is_some() {
 5903            return None;
 5904        }
 5905
 5906        let provider = self.semantics_provider.clone()?;
 5907        let buffer = self.buffer.read(cx);
 5908        let newest_selection = self.selections.newest_anchor().clone();
 5909        let cursor_position = newest_selection.head();
 5910        let (cursor_buffer, cursor_buffer_position) =
 5911            buffer.text_anchor_for_position(cursor_position, cx)?;
 5912        let (tail_buffer, tail_buffer_position) =
 5913            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5914        if cursor_buffer != tail_buffer {
 5915            return None;
 5916        }
 5917
 5918        let snapshot = cursor_buffer.read(cx).snapshot();
 5919        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5920        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5921        if start_word_range != end_word_range {
 5922            self.document_highlights_task.take();
 5923            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5924            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5925            return None;
 5926        }
 5927
 5928        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5929        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5930            cx.background_executor()
 5931                .timer(Duration::from_millis(debounce))
 5932                .await;
 5933
 5934            let highlights = if let Some(highlights) = cx
 5935                .update(|cx| {
 5936                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5937                })
 5938                .ok()
 5939                .flatten()
 5940            {
 5941                highlights.await.log_err()
 5942            } else {
 5943                None
 5944            };
 5945
 5946            if let Some(highlights) = highlights {
 5947                this.update(cx, |this, cx| {
 5948                    if this.pending_rename.is_some() {
 5949                        return;
 5950                    }
 5951
 5952                    let buffer_id = cursor_position.buffer_id;
 5953                    let buffer = this.buffer.read(cx);
 5954                    if !buffer
 5955                        .text_anchor_for_position(cursor_position, cx)
 5956                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5957                    {
 5958                        return;
 5959                    }
 5960
 5961                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5962                    let mut write_ranges = Vec::new();
 5963                    let mut read_ranges = Vec::new();
 5964                    for highlight in highlights {
 5965                        for (excerpt_id, excerpt_range) in
 5966                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5967                        {
 5968                            let start = highlight
 5969                                .range
 5970                                .start
 5971                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5972                            let end = highlight
 5973                                .range
 5974                                .end
 5975                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5976                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5977                                continue;
 5978                            }
 5979
 5980                            let range = Anchor {
 5981                                buffer_id,
 5982                                excerpt_id,
 5983                                text_anchor: start,
 5984                                diff_base_anchor: None,
 5985                            }..Anchor {
 5986                                buffer_id,
 5987                                excerpt_id,
 5988                                text_anchor: end,
 5989                                diff_base_anchor: None,
 5990                            };
 5991                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5992                                write_ranges.push(range);
 5993                            } else {
 5994                                read_ranges.push(range);
 5995                            }
 5996                        }
 5997                    }
 5998
 5999                    this.highlight_background::<DocumentHighlightRead>(
 6000                        &read_ranges,
 6001                        |theme| theme.editor_document_highlight_read_background,
 6002                        cx,
 6003                    );
 6004                    this.highlight_background::<DocumentHighlightWrite>(
 6005                        &write_ranges,
 6006                        |theme| theme.editor_document_highlight_write_background,
 6007                        cx,
 6008                    );
 6009                    cx.notify();
 6010                })
 6011                .log_err();
 6012            }
 6013        }));
 6014        None
 6015    }
 6016
 6017    fn prepare_highlight_query_from_selection(
 6018        &mut self,
 6019        cx: &mut Context<Editor>,
 6020    ) -> Option<(String, Range<Anchor>)> {
 6021        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6022            return None;
 6023        }
 6024        if !EditorSettings::get_global(cx).selection_highlight {
 6025            return None;
 6026        }
 6027        if self.selections.count() != 1 || self.selections.line_mode {
 6028            return None;
 6029        }
 6030        let selection = self.selections.newest::<Point>(cx);
 6031        if selection.is_empty() || selection.start.row != selection.end.row {
 6032            return None;
 6033        }
 6034        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6035        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6036        let query = multi_buffer_snapshot
 6037            .text_for_range(selection_anchor_range.clone())
 6038            .collect::<String>();
 6039        if query.trim().is_empty() {
 6040            return None;
 6041        }
 6042        Some((query, selection_anchor_range))
 6043    }
 6044
 6045    fn update_selection_occurrence_highlights(
 6046        &mut self,
 6047        query_text: String,
 6048        query_range: Range<Anchor>,
 6049        multi_buffer_range_to_query: Range<Point>,
 6050        use_debounce: bool,
 6051        window: &mut Window,
 6052        cx: &mut Context<Editor>,
 6053    ) -> Task<()> {
 6054        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6055        cx.spawn_in(window, async move |editor, cx| {
 6056            if use_debounce {
 6057                cx.background_executor()
 6058                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6059                    .await;
 6060            }
 6061            let match_task = cx.background_spawn(async move {
 6062                let buffer_ranges = multi_buffer_snapshot
 6063                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6064                    .into_iter()
 6065                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6066                let mut match_ranges = Vec::new();
 6067                let Ok(regex) = project::search::SearchQuery::text(
 6068                    query_text.clone(),
 6069                    false,
 6070                    false,
 6071                    false,
 6072                    Default::default(),
 6073                    Default::default(),
 6074                    false,
 6075                    None,
 6076                ) else {
 6077                    return Vec::default();
 6078                };
 6079                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6080                    match_ranges.extend(
 6081                        regex
 6082                            .search(&buffer_snapshot, Some(search_range.clone()))
 6083                            .await
 6084                            .into_iter()
 6085                            .filter_map(|match_range| {
 6086                                let match_start = buffer_snapshot
 6087                                    .anchor_after(search_range.start + match_range.start);
 6088                                let match_end = buffer_snapshot
 6089                                    .anchor_before(search_range.start + match_range.end);
 6090                                let match_anchor_range = Anchor::range_in_buffer(
 6091                                    excerpt_id,
 6092                                    buffer_snapshot.remote_id(),
 6093                                    match_start..match_end,
 6094                                );
 6095                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6096                            }),
 6097                    );
 6098                }
 6099                match_ranges
 6100            });
 6101            let match_ranges = match_task.await;
 6102            editor
 6103                .update_in(cx, |editor, _, cx| {
 6104                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6105                    if !match_ranges.is_empty() {
 6106                        editor.highlight_background::<SelectedTextHighlight>(
 6107                            &match_ranges,
 6108                            |theme| theme.editor_document_highlight_bracket_background,
 6109                            cx,
 6110                        )
 6111                    }
 6112                })
 6113                .log_err();
 6114        })
 6115    }
 6116
 6117    fn refresh_selected_text_highlights(
 6118        &mut self,
 6119        on_buffer_edit: bool,
 6120        window: &mut Window,
 6121        cx: &mut Context<Editor>,
 6122    ) {
 6123        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6124        else {
 6125            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6126            self.quick_selection_highlight_task.take();
 6127            self.debounced_selection_highlight_task.take();
 6128            return;
 6129        };
 6130        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6131        if on_buffer_edit
 6132            || self
 6133                .quick_selection_highlight_task
 6134                .as_ref()
 6135                .map_or(true, |(prev_anchor_range, _)| {
 6136                    prev_anchor_range != &query_range
 6137                })
 6138        {
 6139            let multi_buffer_visible_start = self
 6140                .scroll_manager
 6141                .anchor()
 6142                .anchor
 6143                .to_point(&multi_buffer_snapshot);
 6144            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6145                multi_buffer_visible_start
 6146                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6147                Bias::Left,
 6148            );
 6149            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6150            self.quick_selection_highlight_task = Some((
 6151                query_range.clone(),
 6152                self.update_selection_occurrence_highlights(
 6153                    query_text.clone(),
 6154                    query_range.clone(),
 6155                    multi_buffer_visible_range,
 6156                    false,
 6157                    window,
 6158                    cx,
 6159                ),
 6160            ));
 6161        }
 6162        if on_buffer_edit
 6163            || self
 6164                .debounced_selection_highlight_task
 6165                .as_ref()
 6166                .map_or(true, |(prev_anchor_range, _)| {
 6167                    prev_anchor_range != &query_range
 6168                })
 6169        {
 6170            let multi_buffer_start = multi_buffer_snapshot
 6171                .anchor_before(0)
 6172                .to_point(&multi_buffer_snapshot);
 6173            let multi_buffer_end = multi_buffer_snapshot
 6174                .anchor_after(multi_buffer_snapshot.len())
 6175                .to_point(&multi_buffer_snapshot);
 6176            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6177            self.debounced_selection_highlight_task = Some((
 6178                query_range.clone(),
 6179                self.update_selection_occurrence_highlights(
 6180                    query_text,
 6181                    query_range,
 6182                    multi_buffer_full_range,
 6183                    true,
 6184                    window,
 6185                    cx,
 6186                ),
 6187            ));
 6188        }
 6189    }
 6190
 6191    pub fn refresh_inline_completion(
 6192        &mut self,
 6193        debounce: bool,
 6194        user_requested: bool,
 6195        window: &mut Window,
 6196        cx: &mut Context<Self>,
 6197    ) -> Option<()> {
 6198        let provider = self.edit_prediction_provider()?;
 6199        let cursor = self.selections.newest_anchor().head();
 6200        let (buffer, cursor_buffer_position) =
 6201            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6202
 6203        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6204            self.discard_inline_completion(false, cx);
 6205            return None;
 6206        }
 6207
 6208        if !user_requested
 6209            && (!self.should_show_edit_predictions()
 6210                || !self.is_focused(window)
 6211                || buffer.read(cx).is_empty())
 6212        {
 6213            self.discard_inline_completion(false, cx);
 6214            return None;
 6215        }
 6216
 6217        self.update_visible_inline_completion(window, cx);
 6218        provider.refresh(
 6219            self.project.clone(),
 6220            buffer,
 6221            cursor_buffer_position,
 6222            debounce,
 6223            cx,
 6224        );
 6225        Some(())
 6226    }
 6227
 6228    fn show_edit_predictions_in_menu(&self) -> bool {
 6229        match self.edit_prediction_settings {
 6230            EditPredictionSettings::Disabled => false,
 6231            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6232        }
 6233    }
 6234
 6235    pub fn edit_predictions_enabled(&self) -> bool {
 6236        match self.edit_prediction_settings {
 6237            EditPredictionSettings::Disabled => false,
 6238            EditPredictionSettings::Enabled { .. } => true,
 6239        }
 6240    }
 6241
 6242    fn edit_prediction_requires_modifier(&self) -> bool {
 6243        match self.edit_prediction_settings {
 6244            EditPredictionSettings::Disabled => false,
 6245            EditPredictionSettings::Enabled {
 6246                preview_requires_modifier,
 6247                ..
 6248            } => preview_requires_modifier,
 6249        }
 6250    }
 6251
 6252    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6253        if self.edit_prediction_provider.is_none() {
 6254            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6255        } else {
 6256            let selection = self.selections.newest_anchor();
 6257            let cursor = selection.head();
 6258
 6259            if let Some((buffer, cursor_buffer_position)) =
 6260                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6261            {
 6262                self.edit_prediction_settings =
 6263                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6264            }
 6265        }
 6266    }
 6267
 6268    fn edit_prediction_settings_at_position(
 6269        &self,
 6270        buffer: &Entity<Buffer>,
 6271        buffer_position: language::Anchor,
 6272        cx: &App,
 6273    ) -> EditPredictionSettings {
 6274        if !self.mode.is_full()
 6275            || !self.show_inline_completions_override.unwrap_or(true)
 6276            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6277        {
 6278            return EditPredictionSettings::Disabled;
 6279        }
 6280
 6281        let buffer = buffer.read(cx);
 6282
 6283        let file = buffer.file();
 6284
 6285        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6286            return EditPredictionSettings::Disabled;
 6287        };
 6288
 6289        let by_provider = matches!(
 6290            self.menu_inline_completions_policy,
 6291            MenuInlineCompletionsPolicy::ByProvider
 6292        );
 6293
 6294        let show_in_menu = by_provider
 6295            && self
 6296                .edit_prediction_provider
 6297                .as_ref()
 6298                .map_or(false, |provider| {
 6299                    provider.provider.show_completions_in_menu()
 6300                });
 6301
 6302        let preview_requires_modifier =
 6303            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6304
 6305        EditPredictionSettings::Enabled {
 6306            show_in_menu,
 6307            preview_requires_modifier,
 6308        }
 6309    }
 6310
 6311    fn should_show_edit_predictions(&self) -> bool {
 6312        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6313    }
 6314
 6315    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6316        matches!(
 6317            self.edit_prediction_preview,
 6318            EditPredictionPreview::Active { .. }
 6319        )
 6320    }
 6321
 6322    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6323        let cursor = self.selections.newest_anchor().head();
 6324        if let Some((buffer, cursor_position)) =
 6325            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6326        {
 6327            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6328        } else {
 6329            false
 6330        }
 6331    }
 6332
 6333    pub fn supports_minimap(&self, cx: &App) -> bool {
 6334        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6335    }
 6336
 6337    fn edit_predictions_enabled_in_buffer(
 6338        &self,
 6339        buffer: &Entity<Buffer>,
 6340        buffer_position: language::Anchor,
 6341        cx: &App,
 6342    ) -> bool {
 6343        maybe!({
 6344            if self.read_only(cx) {
 6345                return Some(false);
 6346            }
 6347            let provider = self.edit_prediction_provider()?;
 6348            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6349                return Some(false);
 6350            }
 6351            let buffer = buffer.read(cx);
 6352            let Some(file) = buffer.file() else {
 6353                return Some(true);
 6354            };
 6355            let settings = all_language_settings(Some(file), cx);
 6356            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6357        })
 6358        .unwrap_or(false)
 6359    }
 6360
 6361    fn cycle_inline_completion(
 6362        &mut self,
 6363        direction: Direction,
 6364        window: &mut Window,
 6365        cx: &mut Context<Self>,
 6366    ) -> Option<()> {
 6367        let provider = self.edit_prediction_provider()?;
 6368        let cursor = self.selections.newest_anchor().head();
 6369        let (buffer, cursor_buffer_position) =
 6370            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6371        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6372            return None;
 6373        }
 6374
 6375        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6376        self.update_visible_inline_completion(window, cx);
 6377
 6378        Some(())
 6379    }
 6380
 6381    pub fn show_inline_completion(
 6382        &mut self,
 6383        _: &ShowEditPrediction,
 6384        window: &mut Window,
 6385        cx: &mut Context<Self>,
 6386    ) {
 6387        if !self.has_active_inline_completion() {
 6388            self.refresh_inline_completion(false, true, window, cx);
 6389            return;
 6390        }
 6391
 6392        self.update_visible_inline_completion(window, cx);
 6393    }
 6394
 6395    pub fn display_cursor_names(
 6396        &mut self,
 6397        _: &DisplayCursorNames,
 6398        window: &mut Window,
 6399        cx: &mut Context<Self>,
 6400    ) {
 6401        self.show_cursor_names(window, cx);
 6402    }
 6403
 6404    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6405        self.show_cursor_names = true;
 6406        cx.notify();
 6407        cx.spawn_in(window, async move |this, cx| {
 6408            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6409            this.update(cx, |this, cx| {
 6410                this.show_cursor_names = false;
 6411                cx.notify()
 6412            })
 6413            .ok()
 6414        })
 6415        .detach();
 6416    }
 6417
 6418    pub fn next_edit_prediction(
 6419        &mut self,
 6420        _: &NextEditPrediction,
 6421        window: &mut Window,
 6422        cx: &mut Context<Self>,
 6423    ) {
 6424        if self.has_active_inline_completion() {
 6425            self.cycle_inline_completion(Direction::Next, window, cx);
 6426        } else {
 6427            let is_copilot_disabled = self
 6428                .refresh_inline_completion(false, true, window, cx)
 6429                .is_none();
 6430            if is_copilot_disabled {
 6431                cx.propagate();
 6432            }
 6433        }
 6434    }
 6435
 6436    pub fn previous_edit_prediction(
 6437        &mut self,
 6438        _: &PreviousEditPrediction,
 6439        window: &mut Window,
 6440        cx: &mut Context<Self>,
 6441    ) {
 6442        if self.has_active_inline_completion() {
 6443            self.cycle_inline_completion(Direction::Prev, window, cx);
 6444        } else {
 6445            let is_copilot_disabled = self
 6446                .refresh_inline_completion(false, true, window, cx)
 6447                .is_none();
 6448            if is_copilot_disabled {
 6449                cx.propagate();
 6450            }
 6451        }
 6452    }
 6453
 6454    pub fn accept_edit_prediction(
 6455        &mut self,
 6456        _: &AcceptEditPrediction,
 6457        window: &mut Window,
 6458        cx: &mut Context<Self>,
 6459    ) {
 6460        if self.show_edit_predictions_in_menu() {
 6461            self.hide_context_menu(window, cx);
 6462        }
 6463
 6464        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6465            return;
 6466        };
 6467
 6468        self.report_inline_completion_event(
 6469            active_inline_completion.completion_id.clone(),
 6470            true,
 6471            cx,
 6472        );
 6473
 6474        match &active_inline_completion.completion {
 6475            InlineCompletion::Move { target, .. } => {
 6476                let target = *target;
 6477
 6478                if let Some(position_map) = &self.last_position_map {
 6479                    if position_map
 6480                        .visible_row_range
 6481                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6482                        || !self.edit_prediction_requires_modifier()
 6483                    {
 6484                        self.unfold_ranges(&[target..target], true, false, cx);
 6485                        // Note that this is also done in vim's handler of the Tab action.
 6486                        self.change_selections(
 6487                            Some(Autoscroll::newest()),
 6488                            window,
 6489                            cx,
 6490                            |selections| {
 6491                                selections.select_anchor_ranges([target..target]);
 6492                            },
 6493                        );
 6494                        self.clear_row_highlights::<EditPredictionPreview>();
 6495
 6496                        self.edit_prediction_preview
 6497                            .set_previous_scroll_position(None);
 6498                    } else {
 6499                        self.edit_prediction_preview
 6500                            .set_previous_scroll_position(Some(
 6501                                position_map.snapshot.scroll_anchor,
 6502                            ));
 6503
 6504                        self.highlight_rows::<EditPredictionPreview>(
 6505                            target..target,
 6506                            cx.theme().colors().editor_highlighted_line_background,
 6507                            RowHighlightOptions {
 6508                                autoscroll: true,
 6509                                ..Default::default()
 6510                            },
 6511                            cx,
 6512                        );
 6513                        self.request_autoscroll(Autoscroll::fit(), cx);
 6514                    }
 6515                }
 6516            }
 6517            InlineCompletion::Edit { edits, .. } => {
 6518                if let Some(provider) = self.edit_prediction_provider() {
 6519                    provider.accept(cx);
 6520                }
 6521
 6522                let snapshot = self.buffer.read(cx).snapshot(cx);
 6523                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6524
 6525                self.buffer.update(cx, |buffer, cx| {
 6526                    buffer.edit(edits.iter().cloned(), None, cx)
 6527                });
 6528
 6529                self.change_selections(None, window, cx, |s| {
 6530                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 6531                });
 6532
 6533                self.update_visible_inline_completion(window, cx);
 6534                if self.active_inline_completion.is_none() {
 6535                    self.refresh_inline_completion(true, true, window, cx);
 6536                }
 6537
 6538                cx.notify();
 6539            }
 6540        }
 6541
 6542        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6543    }
 6544
 6545    pub fn accept_partial_inline_completion(
 6546        &mut self,
 6547        _: &AcceptPartialEditPrediction,
 6548        window: &mut Window,
 6549        cx: &mut Context<Self>,
 6550    ) {
 6551        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6552            return;
 6553        };
 6554        if self.selections.count() != 1 {
 6555            return;
 6556        }
 6557
 6558        self.report_inline_completion_event(
 6559            active_inline_completion.completion_id.clone(),
 6560            true,
 6561            cx,
 6562        );
 6563
 6564        match &active_inline_completion.completion {
 6565            InlineCompletion::Move { target, .. } => {
 6566                let target = *target;
 6567                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6568                    selections.select_anchor_ranges([target..target]);
 6569                });
 6570            }
 6571            InlineCompletion::Edit { edits, .. } => {
 6572                // Find an insertion that starts at the cursor position.
 6573                let snapshot = self.buffer.read(cx).snapshot(cx);
 6574                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6575                let insertion = edits.iter().find_map(|(range, text)| {
 6576                    let range = range.to_offset(&snapshot);
 6577                    if range.is_empty() && range.start == cursor_offset {
 6578                        Some(text)
 6579                    } else {
 6580                        None
 6581                    }
 6582                });
 6583
 6584                if let Some(text) = insertion {
 6585                    let mut partial_completion = text
 6586                        .chars()
 6587                        .by_ref()
 6588                        .take_while(|c| c.is_alphabetic())
 6589                        .collect::<String>();
 6590                    if partial_completion.is_empty() {
 6591                        partial_completion = text
 6592                            .chars()
 6593                            .by_ref()
 6594                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6595                            .collect::<String>();
 6596                    }
 6597
 6598                    cx.emit(EditorEvent::InputHandled {
 6599                        utf16_range_to_replace: None,
 6600                        text: partial_completion.clone().into(),
 6601                    });
 6602
 6603                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6604
 6605                    self.refresh_inline_completion(true, true, window, cx);
 6606                    cx.notify();
 6607                } else {
 6608                    self.accept_edit_prediction(&Default::default(), window, cx);
 6609                }
 6610            }
 6611        }
 6612    }
 6613
 6614    fn discard_inline_completion(
 6615        &mut self,
 6616        should_report_inline_completion_event: bool,
 6617        cx: &mut Context<Self>,
 6618    ) -> bool {
 6619        if should_report_inline_completion_event {
 6620            let completion_id = self
 6621                .active_inline_completion
 6622                .as_ref()
 6623                .and_then(|active_completion| active_completion.completion_id.clone());
 6624
 6625            self.report_inline_completion_event(completion_id, false, cx);
 6626        }
 6627
 6628        if let Some(provider) = self.edit_prediction_provider() {
 6629            provider.discard(cx);
 6630        }
 6631
 6632        self.take_active_inline_completion(cx)
 6633    }
 6634
 6635    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6636        let Some(provider) = self.edit_prediction_provider() else {
 6637            return;
 6638        };
 6639
 6640        let Some((_, buffer, _)) = self
 6641            .buffer
 6642            .read(cx)
 6643            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6644        else {
 6645            return;
 6646        };
 6647
 6648        let extension = buffer
 6649            .read(cx)
 6650            .file()
 6651            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6652
 6653        let event_type = match accepted {
 6654            true => "Edit Prediction Accepted",
 6655            false => "Edit Prediction Discarded",
 6656        };
 6657        telemetry::event!(
 6658            event_type,
 6659            provider = provider.name(),
 6660            prediction_id = id,
 6661            suggestion_accepted = accepted,
 6662            file_extension = extension,
 6663        );
 6664    }
 6665
 6666    pub fn has_active_inline_completion(&self) -> bool {
 6667        self.active_inline_completion.is_some()
 6668    }
 6669
 6670    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6671        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6672            return false;
 6673        };
 6674
 6675        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6676        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6677        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6678        true
 6679    }
 6680
 6681    /// Returns true when we're displaying the edit prediction popover below the cursor
 6682    /// like we are not previewing and the LSP autocomplete menu is visible
 6683    /// or we are in `when_holding_modifier` mode.
 6684    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6685        if self.edit_prediction_preview_is_active()
 6686            || !self.show_edit_predictions_in_menu()
 6687            || !self.edit_predictions_enabled()
 6688        {
 6689            return false;
 6690        }
 6691
 6692        if self.has_visible_completions_menu() {
 6693            return true;
 6694        }
 6695
 6696        has_completion && self.edit_prediction_requires_modifier()
 6697    }
 6698
 6699    fn handle_modifiers_changed(
 6700        &mut self,
 6701        modifiers: Modifiers,
 6702        position_map: &PositionMap,
 6703        window: &mut Window,
 6704        cx: &mut Context<Self>,
 6705    ) {
 6706        if self.show_edit_predictions_in_menu() {
 6707            self.update_edit_prediction_preview(&modifiers, window, cx);
 6708        }
 6709
 6710        self.update_selection_mode(&modifiers, position_map, window, cx);
 6711
 6712        let mouse_position = window.mouse_position();
 6713        if !position_map.text_hitbox.is_hovered(window) {
 6714            return;
 6715        }
 6716
 6717        self.update_hovered_link(
 6718            position_map.point_for_position(mouse_position),
 6719            &position_map.snapshot,
 6720            modifiers,
 6721            window,
 6722            cx,
 6723        )
 6724    }
 6725
 6726    fn update_selection_mode(
 6727        &mut self,
 6728        modifiers: &Modifiers,
 6729        position_map: &PositionMap,
 6730        window: &mut Window,
 6731        cx: &mut Context<Self>,
 6732    ) {
 6733        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6734            return;
 6735        }
 6736
 6737        let mouse_position = window.mouse_position();
 6738        let point_for_position = position_map.point_for_position(mouse_position);
 6739        let position = point_for_position.previous_valid;
 6740
 6741        self.select(
 6742            SelectPhase::BeginColumnar {
 6743                position,
 6744                reset: false,
 6745                goal_column: point_for_position.exact_unclipped.column(),
 6746            },
 6747            window,
 6748            cx,
 6749        );
 6750    }
 6751
 6752    fn update_edit_prediction_preview(
 6753        &mut self,
 6754        modifiers: &Modifiers,
 6755        window: &mut Window,
 6756        cx: &mut Context<Self>,
 6757    ) {
 6758        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6759        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6760            return;
 6761        };
 6762
 6763        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6764            if matches!(
 6765                self.edit_prediction_preview,
 6766                EditPredictionPreview::Inactive { .. }
 6767            ) {
 6768                self.edit_prediction_preview = EditPredictionPreview::Active {
 6769                    previous_scroll_position: None,
 6770                    since: Instant::now(),
 6771                };
 6772
 6773                self.update_visible_inline_completion(window, cx);
 6774                cx.notify();
 6775            }
 6776        } else if let EditPredictionPreview::Active {
 6777            previous_scroll_position,
 6778            since,
 6779        } = self.edit_prediction_preview
 6780        {
 6781            if let (Some(previous_scroll_position), Some(position_map)) =
 6782                (previous_scroll_position, self.last_position_map.as_ref())
 6783            {
 6784                self.set_scroll_position(
 6785                    previous_scroll_position
 6786                        .scroll_position(&position_map.snapshot.display_snapshot),
 6787                    window,
 6788                    cx,
 6789                );
 6790            }
 6791
 6792            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6793                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6794            };
 6795            self.clear_row_highlights::<EditPredictionPreview>();
 6796            self.update_visible_inline_completion(window, cx);
 6797            cx.notify();
 6798        }
 6799    }
 6800
 6801    fn update_visible_inline_completion(
 6802        &mut self,
 6803        _window: &mut Window,
 6804        cx: &mut Context<Self>,
 6805    ) -> Option<()> {
 6806        let selection = self.selections.newest_anchor();
 6807        let cursor = selection.head();
 6808        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6809        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6810        let excerpt_id = cursor.excerpt_id;
 6811
 6812        let show_in_menu = self.show_edit_predictions_in_menu();
 6813        let completions_menu_has_precedence = !show_in_menu
 6814            && (self.context_menu.borrow().is_some()
 6815                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6816
 6817        if completions_menu_has_precedence
 6818            || !offset_selection.is_empty()
 6819            || self
 6820                .active_inline_completion
 6821                .as_ref()
 6822                .map_or(false, |completion| {
 6823                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6824                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6825                    !invalidation_range.contains(&offset_selection.head())
 6826                })
 6827        {
 6828            self.discard_inline_completion(false, cx);
 6829            return None;
 6830        }
 6831
 6832        self.take_active_inline_completion(cx);
 6833        let Some(provider) = self.edit_prediction_provider() else {
 6834            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6835            return None;
 6836        };
 6837
 6838        let (buffer, cursor_buffer_position) =
 6839            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6840
 6841        self.edit_prediction_settings =
 6842            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6843
 6844        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6845
 6846        if self.edit_prediction_indent_conflict {
 6847            let cursor_point = cursor.to_point(&multibuffer);
 6848
 6849            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6850
 6851            if let Some((_, indent)) = indents.iter().next() {
 6852                if indent.len == cursor_point.column {
 6853                    self.edit_prediction_indent_conflict = false;
 6854                }
 6855            }
 6856        }
 6857
 6858        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6859        let edits = inline_completion
 6860            .edits
 6861            .into_iter()
 6862            .flat_map(|(range, new_text)| {
 6863                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6864                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6865                Some((start..end, new_text))
 6866            })
 6867            .collect::<Vec<_>>();
 6868        if edits.is_empty() {
 6869            return None;
 6870        }
 6871
 6872        let first_edit_start = edits.first().unwrap().0.start;
 6873        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6874        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6875
 6876        let last_edit_end = edits.last().unwrap().0.end;
 6877        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6878        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6879
 6880        let cursor_row = cursor.to_point(&multibuffer).row;
 6881
 6882        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6883
 6884        let mut inlay_ids = Vec::new();
 6885        let invalidation_row_range;
 6886        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6887            Some(cursor_row..edit_end_row)
 6888        } else if cursor_row > edit_end_row {
 6889            Some(edit_start_row..cursor_row)
 6890        } else {
 6891            None
 6892        };
 6893        let is_move =
 6894            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6895        let completion = if is_move {
 6896            invalidation_row_range =
 6897                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6898            let target = first_edit_start;
 6899            InlineCompletion::Move { target, snapshot }
 6900        } else {
 6901            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6902                && !self.inline_completions_hidden_for_vim_mode;
 6903
 6904            if show_completions_in_buffer {
 6905                if edits
 6906                    .iter()
 6907                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6908                {
 6909                    let mut inlays = Vec::new();
 6910                    for (range, new_text) in &edits {
 6911                        let inlay = Inlay::inline_completion(
 6912                            post_inc(&mut self.next_inlay_id),
 6913                            range.start,
 6914                            new_text.as_str(),
 6915                        );
 6916                        inlay_ids.push(inlay.id);
 6917                        inlays.push(inlay);
 6918                    }
 6919
 6920                    self.splice_inlays(&[], inlays, cx);
 6921                } else {
 6922                    let background_color = cx.theme().status().deleted_background;
 6923                    self.highlight_text::<InlineCompletionHighlight>(
 6924                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6925                        HighlightStyle {
 6926                            background_color: Some(background_color),
 6927                            ..Default::default()
 6928                        },
 6929                        cx,
 6930                    );
 6931                }
 6932            }
 6933
 6934            invalidation_row_range = edit_start_row..edit_end_row;
 6935
 6936            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6937                if provider.show_tab_accept_marker() {
 6938                    EditDisplayMode::TabAccept
 6939                } else {
 6940                    EditDisplayMode::Inline
 6941                }
 6942            } else {
 6943                EditDisplayMode::DiffPopover
 6944            };
 6945
 6946            InlineCompletion::Edit {
 6947                edits,
 6948                edit_preview: inline_completion.edit_preview,
 6949                display_mode,
 6950                snapshot,
 6951            }
 6952        };
 6953
 6954        let invalidation_range = multibuffer
 6955            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6956            ..multibuffer.anchor_after(Point::new(
 6957                invalidation_row_range.end,
 6958                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6959            ));
 6960
 6961        self.stale_inline_completion_in_menu = None;
 6962        self.active_inline_completion = Some(InlineCompletionState {
 6963            inlay_ids,
 6964            completion,
 6965            completion_id: inline_completion.id,
 6966            invalidation_range,
 6967        });
 6968
 6969        cx.notify();
 6970
 6971        Some(())
 6972    }
 6973
 6974    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6975        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6976    }
 6977
 6978    fn clear_tasks(&mut self) {
 6979        self.tasks.clear()
 6980    }
 6981
 6982    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6983        if self.tasks.insert(key, value).is_some() {
 6984            // This case should hopefully be rare, but just in case...
 6985            log::error!(
 6986                "multiple different run targets found on a single line, only the last target will be rendered"
 6987            )
 6988        }
 6989    }
 6990
 6991    /// Get all display points of breakpoints that will be rendered within editor
 6992    ///
 6993    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 6994    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 6995    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 6996    fn active_breakpoints(
 6997        &self,
 6998        range: Range<DisplayRow>,
 6999        window: &mut Window,
 7000        cx: &mut Context<Self>,
 7001    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7002        let mut breakpoint_display_points = HashMap::default();
 7003
 7004        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7005            return breakpoint_display_points;
 7006        };
 7007
 7008        let snapshot = self.snapshot(window, cx);
 7009
 7010        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7011        let Some(project) = self.project.as_ref() else {
 7012            return breakpoint_display_points;
 7013        };
 7014
 7015        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7016            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7017
 7018        for (buffer_snapshot, range, excerpt_id) in
 7019            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7020        {
 7021            let Some(buffer) = project.read_with(cx, |this, cx| {
 7022                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7023            }) else {
 7024                continue;
 7025            };
 7026            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7027                &buffer,
 7028                Some(
 7029                    buffer_snapshot.anchor_before(range.start)
 7030                        ..buffer_snapshot.anchor_after(range.end),
 7031                ),
 7032                buffer_snapshot,
 7033                cx,
 7034            );
 7035            for (breakpoint, state) in breakpoints {
 7036                let multi_buffer_anchor =
 7037                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7038                let position = multi_buffer_anchor
 7039                    .to_point(&multi_buffer_snapshot)
 7040                    .to_display_point(&snapshot);
 7041
 7042                breakpoint_display_points.insert(
 7043                    position.row(),
 7044                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7045                );
 7046            }
 7047        }
 7048
 7049        breakpoint_display_points
 7050    }
 7051
 7052    fn breakpoint_context_menu(
 7053        &self,
 7054        anchor: Anchor,
 7055        window: &mut Window,
 7056        cx: &mut Context<Self>,
 7057    ) -> Entity<ui::ContextMenu> {
 7058        let weak_editor = cx.weak_entity();
 7059        let focus_handle = self.focus_handle(cx);
 7060
 7061        let row = self
 7062            .buffer
 7063            .read(cx)
 7064            .snapshot(cx)
 7065            .summary_for_anchor::<Point>(&anchor)
 7066            .row;
 7067
 7068        let breakpoint = self
 7069            .breakpoint_at_row(row, window, cx)
 7070            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7071
 7072        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7073            "Edit Log Breakpoint"
 7074        } else {
 7075            "Set Log Breakpoint"
 7076        };
 7077
 7078        let condition_breakpoint_msg = if breakpoint
 7079            .as_ref()
 7080            .is_some_and(|bp| bp.1.condition.is_some())
 7081        {
 7082            "Edit Condition Breakpoint"
 7083        } else {
 7084            "Set Condition Breakpoint"
 7085        };
 7086
 7087        let hit_condition_breakpoint_msg = if breakpoint
 7088            .as_ref()
 7089            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7090        {
 7091            "Edit Hit Condition Breakpoint"
 7092        } else {
 7093            "Set Hit Condition Breakpoint"
 7094        };
 7095
 7096        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7097            "Unset Breakpoint"
 7098        } else {
 7099            "Set Breakpoint"
 7100        };
 7101
 7102        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7103            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7104
 7105        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7106            BreakpointState::Enabled => Some("Disable"),
 7107            BreakpointState::Disabled => Some("Enable"),
 7108        });
 7109
 7110        let (anchor, breakpoint) =
 7111            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7112
 7113        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7114            menu.on_blur_subscription(Subscription::new(|| {}))
 7115                .context(focus_handle)
 7116                .when(run_to_cursor, |this| {
 7117                    let weak_editor = weak_editor.clone();
 7118                    this.entry("Run to cursor", None, move |window, cx| {
 7119                        weak_editor
 7120                            .update(cx, |editor, cx| {
 7121                                editor.change_selections(None, window, cx, |s| {
 7122                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7123                                });
 7124                            })
 7125                            .ok();
 7126
 7127                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7128                    })
 7129                    .separator()
 7130                })
 7131                .when_some(toggle_state_msg, |this, msg| {
 7132                    this.entry(msg, None, {
 7133                        let weak_editor = weak_editor.clone();
 7134                        let breakpoint = breakpoint.clone();
 7135                        move |_window, cx| {
 7136                            weak_editor
 7137                                .update(cx, |this, cx| {
 7138                                    this.edit_breakpoint_at_anchor(
 7139                                        anchor,
 7140                                        breakpoint.as_ref().clone(),
 7141                                        BreakpointEditAction::InvertState,
 7142                                        cx,
 7143                                    );
 7144                                })
 7145                                .log_err();
 7146                        }
 7147                    })
 7148                })
 7149                .entry(set_breakpoint_msg, None, {
 7150                    let weak_editor = weak_editor.clone();
 7151                    let breakpoint = breakpoint.clone();
 7152                    move |_window, cx| {
 7153                        weak_editor
 7154                            .update(cx, |this, cx| {
 7155                                this.edit_breakpoint_at_anchor(
 7156                                    anchor,
 7157                                    breakpoint.as_ref().clone(),
 7158                                    BreakpointEditAction::Toggle,
 7159                                    cx,
 7160                                );
 7161                            })
 7162                            .log_err();
 7163                    }
 7164                })
 7165                .entry(log_breakpoint_msg, None, {
 7166                    let breakpoint = breakpoint.clone();
 7167                    let weak_editor = weak_editor.clone();
 7168                    move |window, cx| {
 7169                        weak_editor
 7170                            .update(cx, |this, cx| {
 7171                                this.add_edit_breakpoint_block(
 7172                                    anchor,
 7173                                    breakpoint.as_ref(),
 7174                                    BreakpointPromptEditAction::Log,
 7175                                    window,
 7176                                    cx,
 7177                                );
 7178                            })
 7179                            .log_err();
 7180                    }
 7181                })
 7182                .entry(condition_breakpoint_msg, None, {
 7183                    let breakpoint = breakpoint.clone();
 7184                    let weak_editor = weak_editor.clone();
 7185                    move |window, cx| {
 7186                        weak_editor
 7187                            .update(cx, |this, cx| {
 7188                                this.add_edit_breakpoint_block(
 7189                                    anchor,
 7190                                    breakpoint.as_ref(),
 7191                                    BreakpointPromptEditAction::Condition,
 7192                                    window,
 7193                                    cx,
 7194                                );
 7195                            })
 7196                            .log_err();
 7197                    }
 7198                })
 7199                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7200                    weak_editor
 7201                        .update(cx, |this, cx| {
 7202                            this.add_edit_breakpoint_block(
 7203                                anchor,
 7204                                breakpoint.as_ref(),
 7205                                BreakpointPromptEditAction::HitCondition,
 7206                                window,
 7207                                cx,
 7208                            );
 7209                        })
 7210                        .log_err();
 7211                })
 7212        })
 7213    }
 7214
 7215    fn render_breakpoint(
 7216        &self,
 7217        position: Anchor,
 7218        row: DisplayRow,
 7219        breakpoint: &Breakpoint,
 7220        state: Option<BreakpointSessionState>,
 7221        cx: &mut Context<Self>,
 7222    ) -> IconButton {
 7223        let is_rejected = state.is_some_and(|s| !s.verified);
 7224        // Is it a breakpoint that shows up when hovering over gutter?
 7225        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7226            (false, false),
 7227            |PhantomBreakpointIndicator {
 7228                 is_active,
 7229                 display_row,
 7230                 collides_with_existing_breakpoint,
 7231             }| {
 7232                (
 7233                    is_active && display_row == row,
 7234                    collides_with_existing_breakpoint,
 7235                )
 7236            },
 7237        );
 7238
 7239        let (color, icon) = {
 7240            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7241                (false, false) => ui::IconName::DebugBreakpoint,
 7242                (true, false) => ui::IconName::DebugLogBreakpoint,
 7243                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7244                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7245            };
 7246
 7247            let color = if is_phantom {
 7248                Color::Hint
 7249            } else if is_rejected {
 7250                Color::Disabled
 7251            } else {
 7252                Color::Debugger
 7253            };
 7254
 7255            (color, icon)
 7256        };
 7257
 7258        let breakpoint = Arc::from(breakpoint.clone());
 7259
 7260        let alt_as_text = gpui::Keystroke {
 7261            modifiers: Modifiers::secondary_key(),
 7262            ..Default::default()
 7263        };
 7264        let primary_action_text = if breakpoint.is_disabled() {
 7265            "enable"
 7266        } else if is_phantom && !collides_with_existing {
 7267            "set"
 7268        } else {
 7269            "unset"
 7270        };
 7271        let mut primary_text = format!("Click to {primary_action_text}");
 7272        if collides_with_existing && !breakpoint.is_disabled() {
 7273            use std::fmt::Write;
 7274            write!(primary_text, ", {alt_as_text}-click to disable").ok();
 7275        }
 7276        let primary_text = SharedString::from(primary_text);
 7277        let focus_handle = self.focus_handle.clone();
 7278
 7279        let meta = if is_rejected {
 7280            "No executable code is associated with this line."
 7281        } else {
 7282            "Right-click for more options."
 7283        };
 7284        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7285            .icon_size(IconSize::XSmall)
 7286            .size(ui::ButtonSize::None)
 7287            .when(is_rejected, |this| {
 7288                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7289            })
 7290            .icon_color(color)
 7291            .style(ButtonStyle::Transparent)
 7292            .on_click(cx.listener({
 7293                let breakpoint = breakpoint.clone();
 7294
 7295                move |editor, event: &ClickEvent, window, cx| {
 7296                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7297                        BreakpointEditAction::InvertState
 7298                    } else {
 7299                        BreakpointEditAction::Toggle
 7300                    };
 7301
 7302                    window.focus(&editor.focus_handle(cx));
 7303                    editor.edit_breakpoint_at_anchor(
 7304                        position,
 7305                        breakpoint.as_ref().clone(),
 7306                        edit_action,
 7307                        cx,
 7308                    );
 7309                }
 7310            }))
 7311            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7312                editor.set_breakpoint_context_menu(
 7313                    row,
 7314                    Some(position),
 7315                    event.down.position,
 7316                    window,
 7317                    cx,
 7318                );
 7319            }))
 7320            .tooltip(move |window, cx| {
 7321                Tooltip::with_meta_in(primary_text.clone(), None, meta, &focus_handle, window, cx)
 7322            })
 7323    }
 7324
 7325    fn build_tasks_context(
 7326        project: &Entity<Project>,
 7327        buffer: &Entity<Buffer>,
 7328        buffer_row: u32,
 7329        tasks: &Arc<RunnableTasks>,
 7330        cx: &mut Context<Self>,
 7331    ) -> Task<Option<task::TaskContext>> {
 7332        let position = Point::new(buffer_row, tasks.column);
 7333        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7334        let location = Location {
 7335            buffer: buffer.clone(),
 7336            range: range_start..range_start,
 7337        };
 7338        // Fill in the environmental variables from the tree-sitter captures
 7339        let mut captured_task_variables = TaskVariables::default();
 7340        for (capture_name, value) in tasks.extra_variables.clone() {
 7341            captured_task_variables.insert(
 7342                task::VariableName::Custom(capture_name.into()),
 7343                value.clone(),
 7344            );
 7345        }
 7346        project.update(cx, |project, cx| {
 7347            project.task_store().update(cx, |task_store, cx| {
 7348                task_store.task_context_for_location(captured_task_variables, location, cx)
 7349            })
 7350        })
 7351    }
 7352
 7353    pub fn spawn_nearest_task(
 7354        &mut self,
 7355        action: &SpawnNearestTask,
 7356        window: &mut Window,
 7357        cx: &mut Context<Self>,
 7358    ) {
 7359        let Some((workspace, _)) = self.workspace.clone() else {
 7360            return;
 7361        };
 7362        let Some(project) = self.project.clone() else {
 7363            return;
 7364        };
 7365
 7366        // Try to find a closest, enclosing node using tree-sitter that has a
 7367        // task
 7368        let Some((buffer, buffer_row, tasks)) = self
 7369            .find_enclosing_node_task(cx)
 7370            // Or find the task that's closest in row-distance.
 7371            .or_else(|| self.find_closest_task(cx))
 7372        else {
 7373            return;
 7374        };
 7375
 7376        let reveal_strategy = action.reveal;
 7377        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7378        cx.spawn_in(window, async move |_, cx| {
 7379            let context = task_context.await?;
 7380            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7381
 7382            let resolved = &mut resolved_task.resolved;
 7383            resolved.reveal = reveal_strategy;
 7384
 7385            workspace
 7386                .update_in(cx, |workspace, window, cx| {
 7387                    workspace.schedule_resolved_task(
 7388                        task_source_kind,
 7389                        resolved_task,
 7390                        false,
 7391                        window,
 7392                        cx,
 7393                    );
 7394                })
 7395                .ok()
 7396        })
 7397        .detach();
 7398    }
 7399
 7400    fn find_closest_task(
 7401        &mut self,
 7402        cx: &mut Context<Self>,
 7403    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7404        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7405
 7406        let ((buffer_id, row), tasks) = self
 7407            .tasks
 7408            .iter()
 7409            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7410
 7411        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7412        let tasks = Arc::new(tasks.to_owned());
 7413        Some((buffer, *row, tasks))
 7414    }
 7415
 7416    fn find_enclosing_node_task(
 7417        &mut self,
 7418        cx: &mut Context<Self>,
 7419    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7420        let snapshot = self.buffer.read(cx).snapshot(cx);
 7421        let offset = self.selections.newest::<usize>(cx).head();
 7422        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7423        let buffer_id = excerpt.buffer().remote_id();
 7424
 7425        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7426        let mut cursor = layer.node().walk();
 7427
 7428        while cursor.goto_first_child_for_byte(offset).is_some() {
 7429            if cursor.node().end_byte() == offset {
 7430                cursor.goto_next_sibling();
 7431            }
 7432        }
 7433
 7434        // Ascend to the smallest ancestor that contains the range and has a task.
 7435        loop {
 7436            let node = cursor.node();
 7437            let node_range = node.byte_range();
 7438            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7439
 7440            // Check if this node contains our offset
 7441            if node_range.start <= offset && node_range.end >= offset {
 7442                // If it contains offset, check for task
 7443                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7444                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7445                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7446                }
 7447            }
 7448
 7449            if !cursor.goto_parent() {
 7450                break;
 7451            }
 7452        }
 7453        None
 7454    }
 7455
 7456    fn render_run_indicator(
 7457        &self,
 7458        _style: &EditorStyle,
 7459        is_active: bool,
 7460        row: DisplayRow,
 7461        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7462        cx: &mut Context<Self>,
 7463    ) -> IconButton {
 7464        let color = Color::Muted;
 7465        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7466
 7467        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7468            .shape(ui::IconButtonShape::Square)
 7469            .icon_size(IconSize::XSmall)
 7470            .icon_color(color)
 7471            .toggle_state(is_active)
 7472            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7473                let quick_launch = e.down.button == MouseButton::Left;
 7474                window.focus(&editor.focus_handle(cx));
 7475                editor.toggle_code_actions(
 7476                    &ToggleCodeActions {
 7477                        deployed_from_indicator: Some(row),
 7478                        quick_launch,
 7479                    },
 7480                    window,
 7481                    cx,
 7482                );
 7483            }))
 7484            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7485                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7486            }))
 7487    }
 7488
 7489    pub fn context_menu_visible(&self) -> bool {
 7490        !self.edit_prediction_preview_is_active()
 7491            && self
 7492                .context_menu
 7493                .borrow()
 7494                .as_ref()
 7495                .map_or(false, |menu| menu.visible())
 7496    }
 7497
 7498    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7499        self.context_menu
 7500            .borrow()
 7501            .as_ref()
 7502            .map(|menu| menu.origin())
 7503    }
 7504
 7505    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7506        self.context_menu_options = Some(options);
 7507    }
 7508
 7509    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7510    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7511
 7512    fn render_edit_prediction_popover(
 7513        &mut self,
 7514        text_bounds: &Bounds<Pixels>,
 7515        content_origin: gpui::Point<Pixels>,
 7516        right_margin: Pixels,
 7517        editor_snapshot: &EditorSnapshot,
 7518        visible_row_range: Range<DisplayRow>,
 7519        scroll_top: f32,
 7520        scroll_bottom: f32,
 7521        line_layouts: &[LineWithInvisibles],
 7522        line_height: Pixels,
 7523        scroll_pixel_position: gpui::Point<Pixels>,
 7524        newest_selection_head: Option<DisplayPoint>,
 7525        editor_width: Pixels,
 7526        style: &EditorStyle,
 7527        window: &mut Window,
 7528        cx: &mut App,
 7529    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7530        if self.mode().is_minimap() {
 7531            return None;
 7532        }
 7533        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7534
 7535        if self.edit_prediction_visible_in_cursor_popover(true) {
 7536            return None;
 7537        }
 7538
 7539        match &active_inline_completion.completion {
 7540            InlineCompletion::Move { target, .. } => {
 7541                let target_display_point = target.to_display_point(editor_snapshot);
 7542
 7543                if self.edit_prediction_requires_modifier() {
 7544                    if !self.edit_prediction_preview_is_active() {
 7545                        return None;
 7546                    }
 7547
 7548                    self.render_edit_prediction_modifier_jump_popover(
 7549                        text_bounds,
 7550                        content_origin,
 7551                        visible_row_range,
 7552                        line_layouts,
 7553                        line_height,
 7554                        scroll_pixel_position,
 7555                        newest_selection_head,
 7556                        target_display_point,
 7557                        window,
 7558                        cx,
 7559                    )
 7560                } else {
 7561                    self.render_edit_prediction_eager_jump_popover(
 7562                        text_bounds,
 7563                        content_origin,
 7564                        editor_snapshot,
 7565                        visible_row_range,
 7566                        scroll_top,
 7567                        scroll_bottom,
 7568                        line_height,
 7569                        scroll_pixel_position,
 7570                        target_display_point,
 7571                        editor_width,
 7572                        window,
 7573                        cx,
 7574                    )
 7575                }
 7576            }
 7577            InlineCompletion::Edit {
 7578                display_mode: EditDisplayMode::Inline,
 7579                ..
 7580            } => None,
 7581            InlineCompletion::Edit {
 7582                display_mode: EditDisplayMode::TabAccept,
 7583                edits,
 7584                ..
 7585            } => {
 7586                let range = &edits.first()?.0;
 7587                let target_display_point = range.end.to_display_point(editor_snapshot);
 7588
 7589                self.render_edit_prediction_end_of_line_popover(
 7590                    "Accept",
 7591                    editor_snapshot,
 7592                    visible_row_range,
 7593                    target_display_point,
 7594                    line_height,
 7595                    scroll_pixel_position,
 7596                    content_origin,
 7597                    editor_width,
 7598                    window,
 7599                    cx,
 7600                )
 7601            }
 7602            InlineCompletion::Edit {
 7603                edits,
 7604                edit_preview,
 7605                display_mode: EditDisplayMode::DiffPopover,
 7606                snapshot,
 7607            } => self.render_edit_prediction_diff_popover(
 7608                text_bounds,
 7609                content_origin,
 7610                right_margin,
 7611                editor_snapshot,
 7612                visible_row_range,
 7613                line_layouts,
 7614                line_height,
 7615                scroll_pixel_position,
 7616                newest_selection_head,
 7617                editor_width,
 7618                style,
 7619                edits,
 7620                edit_preview,
 7621                snapshot,
 7622                window,
 7623                cx,
 7624            ),
 7625        }
 7626    }
 7627
 7628    fn render_edit_prediction_modifier_jump_popover(
 7629        &mut self,
 7630        text_bounds: &Bounds<Pixels>,
 7631        content_origin: gpui::Point<Pixels>,
 7632        visible_row_range: Range<DisplayRow>,
 7633        line_layouts: &[LineWithInvisibles],
 7634        line_height: Pixels,
 7635        scroll_pixel_position: gpui::Point<Pixels>,
 7636        newest_selection_head: Option<DisplayPoint>,
 7637        target_display_point: DisplayPoint,
 7638        window: &mut Window,
 7639        cx: &mut App,
 7640    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7641        let scrolled_content_origin =
 7642            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7643
 7644        const SCROLL_PADDING_Y: Pixels = px(12.);
 7645
 7646        if target_display_point.row() < visible_row_range.start {
 7647            return self.render_edit_prediction_scroll_popover(
 7648                |_| SCROLL_PADDING_Y,
 7649                IconName::ArrowUp,
 7650                visible_row_range,
 7651                line_layouts,
 7652                newest_selection_head,
 7653                scrolled_content_origin,
 7654                window,
 7655                cx,
 7656            );
 7657        } else if target_display_point.row() >= visible_row_range.end {
 7658            return self.render_edit_prediction_scroll_popover(
 7659                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7660                IconName::ArrowDown,
 7661                visible_row_range,
 7662                line_layouts,
 7663                newest_selection_head,
 7664                scrolled_content_origin,
 7665                window,
 7666                cx,
 7667            );
 7668        }
 7669
 7670        const POLE_WIDTH: Pixels = px(2.);
 7671
 7672        let line_layout =
 7673            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7674        let target_column = target_display_point.column() as usize;
 7675
 7676        let target_x = line_layout.x_for_index(target_column);
 7677        let target_y =
 7678            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7679
 7680        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7681
 7682        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7683        border_color.l += 0.001;
 7684
 7685        let mut element = v_flex()
 7686            .items_end()
 7687            .when(flag_on_right, |el| el.items_start())
 7688            .child(if flag_on_right {
 7689                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7690                    .rounded_bl(px(0.))
 7691                    .rounded_tl(px(0.))
 7692                    .border_l_2()
 7693                    .border_color(border_color)
 7694            } else {
 7695                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7696                    .rounded_br(px(0.))
 7697                    .rounded_tr(px(0.))
 7698                    .border_r_2()
 7699                    .border_color(border_color)
 7700            })
 7701            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7702            .into_any();
 7703
 7704        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7705
 7706        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7707            - point(
 7708                if flag_on_right {
 7709                    POLE_WIDTH
 7710                } else {
 7711                    size.width - POLE_WIDTH
 7712                },
 7713                size.height - line_height,
 7714            );
 7715
 7716        origin.x = origin.x.max(content_origin.x);
 7717
 7718        element.prepaint_at(origin, window, cx);
 7719
 7720        Some((element, origin))
 7721    }
 7722
 7723    fn render_edit_prediction_scroll_popover(
 7724        &mut self,
 7725        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7726        scroll_icon: IconName,
 7727        visible_row_range: Range<DisplayRow>,
 7728        line_layouts: &[LineWithInvisibles],
 7729        newest_selection_head: Option<DisplayPoint>,
 7730        scrolled_content_origin: gpui::Point<Pixels>,
 7731        window: &mut Window,
 7732        cx: &mut App,
 7733    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7734        let mut element = self
 7735            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7736            .into_any();
 7737
 7738        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7739
 7740        let cursor = newest_selection_head?;
 7741        let cursor_row_layout =
 7742            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7743        let cursor_column = cursor.column() as usize;
 7744
 7745        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7746
 7747        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7748
 7749        element.prepaint_at(origin, window, cx);
 7750        Some((element, origin))
 7751    }
 7752
 7753    fn render_edit_prediction_eager_jump_popover(
 7754        &mut self,
 7755        text_bounds: &Bounds<Pixels>,
 7756        content_origin: gpui::Point<Pixels>,
 7757        editor_snapshot: &EditorSnapshot,
 7758        visible_row_range: Range<DisplayRow>,
 7759        scroll_top: f32,
 7760        scroll_bottom: f32,
 7761        line_height: Pixels,
 7762        scroll_pixel_position: gpui::Point<Pixels>,
 7763        target_display_point: DisplayPoint,
 7764        editor_width: Pixels,
 7765        window: &mut Window,
 7766        cx: &mut App,
 7767    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7768        if target_display_point.row().as_f32() < scroll_top {
 7769            let mut element = self
 7770                .render_edit_prediction_line_popover(
 7771                    "Jump to Edit",
 7772                    Some(IconName::ArrowUp),
 7773                    window,
 7774                    cx,
 7775                )?
 7776                .into_any();
 7777
 7778            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7779            let offset = point(
 7780                (text_bounds.size.width - size.width) / 2.,
 7781                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7782            );
 7783
 7784            let origin = text_bounds.origin + offset;
 7785            element.prepaint_at(origin, window, cx);
 7786            Some((element, origin))
 7787        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7788            let mut element = self
 7789                .render_edit_prediction_line_popover(
 7790                    "Jump to Edit",
 7791                    Some(IconName::ArrowDown),
 7792                    window,
 7793                    cx,
 7794                )?
 7795                .into_any();
 7796
 7797            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7798            let offset = point(
 7799                (text_bounds.size.width - size.width) / 2.,
 7800                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7801            );
 7802
 7803            let origin = text_bounds.origin + offset;
 7804            element.prepaint_at(origin, window, cx);
 7805            Some((element, origin))
 7806        } else {
 7807            self.render_edit_prediction_end_of_line_popover(
 7808                "Jump to Edit",
 7809                editor_snapshot,
 7810                visible_row_range,
 7811                target_display_point,
 7812                line_height,
 7813                scroll_pixel_position,
 7814                content_origin,
 7815                editor_width,
 7816                window,
 7817                cx,
 7818            )
 7819        }
 7820    }
 7821
 7822    fn render_edit_prediction_end_of_line_popover(
 7823        self: &mut Editor,
 7824        label: &'static str,
 7825        editor_snapshot: &EditorSnapshot,
 7826        visible_row_range: Range<DisplayRow>,
 7827        target_display_point: DisplayPoint,
 7828        line_height: Pixels,
 7829        scroll_pixel_position: gpui::Point<Pixels>,
 7830        content_origin: gpui::Point<Pixels>,
 7831        editor_width: Pixels,
 7832        window: &mut Window,
 7833        cx: &mut App,
 7834    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7835        let target_line_end = DisplayPoint::new(
 7836            target_display_point.row(),
 7837            editor_snapshot.line_len(target_display_point.row()),
 7838        );
 7839
 7840        let mut element = self
 7841            .render_edit_prediction_line_popover(label, None, window, cx)?
 7842            .into_any();
 7843
 7844        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7845
 7846        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7847
 7848        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7849        let mut origin = start_point
 7850            + line_origin
 7851            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7852        origin.x = origin.x.max(content_origin.x);
 7853
 7854        let max_x = content_origin.x + editor_width - size.width;
 7855
 7856        if origin.x > max_x {
 7857            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7858
 7859            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7860                origin.y += offset;
 7861                IconName::ArrowUp
 7862            } else {
 7863                origin.y -= offset;
 7864                IconName::ArrowDown
 7865            };
 7866
 7867            element = self
 7868                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7869                .into_any();
 7870
 7871            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7872
 7873            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7874        }
 7875
 7876        element.prepaint_at(origin, window, cx);
 7877        Some((element, origin))
 7878    }
 7879
 7880    fn render_edit_prediction_diff_popover(
 7881        self: &Editor,
 7882        text_bounds: &Bounds<Pixels>,
 7883        content_origin: gpui::Point<Pixels>,
 7884        right_margin: Pixels,
 7885        editor_snapshot: &EditorSnapshot,
 7886        visible_row_range: Range<DisplayRow>,
 7887        line_layouts: &[LineWithInvisibles],
 7888        line_height: Pixels,
 7889        scroll_pixel_position: gpui::Point<Pixels>,
 7890        newest_selection_head: Option<DisplayPoint>,
 7891        editor_width: Pixels,
 7892        style: &EditorStyle,
 7893        edits: &Vec<(Range<Anchor>, String)>,
 7894        edit_preview: &Option<language::EditPreview>,
 7895        snapshot: &language::BufferSnapshot,
 7896        window: &mut Window,
 7897        cx: &mut App,
 7898    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7899        let edit_start = edits
 7900            .first()
 7901            .unwrap()
 7902            .0
 7903            .start
 7904            .to_display_point(editor_snapshot);
 7905        let edit_end = edits
 7906            .last()
 7907            .unwrap()
 7908            .0
 7909            .end
 7910            .to_display_point(editor_snapshot);
 7911
 7912        let is_visible = visible_row_range.contains(&edit_start.row())
 7913            || visible_row_range.contains(&edit_end.row());
 7914        if !is_visible {
 7915            return None;
 7916        }
 7917
 7918        let highlighted_edits =
 7919            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7920
 7921        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7922        let line_count = highlighted_edits.text.lines().count();
 7923
 7924        const BORDER_WIDTH: Pixels = px(1.);
 7925
 7926        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7927        let has_keybind = keybind.is_some();
 7928
 7929        let mut element = h_flex()
 7930            .items_start()
 7931            .child(
 7932                h_flex()
 7933                    .bg(cx.theme().colors().editor_background)
 7934                    .border(BORDER_WIDTH)
 7935                    .shadow_sm()
 7936                    .border_color(cx.theme().colors().border)
 7937                    .rounded_l_lg()
 7938                    .when(line_count > 1, |el| el.rounded_br_lg())
 7939                    .pr_1()
 7940                    .child(styled_text),
 7941            )
 7942            .child(
 7943                h_flex()
 7944                    .h(line_height + BORDER_WIDTH * 2.)
 7945                    .px_1p5()
 7946                    .gap_1()
 7947                    // Workaround: For some reason, there's a gap if we don't do this
 7948                    .ml(-BORDER_WIDTH)
 7949                    .shadow(smallvec![gpui::BoxShadow {
 7950                        color: gpui::black().opacity(0.05),
 7951                        offset: point(px(1.), px(1.)),
 7952                        blur_radius: px(2.),
 7953                        spread_radius: px(0.),
 7954                    }])
 7955                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7956                    .border(BORDER_WIDTH)
 7957                    .border_color(cx.theme().colors().border)
 7958                    .rounded_r_lg()
 7959                    .id("edit_prediction_diff_popover_keybind")
 7960                    .when(!has_keybind, |el| {
 7961                        let status_colors = cx.theme().status();
 7962
 7963                        el.bg(status_colors.error_background)
 7964                            .border_color(status_colors.error.opacity(0.6))
 7965                            .child(Icon::new(IconName::Info).color(Color::Error))
 7966                            .cursor_default()
 7967                            .hoverable_tooltip(move |_window, cx| {
 7968                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7969                            })
 7970                    })
 7971                    .children(keybind),
 7972            )
 7973            .into_any();
 7974
 7975        let longest_row =
 7976            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7977        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7978            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7979        } else {
 7980            layout_line(
 7981                longest_row,
 7982                editor_snapshot,
 7983                style,
 7984                editor_width,
 7985                |_| false,
 7986                window,
 7987                cx,
 7988            )
 7989            .width
 7990        };
 7991
 7992        let viewport_bounds =
 7993            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 7994                right: -right_margin,
 7995                ..Default::default()
 7996            });
 7997
 7998        let x_after_longest =
 7999            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8000                - scroll_pixel_position.x;
 8001
 8002        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8003
 8004        // Fully visible if it can be displayed within the window (allow overlapping other
 8005        // panes). However, this is only allowed if the popover starts within text_bounds.
 8006        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8007            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8008
 8009        let mut origin = if can_position_to_the_right {
 8010            point(
 8011                x_after_longest,
 8012                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8013                    - scroll_pixel_position.y,
 8014            )
 8015        } else {
 8016            let cursor_row = newest_selection_head.map(|head| head.row());
 8017            let above_edit = edit_start
 8018                .row()
 8019                .0
 8020                .checked_sub(line_count as u32)
 8021                .map(DisplayRow);
 8022            let below_edit = Some(edit_end.row() + 1);
 8023            let above_cursor =
 8024                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8025            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8026
 8027            // Place the edit popover adjacent to the edit if there is a location
 8028            // available that is onscreen and does not obscure the cursor. Otherwise,
 8029            // place it adjacent to the cursor.
 8030            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8031                .into_iter()
 8032                .flatten()
 8033                .find(|&start_row| {
 8034                    let end_row = start_row + line_count as u32;
 8035                    visible_row_range.contains(&start_row)
 8036                        && visible_row_range.contains(&end_row)
 8037                        && cursor_row.map_or(true, |cursor_row| {
 8038                            !((start_row..end_row).contains(&cursor_row))
 8039                        })
 8040                })?;
 8041
 8042            content_origin
 8043                + point(
 8044                    -scroll_pixel_position.x,
 8045                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8046                )
 8047        };
 8048
 8049        origin.x -= BORDER_WIDTH;
 8050
 8051        window.defer_draw(element, origin, 1);
 8052
 8053        // Do not return an element, since it will already be drawn due to defer_draw.
 8054        None
 8055    }
 8056
 8057    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8058        px(30.)
 8059    }
 8060
 8061    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8062        if self.read_only(cx) {
 8063            cx.theme().players().read_only()
 8064        } else {
 8065            self.style.as_ref().unwrap().local_player
 8066        }
 8067    }
 8068
 8069    fn render_edit_prediction_accept_keybind(
 8070        &self,
 8071        window: &mut Window,
 8072        cx: &App,
 8073    ) -> Option<AnyElement> {
 8074        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8075        let accept_keystroke = accept_binding.keystroke()?;
 8076
 8077        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8078
 8079        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8080            Color::Accent
 8081        } else {
 8082            Color::Muted
 8083        };
 8084
 8085        h_flex()
 8086            .px_0p5()
 8087            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8088            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8089            .text_size(TextSize::XSmall.rems(cx))
 8090            .child(h_flex().children(ui::render_modifiers(
 8091                &accept_keystroke.modifiers,
 8092                PlatformStyle::platform(),
 8093                Some(modifiers_color),
 8094                Some(IconSize::XSmall.rems().into()),
 8095                true,
 8096            )))
 8097            .when(is_platform_style_mac, |parent| {
 8098                parent.child(accept_keystroke.key.clone())
 8099            })
 8100            .when(!is_platform_style_mac, |parent| {
 8101                parent.child(
 8102                    Key::new(
 8103                        util::capitalize(&accept_keystroke.key),
 8104                        Some(Color::Default),
 8105                    )
 8106                    .size(Some(IconSize::XSmall.rems().into())),
 8107                )
 8108            })
 8109            .into_any()
 8110            .into()
 8111    }
 8112
 8113    fn render_edit_prediction_line_popover(
 8114        &self,
 8115        label: impl Into<SharedString>,
 8116        icon: Option<IconName>,
 8117        window: &mut Window,
 8118        cx: &App,
 8119    ) -> Option<Stateful<Div>> {
 8120        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8121
 8122        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8123        let has_keybind = keybind.is_some();
 8124
 8125        let result = h_flex()
 8126            .id("ep-line-popover")
 8127            .py_0p5()
 8128            .pl_1()
 8129            .pr(padding_right)
 8130            .gap_1()
 8131            .rounded_md()
 8132            .border_1()
 8133            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8134            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8135            .shadow_sm()
 8136            .when(!has_keybind, |el| {
 8137                let status_colors = cx.theme().status();
 8138
 8139                el.bg(status_colors.error_background)
 8140                    .border_color(status_colors.error.opacity(0.6))
 8141                    .pl_2()
 8142                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8143                    .cursor_default()
 8144                    .hoverable_tooltip(move |_window, cx| {
 8145                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8146                    })
 8147            })
 8148            .children(keybind)
 8149            .child(
 8150                Label::new(label)
 8151                    .size(LabelSize::Small)
 8152                    .when(!has_keybind, |el| {
 8153                        el.color(cx.theme().status().error.into()).strikethrough()
 8154                    }),
 8155            )
 8156            .when(!has_keybind, |el| {
 8157                el.child(
 8158                    h_flex().ml_1().child(
 8159                        Icon::new(IconName::Info)
 8160                            .size(IconSize::Small)
 8161                            .color(cx.theme().status().error.into()),
 8162                    ),
 8163                )
 8164            })
 8165            .when_some(icon, |element, icon| {
 8166                element.child(
 8167                    div()
 8168                        .mt(px(1.5))
 8169                        .child(Icon::new(icon).size(IconSize::Small)),
 8170                )
 8171            });
 8172
 8173        Some(result)
 8174    }
 8175
 8176    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8177        let accent_color = cx.theme().colors().text_accent;
 8178        let editor_bg_color = cx.theme().colors().editor_background;
 8179        editor_bg_color.blend(accent_color.opacity(0.1))
 8180    }
 8181
 8182    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8183        let accent_color = cx.theme().colors().text_accent;
 8184        let editor_bg_color = cx.theme().colors().editor_background;
 8185        editor_bg_color.blend(accent_color.opacity(0.6))
 8186    }
 8187
 8188    fn render_edit_prediction_cursor_popover(
 8189        &self,
 8190        min_width: Pixels,
 8191        max_width: Pixels,
 8192        cursor_point: Point,
 8193        style: &EditorStyle,
 8194        accept_keystroke: Option<&gpui::Keystroke>,
 8195        _window: &Window,
 8196        cx: &mut Context<Editor>,
 8197    ) -> Option<AnyElement> {
 8198        let provider = self.edit_prediction_provider.as_ref()?;
 8199
 8200        if provider.provider.needs_terms_acceptance(cx) {
 8201            return Some(
 8202                h_flex()
 8203                    .min_w(min_width)
 8204                    .flex_1()
 8205                    .px_2()
 8206                    .py_1()
 8207                    .gap_3()
 8208                    .elevation_2(cx)
 8209                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8210                    .id("accept-terms")
 8211                    .cursor_pointer()
 8212                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8213                    .on_click(cx.listener(|this, _event, window, cx| {
 8214                        cx.stop_propagation();
 8215                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8216                        window.dispatch_action(
 8217                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8218                            cx,
 8219                        );
 8220                    }))
 8221                    .child(
 8222                        h_flex()
 8223                            .flex_1()
 8224                            .gap_2()
 8225                            .child(Icon::new(IconName::ZedPredict))
 8226                            .child(Label::new("Accept Terms of Service"))
 8227                            .child(div().w_full())
 8228                            .child(
 8229                                Icon::new(IconName::ArrowUpRight)
 8230                                    .color(Color::Muted)
 8231                                    .size(IconSize::Small),
 8232                            )
 8233                            .into_any_element(),
 8234                    )
 8235                    .into_any(),
 8236            );
 8237        }
 8238
 8239        let is_refreshing = provider.provider.is_refreshing(cx);
 8240
 8241        fn pending_completion_container() -> Div {
 8242            h_flex()
 8243                .h_full()
 8244                .flex_1()
 8245                .gap_2()
 8246                .child(Icon::new(IconName::ZedPredict))
 8247        }
 8248
 8249        let completion = match &self.active_inline_completion {
 8250            Some(prediction) => {
 8251                if !self.has_visible_completions_menu() {
 8252                    const RADIUS: Pixels = px(6.);
 8253                    const BORDER_WIDTH: Pixels = px(1.);
 8254
 8255                    return Some(
 8256                        h_flex()
 8257                            .elevation_2(cx)
 8258                            .border(BORDER_WIDTH)
 8259                            .border_color(cx.theme().colors().border)
 8260                            .when(accept_keystroke.is_none(), |el| {
 8261                                el.border_color(cx.theme().status().error)
 8262                            })
 8263                            .rounded(RADIUS)
 8264                            .rounded_tl(px(0.))
 8265                            .overflow_hidden()
 8266                            .child(div().px_1p5().child(match &prediction.completion {
 8267                                InlineCompletion::Move { target, snapshot } => {
 8268                                    use text::ToPoint as _;
 8269                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8270                                    {
 8271                                        Icon::new(IconName::ZedPredictDown)
 8272                                    } else {
 8273                                        Icon::new(IconName::ZedPredictUp)
 8274                                    }
 8275                                }
 8276                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8277                            }))
 8278                            .child(
 8279                                h_flex()
 8280                                    .gap_1()
 8281                                    .py_1()
 8282                                    .px_2()
 8283                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8284                                    .border_l_1()
 8285                                    .border_color(cx.theme().colors().border)
 8286                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8287                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8288                                        el.child(
 8289                                            Label::new("Hold")
 8290                                                .size(LabelSize::Small)
 8291                                                .when(accept_keystroke.is_none(), |el| {
 8292                                                    el.strikethrough()
 8293                                                })
 8294                                                .line_height_style(LineHeightStyle::UiLabel),
 8295                                        )
 8296                                    })
 8297                                    .id("edit_prediction_cursor_popover_keybind")
 8298                                    .when(accept_keystroke.is_none(), |el| {
 8299                                        let status_colors = cx.theme().status();
 8300
 8301                                        el.bg(status_colors.error_background)
 8302                                            .border_color(status_colors.error.opacity(0.6))
 8303                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8304                                            .cursor_default()
 8305                                            .hoverable_tooltip(move |_window, cx| {
 8306                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8307                                                    .into()
 8308                                            })
 8309                                    })
 8310                                    .when_some(
 8311                                        accept_keystroke.as_ref(),
 8312                                        |el, accept_keystroke| {
 8313                                            el.child(h_flex().children(ui::render_modifiers(
 8314                                                &accept_keystroke.modifiers,
 8315                                                PlatformStyle::platform(),
 8316                                                Some(Color::Default),
 8317                                                Some(IconSize::XSmall.rems().into()),
 8318                                                false,
 8319                                            )))
 8320                                        },
 8321                                    ),
 8322                            )
 8323                            .into_any(),
 8324                    );
 8325                }
 8326
 8327                self.render_edit_prediction_cursor_popover_preview(
 8328                    prediction,
 8329                    cursor_point,
 8330                    style,
 8331                    cx,
 8332                )?
 8333            }
 8334
 8335            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8336                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8337                    stale_completion,
 8338                    cursor_point,
 8339                    style,
 8340                    cx,
 8341                )?,
 8342
 8343                None => {
 8344                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8345                }
 8346            },
 8347
 8348            None => pending_completion_container().child(Label::new("No Prediction")),
 8349        };
 8350
 8351        let completion = if is_refreshing {
 8352            completion
 8353                .with_animation(
 8354                    "loading-completion",
 8355                    Animation::new(Duration::from_secs(2))
 8356                        .repeat()
 8357                        .with_easing(pulsating_between(0.4, 0.8)),
 8358                    |label, delta| label.opacity(delta),
 8359                )
 8360                .into_any_element()
 8361        } else {
 8362            completion.into_any_element()
 8363        };
 8364
 8365        let has_completion = self.active_inline_completion.is_some();
 8366
 8367        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8368        Some(
 8369            h_flex()
 8370                .min_w(min_width)
 8371                .max_w(max_width)
 8372                .flex_1()
 8373                .elevation_2(cx)
 8374                .border_color(cx.theme().colors().border)
 8375                .child(
 8376                    div()
 8377                        .flex_1()
 8378                        .py_1()
 8379                        .px_2()
 8380                        .overflow_hidden()
 8381                        .child(completion),
 8382                )
 8383                .when_some(accept_keystroke, |el, accept_keystroke| {
 8384                    if !accept_keystroke.modifiers.modified() {
 8385                        return el;
 8386                    }
 8387
 8388                    el.child(
 8389                        h_flex()
 8390                            .h_full()
 8391                            .border_l_1()
 8392                            .rounded_r_lg()
 8393                            .border_color(cx.theme().colors().border)
 8394                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8395                            .gap_1()
 8396                            .py_1()
 8397                            .px_2()
 8398                            .child(
 8399                                h_flex()
 8400                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8401                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8402                                    .child(h_flex().children(ui::render_modifiers(
 8403                                        &accept_keystroke.modifiers,
 8404                                        PlatformStyle::platform(),
 8405                                        Some(if !has_completion {
 8406                                            Color::Muted
 8407                                        } else {
 8408                                            Color::Default
 8409                                        }),
 8410                                        None,
 8411                                        false,
 8412                                    ))),
 8413                            )
 8414                            .child(Label::new("Preview").into_any_element())
 8415                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8416                    )
 8417                })
 8418                .into_any(),
 8419        )
 8420    }
 8421
 8422    fn render_edit_prediction_cursor_popover_preview(
 8423        &self,
 8424        completion: &InlineCompletionState,
 8425        cursor_point: Point,
 8426        style: &EditorStyle,
 8427        cx: &mut Context<Editor>,
 8428    ) -> Option<Div> {
 8429        use text::ToPoint as _;
 8430
 8431        fn render_relative_row_jump(
 8432            prefix: impl Into<String>,
 8433            current_row: u32,
 8434            target_row: u32,
 8435        ) -> Div {
 8436            let (row_diff, arrow) = if target_row < current_row {
 8437                (current_row - target_row, IconName::ArrowUp)
 8438            } else {
 8439                (target_row - current_row, IconName::ArrowDown)
 8440            };
 8441
 8442            h_flex()
 8443                .child(
 8444                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8445                        .color(Color::Muted)
 8446                        .size(LabelSize::Small),
 8447                )
 8448                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8449        }
 8450
 8451        match &completion.completion {
 8452            InlineCompletion::Move {
 8453                target, snapshot, ..
 8454            } => Some(
 8455                h_flex()
 8456                    .px_2()
 8457                    .gap_2()
 8458                    .flex_1()
 8459                    .child(
 8460                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8461                            Icon::new(IconName::ZedPredictDown)
 8462                        } else {
 8463                            Icon::new(IconName::ZedPredictUp)
 8464                        },
 8465                    )
 8466                    .child(Label::new("Jump to Edit")),
 8467            ),
 8468
 8469            InlineCompletion::Edit {
 8470                edits,
 8471                edit_preview,
 8472                snapshot,
 8473                display_mode: _,
 8474            } => {
 8475                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8476
 8477                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8478                    &snapshot,
 8479                    &edits,
 8480                    edit_preview.as_ref()?,
 8481                    true,
 8482                    cx,
 8483                )
 8484                .first_line_preview();
 8485
 8486                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8487                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8488
 8489                let preview = h_flex()
 8490                    .gap_1()
 8491                    .min_w_16()
 8492                    .child(styled_text)
 8493                    .when(has_more_lines, |parent| parent.child(""));
 8494
 8495                let left = if first_edit_row != cursor_point.row {
 8496                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8497                        .into_any_element()
 8498                } else {
 8499                    Icon::new(IconName::ZedPredict).into_any_element()
 8500                };
 8501
 8502                Some(
 8503                    h_flex()
 8504                        .h_full()
 8505                        .flex_1()
 8506                        .gap_2()
 8507                        .pr_1()
 8508                        .overflow_x_hidden()
 8509                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8510                        .child(left)
 8511                        .child(preview),
 8512                )
 8513            }
 8514        }
 8515    }
 8516
 8517    fn render_context_menu(
 8518        &self,
 8519        style: &EditorStyle,
 8520        max_height_in_lines: u32,
 8521        window: &mut Window,
 8522        cx: &mut Context<Editor>,
 8523    ) -> Option<AnyElement> {
 8524        let menu = self.context_menu.borrow();
 8525        let menu = menu.as_ref()?;
 8526        if !menu.visible() {
 8527            return None;
 8528        };
 8529        Some(menu.render(style, max_height_in_lines, window, cx))
 8530    }
 8531
 8532    fn render_context_menu_aside(
 8533        &mut self,
 8534        max_size: Size<Pixels>,
 8535        window: &mut Window,
 8536        cx: &mut Context<Editor>,
 8537    ) -> Option<AnyElement> {
 8538        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8539            if menu.visible() {
 8540                menu.render_aside(self, max_size, window, cx)
 8541            } else {
 8542                None
 8543            }
 8544        })
 8545    }
 8546
 8547    fn hide_context_menu(
 8548        &mut self,
 8549        window: &mut Window,
 8550        cx: &mut Context<Self>,
 8551    ) -> Option<CodeContextMenu> {
 8552        cx.notify();
 8553        self.completion_tasks.clear();
 8554        let context_menu = self.context_menu.borrow_mut().take();
 8555        self.stale_inline_completion_in_menu.take();
 8556        self.update_visible_inline_completion(window, cx);
 8557        context_menu
 8558    }
 8559
 8560    fn show_snippet_choices(
 8561        &mut self,
 8562        choices: &Vec<String>,
 8563        selection: Range<Anchor>,
 8564        cx: &mut Context<Self>,
 8565    ) {
 8566        if selection.start.buffer_id.is_none() {
 8567            return;
 8568        }
 8569        let buffer_id = selection.start.buffer_id.unwrap();
 8570        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8571        let id = post_inc(&mut self.next_completion_id);
 8572        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8573
 8574        if let Some(buffer) = buffer {
 8575            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8576                CompletionsMenu::new_snippet_choices(
 8577                    id,
 8578                    true,
 8579                    choices,
 8580                    selection,
 8581                    buffer,
 8582                    snippet_sort_order,
 8583                ),
 8584            ));
 8585        }
 8586    }
 8587
 8588    pub fn insert_snippet(
 8589        &mut self,
 8590        insertion_ranges: &[Range<usize>],
 8591        snippet: Snippet,
 8592        window: &mut Window,
 8593        cx: &mut Context<Self>,
 8594    ) -> Result<()> {
 8595        struct Tabstop<T> {
 8596            is_end_tabstop: bool,
 8597            ranges: Vec<Range<T>>,
 8598            choices: Option<Vec<String>>,
 8599        }
 8600
 8601        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8602            let snippet_text: Arc<str> = snippet.text.clone().into();
 8603            let edits = insertion_ranges
 8604                .iter()
 8605                .cloned()
 8606                .map(|range| (range, snippet_text.clone()));
 8607            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8608
 8609            let snapshot = &*buffer.read(cx);
 8610            let snippet = &snippet;
 8611            snippet
 8612                .tabstops
 8613                .iter()
 8614                .map(|tabstop| {
 8615                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8616                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8617                    });
 8618                    let mut tabstop_ranges = tabstop
 8619                        .ranges
 8620                        .iter()
 8621                        .flat_map(|tabstop_range| {
 8622                            let mut delta = 0_isize;
 8623                            insertion_ranges.iter().map(move |insertion_range| {
 8624                                let insertion_start = insertion_range.start as isize + delta;
 8625                                delta +=
 8626                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8627
 8628                                let start = ((insertion_start + tabstop_range.start) as usize)
 8629                                    .min(snapshot.len());
 8630                                let end = ((insertion_start + tabstop_range.end) as usize)
 8631                                    .min(snapshot.len());
 8632                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8633                            })
 8634                        })
 8635                        .collect::<Vec<_>>();
 8636                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8637
 8638                    Tabstop {
 8639                        is_end_tabstop,
 8640                        ranges: tabstop_ranges,
 8641                        choices: tabstop.choices.clone(),
 8642                    }
 8643                })
 8644                .collect::<Vec<_>>()
 8645        });
 8646        if let Some(tabstop) = tabstops.first() {
 8647            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8648                s.select_ranges(tabstop.ranges.iter().cloned());
 8649            });
 8650
 8651            if let Some(choices) = &tabstop.choices {
 8652                if let Some(selection) = tabstop.ranges.first() {
 8653                    self.show_snippet_choices(choices, selection.clone(), cx)
 8654                }
 8655            }
 8656
 8657            // If we're already at the last tabstop and it's at the end of the snippet,
 8658            // we're done, we don't need to keep the state around.
 8659            if !tabstop.is_end_tabstop {
 8660                let choices = tabstops
 8661                    .iter()
 8662                    .map(|tabstop| tabstop.choices.clone())
 8663                    .collect();
 8664
 8665                let ranges = tabstops
 8666                    .into_iter()
 8667                    .map(|tabstop| tabstop.ranges)
 8668                    .collect::<Vec<_>>();
 8669
 8670                self.snippet_stack.push(SnippetState {
 8671                    active_index: 0,
 8672                    ranges,
 8673                    choices,
 8674                });
 8675            }
 8676
 8677            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8678            if self.autoclose_regions.is_empty() {
 8679                let snapshot = self.buffer.read(cx).snapshot(cx);
 8680                for selection in &mut self.selections.all::<Point>(cx) {
 8681                    let selection_head = selection.head();
 8682                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8683                        continue;
 8684                    };
 8685
 8686                    let mut bracket_pair = None;
 8687                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8688                    let prev_chars = snapshot
 8689                        .reversed_chars_at(selection_head)
 8690                        .collect::<String>();
 8691                    for (pair, enabled) in scope.brackets() {
 8692                        if enabled
 8693                            && pair.close
 8694                            && prev_chars.starts_with(pair.start.as_str())
 8695                            && next_chars.starts_with(pair.end.as_str())
 8696                        {
 8697                            bracket_pair = Some(pair.clone());
 8698                            break;
 8699                        }
 8700                    }
 8701                    if let Some(pair) = bracket_pair {
 8702                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8703                        let autoclose_enabled =
 8704                            self.use_autoclose && snapshot_settings.use_autoclose;
 8705                        if autoclose_enabled {
 8706                            let start = snapshot.anchor_after(selection_head);
 8707                            let end = snapshot.anchor_after(selection_head);
 8708                            self.autoclose_regions.push(AutocloseRegion {
 8709                                selection_id: selection.id,
 8710                                range: start..end,
 8711                                pair,
 8712                            });
 8713                        }
 8714                    }
 8715                }
 8716            }
 8717        }
 8718        Ok(())
 8719    }
 8720
 8721    pub fn move_to_next_snippet_tabstop(
 8722        &mut self,
 8723        window: &mut Window,
 8724        cx: &mut Context<Self>,
 8725    ) -> bool {
 8726        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8727    }
 8728
 8729    pub fn move_to_prev_snippet_tabstop(
 8730        &mut self,
 8731        window: &mut Window,
 8732        cx: &mut Context<Self>,
 8733    ) -> bool {
 8734        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8735    }
 8736
 8737    pub fn move_to_snippet_tabstop(
 8738        &mut self,
 8739        bias: Bias,
 8740        window: &mut Window,
 8741        cx: &mut Context<Self>,
 8742    ) -> bool {
 8743        if let Some(mut snippet) = self.snippet_stack.pop() {
 8744            match bias {
 8745                Bias::Left => {
 8746                    if snippet.active_index > 0 {
 8747                        snippet.active_index -= 1;
 8748                    } else {
 8749                        self.snippet_stack.push(snippet);
 8750                        return false;
 8751                    }
 8752                }
 8753                Bias::Right => {
 8754                    if snippet.active_index + 1 < snippet.ranges.len() {
 8755                        snippet.active_index += 1;
 8756                    } else {
 8757                        self.snippet_stack.push(snippet);
 8758                        return false;
 8759                    }
 8760                }
 8761            }
 8762            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8763                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8764                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8765                });
 8766
 8767                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8768                    if let Some(selection) = current_ranges.first() {
 8769                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8770                    }
 8771                }
 8772
 8773                // If snippet state is not at the last tabstop, push it back on the stack
 8774                if snippet.active_index + 1 < snippet.ranges.len() {
 8775                    self.snippet_stack.push(snippet);
 8776                }
 8777                return true;
 8778            }
 8779        }
 8780
 8781        false
 8782    }
 8783
 8784    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8785        self.transact(window, cx, |this, window, cx| {
 8786            this.select_all(&SelectAll, window, cx);
 8787            this.insert("", window, cx);
 8788        });
 8789    }
 8790
 8791    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8792        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8793        self.transact(window, cx, |this, window, cx| {
 8794            this.select_autoclose_pair(window, cx);
 8795            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8796            if !this.linked_edit_ranges.is_empty() {
 8797                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8798                let snapshot = this.buffer.read(cx).snapshot(cx);
 8799
 8800                for selection in selections.iter() {
 8801                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8802                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8803                    if selection_start.buffer_id != selection_end.buffer_id {
 8804                        continue;
 8805                    }
 8806                    if let Some(ranges) =
 8807                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8808                    {
 8809                        for (buffer, entries) in ranges {
 8810                            linked_ranges.entry(buffer).or_default().extend(entries);
 8811                        }
 8812                    }
 8813                }
 8814            }
 8815
 8816            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8817            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8818            for selection in &mut selections {
 8819                if selection.is_empty() {
 8820                    let old_head = selection.head();
 8821                    let mut new_head =
 8822                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8823                            .to_point(&display_map);
 8824                    if let Some((buffer, line_buffer_range)) = display_map
 8825                        .buffer_snapshot
 8826                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8827                    {
 8828                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8829                        let indent_len = match indent_size.kind {
 8830                            IndentKind::Space => {
 8831                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8832                            }
 8833                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8834                        };
 8835                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8836                            let indent_len = indent_len.get();
 8837                            new_head = cmp::min(
 8838                                new_head,
 8839                                MultiBufferPoint::new(
 8840                                    old_head.row,
 8841                                    ((old_head.column - 1) / indent_len) * indent_len,
 8842                                ),
 8843                            );
 8844                        }
 8845                    }
 8846
 8847                    selection.set_head(new_head, SelectionGoal::None);
 8848                }
 8849            }
 8850
 8851            this.signature_help_state.set_backspace_pressed(true);
 8852            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8853                s.select(selections)
 8854            });
 8855            this.insert("", window, cx);
 8856            let empty_str: Arc<str> = Arc::from("");
 8857            for (buffer, edits) in linked_ranges {
 8858                let snapshot = buffer.read(cx).snapshot();
 8859                use text::ToPoint as TP;
 8860
 8861                let edits = edits
 8862                    .into_iter()
 8863                    .map(|range| {
 8864                        let end_point = TP::to_point(&range.end, &snapshot);
 8865                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8866
 8867                        if end_point == start_point {
 8868                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8869                                .saturating_sub(1);
 8870                            start_point =
 8871                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8872                        };
 8873
 8874                        (start_point..end_point, empty_str.clone())
 8875                    })
 8876                    .sorted_by_key(|(range, _)| range.start)
 8877                    .collect::<Vec<_>>();
 8878                buffer.update(cx, |this, cx| {
 8879                    this.edit(edits, None, cx);
 8880                })
 8881            }
 8882            this.refresh_inline_completion(true, false, window, cx);
 8883            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8884        });
 8885    }
 8886
 8887    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8888        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8889        self.transact(window, cx, |this, window, cx| {
 8890            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8891                s.move_with(|map, selection| {
 8892                    if selection.is_empty() {
 8893                        let cursor = movement::right(map, selection.head());
 8894                        selection.end = cursor;
 8895                        selection.reversed = true;
 8896                        selection.goal = SelectionGoal::None;
 8897                    }
 8898                })
 8899            });
 8900            this.insert("", window, cx);
 8901            this.refresh_inline_completion(true, false, window, cx);
 8902        });
 8903    }
 8904
 8905    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8906        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8907        if self.move_to_prev_snippet_tabstop(window, cx) {
 8908            return;
 8909        }
 8910        self.outdent(&Outdent, window, cx);
 8911    }
 8912
 8913    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8914        if self.move_to_next_snippet_tabstop(window, cx) {
 8915            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8916            return;
 8917        }
 8918        if self.read_only(cx) {
 8919            return;
 8920        }
 8921        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8922        let mut selections = self.selections.all_adjusted(cx);
 8923        let buffer = self.buffer.read(cx);
 8924        let snapshot = buffer.snapshot(cx);
 8925        let rows_iter = selections.iter().map(|s| s.head().row);
 8926        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8927
 8928        let has_some_cursor_in_whitespace = selections
 8929            .iter()
 8930            .filter(|selection| selection.is_empty())
 8931            .any(|selection| {
 8932                let cursor = selection.head();
 8933                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8934                cursor.column < current_indent.len
 8935            });
 8936
 8937        let mut edits = Vec::new();
 8938        let mut prev_edited_row = 0;
 8939        let mut row_delta = 0;
 8940        for selection in &mut selections {
 8941            if selection.start.row != prev_edited_row {
 8942                row_delta = 0;
 8943            }
 8944            prev_edited_row = selection.end.row;
 8945
 8946            // If the selection is non-empty, then increase the indentation of the selected lines.
 8947            if !selection.is_empty() {
 8948                row_delta =
 8949                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8950                continue;
 8951            }
 8952
 8953            let cursor = selection.head();
 8954            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8955            if let Some(suggested_indent) =
 8956                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8957            {
 8958                // Don't do anything if already at suggested indent
 8959                // and there is any other cursor which is not
 8960                if has_some_cursor_in_whitespace
 8961                    && cursor.column == current_indent.len
 8962                    && current_indent.len == suggested_indent.len
 8963                {
 8964                    continue;
 8965                }
 8966
 8967                // Adjust line and move cursor to suggested indent
 8968                // if cursor is not at suggested indent
 8969                if cursor.column < suggested_indent.len
 8970                    && cursor.column <= current_indent.len
 8971                    && current_indent.len <= suggested_indent.len
 8972                {
 8973                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8974                    selection.end = selection.start;
 8975                    if row_delta == 0 {
 8976                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8977                            cursor.row,
 8978                            current_indent,
 8979                            suggested_indent,
 8980                        ));
 8981                        row_delta = suggested_indent.len - current_indent.len;
 8982                    }
 8983                    continue;
 8984                }
 8985
 8986                // If current indent is more than suggested indent
 8987                // only move cursor to current indent and skip indent
 8988                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 8989                    selection.start = Point::new(cursor.row, current_indent.len);
 8990                    selection.end = selection.start;
 8991                    continue;
 8992                }
 8993            }
 8994
 8995            // Otherwise, insert a hard or soft tab.
 8996            let settings = buffer.language_settings_at(cursor, cx);
 8997            let tab_size = if settings.hard_tabs {
 8998                IndentSize::tab()
 8999            } else {
 9000                let tab_size = settings.tab_size.get();
 9001                let indent_remainder = snapshot
 9002                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9003                    .flat_map(str::chars)
 9004                    .fold(row_delta % tab_size, |counter: u32, c| {
 9005                        if c == '\t' {
 9006                            0
 9007                        } else {
 9008                            (counter + 1) % tab_size
 9009                        }
 9010                    });
 9011
 9012                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9013                IndentSize::spaces(chars_to_next_tab_stop)
 9014            };
 9015            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9016            selection.end = selection.start;
 9017            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9018            row_delta += tab_size.len;
 9019        }
 9020
 9021        self.transact(window, cx, |this, window, cx| {
 9022            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9023            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9024                s.select(selections)
 9025            });
 9026            this.refresh_inline_completion(true, false, window, cx);
 9027        });
 9028    }
 9029
 9030    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9031        if self.read_only(cx) {
 9032            return;
 9033        }
 9034        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9035        let mut selections = self.selections.all::<Point>(cx);
 9036        let mut prev_edited_row = 0;
 9037        let mut row_delta = 0;
 9038        let mut edits = Vec::new();
 9039        let buffer = self.buffer.read(cx);
 9040        let snapshot = buffer.snapshot(cx);
 9041        for selection in &mut selections {
 9042            if selection.start.row != prev_edited_row {
 9043                row_delta = 0;
 9044            }
 9045            prev_edited_row = selection.end.row;
 9046
 9047            row_delta =
 9048                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9049        }
 9050
 9051        self.transact(window, cx, |this, window, cx| {
 9052            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9053            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9054                s.select(selections)
 9055            });
 9056        });
 9057    }
 9058
 9059    fn indent_selection(
 9060        buffer: &MultiBuffer,
 9061        snapshot: &MultiBufferSnapshot,
 9062        selection: &mut Selection<Point>,
 9063        edits: &mut Vec<(Range<Point>, String)>,
 9064        delta_for_start_row: u32,
 9065        cx: &App,
 9066    ) -> u32 {
 9067        let settings = buffer.language_settings_at(selection.start, cx);
 9068        let tab_size = settings.tab_size.get();
 9069        let indent_kind = if settings.hard_tabs {
 9070            IndentKind::Tab
 9071        } else {
 9072            IndentKind::Space
 9073        };
 9074        let mut start_row = selection.start.row;
 9075        let mut end_row = selection.end.row + 1;
 9076
 9077        // If a selection ends at the beginning of a line, don't indent
 9078        // that last line.
 9079        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9080            end_row -= 1;
 9081        }
 9082
 9083        // Avoid re-indenting a row that has already been indented by a
 9084        // previous selection, but still update this selection's column
 9085        // to reflect that indentation.
 9086        if delta_for_start_row > 0 {
 9087            start_row += 1;
 9088            selection.start.column += delta_for_start_row;
 9089            if selection.end.row == selection.start.row {
 9090                selection.end.column += delta_for_start_row;
 9091            }
 9092        }
 9093
 9094        let mut delta_for_end_row = 0;
 9095        let has_multiple_rows = start_row + 1 != end_row;
 9096        for row in start_row..end_row {
 9097            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9098            let indent_delta = match (current_indent.kind, indent_kind) {
 9099                (IndentKind::Space, IndentKind::Space) => {
 9100                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9101                    IndentSize::spaces(columns_to_next_tab_stop)
 9102                }
 9103                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9104                (_, IndentKind::Tab) => IndentSize::tab(),
 9105            };
 9106
 9107            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9108                0
 9109            } else {
 9110                selection.start.column
 9111            };
 9112            let row_start = Point::new(row, start);
 9113            edits.push((
 9114                row_start..row_start,
 9115                indent_delta.chars().collect::<String>(),
 9116            ));
 9117
 9118            // Update this selection's endpoints to reflect the indentation.
 9119            if row == selection.start.row {
 9120                selection.start.column += indent_delta.len;
 9121            }
 9122            if row == selection.end.row {
 9123                selection.end.column += indent_delta.len;
 9124                delta_for_end_row = indent_delta.len;
 9125            }
 9126        }
 9127
 9128        if selection.start.row == selection.end.row {
 9129            delta_for_start_row + delta_for_end_row
 9130        } else {
 9131            delta_for_end_row
 9132        }
 9133    }
 9134
 9135    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9136        if self.read_only(cx) {
 9137            return;
 9138        }
 9139        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9140        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9141        let selections = self.selections.all::<Point>(cx);
 9142        let mut deletion_ranges = Vec::new();
 9143        let mut last_outdent = None;
 9144        {
 9145            let buffer = self.buffer.read(cx);
 9146            let snapshot = buffer.snapshot(cx);
 9147            for selection in &selections {
 9148                let settings = buffer.language_settings_at(selection.start, cx);
 9149                let tab_size = settings.tab_size.get();
 9150                let mut rows = selection.spanned_rows(false, &display_map);
 9151
 9152                // Avoid re-outdenting a row that has already been outdented by a
 9153                // previous selection.
 9154                if let Some(last_row) = last_outdent {
 9155                    if last_row == rows.start {
 9156                        rows.start = rows.start.next_row();
 9157                    }
 9158                }
 9159                let has_multiple_rows = rows.len() > 1;
 9160                for row in rows.iter_rows() {
 9161                    let indent_size = snapshot.indent_size_for_line(row);
 9162                    if indent_size.len > 0 {
 9163                        let deletion_len = match indent_size.kind {
 9164                            IndentKind::Space => {
 9165                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9166                                if columns_to_prev_tab_stop == 0 {
 9167                                    tab_size
 9168                                } else {
 9169                                    columns_to_prev_tab_stop
 9170                                }
 9171                            }
 9172                            IndentKind::Tab => 1,
 9173                        };
 9174                        let start = if has_multiple_rows
 9175                            || deletion_len > selection.start.column
 9176                            || indent_size.len < selection.start.column
 9177                        {
 9178                            0
 9179                        } else {
 9180                            selection.start.column - deletion_len
 9181                        };
 9182                        deletion_ranges.push(
 9183                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9184                        );
 9185                        last_outdent = Some(row);
 9186                    }
 9187                }
 9188            }
 9189        }
 9190
 9191        self.transact(window, cx, |this, window, cx| {
 9192            this.buffer.update(cx, |buffer, cx| {
 9193                let empty_str: Arc<str> = Arc::default();
 9194                buffer.edit(
 9195                    deletion_ranges
 9196                        .into_iter()
 9197                        .map(|range| (range, empty_str.clone())),
 9198                    None,
 9199                    cx,
 9200                );
 9201            });
 9202            let selections = this.selections.all::<usize>(cx);
 9203            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9204                s.select(selections)
 9205            });
 9206        });
 9207    }
 9208
 9209    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9210        if self.read_only(cx) {
 9211            return;
 9212        }
 9213        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9214        let selections = self
 9215            .selections
 9216            .all::<usize>(cx)
 9217            .into_iter()
 9218            .map(|s| s.range());
 9219
 9220        self.transact(window, cx, |this, window, cx| {
 9221            this.buffer.update(cx, |buffer, cx| {
 9222                buffer.autoindent_ranges(selections, cx);
 9223            });
 9224            let selections = this.selections.all::<usize>(cx);
 9225            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9226                s.select(selections)
 9227            });
 9228        });
 9229    }
 9230
 9231    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9232        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9233        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9234        let selections = self.selections.all::<Point>(cx);
 9235
 9236        let mut new_cursors = Vec::new();
 9237        let mut edit_ranges = Vec::new();
 9238        let mut selections = selections.iter().peekable();
 9239        while let Some(selection) = selections.next() {
 9240            let mut rows = selection.spanned_rows(false, &display_map);
 9241            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9242
 9243            // Accumulate contiguous regions of rows that we want to delete.
 9244            while let Some(next_selection) = selections.peek() {
 9245                let next_rows = next_selection.spanned_rows(false, &display_map);
 9246                if next_rows.start <= rows.end {
 9247                    rows.end = next_rows.end;
 9248                    selections.next().unwrap();
 9249                } else {
 9250                    break;
 9251                }
 9252            }
 9253
 9254            let buffer = &display_map.buffer_snapshot;
 9255            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9256            let edit_end;
 9257            let cursor_buffer_row;
 9258            if buffer.max_point().row >= rows.end.0 {
 9259                // If there's a line after the range, delete the \n from the end of the row range
 9260                // and position the cursor on the next line.
 9261                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9262                cursor_buffer_row = rows.end;
 9263            } else {
 9264                // If there isn't a line after the range, delete the \n from the line before the
 9265                // start of the row range and position the cursor there.
 9266                edit_start = edit_start.saturating_sub(1);
 9267                edit_end = buffer.len();
 9268                cursor_buffer_row = rows.start.previous_row();
 9269            }
 9270
 9271            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9272            *cursor.column_mut() =
 9273                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9274
 9275            new_cursors.push((
 9276                selection.id,
 9277                buffer.anchor_after(cursor.to_point(&display_map)),
 9278            ));
 9279            edit_ranges.push(edit_start..edit_end);
 9280        }
 9281
 9282        self.transact(window, cx, |this, window, cx| {
 9283            let buffer = this.buffer.update(cx, |buffer, cx| {
 9284                let empty_str: Arc<str> = Arc::default();
 9285                buffer.edit(
 9286                    edit_ranges
 9287                        .into_iter()
 9288                        .map(|range| (range, empty_str.clone())),
 9289                    None,
 9290                    cx,
 9291                );
 9292                buffer.snapshot(cx)
 9293            });
 9294            let new_selections = new_cursors
 9295                .into_iter()
 9296                .map(|(id, cursor)| {
 9297                    let cursor = cursor.to_point(&buffer);
 9298                    Selection {
 9299                        id,
 9300                        start: cursor,
 9301                        end: cursor,
 9302                        reversed: false,
 9303                        goal: SelectionGoal::None,
 9304                    }
 9305                })
 9306                .collect();
 9307
 9308            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9309                s.select(new_selections);
 9310            });
 9311        });
 9312    }
 9313
 9314    pub fn join_lines_impl(
 9315        &mut self,
 9316        insert_whitespace: bool,
 9317        window: &mut Window,
 9318        cx: &mut Context<Self>,
 9319    ) {
 9320        if self.read_only(cx) {
 9321            return;
 9322        }
 9323        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9324        for selection in self.selections.all::<Point>(cx) {
 9325            let start = MultiBufferRow(selection.start.row);
 9326            // Treat single line selections as if they include the next line. Otherwise this action
 9327            // would do nothing for single line selections individual cursors.
 9328            let end = if selection.start.row == selection.end.row {
 9329                MultiBufferRow(selection.start.row + 1)
 9330            } else {
 9331                MultiBufferRow(selection.end.row)
 9332            };
 9333
 9334            if let Some(last_row_range) = row_ranges.last_mut() {
 9335                if start <= last_row_range.end {
 9336                    last_row_range.end = end;
 9337                    continue;
 9338                }
 9339            }
 9340            row_ranges.push(start..end);
 9341        }
 9342
 9343        let snapshot = self.buffer.read(cx).snapshot(cx);
 9344        let mut cursor_positions = Vec::new();
 9345        for row_range in &row_ranges {
 9346            let anchor = snapshot.anchor_before(Point::new(
 9347                row_range.end.previous_row().0,
 9348                snapshot.line_len(row_range.end.previous_row()),
 9349            ));
 9350            cursor_positions.push(anchor..anchor);
 9351        }
 9352
 9353        self.transact(window, cx, |this, window, cx| {
 9354            for row_range in row_ranges.into_iter().rev() {
 9355                for row in row_range.iter_rows().rev() {
 9356                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9357                    let next_line_row = row.next_row();
 9358                    let indent = snapshot.indent_size_for_line(next_line_row);
 9359                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9360
 9361                    let replace =
 9362                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9363                            " "
 9364                        } else {
 9365                            ""
 9366                        };
 9367
 9368                    this.buffer.update(cx, |buffer, cx| {
 9369                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9370                    });
 9371                }
 9372            }
 9373
 9374            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9375                s.select_anchor_ranges(cursor_positions)
 9376            });
 9377        });
 9378    }
 9379
 9380    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9381        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9382        self.join_lines_impl(true, window, cx);
 9383    }
 9384
 9385    pub fn sort_lines_case_sensitive(
 9386        &mut self,
 9387        _: &SortLinesCaseSensitive,
 9388        window: &mut Window,
 9389        cx: &mut Context<Self>,
 9390    ) {
 9391        self.manipulate_lines(window, cx, |lines| lines.sort())
 9392    }
 9393
 9394    pub fn sort_lines_case_insensitive(
 9395        &mut self,
 9396        _: &SortLinesCaseInsensitive,
 9397        window: &mut Window,
 9398        cx: &mut Context<Self>,
 9399    ) {
 9400        self.manipulate_lines(window, cx, |lines| {
 9401            lines.sort_by_key(|line| line.to_lowercase())
 9402        })
 9403    }
 9404
 9405    pub fn unique_lines_case_insensitive(
 9406        &mut self,
 9407        _: &UniqueLinesCaseInsensitive,
 9408        window: &mut Window,
 9409        cx: &mut Context<Self>,
 9410    ) {
 9411        self.manipulate_lines(window, cx, |lines| {
 9412            let mut seen = HashSet::default();
 9413            lines.retain(|line| seen.insert(line.to_lowercase()));
 9414        })
 9415    }
 9416
 9417    pub fn unique_lines_case_sensitive(
 9418        &mut self,
 9419        _: &UniqueLinesCaseSensitive,
 9420        window: &mut Window,
 9421        cx: &mut Context<Self>,
 9422    ) {
 9423        self.manipulate_lines(window, cx, |lines| {
 9424            let mut seen = HashSet::default();
 9425            lines.retain(|line| seen.insert(*line));
 9426        })
 9427    }
 9428
 9429    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9430        let Some(project) = self.project.clone() else {
 9431            return;
 9432        };
 9433        self.reload(project, window, cx)
 9434            .detach_and_notify_err(window, cx);
 9435    }
 9436
 9437    pub fn restore_file(
 9438        &mut self,
 9439        _: &::git::RestoreFile,
 9440        window: &mut Window,
 9441        cx: &mut Context<Self>,
 9442    ) {
 9443        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9444        let mut buffer_ids = HashSet::default();
 9445        let snapshot = self.buffer().read(cx).snapshot(cx);
 9446        for selection in self.selections.all::<usize>(cx) {
 9447            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9448        }
 9449
 9450        let buffer = self.buffer().read(cx);
 9451        let ranges = buffer_ids
 9452            .into_iter()
 9453            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9454            .collect::<Vec<_>>();
 9455
 9456        self.restore_hunks_in_ranges(ranges, window, cx);
 9457    }
 9458
 9459    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9460        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9461        let selections = self
 9462            .selections
 9463            .all(cx)
 9464            .into_iter()
 9465            .map(|s| s.range())
 9466            .collect();
 9467        self.restore_hunks_in_ranges(selections, window, cx);
 9468    }
 9469
 9470    pub fn restore_hunks_in_ranges(
 9471        &mut self,
 9472        ranges: Vec<Range<Point>>,
 9473        window: &mut Window,
 9474        cx: &mut Context<Editor>,
 9475    ) {
 9476        let mut revert_changes = HashMap::default();
 9477        let chunk_by = self
 9478            .snapshot(window, cx)
 9479            .hunks_for_ranges(ranges)
 9480            .into_iter()
 9481            .chunk_by(|hunk| hunk.buffer_id);
 9482        for (buffer_id, hunks) in &chunk_by {
 9483            let hunks = hunks.collect::<Vec<_>>();
 9484            for hunk in &hunks {
 9485                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9486            }
 9487            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9488        }
 9489        drop(chunk_by);
 9490        if !revert_changes.is_empty() {
 9491            self.transact(window, cx, |editor, window, cx| {
 9492                editor.restore(revert_changes, window, cx);
 9493            });
 9494        }
 9495    }
 9496
 9497    pub fn open_active_item_in_terminal(
 9498        &mut self,
 9499        _: &OpenInTerminal,
 9500        window: &mut Window,
 9501        cx: &mut Context<Self>,
 9502    ) {
 9503        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9504            let project_path = buffer.read(cx).project_path(cx)?;
 9505            let project = self.project.as_ref()?.read(cx);
 9506            let entry = project.entry_for_path(&project_path, cx)?;
 9507            let parent = match &entry.canonical_path {
 9508                Some(canonical_path) => canonical_path.to_path_buf(),
 9509                None => project.absolute_path(&project_path, cx)?,
 9510            }
 9511            .parent()?
 9512            .to_path_buf();
 9513            Some(parent)
 9514        }) {
 9515            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9516        }
 9517    }
 9518
 9519    fn set_breakpoint_context_menu(
 9520        &mut self,
 9521        display_row: DisplayRow,
 9522        position: Option<Anchor>,
 9523        clicked_point: gpui::Point<Pixels>,
 9524        window: &mut Window,
 9525        cx: &mut Context<Self>,
 9526    ) {
 9527        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9528            return;
 9529        }
 9530        let source = self
 9531            .buffer
 9532            .read(cx)
 9533            .snapshot(cx)
 9534            .anchor_before(Point::new(display_row.0, 0u32));
 9535
 9536        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9537
 9538        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9539            self,
 9540            source,
 9541            clicked_point,
 9542            context_menu,
 9543            window,
 9544            cx,
 9545        );
 9546    }
 9547
 9548    fn add_edit_breakpoint_block(
 9549        &mut self,
 9550        anchor: Anchor,
 9551        breakpoint: &Breakpoint,
 9552        edit_action: BreakpointPromptEditAction,
 9553        window: &mut Window,
 9554        cx: &mut Context<Self>,
 9555    ) {
 9556        let weak_editor = cx.weak_entity();
 9557        let bp_prompt = cx.new(|cx| {
 9558            BreakpointPromptEditor::new(
 9559                weak_editor,
 9560                anchor,
 9561                breakpoint.clone(),
 9562                edit_action,
 9563                window,
 9564                cx,
 9565            )
 9566        });
 9567
 9568        let height = bp_prompt.update(cx, |this, cx| {
 9569            this.prompt
 9570                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9571        });
 9572        let cloned_prompt = bp_prompt.clone();
 9573        let blocks = vec![BlockProperties {
 9574            style: BlockStyle::Sticky,
 9575            placement: BlockPlacement::Above(anchor),
 9576            height: Some(height),
 9577            render: Arc::new(move |cx| {
 9578                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9579                cloned_prompt.clone().into_any_element()
 9580            }),
 9581            priority: 0,
 9582            render_in_minimap: true,
 9583        }];
 9584
 9585        let focus_handle = bp_prompt.focus_handle(cx);
 9586        window.focus(&focus_handle);
 9587
 9588        let block_ids = self.insert_blocks(blocks, None, cx);
 9589        bp_prompt.update(cx, |prompt, _| {
 9590            prompt.add_block_ids(block_ids);
 9591        });
 9592    }
 9593
 9594    pub(crate) fn breakpoint_at_row(
 9595        &self,
 9596        row: u32,
 9597        window: &mut Window,
 9598        cx: &mut Context<Self>,
 9599    ) -> Option<(Anchor, Breakpoint)> {
 9600        let snapshot = self.snapshot(window, cx);
 9601        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9602
 9603        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9604    }
 9605
 9606    pub(crate) fn breakpoint_at_anchor(
 9607        &self,
 9608        breakpoint_position: Anchor,
 9609        snapshot: &EditorSnapshot,
 9610        cx: &mut Context<Self>,
 9611    ) -> Option<(Anchor, Breakpoint)> {
 9612        let project = self.project.clone()?;
 9613
 9614        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9615            snapshot
 9616                .buffer_snapshot
 9617                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9618        })?;
 9619
 9620        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9621        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9622        let buffer_snapshot = buffer.read(cx).snapshot();
 9623
 9624        let row = buffer_snapshot
 9625            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9626            .row;
 9627
 9628        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9629        let anchor_end = snapshot
 9630            .buffer_snapshot
 9631            .anchor_after(Point::new(row, line_len));
 9632
 9633        let bp = self
 9634            .breakpoint_store
 9635            .as_ref()?
 9636            .read_with(cx, |breakpoint_store, cx| {
 9637                breakpoint_store
 9638                    .breakpoints(
 9639                        &buffer,
 9640                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9641                        &buffer_snapshot,
 9642                        cx,
 9643                    )
 9644                    .next()
 9645                    .and_then(|(bp, _)| {
 9646                        let breakpoint_row = buffer_snapshot
 9647                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9648                            .row;
 9649
 9650                        if breakpoint_row == row {
 9651                            snapshot
 9652                                .buffer_snapshot
 9653                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9654                                .map(|position| (position, bp.bp.clone()))
 9655                        } else {
 9656                            None
 9657                        }
 9658                    })
 9659            });
 9660        bp
 9661    }
 9662
 9663    pub fn edit_log_breakpoint(
 9664        &mut self,
 9665        _: &EditLogBreakpoint,
 9666        window: &mut Window,
 9667        cx: &mut Context<Self>,
 9668    ) {
 9669        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9670            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9671                message: None,
 9672                state: BreakpointState::Enabled,
 9673                condition: None,
 9674                hit_condition: None,
 9675            });
 9676
 9677            self.add_edit_breakpoint_block(
 9678                anchor,
 9679                &breakpoint,
 9680                BreakpointPromptEditAction::Log,
 9681                window,
 9682                cx,
 9683            );
 9684        }
 9685    }
 9686
 9687    fn breakpoints_at_cursors(
 9688        &self,
 9689        window: &mut Window,
 9690        cx: &mut Context<Self>,
 9691    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9692        let snapshot = self.snapshot(window, cx);
 9693        let cursors = self
 9694            .selections
 9695            .disjoint_anchors()
 9696            .into_iter()
 9697            .map(|selection| {
 9698                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9699
 9700                let breakpoint_position = self
 9701                    .breakpoint_at_row(cursor_position.row, window, cx)
 9702                    .map(|bp| bp.0)
 9703                    .unwrap_or_else(|| {
 9704                        snapshot
 9705                            .display_snapshot
 9706                            .buffer_snapshot
 9707                            .anchor_after(Point::new(cursor_position.row, 0))
 9708                    });
 9709
 9710                let breakpoint = self
 9711                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9712                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9713
 9714                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9715            })
 9716            // 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.
 9717            .collect::<HashMap<Anchor, _>>();
 9718
 9719        cursors.into_iter().collect()
 9720    }
 9721
 9722    pub fn enable_breakpoint(
 9723        &mut self,
 9724        _: &crate::actions::EnableBreakpoint,
 9725        window: &mut Window,
 9726        cx: &mut Context<Self>,
 9727    ) {
 9728        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9729            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9730                continue;
 9731            };
 9732            self.edit_breakpoint_at_anchor(
 9733                anchor,
 9734                breakpoint,
 9735                BreakpointEditAction::InvertState,
 9736                cx,
 9737            );
 9738        }
 9739    }
 9740
 9741    pub fn disable_breakpoint(
 9742        &mut self,
 9743        _: &crate::actions::DisableBreakpoint,
 9744        window: &mut Window,
 9745        cx: &mut Context<Self>,
 9746    ) {
 9747        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9748            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9749                continue;
 9750            };
 9751            self.edit_breakpoint_at_anchor(
 9752                anchor,
 9753                breakpoint,
 9754                BreakpointEditAction::InvertState,
 9755                cx,
 9756            );
 9757        }
 9758    }
 9759
 9760    pub fn toggle_breakpoint(
 9761        &mut self,
 9762        _: &crate::actions::ToggleBreakpoint,
 9763        window: &mut Window,
 9764        cx: &mut Context<Self>,
 9765    ) {
 9766        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9767            if let Some(breakpoint) = breakpoint {
 9768                self.edit_breakpoint_at_anchor(
 9769                    anchor,
 9770                    breakpoint,
 9771                    BreakpointEditAction::Toggle,
 9772                    cx,
 9773                );
 9774            } else {
 9775                self.edit_breakpoint_at_anchor(
 9776                    anchor,
 9777                    Breakpoint::new_standard(),
 9778                    BreakpointEditAction::Toggle,
 9779                    cx,
 9780                );
 9781            }
 9782        }
 9783    }
 9784
 9785    pub fn edit_breakpoint_at_anchor(
 9786        &mut self,
 9787        breakpoint_position: Anchor,
 9788        breakpoint: Breakpoint,
 9789        edit_action: BreakpointEditAction,
 9790        cx: &mut Context<Self>,
 9791    ) {
 9792        let Some(breakpoint_store) = &self.breakpoint_store else {
 9793            return;
 9794        };
 9795
 9796        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9797            if breakpoint_position == Anchor::min() {
 9798                self.buffer()
 9799                    .read(cx)
 9800                    .excerpt_buffer_ids()
 9801                    .into_iter()
 9802                    .next()
 9803            } else {
 9804                None
 9805            }
 9806        }) else {
 9807            return;
 9808        };
 9809
 9810        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9811            return;
 9812        };
 9813
 9814        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9815            breakpoint_store.toggle_breakpoint(
 9816                buffer,
 9817                BreakpointWithPosition {
 9818                    position: breakpoint_position.text_anchor,
 9819                    bp: breakpoint,
 9820                },
 9821                edit_action,
 9822                cx,
 9823            );
 9824        });
 9825
 9826        cx.notify();
 9827    }
 9828
 9829    #[cfg(any(test, feature = "test-support"))]
 9830    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9831        self.breakpoint_store.clone()
 9832    }
 9833
 9834    pub fn prepare_restore_change(
 9835        &self,
 9836        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9837        hunk: &MultiBufferDiffHunk,
 9838        cx: &mut App,
 9839    ) -> Option<()> {
 9840        if hunk.is_created_file() {
 9841            return None;
 9842        }
 9843        let buffer = self.buffer.read(cx);
 9844        let diff = buffer.diff_for(hunk.buffer_id)?;
 9845        let buffer = buffer.buffer(hunk.buffer_id)?;
 9846        let buffer = buffer.read(cx);
 9847        let original_text = diff
 9848            .read(cx)
 9849            .base_text()
 9850            .as_rope()
 9851            .slice(hunk.diff_base_byte_range.clone());
 9852        let buffer_snapshot = buffer.snapshot();
 9853        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9854        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9855            probe
 9856                .0
 9857                .start
 9858                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9859                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9860        }) {
 9861            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9862            Some(())
 9863        } else {
 9864            None
 9865        }
 9866    }
 9867
 9868    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9869        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9870    }
 9871
 9872    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9873        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9874    }
 9875
 9876    fn manipulate_lines<Fn>(
 9877        &mut self,
 9878        window: &mut Window,
 9879        cx: &mut Context<Self>,
 9880        mut callback: Fn,
 9881    ) where
 9882        Fn: FnMut(&mut Vec<&str>),
 9883    {
 9884        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9885
 9886        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9887        let buffer = self.buffer.read(cx).snapshot(cx);
 9888
 9889        let mut edits = Vec::new();
 9890
 9891        let selections = self.selections.all::<Point>(cx);
 9892        let mut selections = selections.iter().peekable();
 9893        let mut contiguous_row_selections = Vec::new();
 9894        let mut new_selections = Vec::new();
 9895        let mut added_lines = 0;
 9896        let mut removed_lines = 0;
 9897
 9898        while let Some(selection) = selections.next() {
 9899            let (start_row, end_row) = consume_contiguous_rows(
 9900                &mut contiguous_row_selections,
 9901                selection,
 9902                &display_map,
 9903                &mut selections,
 9904            );
 9905
 9906            let start_point = Point::new(start_row.0, 0);
 9907            let end_point = Point::new(
 9908                end_row.previous_row().0,
 9909                buffer.line_len(end_row.previous_row()),
 9910            );
 9911            let text = buffer
 9912                .text_for_range(start_point..end_point)
 9913                .collect::<String>();
 9914
 9915            let mut lines = text.split('\n').collect_vec();
 9916
 9917            let lines_before = lines.len();
 9918            callback(&mut lines);
 9919            let lines_after = lines.len();
 9920
 9921            edits.push((start_point..end_point, lines.join("\n")));
 9922
 9923            // Selections must change based on added and removed line count
 9924            let start_row =
 9925                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9926            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9927            new_selections.push(Selection {
 9928                id: selection.id,
 9929                start: start_row,
 9930                end: end_row,
 9931                goal: SelectionGoal::None,
 9932                reversed: selection.reversed,
 9933            });
 9934
 9935            if lines_after > lines_before {
 9936                added_lines += lines_after - lines_before;
 9937            } else if lines_before > lines_after {
 9938                removed_lines += lines_before - lines_after;
 9939            }
 9940        }
 9941
 9942        self.transact(window, cx, |this, window, cx| {
 9943            let buffer = this.buffer.update(cx, |buffer, cx| {
 9944                buffer.edit(edits, None, cx);
 9945                buffer.snapshot(cx)
 9946            });
 9947
 9948            // Recalculate offsets on newly edited buffer
 9949            let new_selections = new_selections
 9950                .iter()
 9951                .map(|s| {
 9952                    let start_point = Point::new(s.start.0, 0);
 9953                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9954                    Selection {
 9955                        id: s.id,
 9956                        start: buffer.point_to_offset(start_point),
 9957                        end: buffer.point_to_offset(end_point),
 9958                        goal: s.goal,
 9959                        reversed: s.reversed,
 9960                    }
 9961                })
 9962                .collect();
 9963
 9964            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9965                s.select(new_selections);
 9966            });
 9967
 9968            this.request_autoscroll(Autoscroll::fit(), cx);
 9969        });
 9970    }
 9971
 9972    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9973        self.manipulate_text(window, cx, |text| {
 9974            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9975            if has_upper_case_characters {
 9976                text.to_lowercase()
 9977            } else {
 9978                text.to_uppercase()
 9979            }
 9980        })
 9981    }
 9982
 9983    pub fn convert_to_upper_case(
 9984        &mut self,
 9985        _: &ConvertToUpperCase,
 9986        window: &mut Window,
 9987        cx: &mut Context<Self>,
 9988    ) {
 9989        self.manipulate_text(window, cx, |text| text.to_uppercase())
 9990    }
 9991
 9992    pub fn convert_to_lower_case(
 9993        &mut self,
 9994        _: &ConvertToLowerCase,
 9995        window: &mut Window,
 9996        cx: &mut Context<Self>,
 9997    ) {
 9998        self.manipulate_text(window, cx, |text| text.to_lowercase())
 9999    }
10000
10001    pub fn convert_to_title_case(
10002        &mut self,
10003        _: &ConvertToTitleCase,
10004        window: &mut Window,
10005        cx: &mut Context<Self>,
10006    ) {
10007        self.manipulate_text(window, cx, |text| {
10008            text.split('\n')
10009                .map(|line| line.to_case(Case::Title))
10010                .join("\n")
10011        })
10012    }
10013
10014    pub fn convert_to_snake_case(
10015        &mut self,
10016        _: &ConvertToSnakeCase,
10017        window: &mut Window,
10018        cx: &mut Context<Self>,
10019    ) {
10020        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10021    }
10022
10023    pub fn convert_to_kebab_case(
10024        &mut self,
10025        _: &ConvertToKebabCase,
10026        window: &mut Window,
10027        cx: &mut Context<Self>,
10028    ) {
10029        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10030    }
10031
10032    pub fn convert_to_upper_camel_case(
10033        &mut self,
10034        _: &ConvertToUpperCamelCase,
10035        window: &mut Window,
10036        cx: &mut Context<Self>,
10037    ) {
10038        self.manipulate_text(window, cx, |text| {
10039            text.split('\n')
10040                .map(|line| line.to_case(Case::UpperCamel))
10041                .join("\n")
10042        })
10043    }
10044
10045    pub fn convert_to_lower_camel_case(
10046        &mut self,
10047        _: &ConvertToLowerCamelCase,
10048        window: &mut Window,
10049        cx: &mut Context<Self>,
10050    ) {
10051        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10052    }
10053
10054    pub fn convert_to_opposite_case(
10055        &mut self,
10056        _: &ConvertToOppositeCase,
10057        window: &mut Window,
10058        cx: &mut Context<Self>,
10059    ) {
10060        self.manipulate_text(window, cx, |text| {
10061            text.chars()
10062                .fold(String::with_capacity(text.len()), |mut t, c| {
10063                    if c.is_uppercase() {
10064                        t.extend(c.to_lowercase());
10065                    } else {
10066                        t.extend(c.to_uppercase());
10067                    }
10068                    t
10069                })
10070        })
10071    }
10072
10073    pub fn convert_to_rot13(
10074        &mut self,
10075        _: &ConvertToRot13,
10076        window: &mut Window,
10077        cx: &mut Context<Self>,
10078    ) {
10079        self.manipulate_text(window, cx, |text| {
10080            text.chars()
10081                .map(|c| match c {
10082                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10083                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10084                    _ => c,
10085                })
10086                .collect()
10087        })
10088    }
10089
10090    pub fn convert_to_rot47(
10091        &mut self,
10092        _: &ConvertToRot47,
10093        window: &mut Window,
10094        cx: &mut Context<Self>,
10095    ) {
10096        self.manipulate_text(window, cx, |text| {
10097            text.chars()
10098                .map(|c| {
10099                    let code_point = c as u32;
10100                    if code_point >= 33 && code_point <= 126 {
10101                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10102                    }
10103                    c
10104                })
10105                .collect()
10106        })
10107    }
10108
10109    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10110    where
10111        Fn: FnMut(&str) -> String,
10112    {
10113        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10114        let buffer = self.buffer.read(cx).snapshot(cx);
10115
10116        let mut new_selections = Vec::new();
10117        let mut edits = Vec::new();
10118        let mut selection_adjustment = 0i32;
10119
10120        for selection in self.selections.all::<usize>(cx) {
10121            let selection_is_empty = selection.is_empty();
10122
10123            let (start, end) = if selection_is_empty {
10124                let word_range = movement::surrounding_word(
10125                    &display_map,
10126                    selection.start.to_display_point(&display_map),
10127                );
10128                let start = word_range.start.to_offset(&display_map, Bias::Left);
10129                let end = word_range.end.to_offset(&display_map, Bias::Left);
10130                (start, end)
10131            } else {
10132                (selection.start, selection.end)
10133            };
10134
10135            let text = buffer.text_for_range(start..end).collect::<String>();
10136            let old_length = text.len() as i32;
10137            let text = callback(&text);
10138
10139            new_selections.push(Selection {
10140                start: (start as i32 - selection_adjustment) as usize,
10141                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10142                goal: SelectionGoal::None,
10143                ..selection
10144            });
10145
10146            selection_adjustment += old_length - text.len() as i32;
10147
10148            edits.push((start..end, text));
10149        }
10150
10151        self.transact(window, cx, |this, window, cx| {
10152            this.buffer.update(cx, |buffer, cx| {
10153                buffer.edit(edits, None, cx);
10154            });
10155
10156            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10157                s.select(new_selections);
10158            });
10159
10160            this.request_autoscroll(Autoscroll::fit(), cx);
10161        });
10162    }
10163
10164    pub fn duplicate(
10165        &mut self,
10166        upwards: bool,
10167        whole_lines: bool,
10168        window: &mut Window,
10169        cx: &mut Context<Self>,
10170    ) {
10171        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10172
10173        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10174        let buffer = &display_map.buffer_snapshot;
10175        let selections = self.selections.all::<Point>(cx);
10176
10177        let mut edits = Vec::new();
10178        let mut selections_iter = selections.iter().peekable();
10179        while let Some(selection) = selections_iter.next() {
10180            let mut rows = selection.spanned_rows(false, &display_map);
10181            // duplicate line-wise
10182            if whole_lines || selection.start == selection.end {
10183                // Avoid duplicating the same lines twice.
10184                while let Some(next_selection) = selections_iter.peek() {
10185                    let next_rows = next_selection.spanned_rows(false, &display_map);
10186                    if next_rows.start < rows.end {
10187                        rows.end = next_rows.end;
10188                        selections_iter.next().unwrap();
10189                    } else {
10190                        break;
10191                    }
10192                }
10193
10194                // Copy the text from the selected row region and splice it either at the start
10195                // or end of the region.
10196                let start = Point::new(rows.start.0, 0);
10197                let end = Point::new(
10198                    rows.end.previous_row().0,
10199                    buffer.line_len(rows.end.previous_row()),
10200                );
10201                let text = buffer
10202                    .text_for_range(start..end)
10203                    .chain(Some("\n"))
10204                    .collect::<String>();
10205                let insert_location = if upwards {
10206                    Point::new(rows.end.0, 0)
10207                } else {
10208                    start
10209                };
10210                edits.push((insert_location..insert_location, text));
10211            } else {
10212                // duplicate character-wise
10213                let start = selection.start;
10214                let end = selection.end;
10215                let text = buffer.text_for_range(start..end).collect::<String>();
10216                edits.push((selection.end..selection.end, text));
10217            }
10218        }
10219
10220        self.transact(window, cx, |this, _, cx| {
10221            this.buffer.update(cx, |buffer, cx| {
10222                buffer.edit(edits, None, cx);
10223            });
10224
10225            this.request_autoscroll(Autoscroll::fit(), cx);
10226        });
10227    }
10228
10229    pub fn duplicate_line_up(
10230        &mut self,
10231        _: &DuplicateLineUp,
10232        window: &mut Window,
10233        cx: &mut Context<Self>,
10234    ) {
10235        self.duplicate(true, true, window, cx);
10236    }
10237
10238    pub fn duplicate_line_down(
10239        &mut self,
10240        _: &DuplicateLineDown,
10241        window: &mut Window,
10242        cx: &mut Context<Self>,
10243    ) {
10244        self.duplicate(false, true, window, cx);
10245    }
10246
10247    pub fn duplicate_selection(
10248        &mut self,
10249        _: &DuplicateSelection,
10250        window: &mut Window,
10251        cx: &mut Context<Self>,
10252    ) {
10253        self.duplicate(false, false, window, cx);
10254    }
10255
10256    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10257        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10258
10259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10260        let buffer = self.buffer.read(cx).snapshot(cx);
10261
10262        let mut edits = Vec::new();
10263        let mut unfold_ranges = Vec::new();
10264        let mut refold_creases = Vec::new();
10265
10266        let selections = self.selections.all::<Point>(cx);
10267        let mut selections = selections.iter().peekable();
10268        let mut contiguous_row_selections = Vec::new();
10269        let mut new_selections = Vec::new();
10270
10271        while let Some(selection) = selections.next() {
10272            // Find all the selections that span a contiguous row range
10273            let (start_row, end_row) = consume_contiguous_rows(
10274                &mut contiguous_row_selections,
10275                selection,
10276                &display_map,
10277                &mut selections,
10278            );
10279
10280            // Move the text spanned by the row range to be before the line preceding the row range
10281            if start_row.0 > 0 {
10282                let range_to_move = Point::new(
10283                    start_row.previous_row().0,
10284                    buffer.line_len(start_row.previous_row()),
10285                )
10286                    ..Point::new(
10287                        end_row.previous_row().0,
10288                        buffer.line_len(end_row.previous_row()),
10289                    );
10290                let insertion_point = display_map
10291                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10292                    .0;
10293
10294                // Don't move lines across excerpts
10295                if buffer
10296                    .excerpt_containing(insertion_point..range_to_move.end)
10297                    .is_some()
10298                {
10299                    let text = buffer
10300                        .text_for_range(range_to_move.clone())
10301                        .flat_map(|s| s.chars())
10302                        .skip(1)
10303                        .chain(['\n'])
10304                        .collect::<String>();
10305
10306                    edits.push((
10307                        buffer.anchor_after(range_to_move.start)
10308                            ..buffer.anchor_before(range_to_move.end),
10309                        String::new(),
10310                    ));
10311                    let insertion_anchor = buffer.anchor_after(insertion_point);
10312                    edits.push((insertion_anchor..insertion_anchor, text));
10313
10314                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10315
10316                    // Move selections up
10317                    new_selections.extend(contiguous_row_selections.drain(..).map(
10318                        |mut selection| {
10319                            selection.start.row -= row_delta;
10320                            selection.end.row -= row_delta;
10321                            selection
10322                        },
10323                    ));
10324
10325                    // Move folds up
10326                    unfold_ranges.push(range_to_move.clone());
10327                    for fold in display_map.folds_in_range(
10328                        buffer.anchor_before(range_to_move.start)
10329                            ..buffer.anchor_after(range_to_move.end),
10330                    ) {
10331                        let mut start = fold.range.start.to_point(&buffer);
10332                        let mut end = fold.range.end.to_point(&buffer);
10333                        start.row -= row_delta;
10334                        end.row -= row_delta;
10335                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10336                    }
10337                }
10338            }
10339
10340            // If we didn't move line(s), preserve the existing selections
10341            new_selections.append(&mut contiguous_row_selections);
10342        }
10343
10344        self.transact(window, cx, |this, window, cx| {
10345            this.unfold_ranges(&unfold_ranges, true, true, cx);
10346            this.buffer.update(cx, |buffer, cx| {
10347                for (range, text) in edits {
10348                    buffer.edit([(range, text)], None, cx);
10349                }
10350            });
10351            this.fold_creases(refold_creases, true, window, cx);
10352            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10353                s.select(new_selections);
10354            })
10355        });
10356    }
10357
10358    pub fn move_line_down(
10359        &mut self,
10360        _: &MoveLineDown,
10361        window: &mut Window,
10362        cx: &mut Context<Self>,
10363    ) {
10364        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10365
10366        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10367        let buffer = self.buffer.read(cx).snapshot(cx);
10368
10369        let mut edits = Vec::new();
10370        let mut unfold_ranges = Vec::new();
10371        let mut refold_creases = Vec::new();
10372
10373        let selections = self.selections.all::<Point>(cx);
10374        let mut selections = selections.iter().peekable();
10375        let mut contiguous_row_selections = Vec::new();
10376        let mut new_selections = Vec::new();
10377
10378        while let Some(selection) = selections.next() {
10379            // Find all the selections that span a contiguous row range
10380            let (start_row, end_row) = consume_contiguous_rows(
10381                &mut contiguous_row_selections,
10382                selection,
10383                &display_map,
10384                &mut selections,
10385            );
10386
10387            // Move the text spanned by the row range to be after the last line of the row range
10388            if end_row.0 <= buffer.max_point().row {
10389                let range_to_move =
10390                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10391                let insertion_point = display_map
10392                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10393                    .0;
10394
10395                // Don't move lines across excerpt boundaries
10396                if buffer
10397                    .excerpt_containing(range_to_move.start..insertion_point)
10398                    .is_some()
10399                {
10400                    let mut text = String::from("\n");
10401                    text.extend(buffer.text_for_range(range_to_move.clone()));
10402                    text.pop(); // Drop trailing newline
10403                    edits.push((
10404                        buffer.anchor_after(range_to_move.start)
10405                            ..buffer.anchor_before(range_to_move.end),
10406                        String::new(),
10407                    ));
10408                    let insertion_anchor = buffer.anchor_after(insertion_point);
10409                    edits.push((insertion_anchor..insertion_anchor, text));
10410
10411                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10412
10413                    // Move selections down
10414                    new_selections.extend(contiguous_row_selections.drain(..).map(
10415                        |mut selection| {
10416                            selection.start.row += row_delta;
10417                            selection.end.row += row_delta;
10418                            selection
10419                        },
10420                    ));
10421
10422                    // Move folds down
10423                    unfold_ranges.push(range_to_move.clone());
10424                    for fold in display_map.folds_in_range(
10425                        buffer.anchor_before(range_to_move.start)
10426                            ..buffer.anchor_after(range_to_move.end),
10427                    ) {
10428                        let mut start = fold.range.start.to_point(&buffer);
10429                        let mut end = fold.range.end.to_point(&buffer);
10430                        start.row += row_delta;
10431                        end.row += row_delta;
10432                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10433                    }
10434                }
10435            }
10436
10437            // If we didn't move line(s), preserve the existing selections
10438            new_selections.append(&mut contiguous_row_selections);
10439        }
10440
10441        self.transact(window, cx, |this, window, cx| {
10442            this.unfold_ranges(&unfold_ranges, true, true, cx);
10443            this.buffer.update(cx, |buffer, cx| {
10444                for (range, text) in edits {
10445                    buffer.edit([(range, text)], None, cx);
10446                }
10447            });
10448            this.fold_creases(refold_creases, true, window, cx);
10449            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10450                s.select(new_selections)
10451            });
10452        });
10453    }
10454
10455    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10456        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10457        let text_layout_details = &self.text_layout_details(window);
10458        self.transact(window, cx, |this, window, cx| {
10459            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10460                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10461                s.move_with(|display_map, selection| {
10462                    if !selection.is_empty() {
10463                        return;
10464                    }
10465
10466                    let mut head = selection.head();
10467                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10468                    if head.column() == display_map.line_len(head.row()) {
10469                        transpose_offset = display_map
10470                            .buffer_snapshot
10471                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10472                    }
10473
10474                    if transpose_offset == 0 {
10475                        return;
10476                    }
10477
10478                    *head.column_mut() += 1;
10479                    head = display_map.clip_point(head, Bias::Right);
10480                    let goal = SelectionGoal::HorizontalPosition(
10481                        display_map
10482                            .x_for_display_point(head, text_layout_details)
10483                            .into(),
10484                    );
10485                    selection.collapse_to(head, goal);
10486
10487                    let transpose_start = display_map
10488                        .buffer_snapshot
10489                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10490                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10491                        let transpose_end = display_map
10492                            .buffer_snapshot
10493                            .clip_offset(transpose_offset + 1, Bias::Right);
10494                        if let Some(ch) =
10495                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10496                        {
10497                            edits.push((transpose_start..transpose_offset, String::new()));
10498                            edits.push((transpose_end..transpose_end, ch.to_string()));
10499                        }
10500                    }
10501                });
10502                edits
10503            });
10504            this.buffer
10505                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10506            let selections = this.selections.all::<usize>(cx);
10507            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10508                s.select(selections);
10509            });
10510        });
10511    }
10512
10513    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10514        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10515        self.rewrap_impl(RewrapOptions::default(), cx)
10516    }
10517
10518    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10519        let buffer = self.buffer.read(cx).snapshot(cx);
10520        let selections = self.selections.all::<Point>(cx);
10521        let mut selections = selections.iter().peekable();
10522
10523        let mut edits = Vec::new();
10524        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10525
10526        while let Some(selection) = selections.next() {
10527            let mut start_row = selection.start.row;
10528            let mut end_row = selection.end.row;
10529
10530            // Skip selections that overlap with a range that has already been rewrapped.
10531            let selection_range = start_row..end_row;
10532            if rewrapped_row_ranges
10533                .iter()
10534                .any(|range| range.overlaps(&selection_range))
10535            {
10536                continue;
10537            }
10538
10539            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10540
10541            // Since not all lines in the selection may be at the same indent
10542            // level, choose the indent size that is the most common between all
10543            // of the lines.
10544            //
10545            // If there is a tie, we use the deepest indent.
10546            let (indent_size, indent_end) = {
10547                let mut indent_size_occurrences = HashMap::default();
10548                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10549
10550                for row in start_row..=end_row {
10551                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10552                    rows_by_indent_size.entry(indent).or_default().push(row);
10553                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10554                }
10555
10556                let indent_size = indent_size_occurrences
10557                    .into_iter()
10558                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10559                    .map(|(indent, _)| indent)
10560                    .unwrap_or_default();
10561                let row = rows_by_indent_size[&indent_size][0];
10562                let indent_end = Point::new(row, indent_size.len);
10563
10564                (indent_size, indent_end)
10565            };
10566
10567            let mut line_prefix = indent_size.chars().collect::<String>();
10568
10569            let mut inside_comment = false;
10570            if let Some(comment_prefix) =
10571                buffer
10572                    .language_scope_at(selection.head())
10573                    .and_then(|language| {
10574                        language
10575                            .line_comment_prefixes()
10576                            .iter()
10577                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10578                            .cloned()
10579                    })
10580            {
10581                line_prefix.push_str(&comment_prefix);
10582                inside_comment = true;
10583            }
10584
10585            let language_settings = buffer.language_settings_at(selection.head(), cx);
10586            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10587                RewrapBehavior::InComments => inside_comment,
10588                RewrapBehavior::InSelections => !selection.is_empty(),
10589                RewrapBehavior::Anywhere => true,
10590            };
10591
10592            let should_rewrap = options.override_language_settings
10593                || allow_rewrap_based_on_language
10594                || self.hard_wrap.is_some();
10595            if !should_rewrap {
10596                continue;
10597            }
10598
10599            if selection.is_empty() {
10600                'expand_upwards: while start_row > 0 {
10601                    let prev_row = start_row - 1;
10602                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10603                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10604                    {
10605                        start_row = prev_row;
10606                    } else {
10607                        break 'expand_upwards;
10608                    }
10609                }
10610
10611                'expand_downwards: while end_row < buffer.max_point().row {
10612                    let next_row = end_row + 1;
10613                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10614                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10615                    {
10616                        end_row = next_row;
10617                    } else {
10618                        break 'expand_downwards;
10619                    }
10620                }
10621            }
10622
10623            let start = Point::new(start_row, 0);
10624            let start_offset = start.to_offset(&buffer);
10625            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10626            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10627            let Some(lines_without_prefixes) = selection_text
10628                .lines()
10629                .map(|line| {
10630                    line.strip_prefix(&line_prefix)
10631                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10632                        .ok_or_else(|| {
10633                            anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
10634                        })
10635                })
10636                .collect::<Result<Vec<_>, _>>()
10637                .log_err()
10638            else {
10639                continue;
10640            };
10641
10642            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10643                buffer
10644                    .language_settings_at(Point::new(start_row, 0), cx)
10645                    .preferred_line_length as usize
10646            });
10647            let wrapped_text = wrap_with_prefix(
10648                line_prefix,
10649                lines_without_prefixes.join("\n"),
10650                wrap_column,
10651                tab_size,
10652                options.preserve_existing_whitespace,
10653            );
10654
10655            // TODO: should always use char-based diff while still supporting cursor behavior that
10656            // matches vim.
10657            let mut diff_options = DiffOptions::default();
10658            if options.override_language_settings {
10659                diff_options.max_word_diff_len = 0;
10660                diff_options.max_word_diff_line_count = 0;
10661            } else {
10662                diff_options.max_word_diff_len = usize::MAX;
10663                diff_options.max_word_diff_line_count = usize::MAX;
10664            }
10665
10666            for (old_range, new_text) in
10667                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10668            {
10669                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10670                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10671                edits.push((edit_start..edit_end, new_text));
10672            }
10673
10674            rewrapped_row_ranges.push(start_row..=end_row);
10675        }
10676
10677        self.buffer
10678            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10679    }
10680
10681    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10682        let mut text = String::new();
10683        let buffer = self.buffer.read(cx).snapshot(cx);
10684        let mut selections = self.selections.all::<Point>(cx);
10685        let mut clipboard_selections = Vec::with_capacity(selections.len());
10686        {
10687            let max_point = buffer.max_point();
10688            let mut is_first = true;
10689            for selection in &mut selections {
10690                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10691                if is_entire_line {
10692                    selection.start = Point::new(selection.start.row, 0);
10693                    if !selection.is_empty() && selection.end.column == 0 {
10694                        selection.end = cmp::min(max_point, selection.end);
10695                    } else {
10696                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10697                    }
10698                    selection.goal = SelectionGoal::None;
10699                }
10700                if is_first {
10701                    is_first = false;
10702                } else {
10703                    text += "\n";
10704                }
10705                let mut len = 0;
10706                for chunk in buffer.text_for_range(selection.start..selection.end) {
10707                    text.push_str(chunk);
10708                    len += chunk.len();
10709                }
10710                clipboard_selections.push(ClipboardSelection {
10711                    len,
10712                    is_entire_line,
10713                    first_line_indent: buffer
10714                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10715                        .len,
10716                });
10717            }
10718        }
10719
10720        self.transact(window, cx, |this, window, cx| {
10721            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10722                s.select(selections);
10723            });
10724            this.insert("", window, cx);
10725        });
10726        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10727    }
10728
10729    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10730        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10731        let item = self.cut_common(window, cx);
10732        cx.write_to_clipboard(item);
10733    }
10734
10735    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10736        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10737        self.change_selections(None, window, cx, |s| {
10738            s.move_with(|snapshot, sel| {
10739                if sel.is_empty() {
10740                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10741                }
10742            });
10743        });
10744        let item = self.cut_common(window, cx);
10745        cx.set_global(KillRing(item))
10746    }
10747
10748    pub fn kill_ring_yank(
10749        &mut self,
10750        _: &KillRingYank,
10751        window: &mut Window,
10752        cx: &mut Context<Self>,
10753    ) {
10754        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10755        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10756            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10757                (kill_ring.text().to_string(), kill_ring.metadata_json())
10758            } else {
10759                return;
10760            }
10761        } else {
10762            return;
10763        };
10764        self.do_paste(&text, metadata, false, window, cx);
10765    }
10766
10767    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10768        self.do_copy(true, cx);
10769    }
10770
10771    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10772        self.do_copy(false, cx);
10773    }
10774
10775    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10776        let selections = self.selections.all::<Point>(cx);
10777        let buffer = self.buffer.read(cx).read(cx);
10778        let mut text = String::new();
10779
10780        let mut clipboard_selections = Vec::with_capacity(selections.len());
10781        {
10782            let max_point = buffer.max_point();
10783            let mut is_first = true;
10784            for selection in &selections {
10785                let mut start = selection.start;
10786                let mut end = selection.end;
10787                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10788                if is_entire_line {
10789                    start = Point::new(start.row, 0);
10790                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10791                }
10792
10793                let mut trimmed_selections = Vec::new();
10794                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10795                    let row = MultiBufferRow(start.row);
10796                    let first_indent = buffer.indent_size_for_line(row);
10797                    if first_indent.len == 0 || start.column > first_indent.len {
10798                        trimmed_selections.push(start..end);
10799                    } else {
10800                        trimmed_selections.push(
10801                            Point::new(row.0, first_indent.len)
10802                                ..Point::new(row.0, buffer.line_len(row)),
10803                        );
10804                        for row in start.row + 1..=end.row {
10805                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10806                            if row == end.row {
10807                                line_len = end.column;
10808                            }
10809                            if line_len == 0 {
10810                                trimmed_selections
10811                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10812                                continue;
10813                            }
10814                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10815                            if row_indent_size.len >= first_indent.len {
10816                                trimmed_selections.push(
10817                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10818                                );
10819                            } else {
10820                                trimmed_selections.clear();
10821                                trimmed_selections.push(start..end);
10822                                break;
10823                            }
10824                        }
10825                    }
10826                } else {
10827                    trimmed_selections.push(start..end);
10828                }
10829
10830                for trimmed_range in trimmed_selections {
10831                    if is_first {
10832                        is_first = false;
10833                    } else {
10834                        text += "\n";
10835                    }
10836                    let mut len = 0;
10837                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10838                        text.push_str(chunk);
10839                        len += chunk.len();
10840                    }
10841                    clipboard_selections.push(ClipboardSelection {
10842                        len,
10843                        is_entire_line,
10844                        first_line_indent: buffer
10845                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10846                            .len,
10847                    });
10848                }
10849            }
10850        }
10851
10852        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10853            text,
10854            clipboard_selections,
10855        ));
10856    }
10857
10858    pub fn do_paste(
10859        &mut self,
10860        text: &String,
10861        clipboard_selections: Option<Vec<ClipboardSelection>>,
10862        handle_entire_lines: bool,
10863        window: &mut Window,
10864        cx: &mut Context<Self>,
10865    ) {
10866        if self.read_only(cx) {
10867            return;
10868        }
10869
10870        let clipboard_text = Cow::Borrowed(text);
10871
10872        self.transact(window, cx, |this, window, cx| {
10873            if let Some(mut clipboard_selections) = clipboard_selections {
10874                let old_selections = this.selections.all::<usize>(cx);
10875                let all_selections_were_entire_line =
10876                    clipboard_selections.iter().all(|s| s.is_entire_line);
10877                let first_selection_indent_column =
10878                    clipboard_selections.first().map(|s| s.first_line_indent);
10879                if clipboard_selections.len() != old_selections.len() {
10880                    clipboard_selections.drain(..);
10881                }
10882                let cursor_offset = this.selections.last::<usize>(cx).head();
10883                let mut auto_indent_on_paste = true;
10884
10885                this.buffer.update(cx, |buffer, cx| {
10886                    let snapshot = buffer.read(cx);
10887                    auto_indent_on_paste = snapshot
10888                        .language_settings_at(cursor_offset, cx)
10889                        .auto_indent_on_paste;
10890
10891                    let mut start_offset = 0;
10892                    let mut edits = Vec::new();
10893                    let mut original_indent_columns = Vec::new();
10894                    for (ix, selection) in old_selections.iter().enumerate() {
10895                        let to_insert;
10896                        let entire_line;
10897                        let original_indent_column;
10898                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10899                            let end_offset = start_offset + clipboard_selection.len;
10900                            to_insert = &clipboard_text[start_offset..end_offset];
10901                            entire_line = clipboard_selection.is_entire_line;
10902                            start_offset = end_offset + 1;
10903                            original_indent_column = Some(clipboard_selection.first_line_indent);
10904                        } else {
10905                            to_insert = clipboard_text.as_str();
10906                            entire_line = all_selections_were_entire_line;
10907                            original_indent_column = first_selection_indent_column
10908                        }
10909
10910                        // If the corresponding selection was empty when this slice of the
10911                        // clipboard text was written, then the entire line containing the
10912                        // selection was copied. If this selection is also currently empty,
10913                        // then paste the line before the current line of the buffer.
10914                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10915                            let column = selection.start.to_point(&snapshot).column as usize;
10916                            let line_start = selection.start - column;
10917                            line_start..line_start
10918                        } else {
10919                            selection.range()
10920                        };
10921
10922                        edits.push((range, to_insert));
10923                        original_indent_columns.push(original_indent_column);
10924                    }
10925                    drop(snapshot);
10926
10927                    buffer.edit(
10928                        edits,
10929                        if auto_indent_on_paste {
10930                            Some(AutoindentMode::Block {
10931                                original_indent_columns,
10932                            })
10933                        } else {
10934                            None
10935                        },
10936                        cx,
10937                    );
10938                });
10939
10940                let selections = this.selections.all::<usize>(cx);
10941                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10942                    s.select(selections)
10943                });
10944            } else {
10945                this.insert(&clipboard_text, window, cx);
10946            }
10947        });
10948    }
10949
10950    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10951        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10952        if let Some(item) = cx.read_from_clipboard() {
10953            let entries = item.entries();
10954
10955            match entries.first() {
10956                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10957                // of all the pasted entries.
10958                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10959                    .do_paste(
10960                        clipboard_string.text(),
10961                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10962                        true,
10963                        window,
10964                        cx,
10965                    ),
10966                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10967            }
10968        }
10969    }
10970
10971    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10972        if self.read_only(cx) {
10973            return;
10974        }
10975
10976        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10977
10978        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10979            if let Some((selections, _)) =
10980                self.selection_history.transaction(transaction_id).cloned()
10981            {
10982                self.change_selections(None, window, cx, |s| {
10983                    s.select_anchors(selections.to_vec());
10984                });
10985            } else {
10986                log::error!(
10987                    "No entry in selection_history found for undo. \
10988                     This may correspond to a bug where undo does not update the selection. \
10989                     If this is occurring, please add details to \
10990                     https://github.com/zed-industries/zed/issues/22692"
10991                );
10992            }
10993            self.request_autoscroll(Autoscroll::fit(), cx);
10994            self.unmark_text(window, cx);
10995            self.refresh_inline_completion(true, false, window, cx);
10996            cx.emit(EditorEvent::Edited { transaction_id });
10997            cx.emit(EditorEvent::TransactionUndone { transaction_id });
10998        }
10999    }
11000
11001    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11002        if self.read_only(cx) {
11003            return;
11004        }
11005
11006        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11007
11008        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11009            if let Some((_, Some(selections))) =
11010                self.selection_history.transaction(transaction_id).cloned()
11011            {
11012                self.change_selections(None, window, cx, |s| {
11013                    s.select_anchors(selections.to_vec());
11014                });
11015            } else {
11016                log::error!(
11017                    "No entry in selection_history found for redo. \
11018                     This may correspond to a bug where undo does not update the selection. \
11019                     If this is occurring, please add details to \
11020                     https://github.com/zed-industries/zed/issues/22692"
11021                );
11022            }
11023            self.request_autoscroll(Autoscroll::fit(), cx);
11024            self.unmark_text(window, cx);
11025            self.refresh_inline_completion(true, false, window, cx);
11026            cx.emit(EditorEvent::Edited { transaction_id });
11027        }
11028    }
11029
11030    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11031        self.buffer
11032            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11033    }
11034
11035    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11036        self.buffer
11037            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11038    }
11039
11040    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11041        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11042        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11043            s.move_with(|map, selection| {
11044                let cursor = if selection.is_empty() {
11045                    movement::left(map, selection.start)
11046                } else {
11047                    selection.start
11048                };
11049                selection.collapse_to(cursor, SelectionGoal::None);
11050            });
11051        })
11052    }
11053
11054    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11055        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11056        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11057            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11058        })
11059    }
11060
11061    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11062        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11063        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11064            s.move_with(|map, selection| {
11065                let cursor = if selection.is_empty() {
11066                    movement::right(map, selection.end)
11067                } else {
11068                    selection.end
11069                };
11070                selection.collapse_to(cursor, SelectionGoal::None)
11071            });
11072        })
11073    }
11074
11075    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11076        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11077        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11078            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11079        })
11080    }
11081
11082    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11083        if self.take_rename(true, window, cx).is_some() {
11084            return;
11085        }
11086
11087        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11088            cx.propagate();
11089            return;
11090        }
11091
11092        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11093
11094        let text_layout_details = &self.text_layout_details(window);
11095        let selection_count = self.selections.count();
11096        let first_selection = self.selections.first_anchor();
11097
11098        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11099            s.move_with(|map, selection| {
11100                if !selection.is_empty() {
11101                    selection.goal = SelectionGoal::None;
11102                }
11103                let (cursor, goal) = movement::up(
11104                    map,
11105                    selection.start,
11106                    selection.goal,
11107                    false,
11108                    text_layout_details,
11109                );
11110                selection.collapse_to(cursor, goal);
11111            });
11112        });
11113
11114        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11115        {
11116            cx.propagate();
11117        }
11118    }
11119
11120    pub fn move_up_by_lines(
11121        &mut self,
11122        action: &MoveUpByLines,
11123        window: &mut Window,
11124        cx: &mut Context<Self>,
11125    ) {
11126        if self.take_rename(true, window, cx).is_some() {
11127            return;
11128        }
11129
11130        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11131            cx.propagate();
11132            return;
11133        }
11134
11135        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11136
11137        let text_layout_details = &self.text_layout_details(window);
11138
11139        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11140            s.move_with(|map, selection| {
11141                if !selection.is_empty() {
11142                    selection.goal = SelectionGoal::None;
11143                }
11144                let (cursor, goal) = movement::up_by_rows(
11145                    map,
11146                    selection.start,
11147                    action.lines,
11148                    selection.goal,
11149                    false,
11150                    text_layout_details,
11151                );
11152                selection.collapse_to(cursor, goal);
11153            });
11154        })
11155    }
11156
11157    pub fn move_down_by_lines(
11158        &mut self,
11159        action: &MoveDownByLines,
11160        window: &mut Window,
11161        cx: &mut Context<Self>,
11162    ) {
11163        if self.take_rename(true, window, cx).is_some() {
11164            return;
11165        }
11166
11167        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11168            cx.propagate();
11169            return;
11170        }
11171
11172        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11173
11174        let text_layout_details = &self.text_layout_details(window);
11175
11176        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11177            s.move_with(|map, selection| {
11178                if !selection.is_empty() {
11179                    selection.goal = SelectionGoal::None;
11180                }
11181                let (cursor, goal) = movement::down_by_rows(
11182                    map,
11183                    selection.start,
11184                    action.lines,
11185                    selection.goal,
11186                    false,
11187                    text_layout_details,
11188                );
11189                selection.collapse_to(cursor, goal);
11190            });
11191        })
11192    }
11193
11194    pub fn select_down_by_lines(
11195        &mut self,
11196        action: &SelectDownByLines,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11201        let text_layout_details = &self.text_layout_details(window);
11202        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11203            s.move_heads_with(|map, head, goal| {
11204                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11205            })
11206        })
11207    }
11208
11209    pub fn select_up_by_lines(
11210        &mut self,
11211        action: &SelectUpByLines,
11212        window: &mut Window,
11213        cx: &mut Context<Self>,
11214    ) {
11215        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11216        let text_layout_details = &self.text_layout_details(window);
11217        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11218            s.move_heads_with(|map, head, goal| {
11219                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11220            })
11221        })
11222    }
11223
11224    pub fn select_page_up(
11225        &mut self,
11226        _: &SelectPageUp,
11227        window: &mut Window,
11228        cx: &mut Context<Self>,
11229    ) {
11230        let Some(row_count) = self.visible_row_count() else {
11231            return;
11232        };
11233
11234        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11235
11236        let text_layout_details = &self.text_layout_details(window);
11237
11238        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11239            s.move_heads_with(|map, head, goal| {
11240                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11241            })
11242        })
11243    }
11244
11245    pub fn move_page_up(
11246        &mut self,
11247        action: &MovePageUp,
11248        window: &mut Window,
11249        cx: &mut Context<Self>,
11250    ) {
11251        if self.take_rename(true, window, cx).is_some() {
11252            return;
11253        }
11254
11255        if self
11256            .context_menu
11257            .borrow_mut()
11258            .as_mut()
11259            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11260            .unwrap_or(false)
11261        {
11262            return;
11263        }
11264
11265        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11266            cx.propagate();
11267            return;
11268        }
11269
11270        let Some(row_count) = self.visible_row_count() else {
11271            return;
11272        };
11273
11274        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11275
11276        let autoscroll = if action.center_cursor {
11277            Autoscroll::center()
11278        } else {
11279            Autoscroll::fit()
11280        };
11281
11282        let text_layout_details = &self.text_layout_details(window);
11283
11284        self.change_selections(Some(autoscroll), window, cx, |s| {
11285            s.move_with(|map, selection| {
11286                if !selection.is_empty() {
11287                    selection.goal = SelectionGoal::None;
11288                }
11289                let (cursor, goal) = movement::up_by_rows(
11290                    map,
11291                    selection.end,
11292                    row_count,
11293                    selection.goal,
11294                    false,
11295                    text_layout_details,
11296                );
11297                selection.collapse_to(cursor, goal);
11298            });
11299        });
11300    }
11301
11302    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11303        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11304        let text_layout_details = &self.text_layout_details(window);
11305        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11306            s.move_heads_with(|map, head, goal| {
11307                movement::up(map, head, goal, false, text_layout_details)
11308            })
11309        })
11310    }
11311
11312    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11313        self.take_rename(true, window, cx);
11314
11315        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11316            cx.propagate();
11317            return;
11318        }
11319
11320        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11321
11322        let text_layout_details = &self.text_layout_details(window);
11323        let selection_count = self.selections.count();
11324        let first_selection = self.selections.first_anchor();
11325
11326        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11327            s.move_with(|map, selection| {
11328                if !selection.is_empty() {
11329                    selection.goal = SelectionGoal::None;
11330                }
11331                let (cursor, goal) = movement::down(
11332                    map,
11333                    selection.end,
11334                    selection.goal,
11335                    false,
11336                    text_layout_details,
11337                );
11338                selection.collapse_to(cursor, goal);
11339            });
11340        });
11341
11342        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11343        {
11344            cx.propagate();
11345        }
11346    }
11347
11348    pub fn select_page_down(
11349        &mut self,
11350        _: &SelectPageDown,
11351        window: &mut Window,
11352        cx: &mut Context<Self>,
11353    ) {
11354        let Some(row_count) = self.visible_row_count() else {
11355            return;
11356        };
11357
11358        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11359
11360        let text_layout_details = &self.text_layout_details(window);
11361
11362        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11363            s.move_heads_with(|map, head, goal| {
11364                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11365            })
11366        })
11367    }
11368
11369    pub fn move_page_down(
11370        &mut self,
11371        action: &MovePageDown,
11372        window: &mut Window,
11373        cx: &mut Context<Self>,
11374    ) {
11375        if self.take_rename(true, window, cx).is_some() {
11376            return;
11377        }
11378
11379        if self
11380            .context_menu
11381            .borrow_mut()
11382            .as_mut()
11383            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11384            .unwrap_or(false)
11385        {
11386            return;
11387        }
11388
11389        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11390            cx.propagate();
11391            return;
11392        }
11393
11394        let Some(row_count) = self.visible_row_count() else {
11395            return;
11396        };
11397
11398        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11399
11400        let autoscroll = if action.center_cursor {
11401            Autoscroll::center()
11402        } else {
11403            Autoscroll::fit()
11404        };
11405
11406        let text_layout_details = &self.text_layout_details(window);
11407        self.change_selections(Some(autoscroll), window, cx, |s| {
11408            s.move_with(|map, selection| {
11409                if !selection.is_empty() {
11410                    selection.goal = SelectionGoal::None;
11411                }
11412                let (cursor, goal) = movement::down_by_rows(
11413                    map,
11414                    selection.end,
11415                    row_count,
11416                    selection.goal,
11417                    false,
11418                    text_layout_details,
11419                );
11420                selection.collapse_to(cursor, goal);
11421            });
11422        });
11423    }
11424
11425    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11426        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11427        let text_layout_details = &self.text_layout_details(window);
11428        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11429            s.move_heads_with(|map, head, goal| {
11430                movement::down(map, head, goal, false, text_layout_details)
11431            })
11432        });
11433    }
11434
11435    pub fn context_menu_first(
11436        &mut self,
11437        _: &ContextMenuFirst,
11438        _window: &mut Window,
11439        cx: &mut Context<Self>,
11440    ) {
11441        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11442            context_menu.select_first(self.completion_provider.as_deref(), cx);
11443        }
11444    }
11445
11446    pub fn context_menu_prev(
11447        &mut self,
11448        _: &ContextMenuPrevious,
11449        _window: &mut Window,
11450        cx: &mut Context<Self>,
11451    ) {
11452        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11453            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11454        }
11455    }
11456
11457    pub fn context_menu_next(
11458        &mut self,
11459        _: &ContextMenuNext,
11460        _window: &mut Window,
11461        cx: &mut Context<Self>,
11462    ) {
11463        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11464            context_menu.select_next(self.completion_provider.as_deref(), cx);
11465        }
11466    }
11467
11468    pub fn context_menu_last(
11469        &mut self,
11470        _: &ContextMenuLast,
11471        _window: &mut Window,
11472        cx: &mut Context<Self>,
11473    ) {
11474        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11475            context_menu.select_last(self.completion_provider.as_deref(), cx);
11476        }
11477    }
11478
11479    pub fn move_to_previous_word_start(
11480        &mut self,
11481        _: &MoveToPreviousWordStart,
11482        window: &mut Window,
11483        cx: &mut Context<Self>,
11484    ) {
11485        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11486        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11487            s.move_cursors_with(|map, head, _| {
11488                (
11489                    movement::previous_word_start(map, head),
11490                    SelectionGoal::None,
11491                )
11492            });
11493        })
11494    }
11495
11496    pub fn move_to_previous_subword_start(
11497        &mut self,
11498        _: &MoveToPreviousSubwordStart,
11499        window: &mut Window,
11500        cx: &mut Context<Self>,
11501    ) {
11502        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11503        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11504            s.move_cursors_with(|map, head, _| {
11505                (
11506                    movement::previous_subword_start(map, head),
11507                    SelectionGoal::None,
11508                )
11509            });
11510        })
11511    }
11512
11513    pub fn select_to_previous_word_start(
11514        &mut self,
11515        _: &SelectToPreviousWordStart,
11516        window: &mut Window,
11517        cx: &mut Context<Self>,
11518    ) {
11519        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11520        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11521            s.move_heads_with(|map, head, _| {
11522                (
11523                    movement::previous_word_start(map, head),
11524                    SelectionGoal::None,
11525                )
11526            });
11527        })
11528    }
11529
11530    pub fn select_to_previous_subword_start(
11531        &mut self,
11532        _: &SelectToPreviousSubwordStart,
11533        window: &mut Window,
11534        cx: &mut Context<Self>,
11535    ) {
11536        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11537        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11538            s.move_heads_with(|map, head, _| {
11539                (
11540                    movement::previous_subword_start(map, head),
11541                    SelectionGoal::None,
11542                )
11543            });
11544        })
11545    }
11546
11547    pub fn delete_to_previous_word_start(
11548        &mut self,
11549        action: &DeleteToPreviousWordStart,
11550        window: &mut Window,
11551        cx: &mut Context<Self>,
11552    ) {
11553        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11554        self.transact(window, cx, |this, window, cx| {
11555            this.select_autoclose_pair(window, cx);
11556            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11557                s.move_with(|map, selection| {
11558                    if selection.is_empty() {
11559                        let cursor = if action.ignore_newlines {
11560                            movement::previous_word_start(map, selection.head())
11561                        } else {
11562                            movement::previous_word_start_or_newline(map, selection.head())
11563                        };
11564                        selection.set_head(cursor, SelectionGoal::None);
11565                    }
11566                });
11567            });
11568            this.insert("", window, cx);
11569        });
11570    }
11571
11572    pub fn delete_to_previous_subword_start(
11573        &mut self,
11574        _: &DeleteToPreviousSubwordStart,
11575        window: &mut Window,
11576        cx: &mut Context<Self>,
11577    ) {
11578        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11579        self.transact(window, cx, |this, window, cx| {
11580            this.select_autoclose_pair(window, cx);
11581            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11582                s.move_with(|map, selection| {
11583                    if selection.is_empty() {
11584                        let cursor = movement::previous_subword_start(map, selection.head());
11585                        selection.set_head(cursor, SelectionGoal::None);
11586                    }
11587                });
11588            });
11589            this.insert("", window, cx);
11590        });
11591    }
11592
11593    pub fn move_to_next_word_end(
11594        &mut self,
11595        _: &MoveToNextWordEnd,
11596        window: &mut Window,
11597        cx: &mut Context<Self>,
11598    ) {
11599        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11600        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11601            s.move_cursors_with(|map, head, _| {
11602                (movement::next_word_end(map, head), SelectionGoal::None)
11603            });
11604        })
11605    }
11606
11607    pub fn move_to_next_subword_end(
11608        &mut self,
11609        _: &MoveToNextSubwordEnd,
11610        window: &mut Window,
11611        cx: &mut Context<Self>,
11612    ) {
11613        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11614        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11615            s.move_cursors_with(|map, head, _| {
11616                (movement::next_subword_end(map, head), SelectionGoal::None)
11617            });
11618        })
11619    }
11620
11621    pub fn select_to_next_word_end(
11622        &mut self,
11623        _: &SelectToNextWordEnd,
11624        window: &mut Window,
11625        cx: &mut Context<Self>,
11626    ) {
11627        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11628        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11629            s.move_heads_with(|map, head, _| {
11630                (movement::next_word_end(map, head), SelectionGoal::None)
11631            });
11632        })
11633    }
11634
11635    pub fn select_to_next_subword_end(
11636        &mut self,
11637        _: &SelectToNextSubwordEnd,
11638        window: &mut Window,
11639        cx: &mut Context<Self>,
11640    ) {
11641        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11642        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11643            s.move_heads_with(|map, head, _| {
11644                (movement::next_subword_end(map, head), SelectionGoal::None)
11645            });
11646        })
11647    }
11648
11649    pub fn delete_to_next_word_end(
11650        &mut self,
11651        action: &DeleteToNextWordEnd,
11652        window: &mut Window,
11653        cx: &mut Context<Self>,
11654    ) {
11655        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11656        self.transact(window, cx, |this, window, cx| {
11657            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11658                s.move_with(|map, selection| {
11659                    if selection.is_empty() {
11660                        let cursor = if action.ignore_newlines {
11661                            movement::next_word_end(map, selection.head())
11662                        } else {
11663                            movement::next_word_end_or_newline(map, selection.head())
11664                        };
11665                        selection.set_head(cursor, SelectionGoal::None);
11666                    }
11667                });
11668            });
11669            this.insert("", window, cx);
11670        });
11671    }
11672
11673    pub fn delete_to_next_subword_end(
11674        &mut self,
11675        _: &DeleteToNextSubwordEnd,
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 = movement::next_subword_end(map, selection.head());
11685                        selection.set_head(cursor, SelectionGoal::None);
11686                    }
11687                });
11688            });
11689            this.insert("", window, cx);
11690        });
11691    }
11692
11693    pub fn move_to_beginning_of_line(
11694        &mut self,
11695        action: &MoveToBeginningOfLine,
11696        window: &mut Window,
11697        cx: &mut Context<Self>,
11698    ) {
11699        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11700        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11701            s.move_cursors_with(|map, head, _| {
11702                (
11703                    movement::indented_line_beginning(
11704                        map,
11705                        head,
11706                        action.stop_at_soft_wraps,
11707                        action.stop_at_indent,
11708                    ),
11709                    SelectionGoal::None,
11710                )
11711            });
11712        })
11713    }
11714
11715    pub fn select_to_beginning_of_line(
11716        &mut self,
11717        action: &SelectToBeginningOfLine,
11718        window: &mut Window,
11719        cx: &mut Context<Self>,
11720    ) {
11721        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11722        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11723            s.move_heads_with(|map, head, _| {
11724                (
11725                    movement::indented_line_beginning(
11726                        map,
11727                        head,
11728                        action.stop_at_soft_wraps,
11729                        action.stop_at_indent,
11730                    ),
11731                    SelectionGoal::None,
11732                )
11733            });
11734        });
11735    }
11736
11737    pub fn delete_to_beginning_of_line(
11738        &mut self,
11739        action: &DeleteToBeginningOfLine,
11740        window: &mut Window,
11741        cx: &mut Context<Self>,
11742    ) {
11743        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11744        self.transact(window, cx, |this, window, cx| {
11745            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11746                s.move_with(|_, selection| {
11747                    selection.reversed = true;
11748                });
11749            });
11750
11751            this.select_to_beginning_of_line(
11752                &SelectToBeginningOfLine {
11753                    stop_at_soft_wraps: false,
11754                    stop_at_indent: action.stop_at_indent,
11755                },
11756                window,
11757                cx,
11758            );
11759            this.backspace(&Backspace, window, cx);
11760        });
11761    }
11762
11763    pub fn move_to_end_of_line(
11764        &mut self,
11765        action: &MoveToEndOfLine,
11766        window: &mut Window,
11767        cx: &mut Context<Self>,
11768    ) {
11769        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11770        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11771            s.move_cursors_with(|map, head, _| {
11772                (
11773                    movement::line_end(map, head, action.stop_at_soft_wraps),
11774                    SelectionGoal::None,
11775                )
11776            });
11777        })
11778    }
11779
11780    pub fn select_to_end_of_line(
11781        &mut self,
11782        action: &SelectToEndOfLine,
11783        window: &mut Window,
11784        cx: &mut Context<Self>,
11785    ) {
11786        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11787        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11788            s.move_heads_with(|map, head, _| {
11789                (
11790                    movement::line_end(map, head, action.stop_at_soft_wraps),
11791                    SelectionGoal::None,
11792                )
11793            });
11794        })
11795    }
11796
11797    pub fn delete_to_end_of_line(
11798        &mut self,
11799        _: &DeleteToEndOfLine,
11800        window: &mut Window,
11801        cx: &mut Context<Self>,
11802    ) {
11803        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11804        self.transact(window, cx, |this, window, cx| {
11805            this.select_to_end_of_line(
11806                &SelectToEndOfLine {
11807                    stop_at_soft_wraps: false,
11808                },
11809                window,
11810                cx,
11811            );
11812            this.delete(&Delete, window, cx);
11813        });
11814    }
11815
11816    pub fn cut_to_end_of_line(
11817        &mut self,
11818        _: &CutToEndOfLine,
11819        window: &mut Window,
11820        cx: &mut Context<Self>,
11821    ) {
11822        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11823        self.transact(window, cx, |this, window, cx| {
11824            this.select_to_end_of_line(
11825                &SelectToEndOfLine {
11826                    stop_at_soft_wraps: false,
11827                },
11828                window,
11829                cx,
11830            );
11831            this.cut(&Cut, window, cx);
11832        });
11833    }
11834
11835    pub fn move_to_start_of_paragraph(
11836        &mut self,
11837        _: &MoveToStartOfParagraph,
11838        window: &mut Window,
11839        cx: &mut Context<Self>,
11840    ) {
11841        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11842            cx.propagate();
11843            return;
11844        }
11845        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11846        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11847            s.move_with(|map, selection| {
11848                selection.collapse_to(
11849                    movement::start_of_paragraph(map, selection.head(), 1),
11850                    SelectionGoal::None,
11851                )
11852            });
11853        })
11854    }
11855
11856    pub fn move_to_end_of_paragraph(
11857        &mut self,
11858        _: &MoveToEndOfParagraph,
11859        window: &mut Window,
11860        cx: &mut Context<Self>,
11861    ) {
11862        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11863            cx.propagate();
11864            return;
11865        }
11866        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11867        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11868            s.move_with(|map, selection| {
11869                selection.collapse_to(
11870                    movement::end_of_paragraph(map, selection.head(), 1),
11871                    SelectionGoal::None,
11872                )
11873            });
11874        })
11875    }
11876
11877    pub fn select_to_start_of_paragraph(
11878        &mut self,
11879        _: &SelectToStartOfParagraph,
11880        window: &mut Window,
11881        cx: &mut Context<Self>,
11882    ) {
11883        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11884            cx.propagate();
11885            return;
11886        }
11887        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11888        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11889            s.move_heads_with(|map, head, _| {
11890                (
11891                    movement::start_of_paragraph(map, head, 1),
11892                    SelectionGoal::None,
11893                )
11894            });
11895        })
11896    }
11897
11898    pub fn select_to_end_of_paragraph(
11899        &mut self,
11900        _: &SelectToEndOfParagraph,
11901        window: &mut Window,
11902        cx: &mut Context<Self>,
11903    ) {
11904        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11905            cx.propagate();
11906            return;
11907        }
11908        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11909        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11910            s.move_heads_with(|map, head, _| {
11911                (
11912                    movement::end_of_paragraph(map, head, 1),
11913                    SelectionGoal::None,
11914                )
11915            });
11916        })
11917    }
11918
11919    pub fn move_to_start_of_excerpt(
11920        &mut self,
11921        _: &MoveToStartOfExcerpt,
11922        window: &mut Window,
11923        cx: &mut Context<Self>,
11924    ) {
11925        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11926            cx.propagate();
11927            return;
11928        }
11929        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11930        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11931            s.move_with(|map, selection| {
11932                selection.collapse_to(
11933                    movement::start_of_excerpt(
11934                        map,
11935                        selection.head(),
11936                        workspace::searchable::Direction::Prev,
11937                    ),
11938                    SelectionGoal::None,
11939                )
11940            });
11941        })
11942    }
11943
11944    pub fn move_to_start_of_next_excerpt(
11945        &mut self,
11946        _: &MoveToStartOfNextExcerpt,
11947        window: &mut Window,
11948        cx: &mut Context<Self>,
11949    ) {
11950        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11951            cx.propagate();
11952            return;
11953        }
11954
11955        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11956            s.move_with(|map, selection| {
11957                selection.collapse_to(
11958                    movement::start_of_excerpt(
11959                        map,
11960                        selection.head(),
11961                        workspace::searchable::Direction::Next,
11962                    ),
11963                    SelectionGoal::None,
11964                )
11965            });
11966        })
11967    }
11968
11969    pub fn move_to_end_of_excerpt(
11970        &mut self,
11971        _: &MoveToEndOfExcerpt,
11972        window: &mut Window,
11973        cx: &mut Context<Self>,
11974    ) {
11975        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11976            cx.propagate();
11977            return;
11978        }
11979        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11980        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11981            s.move_with(|map, selection| {
11982                selection.collapse_to(
11983                    movement::end_of_excerpt(
11984                        map,
11985                        selection.head(),
11986                        workspace::searchable::Direction::Next,
11987                    ),
11988                    SelectionGoal::None,
11989                )
11990            });
11991        })
11992    }
11993
11994    pub fn move_to_end_of_previous_excerpt(
11995        &mut self,
11996        _: &MoveToEndOfPreviousExcerpt,
11997        window: &mut Window,
11998        cx: &mut Context<Self>,
11999    ) {
12000        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12001            cx.propagate();
12002            return;
12003        }
12004        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12005        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12006            s.move_with(|map, selection| {
12007                selection.collapse_to(
12008                    movement::end_of_excerpt(
12009                        map,
12010                        selection.head(),
12011                        workspace::searchable::Direction::Prev,
12012                    ),
12013                    SelectionGoal::None,
12014                )
12015            });
12016        })
12017    }
12018
12019    pub fn select_to_start_of_excerpt(
12020        &mut self,
12021        _: &SelectToStartOfExcerpt,
12022        window: &mut Window,
12023        cx: &mut Context<Self>,
12024    ) {
12025        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12026            cx.propagate();
12027            return;
12028        }
12029        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12030        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12031            s.move_heads_with(|map, head, _| {
12032                (
12033                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12034                    SelectionGoal::None,
12035                )
12036            });
12037        })
12038    }
12039
12040    pub fn select_to_start_of_next_excerpt(
12041        &mut self,
12042        _: &SelectToStartOfNextExcerpt,
12043        window: &mut Window,
12044        cx: &mut Context<Self>,
12045    ) {
12046        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12047            cx.propagate();
12048            return;
12049        }
12050        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12051        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12052            s.move_heads_with(|map, head, _| {
12053                (
12054                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12055                    SelectionGoal::None,
12056                )
12057            });
12058        })
12059    }
12060
12061    pub fn select_to_end_of_excerpt(
12062        &mut self,
12063        _: &SelectToEndOfExcerpt,
12064        window: &mut Window,
12065        cx: &mut Context<Self>,
12066    ) {
12067        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12068            cx.propagate();
12069            return;
12070        }
12071        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12072        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12073            s.move_heads_with(|map, head, _| {
12074                (
12075                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12076                    SelectionGoal::None,
12077                )
12078            });
12079        })
12080    }
12081
12082    pub fn select_to_end_of_previous_excerpt(
12083        &mut self,
12084        _: &SelectToEndOfPreviousExcerpt,
12085        window: &mut Window,
12086        cx: &mut Context<Self>,
12087    ) {
12088        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12089            cx.propagate();
12090            return;
12091        }
12092        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12093        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12094            s.move_heads_with(|map, head, _| {
12095                (
12096                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12097                    SelectionGoal::None,
12098                )
12099            });
12100        })
12101    }
12102
12103    pub fn move_to_beginning(
12104        &mut self,
12105        _: &MoveToBeginning,
12106        window: &mut Window,
12107        cx: &mut Context<Self>,
12108    ) {
12109        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12110            cx.propagate();
12111            return;
12112        }
12113        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12114        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12115            s.select_ranges(vec![0..0]);
12116        });
12117    }
12118
12119    pub fn select_to_beginning(
12120        &mut self,
12121        _: &SelectToBeginning,
12122        window: &mut Window,
12123        cx: &mut Context<Self>,
12124    ) {
12125        let mut selection = self.selections.last::<Point>(cx);
12126        selection.set_head(Point::zero(), SelectionGoal::None);
12127        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12128        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12129            s.select(vec![selection]);
12130        });
12131    }
12132
12133    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12134        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12135            cx.propagate();
12136            return;
12137        }
12138        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12139        let cursor = self.buffer.read(cx).read(cx).len();
12140        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12141            s.select_ranges(vec![cursor..cursor])
12142        });
12143    }
12144
12145    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12146        self.nav_history = nav_history;
12147    }
12148
12149    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12150        self.nav_history.as_ref()
12151    }
12152
12153    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12154        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12155    }
12156
12157    fn push_to_nav_history(
12158        &mut self,
12159        cursor_anchor: Anchor,
12160        new_position: Option<Point>,
12161        is_deactivate: bool,
12162        cx: &mut Context<Self>,
12163    ) {
12164        if let Some(nav_history) = self.nav_history.as_mut() {
12165            let buffer = self.buffer.read(cx).read(cx);
12166            let cursor_position = cursor_anchor.to_point(&buffer);
12167            let scroll_state = self.scroll_manager.anchor();
12168            let scroll_top_row = scroll_state.top_row(&buffer);
12169            drop(buffer);
12170
12171            if let Some(new_position) = new_position {
12172                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12173                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12174                    return;
12175                }
12176            }
12177
12178            nav_history.push(
12179                Some(NavigationData {
12180                    cursor_anchor,
12181                    cursor_position,
12182                    scroll_anchor: scroll_state,
12183                    scroll_top_row,
12184                }),
12185                cx,
12186            );
12187            cx.emit(EditorEvent::PushedToNavHistory {
12188                anchor: cursor_anchor,
12189                is_deactivate,
12190            })
12191        }
12192    }
12193
12194    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12195        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12196        let buffer = self.buffer.read(cx).snapshot(cx);
12197        let mut selection = self.selections.first::<usize>(cx);
12198        selection.set_head(buffer.len(), SelectionGoal::None);
12199        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12200            s.select(vec![selection]);
12201        });
12202    }
12203
12204    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12205        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12206        let end = self.buffer.read(cx).read(cx).len();
12207        self.change_selections(None, window, cx, |s| {
12208            s.select_ranges(vec![0..end]);
12209        });
12210    }
12211
12212    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12213        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12214        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12215        let mut selections = self.selections.all::<Point>(cx);
12216        let max_point = display_map.buffer_snapshot.max_point();
12217        for selection in &mut selections {
12218            let rows = selection.spanned_rows(true, &display_map);
12219            selection.start = Point::new(rows.start.0, 0);
12220            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12221            selection.reversed = false;
12222        }
12223        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12224            s.select(selections);
12225        });
12226    }
12227
12228    pub fn split_selection_into_lines(
12229        &mut self,
12230        _: &SplitSelectionIntoLines,
12231        window: &mut Window,
12232        cx: &mut Context<Self>,
12233    ) {
12234        let selections = self
12235            .selections
12236            .all::<Point>(cx)
12237            .into_iter()
12238            .map(|selection| selection.start..selection.end)
12239            .collect::<Vec<_>>();
12240        self.unfold_ranges(&selections, true, true, cx);
12241
12242        let mut new_selection_ranges = Vec::new();
12243        {
12244            let buffer = self.buffer.read(cx).read(cx);
12245            for selection in selections {
12246                for row in selection.start.row..selection.end.row {
12247                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12248                    new_selection_ranges.push(cursor..cursor);
12249                }
12250
12251                let is_multiline_selection = selection.start.row != selection.end.row;
12252                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12253                // so this action feels more ergonomic when paired with other selection operations
12254                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12255                if !should_skip_last {
12256                    new_selection_ranges.push(selection.end..selection.end);
12257                }
12258            }
12259        }
12260        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12261            s.select_ranges(new_selection_ranges);
12262        });
12263    }
12264
12265    pub fn add_selection_above(
12266        &mut self,
12267        _: &AddSelectionAbove,
12268        window: &mut Window,
12269        cx: &mut Context<Self>,
12270    ) {
12271        self.add_selection(true, window, cx);
12272    }
12273
12274    pub fn add_selection_below(
12275        &mut self,
12276        _: &AddSelectionBelow,
12277        window: &mut Window,
12278        cx: &mut Context<Self>,
12279    ) {
12280        self.add_selection(false, window, cx);
12281    }
12282
12283    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12284        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12285
12286        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12287        let mut selections = self.selections.all::<Point>(cx);
12288        let text_layout_details = self.text_layout_details(window);
12289        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12290            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12291            let range = oldest_selection.display_range(&display_map).sorted();
12292
12293            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12294            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12295            let positions = start_x.min(end_x)..start_x.max(end_x);
12296
12297            selections.clear();
12298            let mut stack = Vec::new();
12299            for row in range.start.row().0..=range.end.row().0 {
12300                if let Some(selection) = self.selections.build_columnar_selection(
12301                    &display_map,
12302                    DisplayRow(row),
12303                    &positions,
12304                    oldest_selection.reversed,
12305                    &text_layout_details,
12306                ) {
12307                    stack.push(selection.id);
12308                    selections.push(selection);
12309                }
12310            }
12311
12312            if above {
12313                stack.reverse();
12314            }
12315
12316            AddSelectionsState { above, stack }
12317        });
12318
12319        let last_added_selection = *state.stack.last().unwrap();
12320        let mut new_selections = Vec::new();
12321        if above == state.above {
12322            let end_row = if above {
12323                DisplayRow(0)
12324            } else {
12325                display_map.max_point().row()
12326            };
12327
12328            'outer: for selection in selections {
12329                if selection.id == last_added_selection {
12330                    let range = selection.display_range(&display_map).sorted();
12331                    debug_assert_eq!(range.start.row(), range.end.row());
12332                    let mut row = range.start.row();
12333                    let positions =
12334                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12335                            px(start)..px(end)
12336                        } else {
12337                            let start_x =
12338                                display_map.x_for_display_point(range.start, &text_layout_details);
12339                            let end_x =
12340                                display_map.x_for_display_point(range.end, &text_layout_details);
12341                            start_x.min(end_x)..start_x.max(end_x)
12342                        };
12343
12344                    while row != end_row {
12345                        if above {
12346                            row.0 -= 1;
12347                        } else {
12348                            row.0 += 1;
12349                        }
12350
12351                        if let Some(new_selection) = self.selections.build_columnar_selection(
12352                            &display_map,
12353                            row,
12354                            &positions,
12355                            selection.reversed,
12356                            &text_layout_details,
12357                        ) {
12358                            state.stack.push(new_selection.id);
12359                            if above {
12360                                new_selections.push(new_selection);
12361                                new_selections.push(selection);
12362                            } else {
12363                                new_selections.push(selection);
12364                                new_selections.push(new_selection);
12365                            }
12366
12367                            continue 'outer;
12368                        }
12369                    }
12370                }
12371
12372                new_selections.push(selection);
12373            }
12374        } else {
12375            new_selections = selections;
12376            new_selections.retain(|s| s.id != last_added_selection);
12377            state.stack.pop();
12378        }
12379
12380        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12381            s.select(new_selections);
12382        });
12383        if state.stack.len() > 1 {
12384            self.add_selections_state = Some(state);
12385        }
12386    }
12387
12388    fn select_match_ranges(
12389        &mut self,
12390        range: Range<usize>,
12391        reversed: bool,
12392        replace_newest: bool,
12393        auto_scroll: Option<Autoscroll>,
12394        window: &mut Window,
12395        cx: &mut Context<Editor>,
12396    ) {
12397        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12398        self.change_selections(auto_scroll, window, cx, |s| {
12399            if replace_newest {
12400                s.delete(s.newest_anchor().id);
12401            }
12402            if reversed {
12403                s.insert_range(range.end..range.start);
12404            } else {
12405                s.insert_range(range);
12406            }
12407        });
12408    }
12409
12410    pub fn select_next_match_internal(
12411        &mut self,
12412        display_map: &DisplaySnapshot,
12413        replace_newest: bool,
12414        autoscroll: Option<Autoscroll>,
12415        window: &mut Window,
12416        cx: &mut Context<Self>,
12417    ) -> Result<()> {
12418        let buffer = &display_map.buffer_snapshot;
12419        let mut selections = self.selections.all::<usize>(cx);
12420        if let Some(mut select_next_state) = self.select_next_state.take() {
12421            let query = &select_next_state.query;
12422            if !select_next_state.done {
12423                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12424                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12425                let mut next_selected_range = None;
12426
12427                let bytes_after_last_selection =
12428                    buffer.bytes_in_range(last_selection.end..buffer.len());
12429                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12430                let query_matches = query
12431                    .stream_find_iter(bytes_after_last_selection)
12432                    .map(|result| (last_selection.end, result))
12433                    .chain(
12434                        query
12435                            .stream_find_iter(bytes_before_first_selection)
12436                            .map(|result| (0, result)),
12437                    );
12438
12439                for (start_offset, query_match) in query_matches {
12440                    let query_match = query_match.unwrap(); // can only fail due to I/O
12441                    let offset_range =
12442                        start_offset + query_match.start()..start_offset + query_match.end();
12443                    let display_range = offset_range.start.to_display_point(display_map)
12444                        ..offset_range.end.to_display_point(display_map);
12445
12446                    if !select_next_state.wordwise
12447                        || (!movement::is_inside_word(display_map, display_range.start)
12448                            && !movement::is_inside_word(display_map, display_range.end))
12449                    {
12450                        // TODO: This is n^2, because we might check all the selections
12451                        if !selections
12452                            .iter()
12453                            .any(|selection| selection.range().overlaps(&offset_range))
12454                        {
12455                            next_selected_range = Some(offset_range);
12456                            break;
12457                        }
12458                    }
12459                }
12460
12461                if let Some(next_selected_range) = next_selected_range {
12462                    self.select_match_ranges(
12463                        next_selected_range,
12464                        last_selection.reversed,
12465                        replace_newest,
12466                        autoscroll,
12467                        window,
12468                        cx,
12469                    );
12470                } else {
12471                    select_next_state.done = true;
12472                }
12473            }
12474
12475            self.select_next_state = Some(select_next_state);
12476        } else {
12477            let mut only_carets = true;
12478            let mut same_text_selected = true;
12479            let mut selected_text = None;
12480
12481            let mut selections_iter = selections.iter().peekable();
12482            while let Some(selection) = selections_iter.next() {
12483                if selection.start != selection.end {
12484                    only_carets = false;
12485                }
12486
12487                if same_text_selected {
12488                    if selected_text.is_none() {
12489                        selected_text =
12490                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12491                    }
12492
12493                    if let Some(next_selection) = selections_iter.peek() {
12494                        if next_selection.range().len() == selection.range().len() {
12495                            let next_selected_text = buffer
12496                                .text_for_range(next_selection.range())
12497                                .collect::<String>();
12498                            if Some(next_selected_text) != selected_text {
12499                                same_text_selected = false;
12500                                selected_text = None;
12501                            }
12502                        } else {
12503                            same_text_selected = false;
12504                            selected_text = None;
12505                        }
12506                    }
12507                }
12508            }
12509
12510            if only_carets {
12511                for selection in &mut selections {
12512                    let word_range = movement::surrounding_word(
12513                        display_map,
12514                        selection.start.to_display_point(display_map),
12515                    );
12516                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12517                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12518                    selection.goal = SelectionGoal::None;
12519                    selection.reversed = false;
12520                    self.select_match_ranges(
12521                        selection.start..selection.end,
12522                        selection.reversed,
12523                        replace_newest,
12524                        autoscroll,
12525                        window,
12526                        cx,
12527                    );
12528                }
12529
12530                if selections.len() == 1 {
12531                    let selection = selections
12532                        .last()
12533                        .expect("ensured that there's only one selection");
12534                    let query = buffer
12535                        .text_for_range(selection.start..selection.end)
12536                        .collect::<String>();
12537                    let is_empty = query.is_empty();
12538                    let select_state = SelectNextState {
12539                        query: AhoCorasick::new(&[query])?,
12540                        wordwise: true,
12541                        done: is_empty,
12542                    };
12543                    self.select_next_state = Some(select_state);
12544                } else {
12545                    self.select_next_state = None;
12546                }
12547            } else if let Some(selected_text) = selected_text {
12548                self.select_next_state = Some(SelectNextState {
12549                    query: AhoCorasick::new(&[selected_text])?,
12550                    wordwise: false,
12551                    done: false,
12552                });
12553                self.select_next_match_internal(
12554                    display_map,
12555                    replace_newest,
12556                    autoscroll,
12557                    window,
12558                    cx,
12559                )?;
12560            }
12561        }
12562        Ok(())
12563    }
12564
12565    pub fn select_all_matches(
12566        &mut self,
12567        _action: &SelectAllMatches,
12568        window: &mut Window,
12569        cx: &mut Context<Self>,
12570    ) -> Result<()> {
12571        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12572
12573        self.push_to_selection_history();
12574        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12575
12576        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12577        let Some(select_next_state) = self.select_next_state.as_mut() else {
12578            return Ok(());
12579        };
12580        if select_next_state.done {
12581            return Ok(());
12582        }
12583
12584        let mut new_selections = Vec::new();
12585
12586        let reversed = self.selections.oldest::<usize>(cx).reversed;
12587        let buffer = &display_map.buffer_snapshot;
12588        let query_matches = select_next_state
12589            .query
12590            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12591
12592        for query_match in query_matches.into_iter() {
12593            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12594            let offset_range = if reversed {
12595                query_match.end()..query_match.start()
12596            } else {
12597                query_match.start()..query_match.end()
12598            };
12599            let display_range = offset_range.start.to_display_point(&display_map)
12600                ..offset_range.end.to_display_point(&display_map);
12601
12602            if !select_next_state.wordwise
12603                || (!movement::is_inside_word(&display_map, display_range.start)
12604                    && !movement::is_inside_word(&display_map, display_range.end))
12605            {
12606                new_selections.push(offset_range.start..offset_range.end);
12607            }
12608        }
12609
12610        select_next_state.done = true;
12611        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12612        self.change_selections(None, window, cx, |selections| {
12613            selections.select_ranges(new_selections)
12614        });
12615
12616        Ok(())
12617    }
12618
12619    pub fn select_next(
12620        &mut self,
12621        action: &SelectNext,
12622        window: &mut Window,
12623        cx: &mut Context<Self>,
12624    ) -> Result<()> {
12625        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12626        self.push_to_selection_history();
12627        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12628        self.select_next_match_internal(
12629            &display_map,
12630            action.replace_newest,
12631            Some(Autoscroll::newest()),
12632            window,
12633            cx,
12634        )?;
12635        Ok(())
12636    }
12637
12638    pub fn select_previous(
12639        &mut self,
12640        action: &SelectPrevious,
12641        window: &mut Window,
12642        cx: &mut Context<Self>,
12643    ) -> Result<()> {
12644        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12645        self.push_to_selection_history();
12646        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12647        let buffer = &display_map.buffer_snapshot;
12648        let mut selections = self.selections.all::<usize>(cx);
12649        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12650            let query = &select_prev_state.query;
12651            if !select_prev_state.done {
12652                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12653                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12654                let mut next_selected_range = None;
12655                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12656                let bytes_before_last_selection =
12657                    buffer.reversed_bytes_in_range(0..last_selection.start);
12658                let bytes_after_first_selection =
12659                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12660                let query_matches = query
12661                    .stream_find_iter(bytes_before_last_selection)
12662                    .map(|result| (last_selection.start, result))
12663                    .chain(
12664                        query
12665                            .stream_find_iter(bytes_after_first_selection)
12666                            .map(|result| (buffer.len(), result)),
12667                    );
12668                for (end_offset, query_match) in query_matches {
12669                    let query_match = query_match.unwrap(); // can only fail due to I/O
12670                    let offset_range =
12671                        end_offset - query_match.end()..end_offset - query_match.start();
12672                    let display_range = offset_range.start.to_display_point(&display_map)
12673                        ..offset_range.end.to_display_point(&display_map);
12674
12675                    if !select_prev_state.wordwise
12676                        || (!movement::is_inside_word(&display_map, display_range.start)
12677                            && !movement::is_inside_word(&display_map, display_range.end))
12678                    {
12679                        next_selected_range = Some(offset_range);
12680                        break;
12681                    }
12682                }
12683
12684                if let Some(next_selected_range) = next_selected_range {
12685                    self.select_match_ranges(
12686                        next_selected_range,
12687                        last_selection.reversed,
12688                        action.replace_newest,
12689                        Some(Autoscroll::newest()),
12690                        window,
12691                        cx,
12692                    );
12693                } else {
12694                    select_prev_state.done = true;
12695                }
12696            }
12697
12698            self.select_prev_state = Some(select_prev_state);
12699        } else {
12700            let mut only_carets = true;
12701            let mut same_text_selected = true;
12702            let mut selected_text = None;
12703
12704            let mut selections_iter = selections.iter().peekable();
12705            while let Some(selection) = selections_iter.next() {
12706                if selection.start != selection.end {
12707                    only_carets = false;
12708                }
12709
12710                if same_text_selected {
12711                    if selected_text.is_none() {
12712                        selected_text =
12713                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12714                    }
12715
12716                    if let Some(next_selection) = selections_iter.peek() {
12717                        if next_selection.range().len() == selection.range().len() {
12718                            let next_selected_text = buffer
12719                                .text_for_range(next_selection.range())
12720                                .collect::<String>();
12721                            if Some(next_selected_text) != selected_text {
12722                                same_text_selected = false;
12723                                selected_text = None;
12724                            }
12725                        } else {
12726                            same_text_selected = false;
12727                            selected_text = None;
12728                        }
12729                    }
12730                }
12731            }
12732
12733            if only_carets {
12734                for selection in &mut selections {
12735                    let word_range = movement::surrounding_word(
12736                        &display_map,
12737                        selection.start.to_display_point(&display_map),
12738                    );
12739                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12740                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12741                    selection.goal = SelectionGoal::None;
12742                    selection.reversed = false;
12743                    self.select_match_ranges(
12744                        selection.start..selection.end,
12745                        selection.reversed,
12746                        action.replace_newest,
12747                        Some(Autoscroll::newest()),
12748                        window,
12749                        cx,
12750                    );
12751                }
12752                if selections.len() == 1 {
12753                    let selection = selections
12754                        .last()
12755                        .expect("ensured that there's only one selection");
12756                    let query = buffer
12757                        .text_for_range(selection.start..selection.end)
12758                        .collect::<String>();
12759                    let is_empty = query.is_empty();
12760                    let select_state = SelectNextState {
12761                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12762                        wordwise: true,
12763                        done: is_empty,
12764                    };
12765                    self.select_prev_state = Some(select_state);
12766                } else {
12767                    self.select_prev_state = None;
12768                }
12769            } else if let Some(selected_text) = selected_text {
12770                self.select_prev_state = Some(SelectNextState {
12771                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12772                    wordwise: false,
12773                    done: false,
12774                });
12775                self.select_previous(action, window, cx)?;
12776            }
12777        }
12778        Ok(())
12779    }
12780
12781    pub fn find_next_match(
12782        &mut self,
12783        _: &FindNextMatch,
12784        window: &mut Window,
12785        cx: &mut Context<Self>,
12786    ) -> Result<()> {
12787        let selections = self.selections.disjoint_anchors();
12788        match selections.first() {
12789            Some(first) if selections.len() >= 2 => {
12790                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12791                    s.select_ranges([first.range()]);
12792                });
12793            }
12794            _ => self.select_next(
12795                &SelectNext {
12796                    replace_newest: true,
12797                },
12798                window,
12799                cx,
12800            )?,
12801        }
12802        Ok(())
12803    }
12804
12805    pub fn find_previous_match(
12806        &mut self,
12807        _: &FindPreviousMatch,
12808        window: &mut Window,
12809        cx: &mut Context<Self>,
12810    ) -> Result<()> {
12811        let selections = self.selections.disjoint_anchors();
12812        match selections.last() {
12813            Some(last) if selections.len() >= 2 => {
12814                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12815                    s.select_ranges([last.range()]);
12816                });
12817            }
12818            _ => self.select_previous(
12819                &SelectPrevious {
12820                    replace_newest: true,
12821                },
12822                window,
12823                cx,
12824            )?,
12825        }
12826        Ok(())
12827    }
12828
12829    pub fn toggle_comments(
12830        &mut self,
12831        action: &ToggleComments,
12832        window: &mut Window,
12833        cx: &mut Context<Self>,
12834    ) {
12835        if self.read_only(cx) {
12836            return;
12837        }
12838        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12839        let text_layout_details = &self.text_layout_details(window);
12840        self.transact(window, cx, |this, window, cx| {
12841            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12842            let mut edits = Vec::new();
12843            let mut selection_edit_ranges = Vec::new();
12844            let mut last_toggled_row = None;
12845            let snapshot = this.buffer.read(cx).read(cx);
12846            let empty_str: Arc<str> = Arc::default();
12847            let mut suffixes_inserted = Vec::new();
12848            let ignore_indent = action.ignore_indent;
12849
12850            fn comment_prefix_range(
12851                snapshot: &MultiBufferSnapshot,
12852                row: MultiBufferRow,
12853                comment_prefix: &str,
12854                comment_prefix_whitespace: &str,
12855                ignore_indent: bool,
12856            ) -> Range<Point> {
12857                let indent_size = if ignore_indent {
12858                    0
12859                } else {
12860                    snapshot.indent_size_for_line(row).len
12861                };
12862
12863                let start = Point::new(row.0, indent_size);
12864
12865                let mut line_bytes = snapshot
12866                    .bytes_in_range(start..snapshot.max_point())
12867                    .flatten()
12868                    .copied();
12869
12870                // If this line currently begins with the line comment prefix, then record
12871                // the range containing the prefix.
12872                if line_bytes
12873                    .by_ref()
12874                    .take(comment_prefix.len())
12875                    .eq(comment_prefix.bytes())
12876                {
12877                    // Include any whitespace that matches the comment prefix.
12878                    let matching_whitespace_len = line_bytes
12879                        .zip(comment_prefix_whitespace.bytes())
12880                        .take_while(|(a, b)| a == b)
12881                        .count() as u32;
12882                    let end = Point::new(
12883                        start.row,
12884                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12885                    );
12886                    start..end
12887                } else {
12888                    start..start
12889                }
12890            }
12891
12892            fn comment_suffix_range(
12893                snapshot: &MultiBufferSnapshot,
12894                row: MultiBufferRow,
12895                comment_suffix: &str,
12896                comment_suffix_has_leading_space: bool,
12897            ) -> Range<Point> {
12898                let end = Point::new(row.0, snapshot.line_len(row));
12899                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12900
12901                let mut line_end_bytes = snapshot
12902                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12903                    .flatten()
12904                    .copied();
12905
12906                let leading_space_len = if suffix_start_column > 0
12907                    && line_end_bytes.next() == Some(b' ')
12908                    && comment_suffix_has_leading_space
12909                {
12910                    1
12911                } else {
12912                    0
12913                };
12914
12915                // If this line currently begins with the line comment prefix, then record
12916                // the range containing the prefix.
12917                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12918                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12919                    start..end
12920                } else {
12921                    end..end
12922                }
12923            }
12924
12925            // TODO: Handle selections that cross excerpts
12926            for selection in &mut selections {
12927                let start_column = snapshot
12928                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12929                    .len;
12930                let language = if let Some(language) =
12931                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12932                {
12933                    language
12934                } else {
12935                    continue;
12936                };
12937
12938                selection_edit_ranges.clear();
12939
12940                // If multiple selections contain a given row, avoid processing that
12941                // row more than once.
12942                let mut start_row = MultiBufferRow(selection.start.row);
12943                if last_toggled_row == Some(start_row) {
12944                    start_row = start_row.next_row();
12945                }
12946                let end_row =
12947                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12948                        MultiBufferRow(selection.end.row - 1)
12949                    } else {
12950                        MultiBufferRow(selection.end.row)
12951                    };
12952                last_toggled_row = Some(end_row);
12953
12954                if start_row > end_row {
12955                    continue;
12956                }
12957
12958                // If the language has line comments, toggle those.
12959                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12960
12961                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12962                if ignore_indent {
12963                    full_comment_prefixes = full_comment_prefixes
12964                        .into_iter()
12965                        .map(|s| Arc::from(s.trim_end()))
12966                        .collect();
12967                }
12968
12969                if !full_comment_prefixes.is_empty() {
12970                    let first_prefix = full_comment_prefixes
12971                        .first()
12972                        .expect("prefixes is non-empty");
12973                    let prefix_trimmed_lengths = full_comment_prefixes
12974                        .iter()
12975                        .map(|p| p.trim_end_matches(' ').len())
12976                        .collect::<SmallVec<[usize; 4]>>();
12977
12978                    let mut all_selection_lines_are_comments = true;
12979
12980                    for row in start_row.0..=end_row.0 {
12981                        let row = MultiBufferRow(row);
12982                        if start_row < end_row && snapshot.is_line_blank(row) {
12983                            continue;
12984                        }
12985
12986                        let prefix_range = full_comment_prefixes
12987                            .iter()
12988                            .zip(prefix_trimmed_lengths.iter().copied())
12989                            .map(|(prefix, trimmed_prefix_len)| {
12990                                comment_prefix_range(
12991                                    snapshot.deref(),
12992                                    row,
12993                                    &prefix[..trimmed_prefix_len],
12994                                    &prefix[trimmed_prefix_len..],
12995                                    ignore_indent,
12996                                )
12997                            })
12998                            .max_by_key(|range| range.end.column - range.start.column)
12999                            .expect("prefixes is non-empty");
13000
13001                        if prefix_range.is_empty() {
13002                            all_selection_lines_are_comments = false;
13003                        }
13004
13005                        selection_edit_ranges.push(prefix_range);
13006                    }
13007
13008                    if all_selection_lines_are_comments {
13009                        edits.extend(
13010                            selection_edit_ranges
13011                                .iter()
13012                                .cloned()
13013                                .map(|range| (range, empty_str.clone())),
13014                        );
13015                    } else {
13016                        let min_column = selection_edit_ranges
13017                            .iter()
13018                            .map(|range| range.start.column)
13019                            .min()
13020                            .unwrap_or(0);
13021                        edits.extend(selection_edit_ranges.iter().map(|range| {
13022                            let position = Point::new(range.start.row, min_column);
13023                            (position..position, first_prefix.clone())
13024                        }));
13025                    }
13026                } else if let Some((full_comment_prefix, comment_suffix)) =
13027                    language.block_comment_delimiters()
13028                {
13029                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13030                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13031                    let prefix_range = comment_prefix_range(
13032                        snapshot.deref(),
13033                        start_row,
13034                        comment_prefix,
13035                        comment_prefix_whitespace,
13036                        ignore_indent,
13037                    );
13038                    let suffix_range = comment_suffix_range(
13039                        snapshot.deref(),
13040                        end_row,
13041                        comment_suffix.trim_start_matches(' '),
13042                        comment_suffix.starts_with(' '),
13043                    );
13044
13045                    if prefix_range.is_empty() || suffix_range.is_empty() {
13046                        edits.push((
13047                            prefix_range.start..prefix_range.start,
13048                            full_comment_prefix.clone(),
13049                        ));
13050                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13051                        suffixes_inserted.push((end_row, comment_suffix.len()));
13052                    } else {
13053                        edits.push((prefix_range, empty_str.clone()));
13054                        edits.push((suffix_range, empty_str.clone()));
13055                    }
13056                } else {
13057                    continue;
13058                }
13059            }
13060
13061            drop(snapshot);
13062            this.buffer.update(cx, |buffer, cx| {
13063                buffer.edit(edits, None, cx);
13064            });
13065
13066            // Adjust selections so that they end before any comment suffixes that
13067            // were inserted.
13068            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13069            let mut selections = this.selections.all::<Point>(cx);
13070            let snapshot = this.buffer.read(cx).read(cx);
13071            for selection in &mut selections {
13072                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13073                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13074                        Ordering::Less => {
13075                            suffixes_inserted.next();
13076                            continue;
13077                        }
13078                        Ordering::Greater => break,
13079                        Ordering::Equal => {
13080                            if selection.end.column == snapshot.line_len(row) {
13081                                if selection.is_empty() {
13082                                    selection.start.column -= suffix_len as u32;
13083                                }
13084                                selection.end.column -= suffix_len as u32;
13085                            }
13086                            break;
13087                        }
13088                    }
13089                }
13090            }
13091
13092            drop(snapshot);
13093            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13094                s.select(selections)
13095            });
13096
13097            let selections = this.selections.all::<Point>(cx);
13098            let selections_on_single_row = selections.windows(2).all(|selections| {
13099                selections[0].start.row == selections[1].start.row
13100                    && selections[0].end.row == selections[1].end.row
13101                    && selections[0].start.row == selections[0].end.row
13102            });
13103            let selections_selecting = selections
13104                .iter()
13105                .any(|selection| selection.start != selection.end);
13106            let advance_downwards = action.advance_downwards
13107                && selections_on_single_row
13108                && !selections_selecting
13109                && !matches!(this.mode, EditorMode::SingleLine { .. });
13110
13111            if advance_downwards {
13112                let snapshot = this.buffer.read(cx).snapshot(cx);
13113
13114                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13115                    s.move_cursors_with(|display_snapshot, display_point, _| {
13116                        let mut point = display_point.to_point(display_snapshot);
13117                        point.row += 1;
13118                        point = snapshot.clip_point(point, Bias::Left);
13119                        let display_point = point.to_display_point(display_snapshot);
13120                        let goal = SelectionGoal::HorizontalPosition(
13121                            display_snapshot
13122                                .x_for_display_point(display_point, text_layout_details)
13123                                .into(),
13124                        );
13125                        (display_point, goal)
13126                    })
13127                });
13128            }
13129        });
13130    }
13131
13132    pub fn select_enclosing_symbol(
13133        &mut self,
13134        _: &SelectEnclosingSymbol,
13135        window: &mut Window,
13136        cx: &mut Context<Self>,
13137    ) {
13138        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13139
13140        let buffer = self.buffer.read(cx).snapshot(cx);
13141        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13142
13143        fn update_selection(
13144            selection: &Selection<usize>,
13145            buffer_snap: &MultiBufferSnapshot,
13146        ) -> Option<Selection<usize>> {
13147            let cursor = selection.head();
13148            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13149            for symbol in symbols.iter().rev() {
13150                let start = symbol.range.start.to_offset(buffer_snap);
13151                let end = symbol.range.end.to_offset(buffer_snap);
13152                let new_range = start..end;
13153                if start < selection.start || end > selection.end {
13154                    return Some(Selection {
13155                        id: selection.id,
13156                        start: new_range.start,
13157                        end: new_range.end,
13158                        goal: SelectionGoal::None,
13159                        reversed: selection.reversed,
13160                    });
13161                }
13162            }
13163            None
13164        }
13165
13166        let mut selected_larger_symbol = false;
13167        let new_selections = old_selections
13168            .iter()
13169            .map(|selection| match update_selection(selection, &buffer) {
13170                Some(new_selection) => {
13171                    if new_selection.range() != selection.range() {
13172                        selected_larger_symbol = true;
13173                    }
13174                    new_selection
13175                }
13176                None => selection.clone(),
13177            })
13178            .collect::<Vec<_>>();
13179
13180        if selected_larger_symbol {
13181            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13182                s.select(new_selections);
13183            });
13184        }
13185    }
13186
13187    pub fn select_larger_syntax_node(
13188        &mut self,
13189        _: &SelectLargerSyntaxNode,
13190        window: &mut Window,
13191        cx: &mut Context<Self>,
13192    ) {
13193        let Some(visible_row_count) = self.visible_row_count() else {
13194            return;
13195        };
13196        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13197        if old_selections.is_empty() {
13198            return;
13199        }
13200
13201        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13202
13203        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13204        let buffer = self.buffer.read(cx).snapshot(cx);
13205
13206        let mut selected_larger_node = false;
13207        let mut new_selections = old_selections
13208            .iter()
13209            .map(|selection| {
13210                let old_range = selection.start..selection.end;
13211
13212                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13213                    // manually select word at selection
13214                    if ["string_content", "inline"].contains(&node.kind()) {
13215                        let word_range = {
13216                            let display_point = buffer
13217                                .offset_to_point(old_range.start)
13218                                .to_display_point(&display_map);
13219                            let Range { start, end } =
13220                                movement::surrounding_word(&display_map, display_point);
13221                            start.to_point(&display_map).to_offset(&buffer)
13222                                ..end.to_point(&display_map).to_offset(&buffer)
13223                        };
13224                        // ignore if word is already selected
13225                        if !word_range.is_empty() && old_range != word_range {
13226                            let last_word_range = {
13227                                let display_point = buffer
13228                                    .offset_to_point(old_range.end)
13229                                    .to_display_point(&display_map);
13230                                let Range { start, end } =
13231                                    movement::surrounding_word(&display_map, display_point);
13232                                start.to_point(&display_map).to_offset(&buffer)
13233                                    ..end.to_point(&display_map).to_offset(&buffer)
13234                            };
13235                            // only select word if start and end point belongs to same word
13236                            if word_range == last_word_range {
13237                                selected_larger_node = true;
13238                                return Selection {
13239                                    id: selection.id,
13240                                    start: word_range.start,
13241                                    end: word_range.end,
13242                                    goal: SelectionGoal::None,
13243                                    reversed: selection.reversed,
13244                                };
13245                            }
13246                        }
13247                    }
13248                }
13249
13250                let mut new_range = old_range.clone();
13251                while let Some((_node, containing_range)) =
13252                    buffer.syntax_ancestor(new_range.clone())
13253                {
13254                    new_range = match containing_range {
13255                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13256                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13257                    };
13258                    if !display_map.intersects_fold(new_range.start)
13259                        && !display_map.intersects_fold(new_range.end)
13260                    {
13261                        break;
13262                    }
13263                }
13264
13265                selected_larger_node |= new_range != old_range;
13266                Selection {
13267                    id: selection.id,
13268                    start: new_range.start,
13269                    end: new_range.end,
13270                    goal: SelectionGoal::None,
13271                    reversed: selection.reversed,
13272                }
13273            })
13274            .collect::<Vec<_>>();
13275
13276        if !selected_larger_node {
13277            return; // don't put this call in the history
13278        }
13279
13280        // scroll based on transformation done to the last selection created by the user
13281        let (last_old, last_new) = old_selections
13282            .last()
13283            .zip(new_selections.last().cloned())
13284            .expect("old_selections isn't empty");
13285
13286        // revert selection
13287        let is_selection_reversed = {
13288            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13289            new_selections.last_mut().expect("checked above").reversed =
13290                should_newest_selection_be_reversed;
13291            should_newest_selection_be_reversed
13292        };
13293
13294        if selected_larger_node {
13295            self.select_syntax_node_history.disable_clearing = true;
13296            self.change_selections(None, window, cx, |s| {
13297                s.select(new_selections.clone());
13298            });
13299            self.select_syntax_node_history.disable_clearing = false;
13300        }
13301
13302        let start_row = last_new.start.to_display_point(&display_map).row().0;
13303        let end_row = last_new.end.to_display_point(&display_map).row().0;
13304        let selection_height = end_row - start_row + 1;
13305        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13306
13307        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13308        let scroll_behavior = if fits_on_the_screen {
13309            self.request_autoscroll(Autoscroll::fit(), cx);
13310            SelectSyntaxNodeScrollBehavior::FitSelection
13311        } else if is_selection_reversed {
13312            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13313            SelectSyntaxNodeScrollBehavior::CursorTop
13314        } else {
13315            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13316            SelectSyntaxNodeScrollBehavior::CursorBottom
13317        };
13318
13319        self.select_syntax_node_history.push((
13320            old_selections,
13321            scroll_behavior,
13322            is_selection_reversed,
13323        ));
13324    }
13325
13326    pub fn select_smaller_syntax_node(
13327        &mut self,
13328        _: &SelectSmallerSyntaxNode,
13329        window: &mut Window,
13330        cx: &mut Context<Self>,
13331    ) {
13332        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13333
13334        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13335            self.select_syntax_node_history.pop()
13336        {
13337            if let Some(selection) = selections.last_mut() {
13338                selection.reversed = is_selection_reversed;
13339            }
13340
13341            self.select_syntax_node_history.disable_clearing = true;
13342            self.change_selections(None, window, cx, |s| {
13343                s.select(selections.to_vec());
13344            });
13345            self.select_syntax_node_history.disable_clearing = false;
13346
13347            match scroll_behavior {
13348                SelectSyntaxNodeScrollBehavior::CursorTop => {
13349                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13350                }
13351                SelectSyntaxNodeScrollBehavior::FitSelection => {
13352                    self.request_autoscroll(Autoscroll::fit(), cx);
13353                }
13354                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13355                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13356                }
13357            }
13358        }
13359    }
13360
13361    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13362        if !EditorSettings::get_global(cx).gutter.runnables {
13363            self.clear_tasks();
13364            return Task::ready(());
13365        }
13366        let project = self.project.as_ref().map(Entity::downgrade);
13367        let task_sources = self.lsp_task_sources(cx);
13368        cx.spawn_in(window, async move |editor, cx| {
13369            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13370            let Some(project) = project.and_then(|p| p.upgrade()) else {
13371                return;
13372            };
13373            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13374                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13375            }) else {
13376                return;
13377            };
13378
13379            let hide_runnables = project
13380                .update(cx, |project, cx| {
13381                    // Do not display any test indicators in non-dev server remote projects.
13382                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13383                })
13384                .unwrap_or(true);
13385            if hide_runnables {
13386                return;
13387            }
13388            let new_rows =
13389                cx.background_spawn({
13390                    let snapshot = display_snapshot.clone();
13391                    async move {
13392                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13393                    }
13394                })
13395                    .await;
13396            let Ok(lsp_tasks) =
13397                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13398            else {
13399                return;
13400            };
13401            let lsp_tasks = lsp_tasks.await;
13402
13403            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13404                lsp_tasks
13405                    .into_iter()
13406                    .flat_map(|(kind, tasks)| {
13407                        tasks.into_iter().filter_map(move |(location, task)| {
13408                            Some((kind.clone(), location?, task))
13409                        })
13410                    })
13411                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13412                        let buffer = location.target.buffer;
13413                        let buffer_snapshot = buffer.read(cx).snapshot();
13414                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13415                            |(excerpt_id, snapshot, _)| {
13416                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13417                                    display_snapshot
13418                                        .buffer_snapshot
13419                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13420                                } else {
13421                                    None
13422                                }
13423                            },
13424                        );
13425                        if let Some(offset) = offset {
13426                            let task_buffer_range =
13427                                location.target.range.to_point(&buffer_snapshot);
13428                            let context_buffer_range =
13429                                task_buffer_range.to_offset(&buffer_snapshot);
13430                            let context_range = BufferOffset(context_buffer_range.start)
13431                                ..BufferOffset(context_buffer_range.end);
13432
13433                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13434                                .or_insert_with(|| RunnableTasks {
13435                                    templates: Vec::new(),
13436                                    offset,
13437                                    column: task_buffer_range.start.column,
13438                                    extra_variables: HashMap::default(),
13439                                    context_range,
13440                                })
13441                                .templates
13442                                .push((kind, task.original_task().clone()));
13443                        }
13444
13445                        acc
13446                    })
13447            }) else {
13448                return;
13449            };
13450
13451            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13452            editor
13453                .update(cx, |editor, _| {
13454                    editor.clear_tasks();
13455                    for (key, mut value) in rows {
13456                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13457                            value.templates.extend(lsp_tasks.templates);
13458                        }
13459
13460                        editor.insert_tasks(key, value);
13461                    }
13462                    for (key, value) in lsp_tasks_by_rows {
13463                        editor.insert_tasks(key, value);
13464                    }
13465                })
13466                .ok();
13467        })
13468    }
13469    fn fetch_runnable_ranges(
13470        snapshot: &DisplaySnapshot,
13471        range: Range<Anchor>,
13472    ) -> Vec<language::RunnableRange> {
13473        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13474    }
13475
13476    fn runnable_rows(
13477        project: Entity<Project>,
13478        snapshot: DisplaySnapshot,
13479        runnable_ranges: Vec<RunnableRange>,
13480        mut cx: AsyncWindowContext,
13481    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13482        runnable_ranges
13483            .into_iter()
13484            .filter_map(|mut runnable| {
13485                let tasks = cx
13486                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13487                    .ok()?;
13488                if tasks.is_empty() {
13489                    return None;
13490                }
13491
13492                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13493
13494                let row = snapshot
13495                    .buffer_snapshot
13496                    .buffer_line_for_row(MultiBufferRow(point.row))?
13497                    .1
13498                    .start
13499                    .row;
13500
13501                let context_range =
13502                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13503                Some((
13504                    (runnable.buffer_id, row),
13505                    RunnableTasks {
13506                        templates: tasks,
13507                        offset: snapshot
13508                            .buffer_snapshot
13509                            .anchor_before(runnable.run_range.start),
13510                        context_range,
13511                        column: point.column,
13512                        extra_variables: runnable.extra_captures,
13513                    },
13514                ))
13515            })
13516            .collect()
13517    }
13518
13519    fn templates_with_tags(
13520        project: &Entity<Project>,
13521        runnable: &mut Runnable,
13522        cx: &mut App,
13523    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13524        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13525            let (worktree_id, file) = project
13526                .buffer_for_id(runnable.buffer, cx)
13527                .and_then(|buffer| buffer.read(cx).file())
13528                .map(|file| (file.worktree_id(cx), file.clone()))
13529                .unzip();
13530
13531            (
13532                project.task_store().read(cx).task_inventory().cloned(),
13533                worktree_id,
13534                file,
13535            )
13536        });
13537
13538        let mut templates_with_tags = mem::take(&mut runnable.tags)
13539            .into_iter()
13540            .flat_map(|RunnableTag(tag)| {
13541                inventory
13542                    .as_ref()
13543                    .into_iter()
13544                    .flat_map(|inventory| {
13545                        inventory.read(cx).list_tasks(
13546                            file.clone(),
13547                            Some(runnable.language.clone()),
13548                            worktree_id,
13549                            cx,
13550                        )
13551                    })
13552                    .filter(move |(_, template)| {
13553                        template.tags.iter().any(|source_tag| source_tag == &tag)
13554                    })
13555            })
13556            .sorted_by_key(|(kind, _)| kind.to_owned())
13557            .collect::<Vec<_>>();
13558        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13559            // Strongest source wins; if we have worktree tag binding, prefer that to
13560            // global and language bindings;
13561            // if we have a global binding, prefer that to language binding.
13562            let first_mismatch = templates_with_tags
13563                .iter()
13564                .position(|(tag_source, _)| tag_source != leading_tag_source);
13565            if let Some(index) = first_mismatch {
13566                templates_with_tags.truncate(index);
13567            }
13568        }
13569
13570        templates_with_tags
13571    }
13572
13573    pub fn move_to_enclosing_bracket(
13574        &mut self,
13575        _: &MoveToEnclosingBracket,
13576        window: &mut Window,
13577        cx: &mut Context<Self>,
13578    ) {
13579        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13580        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13581            s.move_offsets_with(|snapshot, selection| {
13582                let Some(enclosing_bracket_ranges) =
13583                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13584                else {
13585                    return;
13586                };
13587
13588                let mut best_length = usize::MAX;
13589                let mut best_inside = false;
13590                let mut best_in_bracket_range = false;
13591                let mut best_destination = None;
13592                for (open, close) in enclosing_bracket_ranges {
13593                    let close = close.to_inclusive();
13594                    let length = close.end() - open.start;
13595                    let inside = selection.start >= open.end && selection.end <= *close.start();
13596                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13597                        || close.contains(&selection.head());
13598
13599                    // If best is next to a bracket and current isn't, skip
13600                    if !in_bracket_range && best_in_bracket_range {
13601                        continue;
13602                    }
13603
13604                    // Prefer smaller lengths unless best is inside and current isn't
13605                    if length > best_length && (best_inside || !inside) {
13606                        continue;
13607                    }
13608
13609                    best_length = length;
13610                    best_inside = inside;
13611                    best_in_bracket_range = in_bracket_range;
13612                    best_destination = Some(
13613                        if close.contains(&selection.start) && close.contains(&selection.end) {
13614                            if inside { open.end } else { open.start }
13615                        } else if inside {
13616                            *close.start()
13617                        } else {
13618                            *close.end()
13619                        },
13620                    );
13621                }
13622
13623                if let Some(destination) = best_destination {
13624                    selection.collapse_to(destination, SelectionGoal::None);
13625                }
13626            })
13627        });
13628    }
13629
13630    pub fn undo_selection(
13631        &mut self,
13632        _: &UndoSelection,
13633        window: &mut Window,
13634        cx: &mut Context<Self>,
13635    ) {
13636        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13637        self.end_selection(window, cx);
13638        self.selection_history.mode = SelectionHistoryMode::Undoing;
13639        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13640            self.change_selections(None, window, cx, |s| {
13641                s.select_anchors(entry.selections.to_vec())
13642            });
13643            self.select_next_state = entry.select_next_state;
13644            self.select_prev_state = entry.select_prev_state;
13645            self.add_selections_state = entry.add_selections_state;
13646            self.request_autoscroll(Autoscroll::newest(), cx);
13647        }
13648        self.selection_history.mode = SelectionHistoryMode::Normal;
13649    }
13650
13651    pub fn redo_selection(
13652        &mut self,
13653        _: &RedoSelection,
13654        window: &mut Window,
13655        cx: &mut Context<Self>,
13656    ) {
13657        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13658        self.end_selection(window, cx);
13659        self.selection_history.mode = SelectionHistoryMode::Redoing;
13660        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13661            self.change_selections(None, window, cx, |s| {
13662                s.select_anchors(entry.selections.to_vec())
13663            });
13664            self.select_next_state = entry.select_next_state;
13665            self.select_prev_state = entry.select_prev_state;
13666            self.add_selections_state = entry.add_selections_state;
13667            self.request_autoscroll(Autoscroll::newest(), cx);
13668        }
13669        self.selection_history.mode = SelectionHistoryMode::Normal;
13670    }
13671
13672    pub fn expand_excerpts(
13673        &mut self,
13674        action: &ExpandExcerpts,
13675        _: &mut Window,
13676        cx: &mut Context<Self>,
13677    ) {
13678        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13679    }
13680
13681    pub fn expand_excerpts_down(
13682        &mut self,
13683        action: &ExpandExcerptsDown,
13684        _: &mut Window,
13685        cx: &mut Context<Self>,
13686    ) {
13687        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13688    }
13689
13690    pub fn expand_excerpts_up(
13691        &mut self,
13692        action: &ExpandExcerptsUp,
13693        _: &mut Window,
13694        cx: &mut Context<Self>,
13695    ) {
13696        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13697    }
13698
13699    pub fn expand_excerpts_for_direction(
13700        &mut self,
13701        lines: u32,
13702        direction: ExpandExcerptDirection,
13703
13704        cx: &mut Context<Self>,
13705    ) {
13706        let selections = self.selections.disjoint_anchors();
13707
13708        let lines = if lines == 0 {
13709            EditorSettings::get_global(cx).expand_excerpt_lines
13710        } else {
13711            lines
13712        };
13713
13714        self.buffer.update(cx, |buffer, cx| {
13715            let snapshot = buffer.snapshot(cx);
13716            let mut excerpt_ids = selections
13717                .iter()
13718                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13719                .collect::<Vec<_>>();
13720            excerpt_ids.sort();
13721            excerpt_ids.dedup();
13722            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13723        })
13724    }
13725
13726    pub fn expand_excerpt(
13727        &mut self,
13728        excerpt: ExcerptId,
13729        direction: ExpandExcerptDirection,
13730        window: &mut Window,
13731        cx: &mut Context<Self>,
13732    ) {
13733        let current_scroll_position = self.scroll_position(cx);
13734        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13735        let mut should_scroll_up = false;
13736
13737        if direction == ExpandExcerptDirection::Down {
13738            let multi_buffer = self.buffer.read(cx);
13739            let snapshot = multi_buffer.snapshot(cx);
13740            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13741                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13742                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13743                        let buffer_snapshot = buffer.read(cx).snapshot();
13744                        let excerpt_end_row =
13745                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13746                        let last_row = buffer_snapshot.max_point().row;
13747                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13748                        should_scroll_up = lines_below >= lines_to_expand;
13749                    }
13750                }
13751            }
13752        }
13753
13754        self.buffer.update(cx, |buffer, cx| {
13755            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13756        });
13757
13758        if should_scroll_up {
13759            let new_scroll_position =
13760                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13761            self.set_scroll_position(new_scroll_position, window, cx);
13762        }
13763    }
13764
13765    pub fn go_to_singleton_buffer_point(
13766        &mut self,
13767        point: Point,
13768        window: &mut Window,
13769        cx: &mut Context<Self>,
13770    ) {
13771        self.go_to_singleton_buffer_range(point..point, window, cx);
13772    }
13773
13774    pub fn go_to_singleton_buffer_range(
13775        &mut self,
13776        range: Range<Point>,
13777        window: &mut Window,
13778        cx: &mut Context<Self>,
13779    ) {
13780        let multibuffer = self.buffer().read(cx);
13781        let Some(buffer) = multibuffer.as_singleton() else {
13782            return;
13783        };
13784        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13785            return;
13786        };
13787        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13788            return;
13789        };
13790        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13791            s.select_anchor_ranges([start..end])
13792        });
13793    }
13794
13795    pub fn go_to_diagnostic(
13796        &mut self,
13797        _: &GoToDiagnostic,
13798        window: &mut Window,
13799        cx: &mut Context<Self>,
13800    ) {
13801        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13802        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13803    }
13804
13805    pub fn go_to_prev_diagnostic(
13806        &mut self,
13807        _: &GoToPreviousDiagnostic,
13808        window: &mut Window,
13809        cx: &mut Context<Self>,
13810    ) {
13811        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13812        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13813    }
13814
13815    pub fn go_to_diagnostic_impl(
13816        &mut self,
13817        direction: Direction,
13818        window: &mut Window,
13819        cx: &mut Context<Self>,
13820    ) {
13821        let buffer = self.buffer.read(cx).snapshot(cx);
13822        let selection = self.selections.newest::<usize>(cx);
13823
13824        let mut active_group_id = None;
13825        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13826            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13827                active_group_id = Some(active_group.group_id);
13828            }
13829        }
13830
13831        fn filtered(
13832            snapshot: EditorSnapshot,
13833            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13834        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13835            diagnostics
13836                .filter(|entry| entry.range.start != entry.range.end)
13837                .filter(|entry| !entry.diagnostic.is_unnecessary)
13838                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13839        }
13840
13841        let snapshot = self.snapshot(window, cx);
13842        let before = filtered(
13843            snapshot.clone(),
13844            buffer
13845                .diagnostics_in_range(0..selection.start)
13846                .filter(|entry| entry.range.start <= selection.start),
13847        );
13848        let after = filtered(
13849            snapshot,
13850            buffer
13851                .diagnostics_in_range(selection.start..buffer.len())
13852                .filter(|entry| entry.range.start >= selection.start),
13853        );
13854
13855        let mut found: Option<DiagnosticEntry<usize>> = None;
13856        if direction == Direction::Prev {
13857            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13858            {
13859                for diagnostic in prev_diagnostics.into_iter().rev() {
13860                    if diagnostic.range.start != selection.start
13861                        || active_group_id
13862                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13863                    {
13864                        found = Some(diagnostic);
13865                        break 'outer;
13866                    }
13867                }
13868            }
13869        } else {
13870            for diagnostic in after.chain(before) {
13871                if diagnostic.range.start != selection.start
13872                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13873                {
13874                    found = Some(diagnostic);
13875                    break;
13876                }
13877            }
13878        }
13879        let Some(next_diagnostic) = found else {
13880            return;
13881        };
13882
13883        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13884            return;
13885        };
13886        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13887            s.select_ranges(vec![
13888                next_diagnostic.range.start..next_diagnostic.range.start,
13889            ])
13890        });
13891        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13892        self.refresh_inline_completion(false, true, window, cx);
13893    }
13894
13895    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13896        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13897        let snapshot = self.snapshot(window, cx);
13898        let selection = self.selections.newest::<Point>(cx);
13899        self.go_to_hunk_before_or_after_position(
13900            &snapshot,
13901            selection.head(),
13902            Direction::Next,
13903            window,
13904            cx,
13905        );
13906    }
13907
13908    pub fn go_to_hunk_before_or_after_position(
13909        &mut self,
13910        snapshot: &EditorSnapshot,
13911        position: Point,
13912        direction: Direction,
13913        window: &mut Window,
13914        cx: &mut Context<Editor>,
13915    ) {
13916        let row = if direction == Direction::Next {
13917            self.hunk_after_position(snapshot, position)
13918                .map(|hunk| hunk.row_range.start)
13919        } else {
13920            self.hunk_before_position(snapshot, position)
13921        };
13922
13923        if let Some(row) = row {
13924            let destination = Point::new(row.0, 0);
13925            let autoscroll = Autoscroll::center();
13926
13927            self.unfold_ranges(&[destination..destination], false, false, cx);
13928            self.change_selections(Some(autoscroll), window, cx, |s| {
13929                s.select_ranges([destination..destination]);
13930            });
13931        }
13932    }
13933
13934    fn hunk_after_position(
13935        &mut self,
13936        snapshot: &EditorSnapshot,
13937        position: Point,
13938    ) -> Option<MultiBufferDiffHunk> {
13939        snapshot
13940            .buffer_snapshot
13941            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13942            .find(|hunk| hunk.row_range.start.0 > position.row)
13943            .or_else(|| {
13944                snapshot
13945                    .buffer_snapshot
13946                    .diff_hunks_in_range(Point::zero()..position)
13947                    .find(|hunk| hunk.row_range.end.0 < position.row)
13948            })
13949    }
13950
13951    fn go_to_prev_hunk(
13952        &mut self,
13953        _: &GoToPreviousHunk,
13954        window: &mut Window,
13955        cx: &mut Context<Self>,
13956    ) {
13957        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13958        let snapshot = self.snapshot(window, cx);
13959        let selection = self.selections.newest::<Point>(cx);
13960        self.go_to_hunk_before_or_after_position(
13961            &snapshot,
13962            selection.head(),
13963            Direction::Prev,
13964            window,
13965            cx,
13966        );
13967    }
13968
13969    fn hunk_before_position(
13970        &mut self,
13971        snapshot: &EditorSnapshot,
13972        position: Point,
13973    ) -> Option<MultiBufferRow> {
13974        snapshot
13975            .buffer_snapshot
13976            .diff_hunk_before(position)
13977            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13978    }
13979
13980    fn go_to_next_change(
13981        &mut self,
13982        _: &GoToNextChange,
13983        window: &mut Window,
13984        cx: &mut Context<Self>,
13985    ) {
13986        if let Some(selections) = self
13987            .change_list
13988            .next_change(1, Direction::Next)
13989            .map(|s| s.to_vec())
13990        {
13991            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13992                let map = s.display_map();
13993                s.select_display_ranges(selections.iter().map(|a| {
13994                    let point = a.to_display_point(&map);
13995                    point..point
13996                }))
13997            })
13998        }
13999    }
14000
14001    fn go_to_previous_change(
14002        &mut self,
14003        _: &GoToPreviousChange,
14004        window: &mut Window,
14005        cx: &mut Context<Self>,
14006    ) {
14007        if let Some(selections) = self
14008            .change_list
14009            .next_change(1, Direction::Prev)
14010            .map(|s| s.to_vec())
14011        {
14012            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14013                let map = s.display_map();
14014                s.select_display_ranges(selections.iter().map(|a| {
14015                    let point = a.to_display_point(&map);
14016                    point..point
14017                }))
14018            })
14019        }
14020    }
14021
14022    fn go_to_line<T: 'static>(
14023        &mut self,
14024        position: Anchor,
14025        highlight_color: Option<Hsla>,
14026        window: &mut Window,
14027        cx: &mut Context<Self>,
14028    ) {
14029        let snapshot = self.snapshot(window, cx).display_snapshot;
14030        let position = position.to_point(&snapshot.buffer_snapshot);
14031        let start = snapshot
14032            .buffer_snapshot
14033            .clip_point(Point::new(position.row, 0), Bias::Left);
14034        let end = start + Point::new(1, 0);
14035        let start = snapshot.buffer_snapshot.anchor_before(start);
14036        let end = snapshot.buffer_snapshot.anchor_before(end);
14037
14038        self.highlight_rows::<T>(
14039            start..end,
14040            highlight_color
14041                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14042            Default::default(),
14043            cx,
14044        );
14045
14046        if self.buffer.read(cx).is_singleton() {
14047            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14048        }
14049    }
14050
14051    pub fn go_to_definition(
14052        &mut self,
14053        _: &GoToDefinition,
14054        window: &mut Window,
14055        cx: &mut Context<Self>,
14056    ) -> Task<Result<Navigated>> {
14057        let definition =
14058            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14059        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14060        cx.spawn_in(window, async move |editor, cx| {
14061            if definition.await? == Navigated::Yes {
14062                return Ok(Navigated::Yes);
14063            }
14064            match fallback_strategy {
14065                GoToDefinitionFallback::None => Ok(Navigated::No),
14066                GoToDefinitionFallback::FindAllReferences => {
14067                    match editor.update_in(cx, |editor, window, cx| {
14068                        editor.find_all_references(&FindAllReferences, window, cx)
14069                    })? {
14070                        Some(references) => references.await,
14071                        None => Ok(Navigated::No),
14072                    }
14073                }
14074            }
14075        })
14076    }
14077
14078    pub fn go_to_declaration(
14079        &mut self,
14080        _: &GoToDeclaration,
14081        window: &mut Window,
14082        cx: &mut Context<Self>,
14083    ) -> Task<Result<Navigated>> {
14084        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14085    }
14086
14087    pub fn go_to_declaration_split(
14088        &mut self,
14089        _: &GoToDeclaration,
14090        window: &mut Window,
14091        cx: &mut Context<Self>,
14092    ) -> Task<Result<Navigated>> {
14093        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14094    }
14095
14096    pub fn go_to_implementation(
14097        &mut self,
14098        _: &GoToImplementation,
14099        window: &mut Window,
14100        cx: &mut Context<Self>,
14101    ) -> Task<Result<Navigated>> {
14102        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14103    }
14104
14105    pub fn go_to_implementation_split(
14106        &mut self,
14107        _: &GoToImplementationSplit,
14108        window: &mut Window,
14109        cx: &mut Context<Self>,
14110    ) -> Task<Result<Navigated>> {
14111        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14112    }
14113
14114    pub fn go_to_type_definition(
14115        &mut self,
14116        _: &GoToTypeDefinition,
14117        window: &mut Window,
14118        cx: &mut Context<Self>,
14119    ) -> Task<Result<Navigated>> {
14120        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14121    }
14122
14123    pub fn go_to_definition_split(
14124        &mut self,
14125        _: &GoToDefinitionSplit,
14126        window: &mut Window,
14127        cx: &mut Context<Self>,
14128    ) -> Task<Result<Navigated>> {
14129        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14130    }
14131
14132    pub fn go_to_type_definition_split(
14133        &mut self,
14134        _: &GoToTypeDefinitionSplit,
14135        window: &mut Window,
14136        cx: &mut Context<Self>,
14137    ) -> Task<Result<Navigated>> {
14138        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14139    }
14140
14141    fn go_to_definition_of_kind(
14142        &mut self,
14143        kind: GotoDefinitionKind,
14144        split: bool,
14145        window: &mut Window,
14146        cx: &mut Context<Self>,
14147    ) -> Task<Result<Navigated>> {
14148        let Some(provider) = self.semantics_provider.clone() else {
14149            return Task::ready(Ok(Navigated::No));
14150        };
14151        let head = self.selections.newest::<usize>(cx).head();
14152        let buffer = self.buffer.read(cx);
14153        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14154            text_anchor
14155        } else {
14156            return Task::ready(Ok(Navigated::No));
14157        };
14158
14159        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14160            return Task::ready(Ok(Navigated::No));
14161        };
14162
14163        cx.spawn_in(window, async move |editor, cx| {
14164            let definitions = definitions.await?;
14165            let navigated = editor
14166                .update_in(cx, |editor, window, cx| {
14167                    editor.navigate_to_hover_links(
14168                        Some(kind),
14169                        definitions
14170                            .into_iter()
14171                            .filter(|location| {
14172                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14173                            })
14174                            .map(HoverLink::Text)
14175                            .collect::<Vec<_>>(),
14176                        split,
14177                        window,
14178                        cx,
14179                    )
14180                })?
14181                .await?;
14182            anyhow::Ok(navigated)
14183        })
14184    }
14185
14186    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14187        let selection = self.selections.newest_anchor();
14188        let head = selection.head();
14189        let tail = selection.tail();
14190
14191        let Some((buffer, start_position)) =
14192            self.buffer.read(cx).text_anchor_for_position(head, cx)
14193        else {
14194            return;
14195        };
14196
14197        let end_position = if head != tail {
14198            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14199                return;
14200            };
14201            Some(pos)
14202        } else {
14203            None
14204        };
14205
14206        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14207            let url = if let Some(end_pos) = end_position {
14208                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14209            } else {
14210                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14211            };
14212
14213            if let Some(url) = url {
14214                editor.update(cx, |_, cx| {
14215                    cx.open_url(&url);
14216                })
14217            } else {
14218                Ok(())
14219            }
14220        });
14221
14222        url_finder.detach();
14223    }
14224
14225    pub fn open_selected_filename(
14226        &mut self,
14227        _: &OpenSelectedFilename,
14228        window: &mut Window,
14229        cx: &mut Context<Self>,
14230    ) {
14231        let Some(workspace) = self.workspace() else {
14232            return;
14233        };
14234
14235        let position = self.selections.newest_anchor().head();
14236
14237        let Some((buffer, buffer_position)) =
14238            self.buffer.read(cx).text_anchor_for_position(position, cx)
14239        else {
14240            return;
14241        };
14242
14243        let project = self.project.clone();
14244
14245        cx.spawn_in(window, async move |_, cx| {
14246            let result = find_file(&buffer, project, buffer_position, cx).await;
14247
14248            if let Some((_, path)) = result {
14249                workspace
14250                    .update_in(cx, |workspace, window, cx| {
14251                        workspace.open_resolved_path(path, window, cx)
14252                    })?
14253                    .await?;
14254            }
14255            anyhow::Ok(())
14256        })
14257        .detach();
14258    }
14259
14260    pub(crate) fn navigate_to_hover_links(
14261        &mut self,
14262        kind: Option<GotoDefinitionKind>,
14263        mut definitions: Vec<HoverLink>,
14264        split: bool,
14265        window: &mut Window,
14266        cx: &mut Context<Editor>,
14267    ) -> Task<Result<Navigated>> {
14268        // If there is one definition, just open it directly
14269        if definitions.len() == 1 {
14270            let definition = definitions.pop().unwrap();
14271
14272            enum TargetTaskResult {
14273                Location(Option<Location>),
14274                AlreadyNavigated,
14275            }
14276
14277            let target_task = match definition {
14278                HoverLink::Text(link) => {
14279                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14280                }
14281                HoverLink::InlayHint(lsp_location, server_id) => {
14282                    let computation =
14283                        self.compute_target_location(lsp_location, server_id, window, cx);
14284                    cx.background_spawn(async move {
14285                        let location = computation.await?;
14286                        Ok(TargetTaskResult::Location(location))
14287                    })
14288                }
14289                HoverLink::Url(url) => {
14290                    cx.open_url(&url);
14291                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14292                }
14293                HoverLink::File(path) => {
14294                    if let Some(workspace) = self.workspace() {
14295                        cx.spawn_in(window, async move |_, cx| {
14296                            workspace
14297                                .update_in(cx, |workspace, window, cx| {
14298                                    workspace.open_resolved_path(path, window, cx)
14299                                })?
14300                                .await
14301                                .map(|_| TargetTaskResult::AlreadyNavigated)
14302                        })
14303                    } else {
14304                        Task::ready(Ok(TargetTaskResult::Location(None)))
14305                    }
14306                }
14307            };
14308            cx.spawn_in(window, async move |editor, cx| {
14309                let target = match target_task.await.context("target resolution task")? {
14310                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14311                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14312                    TargetTaskResult::Location(Some(target)) => target,
14313                };
14314
14315                editor.update_in(cx, |editor, window, cx| {
14316                    let Some(workspace) = editor.workspace() else {
14317                        return Navigated::No;
14318                    };
14319                    let pane = workspace.read(cx).active_pane().clone();
14320
14321                    let range = target.range.to_point(target.buffer.read(cx));
14322                    let range = editor.range_for_match(&range);
14323                    let range = collapse_multiline_range(range);
14324
14325                    if !split
14326                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14327                    {
14328                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14329                    } else {
14330                        window.defer(cx, move |window, cx| {
14331                            let target_editor: Entity<Self> =
14332                                workspace.update(cx, |workspace, cx| {
14333                                    let pane = if split {
14334                                        workspace.adjacent_pane(window, cx)
14335                                    } else {
14336                                        workspace.active_pane().clone()
14337                                    };
14338
14339                                    workspace.open_project_item(
14340                                        pane,
14341                                        target.buffer.clone(),
14342                                        true,
14343                                        true,
14344                                        window,
14345                                        cx,
14346                                    )
14347                                });
14348                            target_editor.update(cx, |target_editor, cx| {
14349                                // When selecting a definition in a different buffer, disable the nav history
14350                                // to avoid creating a history entry at the previous cursor location.
14351                                pane.update(cx, |pane, _| pane.disable_history());
14352                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14353                                pane.update(cx, |pane, _| pane.enable_history());
14354                            });
14355                        });
14356                    }
14357                    Navigated::Yes
14358                })
14359            })
14360        } else if !definitions.is_empty() {
14361            cx.spawn_in(window, async move |editor, cx| {
14362                let (title, location_tasks, workspace) = editor
14363                    .update_in(cx, |editor, window, cx| {
14364                        let tab_kind = match kind {
14365                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14366                            _ => "Definitions",
14367                        };
14368                        let title = definitions
14369                            .iter()
14370                            .find_map(|definition| match definition {
14371                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14372                                    let buffer = origin.buffer.read(cx);
14373                                    format!(
14374                                        "{} for {}",
14375                                        tab_kind,
14376                                        buffer
14377                                            .text_for_range(origin.range.clone())
14378                                            .collect::<String>()
14379                                    )
14380                                }),
14381                                HoverLink::InlayHint(_, _) => None,
14382                                HoverLink::Url(_) => None,
14383                                HoverLink::File(_) => None,
14384                            })
14385                            .unwrap_or(tab_kind.to_string());
14386                        let location_tasks = definitions
14387                            .into_iter()
14388                            .map(|definition| match definition {
14389                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14390                                HoverLink::InlayHint(lsp_location, server_id) => editor
14391                                    .compute_target_location(lsp_location, server_id, window, cx),
14392                                HoverLink::Url(_) => Task::ready(Ok(None)),
14393                                HoverLink::File(_) => Task::ready(Ok(None)),
14394                            })
14395                            .collect::<Vec<_>>();
14396                        (title, location_tasks, editor.workspace().clone())
14397                    })
14398                    .context("location tasks preparation")?;
14399
14400                let locations = future::join_all(location_tasks)
14401                    .await
14402                    .into_iter()
14403                    .filter_map(|location| location.transpose())
14404                    .collect::<Result<_>>()
14405                    .context("location tasks")?;
14406
14407                let Some(workspace) = workspace else {
14408                    return Ok(Navigated::No);
14409                };
14410                let opened = workspace
14411                    .update_in(cx, |workspace, window, cx| {
14412                        Self::open_locations_in_multibuffer(
14413                            workspace,
14414                            locations,
14415                            title,
14416                            split,
14417                            MultibufferSelectionMode::First,
14418                            window,
14419                            cx,
14420                        )
14421                    })
14422                    .ok();
14423
14424                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14425            })
14426        } else {
14427            Task::ready(Ok(Navigated::No))
14428        }
14429    }
14430
14431    fn compute_target_location(
14432        &self,
14433        lsp_location: lsp::Location,
14434        server_id: LanguageServerId,
14435        window: &mut Window,
14436        cx: &mut Context<Self>,
14437    ) -> Task<anyhow::Result<Option<Location>>> {
14438        let Some(project) = self.project.clone() else {
14439            return Task::ready(Ok(None));
14440        };
14441
14442        cx.spawn_in(window, async move |editor, cx| {
14443            let location_task = editor.update(cx, |_, cx| {
14444                project.update(cx, |project, cx| {
14445                    let language_server_name = project
14446                        .language_server_statuses(cx)
14447                        .find(|(id, _)| server_id == *id)
14448                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14449                    language_server_name.map(|language_server_name| {
14450                        project.open_local_buffer_via_lsp(
14451                            lsp_location.uri.clone(),
14452                            server_id,
14453                            language_server_name,
14454                            cx,
14455                        )
14456                    })
14457                })
14458            })?;
14459            let location = match location_task {
14460                Some(task) => Some({
14461                    let target_buffer_handle = task.await.context("open local buffer")?;
14462                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14463                        let target_start = target_buffer
14464                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14465                        let target_end = target_buffer
14466                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14467                        target_buffer.anchor_after(target_start)
14468                            ..target_buffer.anchor_before(target_end)
14469                    })?;
14470                    Location {
14471                        buffer: target_buffer_handle,
14472                        range,
14473                    }
14474                }),
14475                None => None,
14476            };
14477            Ok(location)
14478        })
14479    }
14480
14481    pub fn find_all_references(
14482        &mut self,
14483        _: &FindAllReferences,
14484        window: &mut Window,
14485        cx: &mut Context<Self>,
14486    ) -> Option<Task<Result<Navigated>>> {
14487        let selection = self.selections.newest::<usize>(cx);
14488        let multi_buffer = self.buffer.read(cx);
14489        let head = selection.head();
14490
14491        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14492        let head_anchor = multi_buffer_snapshot.anchor_at(
14493            head,
14494            if head < selection.tail() {
14495                Bias::Right
14496            } else {
14497                Bias::Left
14498            },
14499        );
14500
14501        match self
14502            .find_all_references_task_sources
14503            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14504        {
14505            Ok(_) => {
14506                log::info!(
14507                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14508                );
14509                return None;
14510            }
14511            Err(i) => {
14512                self.find_all_references_task_sources.insert(i, head_anchor);
14513            }
14514        }
14515
14516        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14517        let workspace = self.workspace()?;
14518        let project = workspace.read(cx).project().clone();
14519        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14520        Some(cx.spawn_in(window, async move |editor, cx| {
14521            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14522                if let Ok(i) = editor
14523                    .find_all_references_task_sources
14524                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14525                {
14526                    editor.find_all_references_task_sources.remove(i);
14527                }
14528            });
14529
14530            let locations = references.await?;
14531            if locations.is_empty() {
14532                return anyhow::Ok(Navigated::No);
14533            }
14534
14535            workspace.update_in(cx, |workspace, window, cx| {
14536                let title = locations
14537                    .first()
14538                    .as_ref()
14539                    .map(|location| {
14540                        let buffer = location.buffer.read(cx);
14541                        format!(
14542                            "References to `{}`",
14543                            buffer
14544                                .text_for_range(location.range.clone())
14545                                .collect::<String>()
14546                        )
14547                    })
14548                    .unwrap();
14549                Self::open_locations_in_multibuffer(
14550                    workspace,
14551                    locations,
14552                    title,
14553                    false,
14554                    MultibufferSelectionMode::First,
14555                    window,
14556                    cx,
14557                );
14558                Navigated::Yes
14559            })
14560        }))
14561    }
14562
14563    /// Opens a multibuffer with the given project locations in it
14564    pub fn open_locations_in_multibuffer(
14565        workspace: &mut Workspace,
14566        mut locations: Vec<Location>,
14567        title: String,
14568        split: bool,
14569        multibuffer_selection_mode: MultibufferSelectionMode,
14570        window: &mut Window,
14571        cx: &mut Context<Workspace>,
14572    ) {
14573        // If there are multiple definitions, open them in a multibuffer
14574        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14575        let mut locations = locations.into_iter().peekable();
14576        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14577        let capability = workspace.project().read(cx).capability();
14578
14579        let excerpt_buffer = cx.new(|cx| {
14580            let mut multibuffer = MultiBuffer::new(capability);
14581            while let Some(location) = locations.next() {
14582                let buffer = location.buffer.read(cx);
14583                let mut ranges_for_buffer = Vec::new();
14584                let range = location.range.to_point(buffer);
14585                ranges_for_buffer.push(range.clone());
14586
14587                while let Some(next_location) = locations.peek() {
14588                    if next_location.buffer == location.buffer {
14589                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14590                        locations.next();
14591                    } else {
14592                        break;
14593                    }
14594                }
14595
14596                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14597                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14598                    PathKey::for_buffer(&location.buffer, cx),
14599                    location.buffer.clone(),
14600                    ranges_for_buffer,
14601                    DEFAULT_MULTIBUFFER_CONTEXT,
14602                    cx,
14603                );
14604                ranges.extend(new_ranges)
14605            }
14606
14607            multibuffer.with_title(title)
14608        });
14609
14610        let editor = cx.new(|cx| {
14611            Editor::for_multibuffer(
14612                excerpt_buffer,
14613                Some(workspace.project().clone()),
14614                window,
14615                cx,
14616            )
14617        });
14618        editor.update(cx, |editor, cx| {
14619            match multibuffer_selection_mode {
14620                MultibufferSelectionMode::First => {
14621                    if let Some(first_range) = ranges.first() {
14622                        editor.change_selections(None, window, cx, |selections| {
14623                            selections.clear_disjoint();
14624                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14625                        });
14626                    }
14627                    editor.highlight_background::<Self>(
14628                        &ranges,
14629                        |theme| theme.editor_highlighted_line_background,
14630                        cx,
14631                    );
14632                }
14633                MultibufferSelectionMode::All => {
14634                    editor.change_selections(None, window, cx, |selections| {
14635                        selections.clear_disjoint();
14636                        selections.select_anchor_ranges(ranges);
14637                    });
14638                }
14639            }
14640            editor.register_buffers_with_language_servers(cx);
14641        });
14642
14643        let item = Box::new(editor);
14644        let item_id = item.item_id();
14645
14646        if split {
14647            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14648        } else {
14649            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14650                let (preview_item_id, preview_item_idx) =
14651                    workspace.active_pane().update(cx, |pane, _| {
14652                        (pane.preview_item_id(), pane.preview_item_idx())
14653                    });
14654
14655                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14656
14657                if let Some(preview_item_id) = preview_item_id {
14658                    workspace.active_pane().update(cx, |pane, cx| {
14659                        pane.remove_item(preview_item_id, false, false, window, cx);
14660                    });
14661                }
14662            } else {
14663                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14664            }
14665        }
14666        workspace.active_pane().update(cx, |pane, cx| {
14667            pane.set_preview_item_id(Some(item_id), cx);
14668        });
14669    }
14670
14671    pub fn rename(
14672        &mut self,
14673        _: &Rename,
14674        window: &mut Window,
14675        cx: &mut Context<Self>,
14676    ) -> Option<Task<Result<()>>> {
14677        use language::ToOffset as _;
14678
14679        let provider = self.semantics_provider.clone()?;
14680        let selection = self.selections.newest_anchor().clone();
14681        let (cursor_buffer, cursor_buffer_position) = self
14682            .buffer
14683            .read(cx)
14684            .text_anchor_for_position(selection.head(), cx)?;
14685        let (tail_buffer, cursor_buffer_position_end) = self
14686            .buffer
14687            .read(cx)
14688            .text_anchor_for_position(selection.tail(), cx)?;
14689        if tail_buffer != cursor_buffer {
14690            return None;
14691        }
14692
14693        let snapshot = cursor_buffer.read(cx).snapshot();
14694        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14695        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14696        let prepare_rename = provider
14697            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14698            .unwrap_or_else(|| Task::ready(Ok(None)));
14699        drop(snapshot);
14700
14701        Some(cx.spawn_in(window, async move |this, cx| {
14702            let rename_range = if let Some(range) = prepare_rename.await? {
14703                Some(range)
14704            } else {
14705                this.update(cx, |this, cx| {
14706                    let buffer = this.buffer.read(cx).snapshot(cx);
14707                    let mut buffer_highlights = this
14708                        .document_highlights_for_position(selection.head(), &buffer)
14709                        .filter(|highlight| {
14710                            highlight.start.excerpt_id == selection.head().excerpt_id
14711                                && highlight.end.excerpt_id == selection.head().excerpt_id
14712                        });
14713                    buffer_highlights
14714                        .next()
14715                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14716                })?
14717            };
14718            if let Some(rename_range) = rename_range {
14719                this.update_in(cx, |this, window, cx| {
14720                    let snapshot = cursor_buffer.read(cx).snapshot();
14721                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14722                    let cursor_offset_in_rename_range =
14723                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14724                    let cursor_offset_in_rename_range_end =
14725                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14726
14727                    this.take_rename(false, window, cx);
14728                    let buffer = this.buffer.read(cx).read(cx);
14729                    let cursor_offset = selection.head().to_offset(&buffer);
14730                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14731                    let rename_end = rename_start + rename_buffer_range.len();
14732                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14733                    let mut old_highlight_id = None;
14734                    let old_name: Arc<str> = buffer
14735                        .chunks(rename_start..rename_end, true)
14736                        .map(|chunk| {
14737                            if old_highlight_id.is_none() {
14738                                old_highlight_id = chunk.syntax_highlight_id;
14739                            }
14740                            chunk.text
14741                        })
14742                        .collect::<String>()
14743                        .into();
14744
14745                    drop(buffer);
14746
14747                    // Position the selection in the rename editor so that it matches the current selection.
14748                    this.show_local_selections = false;
14749                    let rename_editor = cx.new(|cx| {
14750                        let mut editor = Editor::single_line(window, cx);
14751                        editor.buffer.update(cx, |buffer, cx| {
14752                            buffer.edit([(0..0, old_name.clone())], None, cx)
14753                        });
14754                        let rename_selection_range = match cursor_offset_in_rename_range
14755                            .cmp(&cursor_offset_in_rename_range_end)
14756                        {
14757                            Ordering::Equal => {
14758                                editor.select_all(&SelectAll, window, cx);
14759                                return editor;
14760                            }
14761                            Ordering::Less => {
14762                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14763                            }
14764                            Ordering::Greater => {
14765                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14766                            }
14767                        };
14768                        if rename_selection_range.end > old_name.len() {
14769                            editor.select_all(&SelectAll, window, cx);
14770                        } else {
14771                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14772                                s.select_ranges([rename_selection_range]);
14773                            });
14774                        }
14775                        editor
14776                    });
14777                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14778                        if e == &EditorEvent::Focused {
14779                            cx.emit(EditorEvent::FocusedIn)
14780                        }
14781                    })
14782                    .detach();
14783
14784                    let write_highlights =
14785                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14786                    let read_highlights =
14787                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14788                    let ranges = write_highlights
14789                        .iter()
14790                        .flat_map(|(_, ranges)| ranges.iter())
14791                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14792                        .cloned()
14793                        .collect();
14794
14795                    this.highlight_text::<Rename>(
14796                        ranges,
14797                        HighlightStyle {
14798                            fade_out: Some(0.6),
14799                            ..Default::default()
14800                        },
14801                        cx,
14802                    );
14803                    let rename_focus_handle = rename_editor.focus_handle(cx);
14804                    window.focus(&rename_focus_handle);
14805                    let block_id = this.insert_blocks(
14806                        [BlockProperties {
14807                            style: BlockStyle::Flex,
14808                            placement: BlockPlacement::Below(range.start),
14809                            height: Some(1),
14810                            render: Arc::new({
14811                                let rename_editor = rename_editor.clone();
14812                                move |cx: &mut BlockContext| {
14813                                    let mut text_style = cx.editor_style.text.clone();
14814                                    if let Some(highlight_style) = old_highlight_id
14815                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14816                                    {
14817                                        text_style = text_style.highlight(highlight_style);
14818                                    }
14819                                    div()
14820                                        .block_mouse_down()
14821                                        .pl(cx.anchor_x)
14822                                        .child(EditorElement::new(
14823                                            &rename_editor,
14824                                            EditorStyle {
14825                                                background: cx.theme().system().transparent,
14826                                                local_player: cx.editor_style.local_player,
14827                                                text: text_style,
14828                                                scrollbar_width: cx.editor_style.scrollbar_width,
14829                                                syntax: cx.editor_style.syntax.clone(),
14830                                                status: cx.editor_style.status.clone(),
14831                                                inlay_hints_style: HighlightStyle {
14832                                                    font_weight: Some(FontWeight::BOLD),
14833                                                    ..make_inlay_hints_style(cx.app)
14834                                                },
14835                                                inline_completion_styles: make_suggestion_styles(
14836                                                    cx.app,
14837                                                ),
14838                                                ..EditorStyle::default()
14839                                            },
14840                                        ))
14841                                        .into_any_element()
14842                                }
14843                            }),
14844                            priority: 0,
14845                            render_in_minimap: true,
14846                        }],
14847                        Some(Autoscroll::fit()),
14848                        cx,
14849                    )[0];
14850                    this.pending_rename = Some(RenameState {
14851                        range,
14852                        old_name,
14853                        editor: rename_editor,
14854                        block_id,
14855                    });
14856                })?;
14857            }
14858
14859            Ok(())
14860        }))
14861    }
14862
14863    pub fn confirm_rename(
14864        &mut self,
14865        _: &ConfirmRename,
14866        window: &mut Window,
14867        cx: &mut Context<Self>,
14868    ) -> Option<Task<Result<()>>> {
14869        let rename = self.take_rename(false, window, cx)?;
14870        let workspace = self.workspace()?.downgrade();
14871        let (buffer, start) = self
14872            .buffer
14873            .read(cx)
14874            .text_anchor_for_position(rename.range.start, cx)?;
14875        let (end_buffer, _) = self
14876            .buffer
14877            .read(cx)
14878            .text_anchor_for_position(rename.range.end, cx)?;
14879        if buffer != end_buffer {
14880            return None;
14881        }
14882
14883        let old_name = rename.old_name;
14884        let new_name = rename.editor.read(cx).text(cx);
14885
14886        let rename = self.semantics_provider.as_ref()?.perform_rename(
14887            &buffer,
14888            start,
14889            new_name.clone(),
14890            cx,
14891        )?;
14892
14893        Some(cx.spawn_in(window, async move |editor, cx| {
14894            let project_transaction = rename.await?;
14895            Self::open_project_transaction(
14896                &editor,
14897                workspace,
14898                project_transaction,
14899                format!("Rename: {}{}", old_name, new_name),
14900                cx,
14901            )
14902            .await?;
14903
14904            editor.update(cx, |editor, cx| {
14905                editor.refresh_document_highlights(cx);
14906            })?;
14907            Ok(())
14908        }))
14909    }
14910
14911    fn take_rename(
14912        &mut self,
14913        moving_cursor: bool,
14914        window: &mut Window,
14915        cx: &mut Context<Self>,
14916    ) -> Option<RenameState> {
14917        let rename = self.pending_rename.take()?;
14918        if rename.editor.focus_handle(cx).is_focused(window) {
14919            window.focus(&self.focus_handle);
14920        }
14921
14922        self.remove_blocks(
14923            [rename.block_id].into_iter().collect(),
14924            Some(Autoscroll::fit()),
14925            cx,
14926        );
14927        self.clear_highlights::<Rename>(cx);
14928        self.show_local_selections = true;
14929
14930        if moving_cursor {
14931            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14932                editor.selections.newest::<usize>(cx).head()
14933            });
14934
14935            // Update the selection to match the position of the selection inside
14936            // the rename editor.
14937            let snapshot = self.buffer.read(cx).read(cx);
14938            let rename_range = rename.range.to_offset(&snapshot);
14939            let cursor_in_editor = snapshot
14940                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14941                .min(rename_range.end);
14942            drop(snapshot);
14943
14944            self.change_selections(None, window, cx, |s| {
14945                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14946            });
14947        } else {
14948            self.refresh_document_highlights(cx);
14949        }
14950
14951        Some(rename)
14952    }
14953
14954    pub fn pending_rename(&self) -> Option<&RenameState> {
14955        self.pending_rename.as_ref()
14956    }
14957
14958    fn format(
14959        &mut self,
14960        _: &Format,
14961        window: &mut Window,
14962        cx: &mut Context<Self>,
14963    ) -> Option<Task<Result<()>>> {
14964        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14965
14966        let project = match &self.project {
14967            Some(project) => project.clone(),
14968            None => return None,
14969        };
14970
14971        Some(self.perform_format(
14972            project,
14973            FormatTrigger::Manual,
14974            FormatTarget::Buffers,
14975            window,
14976            cx,
14977        ))
14978    }
14979
14980    fn format_selections(
14981        &mut self,
14982        _: &FormatSelections,
14983        window: &mut Window,
14984        cx: &mut Context<Self>,
14985    ) -> Option<Task<Result<()>>> {
14986        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14987
14988        let project = match &self.project {
14989            Some(project) => project.clone(),
14990            None => return None,
14991        };
14992
14993        let ranges = self
14994            .selections
14995            .all_adjusted(cx)
14996            .into_iter()
14997            .map(|selection| selection.range())
14998            .collect_vec();
14999
15000        Some(self.perform_format(
15001            project,
15002            FormatTrigger::Manual,
15003            FormatTarget::Ranges(ranges),
15004            window,
15005            cx,
15006        ))
15007    }
15008
15009    fn perform_format(
15010        &mut self,
15011        project: Entity<Project>,
15012        trigger: FormatTrigger,
15013        target: FormatTarget,
15014        window: &mut Window,
15015        cx: &mut Context<Self>,
15016    ) -> Task<Result<()>> {
15017        let buffer = self.buffer.clone();
15018        let (buffers, target) = match target {
15019            FormatTarget::Buffers => {
15020                let mut buffers = buffer.read(cx).all_buffers();
15021                if trigger == FormatTrigger::Save {
15022                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15023                }
15024                (buffers, LspFormatTarget::Buffers)
15025            }
15026            FormatTarget::Ranges(selection_ranges) => {
15027                let multi_buffer = buffer.read(cx);
15028                let snapshot = multi_buffer.read(cx);
15029                let mut buffers = HashSet::default();
15030                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15031                    BTreeMap::new();
15032                for selection_range in selection_ranges {
15033                    for (buffer, buffer_range, _) in
15034                        snapshot.range_to_buffer_ranges(selection_range)
15035                    {
15036                        let buffer_id = buffer.remote_id();
15037                        let start = buffer.anchor_before(buffer_range.start);
15038                        let end = buffer.anchor_after(buffer_range.end);
15039                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15040                        buffer_id_to_ranges
15041                            .entry(buffer_id)
15042                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15043                            .or_insert_with(|| vec![start..end]);
15044                    }
15045                }
15046                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15047            }
15048        };
15049
15050        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15051        let selections_prev = transaction_id_prev
15052            .and_then(|transaction_id_prev| {
15053                // default to selections as they were after the last edit, if we have them,
15054                // instead of how they are now.
15055                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15056                // will take you back to where you made the last edit, instead of staying where you scrolled
15057                self.selection_history
15058                    .transaction(transaction_id_prev)
15059                    .map(|t| t.0.clone())
15060            })
15061            .unwrap_or_else(|| {
15062                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15063                self.selections.disjoint_anchors()
15064            });
15065
15066        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15067        let format = project.update(cx, |project, cx| {
15068            project.format(buffers, target, true, trigger, cx)
15069        });
15070
15071        cx.spawn_in(window, async move |editor, cx| {
15072            let transaction = futures::select_biased! {
15073                transaction = format.log_err().fuse() => transaction,
15074                () = timeout => {
15075                    log::warn!("timed out waiting for formatting");
15076                    None
15077                }
15078            };
15079
15080            buffer
15081                .update(cx, |buffer, cx| {
15082                    if let Some(transaction) = transaction {
15083                        if !buffer.is_singleton() {
15084                            buffer.push_transaction(&transaction.0, cx);
15085                        }
15086                    }
15087                    cx.notify();
15088                })
15089                .ok();
15090
15091            if let Some(transaction_id_now) =
15092                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15093            {
15094                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15095                if has_new_transaction {
15096                    _ = editor.update(cx, |editor, _| {
15097                        editor
15098                            .selection_history
15099                            .insert_transaction(transaction_id_now, selections_prev);
15100                    });
15101                }
15102            }
15103
15104            Ok(())
15105        })
15106    }
15107
15108    fn organize_imports(
15109        &mut self,
15110        _: &OrganizeImports,
15111        window: &mut Window,
15112        cx: &mut Context<Self>,
15113    ) -> Option<Task<Result<()>>> {
15114        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15115        let project = match &self.project {
15116            Some(project) => project.clone(),
15117            None => return None,
15118        };
15119        Some(self.perform_code_action_kind(
15120            project,
15121            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15122            window,
15123            cx,
15124        ))
15125    }
15126
15127    fn perform_code_action_kind(
15128        &mut self,
15129        project: Entity<Project>,
15130        kind: CodeActionKind,
15131        window: &mut Window,
15132        cx: &mut Context<Self>,
15133    ) -> Task<Result<()>> {
15134        let buffer = self.buffer.clone();
15135        let buffers = buffer.read(cx).all_buffers();
15136        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15137        let apply_action = project.update(cx, |project, cx| {
15138            project.apply_code_action_kind(buffers, kind, true, cx)
15139        });
15140        cx.spawn_in(window, async move |_, cx| {
15141            let transaction = futures::select_biased! {
15142                () = timeout => {
15143                    log::warn!("timed out waiting for executing code action");
15144                    None
15145                }
15146                transaction = apply_action.log_err().fuse() => transaction,
15147            };
15148            buffer
15149                .update(cx, |buffer, cx| {
15150                    // check if we need this
15151                    if let Some(transaction) = transaction {
15152                        if !buffer.is_singleton() {
15153                            buffer.push_transaction(&transaction.0, cx);
15154                        }
15155                    }
15156                    cx.notify();
15157                })
15158                .ok();
15159            Ok(())
15160        })
15161    }
15162
15163    fn restart_language_server(
15164        &mut self,
15165        _: &RestartLanguageServer,
15166        _: &mut Window,
15167        cx: &mut Context<Self>,
15168    ) {
15169        if let Some(project) = self.project.clone() {
15170            self.buffer.update(cx, |multi_buffer, cx| {
15171                project.update(cx, |project, cx| {
15172                    project.restart_language_servers_for_buffers(
15173                        multi_buffer.all_buffers().into_iter().collect(),
15174                        cx,
15175                    );
15176                });
15177            })
15178        }
15179    }
15180
15181    fn stop_language_server(
15182        &mut self,
15183        _: &StopLanguageServer,
15184        _: &mut Window,
15185        cx: &mut Context<Self>,
15186    ) {
15187        if let Some(project) = self.project.clone() {
15188            self.buffer.update(cx, |multi_buffer, cx| {
15189                project.update(cx, |project, cx| {
15190                    project.stop_language_servers_for_buffers(
15191                        multi_buffer.all_buffers().into_iter().collect(),
15192                        cx,
15193                    );
15194                    cx.emit(project::Event::RefreshInlayHints);
15195                });
15196            });
15197        }
15198    }
15199
15200    fn cancel_language_server_work(
15201        workspace: &mut Workspace,
15202        _: &actions::CancelLanguageServerWork,
15203        _: &mut Window,
15204        cx: &mut Context<Workspace>,
15205    ) {
15206        let project = workspace.project();
15207        let buffers = workspace
15208            .active_item(cx)
15209            .and_then(|item| item.act_as::<Editor>(cx))
15210            .map_or(HashSet::default(), |editor| {
15211                editor.read(cx).buffer.read(cx).all_buffers()
15212            });
15213        project.update(cx, |project, cx| {
15214            project.cancel_language_server_work_for_buffers(buffers, cx);
15215        });
15216    }
15217
15218    fn show_character_palette(
15219        &mut self,
15220        _: &ShowCharacterPalette,
15221        window: &mut Window,
15222        _: &mut Context<Self>,
15223    ) {
15224        window.show_character_palette();
15225    }
15226
15227    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15228        if self.mode.is_minimap() {
15229            return;
15230        }
15231
15232        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15233            let buffer = self.buffer.read(cx).snapshot(cx);
15234            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15235            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15236            let is_valid = buffer
15237                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15238                .any(|entry| {
15239                    entry.diagnostic.is_primary
15240                        && !entry.range.is_empty()
15241                        && entry.range.start == primary_range_start
15242                        && entry.diagnostic.message == active_diagnostics.active_message
15243                });
15244
15245            if !is_valid {
15246                self.dismiss_diagnostics(cx);
15247            }
15248        }
15249    }
15250
15251    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15252        match &self.active_diagnostics {
15253            ActiveDiagnostic::Group(group) => Some(group),
15254            _ => None,
15255        }
15256    }
15257
15258    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15259        self.dismiss_diagnostics(cx);
15260        self.active_diagnostics = ActiveDiagnostic::All;
15261    }
15262
15263    fn activate_diagnostics(
15264        &mut self,
15265        buffer_id: BufferId,
15266        diagnostic: DiagnosticEntry<usize>,
15267        window: &mut Window,
15268        cx: &mut Context<Self>,
15269    ) {
15270        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15271            return;
15272        }
15273        self.dismiss_diagnostics(cx);
15274        let snapshot = self.snapshot(window, cx);
15275        let buffer = self.buffer.read(cx).snapshot(cx);
15276        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15277            return;
15278        };
15279
15280        let diagnostic_group = buffer
15281            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15282            .collect::<Vec<_>>();
15283
15284        let blocks =
15285            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15286
15287        let blocks = self.display_map.update(cx, |display_map, cx| {
15288            display_map.insert_blocks(blocks, cx).into_iter().collect()
15289        });
15290        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15291            active_range: buffer.anchor_before(diagnostic.range.start)
15292                ..buffer.anchor_after(diagnostic.range.end),
15293            active_message: diagnostic.diagnostic.message.clone(),
15294            group_id: diagnostic.diagnostic.group_id,
15295            blocks,
15296        });
15297        cx.notify();
15298    }
15299
15300    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15301        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15302            return;
15303        };
15304
15305        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15306        if let ActiveDiagnostic::Group(group) = prev {
15307            self.display_map.update(cx, |display_map, cx| {
15308                display_map.remove_blocks(group.blocks, cx);
15309            });
15310            cx.notify();
15311        }
15312    }
15313
15314    /// Disable inline diagnostics rendering for this editor.
15315    pub fn disable_inline_diagnostics(&mut self) {
15316        self.inline_diagnostics_enabled = false;
15317        self.inline_diagnostics_update = Task::ready(());
15318        self.inline_diagnostics.clear();
15319    }
15320
15321    pub fn diagnostics_enabled(&self) -> bool {
15322        self.mode.is_full()
15323    }
15324
15325    pub fn inline_diagnostics_enabled(&self) -> bool {
15326        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15327    }
15328
15329    pub fn show_inline_diagnostics(&self) -> bool {
15330        self.show_inline_diagnostics
15331    }
15332
15333    pub fn toggle_inline_diagnostics(
15334        &mut self,
15335        _: &ToggleInlineDiagnostics,
15336        window: &mut Window,
15337        cx: &mut Context<Editor>,
15338    ) {
15339        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15340        self.refresh_inline_diagnostics(false, window, cx);
15341    }
15342
15343    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15344        self.diagnostics_max_severity = severity;
15345        self.display_map.update(cx, |display_map, _| {
15346            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15347        });
15348    }
15349
15350    pub fn toggle_diagnostics(
15351        &mut self,
15352        _: &ToggleDiagnostics,
15353        window: &mut Window,
15354        cx: &mut Context<Editor>,
15355    ) {
15356        if !self.diagnostics_enabled() {
15357            return;
15358        }
15359
15360        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15361            EditorSettings::get_global(cx)
15362                .diagnostics_max_severity
15363                .filter(|severity| severity != &DiagnosticSeverity::Off)
15364                .unwrap_or(DiagnosticSeverity::Hint)
15365        } else {
15366            DiagnosticSeverity::Off
15367        };
15368        self.set_max_diagnostics_severity(new_severity, cx);
15369        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15370            self.active_diagnostics = ActiveDiagnostic::None;
15371            self.inline_diagnostics_update = Task::ready(());
15372            self.inline_diagnostics.clear();
15373        } else {
15374            self.refresh_inline_diagnostics(false, window, cx);
15375        }
15376
15377        cx.notify();
15378    }
15379
15380    pub fn toggle_minimap(
15381        &mut self,
15382        _: &ToggleMinimap,
15383        window: &mut Window,
15384        cx: &mut Context<Editor>,
15385    ) {
15386        if self.supports_minimap(cx) {
15387            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15388        }
15389    }
15390
15391    fn refresh_inline_diagnostics(
15392        &mut self,
15393        debounce: bool,
15394        window: &mut Window,
15395        cx: &mut Context<Self>,
15396    ) {
15397        let max_severity = ProjectSettings::get_global(cx)
15398            .diagnostics
15399            .inline
15400            .max_severity
15401            .unwrap_or(self.diagnostics_max_severity);
15402
15403        if self.mode.is_minimap()
15404            || !self.inline_diagnostics_enabled()
15405            || !self.show_inline_diagnostics
15406            || max_severity == DiagnosticSeverity::Off
15407        {
15408            self.inline_diagnostics_update = Task::ready(());
15409            self.inline_diagnostics.clear();
15410            return;
15411        }
15412
15413        let debounce_ms = ProjectSettings::get_global(cx)
15414            .diagnostics
15415            .inline
15416            .update_debounce_ms;
15417        let debounce = if debounce && debounce_ms > 0 {
15418            Some(Duration::from_millis(debounce_ms))
15419        } else {
15420            None
15421        };
15422        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15423            let editor = editor.upgrade().unwrap();
15424
15425            if let Some(debounce) = debounce {
15426                cx.background_executor().timer(debounce).await;
15427            }
15428            let Some(snapshot) = editor
15429                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15430                .ok()
15431            else {
15432                return;
15433            };
15434
15435            let new_inline_diagnostics = cx
15436                .background_spawn(async move {
15437                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15438                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15439                        let message = diagnostic_entry
15440                            .diagnostic
15441                            .message
15442                            .split_once('\n')
15443                            .map(|(line, _)| line)
15444                            .map(SharedString::new)
15445                            .unwrap_or_else(|| {
15446                                SharedString::from(diagnostic_entry.diagnostic.message)
15447                            });
15448                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15449                        let (Ok(i) | Err(i)) = inline_diagnostics
15450                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15451                        inline_diagnostics.insert(
15452                            i,
15453                            (
15454                                start_anchor,
15455                                InlineDiagnostic {
15456                                    message,
15457                                    group_id: diagnostic_entry.diagnostic.group_id,
15458                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15459                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15460                                    severity: diagnostic_entry.diagnostic.severity,
15461                                },
15462                            ),
15463                        );
15464                    }
15465                    inline_diagnostics
15466                })
15467                .await;
15468
15469            editor
15470                .update(cx, |editor, cx| {
15471                    editor.inline_diagnostics = new_inline_diagnostics;
15472                    cx.notify();
15473                })
15474                .ok();
15475        });
15476    }
15477
15478    pub fn set_selections_from_remote(
15479        &mut self,
15480        selections: Vec<Selection<Anchor>>,
15481        pending_selection: Option<Selection<Anchor>>,
15482        window: &mut Window,
15483        cx: &mut Context<Self>,
15484    ) {
15485        let old_cursor_position = self.selections.newest_anchor().head();
15486        self.selections.change_with(cx, |s| {
15487            s.select_anchors(selections);
15488            if let Some(pending_selection) = pending_selection {
15489                s.set_pending(pending_selection, SelectMode::Character);
15490            } else {
15491                s.clear_pending();
15492            }
15493        });
15494        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15495    }
15496
15497    fn push_to_selection_history(&mut self) {
15498        self.selection_history.push(SelectionHistoryEntry {
15499            selections: self.selections.disjoint_anchors(),
15500            select_next_state: self.select_next_state.clone(),
15501            select_prev_state: self.select_prev_state.clone(),
15502            add_selections_state: self.add_selections_state.clone(),
15503        });
15504    }
15505
15506    pub fn transact(
15507        &mut self,
15508        window: &mut Window,
15509        cx: &mut Context<Self>,
15510        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15511    ) -> Option<TransactionId> {
15512        self.start_transaction_at(Instant::now(), window, cx);
15513        update(self, window, cx);
15514        self.end_transaction_at(Instant::now(), cx)
15515    }
15516
15517    pub fn start_transaction_at(
15518        &mut self,
15519        now: Instant,
15520        window: &mut Window,
15521        cx: &mut Context<Self>,
15522    ) {
15523        self.end_selection(window, cx);
15524        if let Some(tx_id) = self
15525            .buffer
15526            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15527        {
15528            self.selection_history
15529                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15530            cx.emit(EditorEvent::TransactionBegun {
15531                transaction_id: tx_id,
15532            })
15533        }
15534    }
15535
15536    pub fn end_transaction_at(
15537        &mut self,
15538        now: Instant,
15539        cx: &mut Context<Self>,
15540    ) -> Option<TransactionId> {
15541        if let Some(transaction_id) = self
15542            .buffer
15543            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15544        {
15545            if let Some((_, end_selections)) =
15546                self.selection_history.transaction_mut(transaction_id)
15547            {
15548                *end_selections = Some(self.selections.disjoint_anchors());
15549            } else {
15550                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15551            }
15552
15553            cx.emit(EditorEvent::Edited { transaction_id });
15554            Some(transaction_id)
15555        } else {
15556            None
15557        }
15558    }
15559
15560    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15561        if self.selection_mark_mode {
15562            self.change_selections(None, window, cx, |s| {
15563                s.move_with(|_, sel| {
15564                    sel.collapse_to(sel.head(), SelectionGoal::None);
15565                });
15566            })
15567        }
15568        self.selection_mark_mode = true;
15569        cx.notify();
15570    }
15571
15572    pub fn swap_selection_ends(
15573        &mut self,
15574        _: &actions::SwapSelectionEnds,
15575        window: &mut Window,
15576        cx: &mut Context<Self>,
15577    ) {
15578        self.change_selections(None, window, cx, |s| {
15579            s.move_with(|_, sel| {
15580                if sel.start != sel.end {
15581                    sel.reversed = !sel.reversed
15582                }
15583            });
15584        });
15585        self.request_autoscroll(Autoscroll::newest(), cx);
15586        cx.notify();
15587    }
15588
15589    pub fn toggle_fold(
15590        &mut self,
15591        _: &actions::ToggleFold,
15592        window: &mut Window,
15593        cx: &mut Context<Self>,
15594    ) {
15595        if self.is_singleton(cx) {
15596            let selection = self.selections.newest::<Point>(cx);
15597
15598            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15599            let range = if selection.is_empty() {
15600                let point = selection.head().to_display_point(&display_map);
15601                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15602                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15603                    .to_point(&display_map);
15604                start..end
15605            } else {
15606                selection.range()
15607            };
15608            if display_map.folds_in_range(range).next().is_some() {
15609                self.unfold_lines(&Default::default(), window, cx)
15610            } else {
15611                self.fold(&Default::default(), window, cx)
15612            }
15613        } else {
15614            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15615            let buffer_ids: HashSet<_> = self
15616                .selections
15617                .disjoint_anchor_ranges()
15618                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15619                .collect();
15620
15621            let should_unfold = buffer_ids
15622                .iter()
15623                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15624
15625            for buffer_id in buffer_ids {
15626                if should_unfold {
15627                    self.unfold_buffer(buffer_id, cx);
15628                } else {
15629                    self.fold_buffer(buffer_id, cx);
15630                }
15631            }
15632        }
15633    }
15634
15635    pub fn toggle_fold_recursive(
15636        &mut self,
15637        _: &actions::ToggleFoldRecursive,
15638        window: &mut Window,
15639        cx: &mut Context<Self>,
15640    ) {
15641        let selection = self.selections.newest::<Point>(cx);
15642
15643        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15644        let range = if selection.is_empty() {
15645            let point = selection.head().to_display_point(&display_map);
15646            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15647            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15648                .to_point(&display_map);
15649            start..end
15650        } else {
15651            selection.range()
15652        };
15653        if display_map.folds_in_range(range).next().is_some() {
15654            self.unfold_recursive(&Default::default(), window, cx)
15655        } else {
15656            self.fold_recursive(&Default::default(), window, cx)
15657        }
15658    }
15659
15660    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15661        if self.is_singleton(cx) {
15662            let mut to_fold = Vec::new();
15663            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15664            let selections = self.selections.all_adjusted(cx);
15665
15666            for selection in selections {
15667                let range = selection.range().sorted();
15668                let buffer_start_row = range.start.row;
15669
15670                if range.start.row != range.end.row {
15671                    let mut found = false;
15672                    let mut row = range.start.row;
15673                    while row <= range.end.row {
15674                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15675                        {
15676                            found = true;
15677                            row = crease.range().end.row + 1;
15678                            to_fold.push(crease);
15679                        } else {
15680                            row += 1
15681                        }
15682                    }
15683                    if found {
15684                        continue;
15685                    }
15686                }
15687
15688                for row in (0..=range.start.row).rev() {
15689                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15690                        if crease.range().end.row >= buffer_start_row {
15691                            to_fold.push(crease);
15692                            if row <= range.start.row {
15693                                break;
15694                            }
15695                        }
15696                    }
15697                }
15698            }
15699
15700            self.fold_creases(to_fold, true, window, cx);
15701        } else {
15702            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15703            let buffer_ids = self
15704                .selections
15705                .disjoint_anchor_ranges()
15706                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15707                .collect::<HashSet<_>>();
15708            for buffer_id in buffer_ids {
15709                self.fold_buffer(buffer_id, cx);
15710            }
15711        }
15712    }
15713
15714    fn fold_at_level(
15715        &mut self,
15716        fold_at: &FoldAtLevel,
15717        window: &mut Window,
15718        cx: &mut Context<Self>,
15719    ) {
15720        if !self.buffer.read(cx).is_singleton() {
15721            return;
15722        }
15723
15724        let fold_at_level = fold_at.0;
15725        let snapshot = self.buffer.read(cx).snapshot(cx);
15726        let mut to_fold = Vec::new();
15727        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15728
15729        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15730            while start_row < end_row {
15731                match self
15732                    .snapshot(window, cx)
15733                    .crease_for_buffer_row(MultiBufferRow(start_row))
15734                {
15735                    Some(crease) => {
15736                        let nested_start_row = crease.range().start.row + 1;
15737                        let nested_end_row = crease.range().end.row;
15738
15739                        if current_level < fold_at_level {
15740                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15741                        } else if current_level == fold_at_level {
15742                            to_fold.push(crease);
15743                        }
15744
15745                        start_row = nested_end_row + 1;
15746                    }
15747                    None => start_row += 1,
15748                }
15749            }
15750        }
15751
15752        self.fold_creases(to_fold, true, window, cx);
15753    }
15754
15755    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15756        if self.buffer.read(cx).is_singleton() {
15757            let mut fold_ranges = Vec::new();
15758            let snapshot = self.buffer.read(cx).snapshot(cx);
15759
15760            for row in 0..snapshot.max_row().0 {
15761                if let Some(foldable_range) = self
15762                    .snapshot(window, cx)
15763                    .crease_for_buffer_row(MultiBufferRow(row))
15764                {
15765                    fold_ranges.push(foldable_range);
15766                }
15767            }
15768
15769            self.fold_creases(fold_ranges, true, window, cx);
15770        } else {
15771            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15772                editor
15773                    .update_in(cx, |editor, _, cx| {
15774                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15775                            editor.fold_buffer(buffer_id, cx);
15776                        }
15777                    })
15778                    .ok();
15779            });
15780        }
15781    }
15782
15783    pub fn fold_function_bodies(
15784        &mut self,
15785        _: &actions::FoldFunctionBodies,
15786        window: &mut Window,
15787        cx: &mut Context<Self>,
15788    ) {
15789        let snapshot = self.buffer.read(cx).snapshot(cx);
15790
15791        let ranges = snapshot
15792            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15793            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15794            .collect::<Vec<_>>();
15795
15796        let creases = ranges
15797            .into_iter()
15798            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15799            .collect();
15800
15801        self.fold_creases(creases, true, window, cx);
15802    }
15803
15804    pub fn fold_recursive(
15805        &mut self,
15806        _: &actions::FoldRecursive,
15807        window: &mut Window,
15808        cx: &mut Context<Self>,
15809    ) {
15810        let mut to_fold = Vec::new();
15811        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15812        let selections = self.selections.all_adjusted(cx);
15813
15814        for selection in selections {
15815            let range = selection.range().sorted();
15816            let buffer_start_row = range.start.row;
15817
15818            if range.start.row != range.end.row {
15819                let mut found = false;
15820                for row in range.start.row..=range.end.row {
15821                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15822                        found = true;
15823                        to_fold.push(crease);
15824                    }
15825                }
15826                if found {
15827                    continue;
15828                }
15829            }
15830
15831            for row in (0..=range.start.row).rev() {
15832                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15833                    if crease.range().end.row >= buffer_start_row {
15834                        to_fold.push(crease);
15835                    } else {
15836                        break;
15837                    }
15838                }
15839            }
15840        }
15841
15842        self.fold_creases(to_fold, true, window, cx);
15843    }
15844
15845    pub fn fold_at(
15846        &mut self,
15847        buffer_row: MultiBufferRow,
15848        window: &mut Window,
15849        cx: &mut Context<Self>,
15850    ) {
15851        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15852
15853        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15854            let autoscroll = self
15855                .selections
15856                .all::<Point>(cx)
15857                .iter()
15858                .any(|selection| crease.range().overlaps(&selection.range()));
15859
15860            self.fold_creases(vec![crease], autoscroll, window, cx);
15861        }
15862    }
15863
15864    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15865        if self.is_singleton(cx) {
15866            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15867            let buffer = &display_map.buffer_snapshot;
15868            let selections = self.selections.all::<Point>(cx);
15869            let ranges = selections
15870                .iter()
15871                .map(|s| {
15872                    let range = s.display_range(&display_map).sorted();
15873                    let mut start = range.start.to_point(&display_map);
15874                    let mut end = range.end.to_point(&display_map);
15875                    start.column = 0;
15876                    end.column = buffer.line_len(MultiBufferRow(end.row));
15877                    start..end
15878                })
15879                .collect::<Vec<_>>();
15880
15881            self.unfold_ranges(&ranges, true, true, cx);
15882        } else {
15883            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15884            let buffer_ids = self
15885                .selections
15886                .disjoint_anchor_ranges()
15887                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15888                .collect::<HashSet<_>>();
15889            for buffer_id in buffer_ids {
15890                self.unfold_buffer(buffer_id, cx);
15891            }
15892        }
15893    }
15894
15895    pub fn unfold_recursive(
15896        &mut self,
15897        _: &UnfoldRecursive,
15898        _window: &mut Window,
15899        cx: &mut Context<Self>,
15900    ) {
15901        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15902        let selections = self.selections.all::<Point>(cx);
15903        let ranges = selections
15904            .iter()
15905            .map(|s| {
15906                let mut range = s.display_range(&display_map).sorted();
15907                *range.start.column_mut() = 0;
15908                *range.end.column_mut() = display_map.line_len(range.end.row());
15909                let start = range.start.to_point(&display_map);
15910                let end = range.end.to_point(&display_map);
15911                start..end
15912            })
15913            .collect::<Vec<_>>();
15914
15915        self.unfold_ranges(&ranges, true, true, cx);
15916    }
15917
15918    pub fn unfold_at(
15919        &mut self,
15920        buffer_row: MultiBufferRow,
15921        _window: &mut Window,
15922        cx: &mut Context<Self>,
15923    ) {
15924        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15925
15926        let intersection_range = Point::new(buffer_row.0, 0)
15927            ..Point::new(
15928                buffer_row.0,
15929                display_map.buffer_snapshot.line_len(buffer_row),
15930            );
15931
15932        let autoscroll = self
15933            .selections
15934            .all::<Point>(cx)
15935            .iter()
15936            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15937
15938        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15939    }
15940
15941    pub fn unfold_all(
15942        &mut self,
15943        _: &actions::UnfoldAll,
15944        _window: &mut Window,
15945        cx: &mut Context<Self>,
15946    ) {
15947        if self.buffer.read(cx).is_singleton() {
15948            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15949            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15950        } else {
15951            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15952                editor
15953                    .update(cx, |editor, cx| {
15954                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15955                            editor.unfold_buffer(buffer_id, cx);
15956                        }
15957                    })
15958                    .ok();
15959            });
15960        }
15961    }
15962
15963    pub fn fold_selected_ranges(
15964        &mut self,
15965        _: &FoldSelectedRanges,
15966        window: &mut Window,
15967        cx: &mut Context<Self>,
15968    ) {
15969        let selections = self.selections.all_adjusted(cx);
15970        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15971        let ranges = selections
15972            .into_iter()
15973            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15974            .collect::<Vec<_>>();
15975        self.fold_creases(ranges, true, window, cx);
15976    }
15977
15978    pub fn fold_ranges<T: ToOffset + Clone>(
15979        &mut self,
15980        ranges: Vec<Range<T>>,
15981        auto_scroll: bool,
15982        window: &mut Window,
15983        cx: &mut Context<Self>,
15984    ) {
15985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15986        let ranges = ranges
15987            .into_iter()
15988            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
15989            .collect::<Vec<_>>();
15990        self.fold_creases(ranges, auto_scroll, window, cx);
15991    }
15992
15993    pub fn fold_creases<T: ToOffset + Clone>(
15994        &mut self,
15995        creases: Vec<Crease<T>>,
15996        auto_scroll: bool,
15997        _window: &mut Window,
15998        cx: &mut Context<Self>,
15999    ) {
16000        if creases.is_empty() {
16001            return;
16002        }
16003
16004        let mut buffers_affected = HashSet::default();
16005        let multi_buffer = self.buffer().read(cx);
16006        for crease in &creases {
16007            if let Some((_, buffer, _)) =
16008                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16009            {
16010                buffers_affected.insert(buffer.read(cx).remote_id());
16011            };
16012        }
16013
16014        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16015
16016        if auto_scroll {
16017            self.request_autoscroll(Autoscroll::fit(), cx);
16018        }
16019
16020        cx.notify();
16021
16022        self.scrollbar_marker_state.dirty = true;
16023        self.folds_did_change(cx);
16024    }
16025
16026    /// Removes any folds whose ranges intersect any of the given ranges.
16027    pub fn unfold_ranges<T: ToOffset + Clone>(
16028        &mut self,
16029        ranges: &[Range<T>],
16030        inclusive: bool,
16031        auto_scroll: bool,
16032        cx: &mut Context<Self>,
16033    ) {
16034        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16035            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16036        });
16037        self.folds_did_change(cx);
16038    }
16039
16040    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16041        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16042            return;
16043        }
16044        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16045        self.display_map.update(cx, |display_map, cx| {
16046            display_map.fold_buffers([buffer_id], cx)
16047        });
16048        cx.emit(EditorEvent::BufferFoldToggled {
16049            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16050            folded: true,
16051        });
16052        cx.notify();
16053    }
16054
16055    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16056        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16057            return;
16058        }
16059        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16060        self.display_map.update(cx, |display_map, cx| {
16061            display_map.unfold_buffers([buffer_id], cx);
16062        });
16063        cx.emit(EditorEvent::BufferFoldToggled {
16064            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16065            folded: false,
16066        });
16067        cx.notify();
16068    }
16069
16070    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16071        self.display_map.read(cx).is_buffer_folded(buffer)
16072    }
16073
16074    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16075        self.display_map.read(cx).folded_buffers()
16076    }
16077
16078    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16079        self.display_map.update(cx, |display_map, cx| {
16080            display_map.disable_header_for_buffer(buffer_id, cx);
16081        });
16082        cx.notify();
16083    }
16084
16085    /// Removes any folds with the given ranges.
16086    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16087        &mut self,
16088        ranges: &[Range<T>],
16089        type_id: TypeId,
16090        auto_scroll: bool,
16091        cx: &mut Context<Self>,
16092    ) {
16093        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16094            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16095        });
16096        self.folds_did_change(cx);
16097    }
16098
16099    fn remove_folds_with<T: ToOffset + Clone>(
16100        &mut self,
16101        ranges: &[Range<T>],
16102        auto_scroll: bool,
16103        cx: &mut Context<Self>,
16104        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16105    ) {
16106        if ranges.is_empty() {
16107            return;
16108        }
16109
16110        let mut buffers_affected = HashSet::default();
16111        let multi_buffer = self.buffer().read(cx);
16112        for range in ranges {
16113            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16114                buffers_affected.insert(buffer.read(cx).remote_id());
16115            };
16116        }
16117
16118        self.display_map.update(cx, update);
16119
16120        if auto_scroll {
16121            self.request_autoscroll(Autoscroll::fit(), cx);
16122        }
16123
16124        cx.notify();
16125        self.scrollbar_marker_state.dirty = true;
16126        self.active_indent_guides_state.dirty = true;
16127    }
16128
16129    pub fn update_fold_widths(
16130        &mut self,
16131        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16132        cx: &mut Context<Self>,
16133    ) -> bool {
16134        self.display_map
16135            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16136    }
16137
16138    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16139        self.display_map.read(cx).fold_placeholder.clone()
16140    }
16141
16142    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16143        self.buffer.update(cx, |buffer, cx| {
16144            buffer.set_all_diff_hunks_expanded(cx);
16145        });
16146    }
16147
16148    pub fn expand_all_diff_hunks(
16149        &mut self,
16150        _: &ExpandAllDiffHunks,
16151        _window: &mut Window,
16152        cx: &mut Context<Self>,
16153    ) {
16154        self.buffer.update(cx, |buffer, cx| {
16155            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16156        });
16157    }
16158
16159    pub fn toggle_selected_diff_hunks(
16160        &mut self,
16161        _: &ToggleSelectedDiffHunks,
16162        _window: &mut Window,
16163        cx: &mut Context<Self>,
16164    ) {
16165        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16166        self.toggle_diff_hunks_in_ranges(ranges, cx);
16167    }
16168
16169    pub fn diff_hunks_in_ranges<'a>(
16170        &'a self,
16171        ranges: &'a [Range<Anchor>],
16172        buffer: &'a MultiBufferSnapshot,
16173    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16174        ranges.iter().flat_map(move |range| {
16175            let end_excerpt_id = range.end.excerpt_id;
16176            let range = range.to_point(buffer);
16177            let mut peek_end = range.end;
16178            if range.end.row < buffer.max_row().0 {
16179                peek_end = Point::new(range.end.row + 1, 0);
16180            }
16181            buffer
16182                .diff_hunks_in_range(range.start..peek_end)
16183                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16184        })
16185    }
16186
16187    pub fn has_stageable_diff_hunks_in_ranges(
16188        &self,
16189        ranges: &[Range<Anchor>],
16190        snapshot: &MultiBufferSnapshot,
16191    ) -> bool {
16192        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16193        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16194    }
16195
16196    pub fn toggle_staged_selected_diff_hunks(
16197        &mut self,
16198        _: &::git::ToggleStaged,
16199        _: &mut Window,
16200        cx: &mut Context<Self>,
16201    ) {
16202        let snapshot = self.buffer.read(cx).snapshot(cx);
16203        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16204        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16205        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16206    }
16207
16208    pub fn set_render_diff_hunk_controls(
16209        &mut self,
16210        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16211        cx: &mut Context<Self>,
16212    ) {
16213        self.render_diff_hunk_controls = render_diff_hunk_controls;
16214        cx.notify();
16215    }
16216
16217    pub fn stage_and_next(
16218        &mut self,
16219        _: &::git::StageAndNext,
16220        window: &mut Window,
16221        cx: &mut Context<Self>,
16222    ) {
16223        self.do_stage_or_unstage_and_next(true, window, cx);
16224    }
16225
16226    pub fn unstage_and_next(
16227        &mut self,
16228        _: &::git::UnstageAndNext,
16229        window: &mut Window,
16230        cx: &mut Context<Self>,
16231    ) {
16232        self.do_stage_or_unstage_and_next(false, window, cx);
16233    }
16234
16235    pub fn stage_or_unstage_diff_hunks(
16236        &mut self,
16237        stage: bool,
16238        ranges: Vec<Range<Anchor>>,
16239        cx: &mut Context<Self>,
16240    ) {
16241        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16242        cx.spawn(async move |this, cx| {
16243            task.await?;
16244            this.update(cx, |this, cx| {
16245                let snapshot = this.buffer.read(cx).snapshot(cx);
16246                let chunk_by = this
16247                    .diff_hunks_in_ranges(&ranges, &snapshot)
16248                    .chunk_by(|hunk| hunk.buffer_id);
16249                for (buffer_id, hunks) in &chunk_by {
16250                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16251                }
16252            })
16253        })
16254        .detach_and_log_err(cx);
16255    }
16256
16257    fn save_buffers_for_ranges_if_needed(
16258        &mut self,
16259        ranges: &[Range<Anchor>],
16260        cx: &mut Context<Editor>,
16261    ) -> Task<Result<()>> {
16262        let multibuffer = self.buffer.read(cx);
16263        let snapshot = multibuffer.read(cx);
16264        let buffer_ids: HashSet<_> = ranges
16265            .iter()
16266            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16267            .collect();
16268        drop(snapshot);
16269
16270        let mut buffers = HashSet::default();
16271        for buffer_id in buffer_ids {
16272            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16273                let buffer = buffer_entity.read(cx);
16274                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16275                {
16276                    buffers.insert(buffer_entity);
16277                }
16278            }
16279        }
16280
16281        if let Some(project) = &self.project {
16282            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16283        } else {
16284            Task::ready(Ok(()))
16285        }
16286    }
16287
16288    fn do_stage_or_unstage_and_next(
16289        &mut self,
16290        stage: bool,
16291        window: &mut Window,
16292        cx: &mut Context<Self>,
16293    ) {
16294        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16295
16296        if ranges.iter().any(|range| range.start != range.end) {
16297            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16298            return;
16299        }
16300
16301        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16302        let snapshot = self.snapshot(window, cx);
16303        let position = self.selections.newest::<Point>(cx).head();
16304        let mut row = snapshot
16305            .buffer_snapshot
16306            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16307            .find(|hunk| hunk.row_range.start.0 > position.row)
16308            .map(|hunk| hunk.row_range.start);
16309
16310        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16311        // Outside of the project diff editor, wrap around to the beginning.
16312        if !all_diff_hunks_expanded {
16313            row = row.or_else(|| {
16314                snapshot
16315                    .buffer_snapshot
16316                    .diff_hunks_in_range(Point::zero()..position)
16317                    .find(|hunk| hunk.row_range.end.0 < position.row)
16318                    .map(|hunk| hunk.row_range.start)
16319            });
16320        }
16321
16322        if let Some(row) = row {
16323            let destination = Point::new(row.0, 0);
16324            let autoscroll = Autoscroll::center();
16325
16326            self.unfold_ranges(&[destination..destination], false, false, cx);
16327            self.change_selections(Some(autoscroll), window, cx, |s| {
16328                s.select_ranges([destination..destination]);
16329            });
16330        }
16331    }
16332
16333    fn do_stage_or_unstage(
16334        &self,
16335        stage: bool,
16336        buffer_id: BufferId,
16337        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16338        cx: &mut App,
16339    ) -> Option<()> {
16340        let project = self.project.as_ref()?;
16341        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16342        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16343        let buffer_snapshot = buffer.read(cx).snapshot();
16344        let file_exists = buffer_snapshot
16345            .file()
16346            .is_some_and(|file| file.disk_state().exists());
16347        diff.update(cx, |diff, cx| {
16348            diff.stage_or_unstage_hunks(
16349                stage,
16350                &hunks
16351                    .map(|hunk| buffer_diff::DiffHunk {
16352                        buffer_range: hunk.buffer_range,
16353                        diff_base_byte_range: hunk.diff_base_byte_range,
16354                        secondary_status: hunk.secondary_status,
16355                        range: Point::zero()..Point::zero(), // unused
16356                    })
16357                    .collect::<Vec<_>>(),
16358                &buffer_snapshot,
16359                file_exists,
16360                cx,
16361            )
16362        });
16363        None
16364    }
16365
16366    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16367        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16368        self.buffer
16369            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16370    }
16371
16372    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16373        self.buffer.update(cx, |buffer, cx| {
16374            let ranges = vec![Anchor::min()..Anchor::max()];
16375            if !buffer.all_diff_hunks_expanded()
16376                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16377            {
16378                buffer.collapse_diff_hunks(ranges, cx);
16379                true
16380            } else {
16381                false
16382            }
16383        })
16384    }
16385
16386    fn toggle_diff_hunks_in_ranges(
16387        &mut self,
16388        ranges: Vec<Range<Anchor>>,
16389        cx: &mut Context<Editor>,
16390    ) {
16391        self.buffer.update(cx, |buffer, cx| {
16392            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16393            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16394        })
16395    }
16396
16397    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16398        self.buffer.update(cx, |buffer, cx| {
16399            let snapshot = buffer.snapshot(cx);
16400            let excerpt_id = range.end.excerpt_id;
16401            let point_range = range.to_point(&snapshot);
16402            let expand = !buffer.single_hunk_is_expanded(range, cx);
16403            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16404        })
16405    }
16406
16407    pub(crate) fn apply_all_diff_hunks(
16408        &mut self,
16409        _: &ApplyAllDiffHunks,
16410        window: &mut Window,
16411        cx: &mut Context<Self>,
16412    ) {
16413        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16414
16415        let buffers = self.buffer.read(cx).all_buffers();
16416        for branch_buffer in buffers {
16417            branch_buffer.update(cx, |branch_buffer, cx| {
16418                branch_buffer.merge_into_base(Vec::new(), cx);
16419            });
16420        }
16421
16422        if let Some(project) = self.project.clone() {
16423            self.save(true, project, window, cx).detach_and_log_err(cx);
16424        }
16425    }
16426
16427    pub(crate) fn apply_selected_diff_hunks(
16428        &mut self,
16429        _: &ApplyDiffHunk,
16430        window: &mut Window,
16431        cx: &mut Context<Self>,
16432    ) {
16433        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16434        let snapshot = self.snapshot(window, cx);
16435        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16436        let mut ranges_by_buffer = HashMap::default();
16437        self.transact(window, cx, |editor, _window, cx| {
16438            for hunk in hunks {
16439                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16440                    ranges_by_buffer
16441                        .entry(buffer.clone())
16442                        .or_insert_with(Vec::new)
16443                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16444                }
16445            }
16446
16447            for (buffer, ranges) in ranges_by_buffer {
16448                buffer.update(cx, |buffer, cx| {
16449                    buffer.merge_into_base(ranges, cx);
16450                });
16451            }
16452        });
16453
16454        if let Some(project) = self.project.clone() {
16455            self.save(true, project, window, cx).detach_and_log_err(cx);
16456        }
16457    }
16458
16459    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16460        if hovered != self.gutter_hovered {
16461            self.gutter_hovered = hovered;
16462            cx.notify();
16463        }
16464    }
16465
16466    pub fn insert_blocks(
16467        &mut self,
16468        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16469        autoscroll: Option<Autoscroll>,
16470        cx: &mut Context<Self>,
16471    ) -> Vec<CustomBlockId> {
16472        let blocks = self
16473            .display_map
16474            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16475        if let Some(autoscroll) = autoscroll {
16476            self.request_autoscroll(autoscroll, cx);
16477        }
16478        cx.notify();
16479        blocks
16480    }
16481
16482    pub fn resize_blocks(
16483        &mut self,
16484        heights: HashMap<CustomBlockId, u32>,
16485        autoscroll: Option<Autoscroll>,
16486        cx: &mut Context<Self>,
16487    ) {
16488        self.display_map
16489            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16490        if let Some(autoscroll) = autoscroll {
16491            self.request_autoscroll(autoscroll, cx);
16492        }
16493        cx.notify();
16494    }
16495
16496    pub fn replace_blocks(
16497        &mut self,
16498        renderers: HashMap<CustomBlockId, RenderBlock>,
16499        autoscroll: Option<Autoscroll>,
16500        cx: &mut Context<Self>,
16501    ) {
16502        self.display_map
16503            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16504        if let Some(autoscroll) = autoscroll {
16505            self.request_autoscroll(autoscroll, cx);
16506        }
16507        cx.notify();
16508    }
16509
16510    pub fn remove_blocks(
16511        &mut self,
16512        block_ids: HashSet<CustomBlockId>,
16513        autoscroll: Option<Autoscroll>,
16514        cx: &mut Context<Self>,
16515    ) {
16516        self.display_map.update(cx, |display_map, cx| {
16517            display_map.remove_blocks(block_ids, cx)
16518        });
16519        if let Some(autoscroll) = autoscroll {
16520            self.request_autoscroll(autoscroll, cx);
16521        }
16522        cx.notify();
16523    }
16524
16525    pub fn row_for_block(
16526        &self,
16527        block_id: CustomBlockId,
16528        cx: &mut Context<Self>,
16529    ) -> Option<DisplayRow> {
16530        self.display_map
16531            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16532    }
16533
16534    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16535        self.focused_block = Some(focused_block);
16536    }
16537
16538    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16539        self.focused_block.take()
16540    }
16541
16542    pub fn insert_creases(
16543        &mut self,
16544        creases: impl IntoIterator<Item = Crease<Anchor>>,
16545        cx: &mut Context<Self>,
16546    ) -> Vec<CreaseId> {
16547        self.display_map
16548            .update(cx, |map, cx| map.insert_creases(creases, cx))
16549    }
16550
16551    pub fn remove_creases(
16552        &mut self,
16553        ids: impl IntoIterator<Item = CreaseId>,
16554        cx: &mut Context<Self>,
16555    ) -> Vec<(CreaseId, Range<Anchor>)> {
16556        self.display_map
16557            .update(cx, |map, cx| map.remove_creases(ids, cx))
16558    }
16559
16560    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16561        self.display_map
16562            .update(cx, |map, cx| map.snapshot(cx))
16563            .longest_row()
16564    }
16565
16566    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16567        self.display_map
16568            .update(cx, |map, cx| map.snapshot(cx))
16569            .max_point()
16570    }
16571
16572    pub fn text(&self, cx: &App) -> String {
16573        self.buffer.read(cx).read(cx).text()
16574    }
16575
16576    pub fn is_empty(&self, cx: &App) -> bool {
16577        self.buffer.read(cx).read(cx).is_empty()
16578    }
16579
16580    pub fn text_option(&self, cx: &App) -> Option<String> {
16581        let text = self.text(cx);
16582        let text = text.trim();
16583
16584        if text.is_empty() {
16585            return None;
16586        }
16587
16588        Some(text.to_string())
16589    }
16590
16591    pub fn set_text(
16592        &mut self,
16593        text: impl Into<Arc<str>>,
16594        window: &mut Window,
16595        cx: &mut Context<Self>,
16596    ) {
16597        self.transact(window, cx, |this, _, cx| {
16598            this.buffer
16599                .read(cx)
16600                .as_singleton()
16601                .expect("you can only call set_text on editors for singleton buffers")
16602                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16603        });
16604    }
16605
16606    pub fn display_text(&self, cx: &mut App) -> String {
16607        self.display_map
16608            .update(cx, |map, cx| map.snapshot(cx))
16609            .text()
16610    }
16611
16612    fn create_minimap(
16613        &self,
16614        minimap_settings: MinimapSettings,
16615        window: &mut Window,
16616        cx: &mut Context<Self>,
16617    ) -> Option<Entity<Self>> {
16618        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16619            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16620    }
16621
16622    fn initialize_new_minimap(
16623        &self,
16624        minimap_settings: MinimapSettings,
16625        window: &mut Window,
16626        cx: &mut Context<Self>,
16627    ) -> Entity<Self> {
16628        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16629
16630        let mut minimap = Editor::new_internal(
16631            EditorMode::Minimap {
16632                parent: cx.weak_entity(),
16633            },
16634            self.buffer.clone(),
16635            self.project.clone(),
16636            Some(self.display_map.clone()),
16637            window,
16638            cx,
16639        );
16640        minimap.scroll_manager.clone_state(&self.scroll_manager);
16641        minimap.set_text_style_refinement(TextStyleRefinement {
16642            font_size: Some(MINIMAP_FONT_SIZE),
16643            font_weight: Some(MINIMAP_FONT_WEIGHT),
16644            ..Default::default()
16645        });
16646        minimap.update_minimap_configuration(minimap_settings, cx);
16647        cx.new(|_| minimap)
16648    }
16649
16650    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16651        let current_line_highlight = minimap_settings
16652            .current_line_highlight
16653            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16654        self.set_current_line_highlight(Some(current_line_highlight));
16655    }
16656
16657    pub fn minimap(&self) -> Option<&Entity<Self>> {
16658        self.minimap
16659            .as_ref()
16660            .filter(|_| self.minimap_visibility.visible())
16661    }
16662
16663    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16664        let mut wrap_guides = smallvec::smallvec![];
16665
16666        if self.show_wrap_guides == Some(false) {
16667            return wrap_guides;
16668        }
16669
16670        let settings = self.buffer.read(cx).language_settings(cx);
16671        if settings.show_wrap_guides {
16672            match self.soft_wrap_mode(cx) {
16673                SoftWrap::Column(soft_wrap) => {
16674                    wrap_guides.push((soft_wrap as usize, true));
16675                }
16676                SoftWrap::Bounded(soft_wrap) => {
16677                    wrap_guides.push((soft_wrap as usize, true));
16678                }
16679                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16680            }
16681            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16682        }
16683
16684        wrap_guides
16685    }
16686
16687    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16688        let settings = self.buffer.read(cx).language_settings(cx);
16689        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16690        match mode {
16691            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16692                SoftWrap::None
16693            }
16694            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16695            language_settings::SoftWrap::PreferredLineLength => {
16696                SoftWrap::Column(settings.preferred_line_length)
16697            }
16698            language_settings::SoftWrap::Bounded => {
16699                SoftWrap::Bounded(settings.preferred_line_length)
16700            }
16701        }
16702    }
16703
16704    pub fn set_soft_wrap_mode(
16705        &mut self,
16706        mode: language_settings::SoftWrap,
16707
16708        cx: &mut Context<Self>,
16709    ) {
16710        self.soft_wrap_mode_override = Some(mode);
16711        cx.notify();
16712    }
16713
16714    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16715        self.hard_wrap = hard_wrap;
16716        cx.notify();
16717    }
16718
16719    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16720        self.text_style_refinement = Some(style);
16721    }
16722
16723    /// called by the Element so we know what style we were most recently rendered with.
16724    pub(crate) fn set_style(
16725        &mut self,
16726        style: EditorStyle,
16727        window: &mut Window,
16728        cx: &mut Context<Self>,
16729    ) {
16730        // We intentionally do not inform the display map about the minimap style
16731        // so that wrapping is not recalculated and stays consistent for the editor
16732        // and its linked minimap.
16733        if !self.mode.is_minimap() {
16734            let rem_size = window.rem_size();
16735            self.display_map.update(cx, |map, cx| {
16736                map.set_font(
16737                    style.text.font(),
16738                    style.text.font_size.to_pixels(rem_size),
16739                    cx,
16740                )
16741            });
16742        }
16743        self.style = Some(style);
16744    }
16745
16746    pub fn style(&self) -> Option<&EditorStyle> {
16747        self.style.as_ref()
16748    }
16749
16750    // Called by the element. This method is not designed to be called outside of the editor
16751    // element's layout code because it does not notify when rewrapping is computed synchronously.
16752    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16753        self.display_map
16754            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16755    }
16756
16757    pub fn set_soft_wrap(&mut self) {
16758        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16759    }
16760
16761    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16762        if self.soft_wrap_mode_override.is_some() {
16763            self.soft_wrap_mode_override.take();
16764        } else {
16765            let soft_wrap = match self.soft_wrap_mode(cx) {
16766                SoftWrap::GitDiff => return,
16767                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16768                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16769                    language_settings::SoftWrap::None
16770                }
16771            };
16772            self.soft_wrap_mode_override = Some(soft_wrap);
16773        }
16774        cx.notify();
16775    }
16776
16777    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16778        let Some(workspace) = self.workspace() else {
16779            return;
16780        };
16781        let fs = workspace.read(cx).app_state().fs.clone();
16782        let current_show = TabBarSettings::get_global(cx).show;
16783        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16784            setting.show = Some(!current_show);
16785        });
16786    }
16787
16788    pub fn toggle_indent_guides(
16789        &mut self,
16790        _: &ToggleIndentGuides,
16791        _: &mut Window,
16792        cx: &mut Context<Self>,
16793    ) {
16794        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16795            self.buffer
16796                .read(cx)
16797                .language_settings(cx)
16798                .indent_guides
16799                .enabled
16800        });
16801        self.show_indent_guides = Some(!currently_enabled);
16802        cx.notify();
16803    }
16804
16805    fn should_show_indent_guides(&self) -> Option<bool> {
16806        self.show_indent_guides
16807    }
16808
16809    pub fn toggle_line_numbers(
16810        &mut self,
16811        _: &ToggleLineNumbers,
16812        _: &mut Window,
16813        cx: &mut Context<Self>,
16814    ) {
16815        let mut editor_settings = EditorSettings::get_global(cx).clone();
16816        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16817        EditorSettings::override_global(editor_settings, cx);
16818    }
16819
16820    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16821        if let Some(show_line_numbers) = self.show_line_numbers {
16822            return show_line_numbers;
16823        }
16824        EditorSettings::get_global(cx).gutter.line_numbers
16825    }
16826
16827    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16828        self.use_relative_line_numbers
16829            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16830    }
16831
16832    pub fn toggle_relative_line_numbers(
16833        &mut self,
16834        _: &ToggleRelativeLineNumbers,
16835        _: &mut Window,
16836        cx: &mut Context<Self>,
16837    ) {
16838        let is_relative = self.should_use_relative_line_numbers(cx);
16839        self.set_relative_line_number(Some(!is_relative), cx)
16840    }
16841
16842    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16843        self.use_relative_line_numbers = is_relative;
16844        cx.notify();
16845    }
16846
16847    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16848        self.show_gutter = show_gutter;
16849        cx.notify();
16850    }
16851
16852    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16853        self.show_scrollbars = show_scrollbars;
16854        cx.notify();
16855    }
16856
16857    pub fn set_minimap_visibility(
16858        &mut self,
16859        minimap_visibility: MinimapVisibility,
16860        window: &mut Window,
16861        cx: &mut Context<Self>,
16862    ) {
16863        if self.minimap_visibility != minimap_visibility {
16864            if minimap_visibility.visible() && self.minimap.is_none() {
16865                let minimap_settings = EditorSettings::get_global(cx).minimap;
16866                self.minimap =
16867                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16868            }
16869            self.minimap_visibility = minimap_visibility;
16870            cx.notify();
16871        }
16872    }
16873
16874    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16875        self.set_show_scrollbars(false, cx);
16876        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16877    }
16878
16879    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16880        self.show_line_numbers = Some(show_line_numbers);
16881        cx.notify();
16882    }
16883
16884    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16885        self.disable_expand_excerpt_buttons = true;
16886        cx.notify();
16887    }
16888
16889    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16890        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16891        cx.notify();
16892    }
16893
16894    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16895        self.show_code_actions = Some(show_code_actions);
16896        cx.notify();
16897    }
16898
16899    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16900        self.show_runnables = Some(show_runnables);
16901        cx.notify();
16902    }
16903
16904    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16905        self.show_breakpoints = Some(show_breakpoints);
16906        cx.notify();
16907    }
16908
16909    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16910        if self.display_map.read(cx).masked != masked {
16911            self.display_map.update(cx, |map, _| map.masked = masked);
16912        }
16913        cx.notify()
16914    }
16915
16916    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16917        self.show_wrap_guides = Some(show_wrap_guides);
16918        cx.notify();
16919    }
16920
16921    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16922        self.show_indent_guides = Some(show_indent_guides);
16923        cx.notify();
16924    }
16925
16926    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16927        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16928            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16929                if let Some(dir) = file.abs_path(cx).parent() {
16930                    return Some(dir.to_owned());
16931                }
16932            }
16933
16934            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16935                return Some(project_path.path.to_path_buf());
16936            }
16937        }
16938
16939        None
16940    }
16941
16942    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16943        self.active_excerpt(cx)?
16944            .1
16945            .read(cx)
16946            .file()
16947            .and_then(|f| f.as_local())
16948    }
16949
16950    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16951        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16952            let buffer = buffer.read(cx);
16953            if let Some(project_path) = buffer.project_path(cx) {
16954                let project = self.project.as_ref()?.read(cx);
16955                project.absolute_path(&project_path, cx)
16956            } else {
16957                buffer
16958                    .file()
16959                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16960            }
16961        })
16962    }
16963
16964    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16965        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16966            let project_path = buffer.read(cx).project_path(cx)?;
16967            let project = self.project.as_ref()?.read(cx);
16968            let entry = project.entry_for_path(&project_path, cx)?;
16969            let path = entry.path.to_path_buf();
16970            Some(path)
16971        })
16972    }
16973
16974    pub fn reveal_in_finder(
16975        &mut self,
16976        _: &RevealInFileManager,
16977        _window: &mut Window,
16978        cx: &mut Context<Self>,
16979    ) {
16980        if let Some(target) = self.target_file(cx) {
16981            cx.reveal_path(&target.abs_path(cx));
16982        }
16983    }
16984
16985    pub fn copy_path(
16986        &mut self,
16987        _: &zed_actions::workspace::CopyPath,
16988        _window: &mut Window,
16989        cx: &mut Context<Self>,
16990    ) {
16991        if let Some(path) = self.target_file_abs_path(cx) {
16992            if let Some(path) = path.to_str() {
16993                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16994            }
16995        }
16996    }
16997
16998    pub fn copy_relative_path(
16999        &mut self,
17000        _: &zed_actions::workspace::CopyRelativePath,
17001        _window: &mut Window,
17002        cx: &mut Context<Self>,
17003    ) {
17004        if let Some(path) = self.target_file_path(cx) {
17005            if let Some(path) = path.to_str() {
17006                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17007            }
17008        }
17009    }
17010
17011    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17012        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17013            buffer.read(cx).project_path(cx)
17014        } else {
17015            None
17016        }
17017    }
17018
17019    // Returns true if the editor handled a go-to-line request
17020    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17021        maybe!({
17022            let breakpoint_store = self.breakpoint_store.as_ref()?;
17023
17024            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17025            else {
17026                self.clear_row_highlights::<ActiveDebugLine>();
17027                return None;
17028            };
17029
17030            let position = active_stack_frame.position;
17031            let buffer_id = position.buffer_id?;
17032            let snapshot = self
17033                .project
17034                .as_ref()?
17035                .read(cx)
17036                .buffer_for_id(buffer_id, cx)?
17037                .read(cx)
17038                .snapshot();
17039
17040            let mut handled = false;
17041            for (id, ExcerptRange { context, .. }) in
17042                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17043            {
17044                if context.start.cmp(&position, &snapshot).is_ge()
17045                    || context.end.cmp(&position, &snapshot).is_lt()
17046                {
17047                    continue;
17048                }
17049                let snapshot = self.buffer.read(cx).snapshot(cx);
17050                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17051
17052                handled = true;
17053                self.clear_row_highlights::<ActiveDebugLine>();
17054
17055                self.go_to_line::<ActiveDebugLine>(
17056                    multibuffer_anchor,
17057                    Some(cx.theme().colors().editor_debugger_active_line_background),
17058                    window,
17059                    cx,
17060                );
17061
17062                cx.notify();
17063            }
17064
17065            handled.then_some(())
17066        })
17067        .is_some()
17068    }
17069
17070    pub fn copy_file_name_without_extension(
17071        &mut self,
17072        _: &CopyFileNameWithoutExtension,
17073        _: &mut Window,
17074        cx: &mut Context<Self>,
17075    ) {
17076        if let Some(file) = self.target_file(cx) {
17077            if let Some(file_stem) = file.path().file_stem() {
17078                if let Some(name) = file_stem.to_str() {
17079                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17080                }
17081            }
17082        }
17083    }
17084
17085    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17086        if let Some(file) = self.target_file(cx) {
17087            if let Some(file_name) = file.path().file_name() {
17088                if let Some(name) = file_name.to_str() {
17089                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17090                }
17091            }
17092        }
17093    }
17094
17095    pub fn toggle_git_blame(
17096        &mut self,
17097        _: &::git::Blame,
17098        window: &mut Window,
17099        cx: &mut Context<Self>,
17100    ) {
17101        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17102
17103        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17104            self.start_git_blame(true, window, cx);
17105        }
17106
17107        cx.notify();
17108    }
17109
17110    pub fn toggle_git_blame_inline(
17111        &mut self,
17112        _: &ToggleGitBlameInline,
17113        window: &mut Window,
17114        cx: &mut Context<Self>,
17115    ) {
17116        self.toggle_git_blame_inline_internal(true, window, cx);
17117        cx.notify();
17118    }
17119
17120    pub fn open_git_blame_commit(
17121        &mut self,
17122        _: &OpenGitBlameCommit,
17123        window: &mut Window,
17124        cx: &mut Context<Self>,
17125    ) {
17126        self.open_git_blame_commit_internal(window, cx);
17127    }
17128
17129    fn open_git_blame_commit_internal(
17130        &mut self,
17131        window: &mut Window,
17132        cx: &mut Context<Self>,
17133    ) -> Option<()> {
17134        let blame = self.blame.as_ref()?;
17135        let snapshot = self.snapshot(window, cx);
17136        let cursor = self.selections.newest::<Point>(cx).head();
17137        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17138        let blame_entry = blame
17139            .update(cx, |blame, cx| {
17140                blame
17141                    .blame_for_rows(
17142                        &[RowInfo {
17143                            buffer_id: Some(buffer.remote_id()),
17144                            buffer_row: Some(point.row),
17145                            ..Default::default()
17146                        }],
17147                        cx,
17148                    )
17149                    .next()
17150            })
17151            .flatten()?;
17152        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17153        let repo = blame.read(cx).repository(cx)?;
17154        let workspace = self.workspace()?.downgrade();
17155        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17156        None
17157    }
17158
17159    pub fn git_blame_inline_enabled(&self) -> bool {
17160        self.git_blame_inline_enabled
17161    }
17162
17163    pub fn toggle_selection_menu(
17164        &mut self,
17165        _: &ToggleSelectionMenu,
17166        _: &mut Window,
17167        cx: &mut Context<Self>,
17168    ) {
17169        self.show_selection_menu = self
17170            .show_selection_menu
17171            .map(|show_selections_menu| !show_selections_menu)
17172            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17173
17174        cx.notify();
17175    }
17176
17177    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17178        self.show_selection_menu
17179            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17180    }
17181
17182    fn start_git_blame(
17183        &mut self,
17184        user_triggered: bool,
17185        window: &mut Window,
17186        cx: &mut Context<Self>,
17187    ) {
17188        if let Some(project) = self.project.as_ref() {
17189            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17190                return;
17191            };
17192
17193            if buffer.read(cx).file().is_none() {
17194                return;
17195            }
17196
17197            let focused = self.focus_handle(cx).contains_focused(window, cx);
17198
17199            let project = project.clone();
17200            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17201            self.blame_subscription =
17202                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17203            self.blame = Some(blame);
17204        }
17205    }
17206
17207    fn toggle_git_blame_inline_internal(
17208        &mut self,
17209        user_triggered: bool,
17210        window: &mut Window,
17211        cx: &mut Context<Self>,
17212    ) {
17213        if self.git_blame_inline_enabled {
17214            self.git_blame_inline_enabled = false;
17215            self.show_git_blame_inline = false;
17216            self.show_git_blame_inline_delay_task.take();
17217        } else {
17218            self.git_blame_inline_enabled = true;
17219            self.start_git_blame_inline(user_triggered, window, cx);
17220        }
17221
17222        cx.notify();
17223    }
17224
17225    fn start_git_blame_inline(
17226        &mut self,
17227        user_triggered: bool,
17228        window: &mut Window,
17229        cx: &mut Context<Self>,
17230    ) {
17231        self.start_git_blame(user_triggered, window, cx);
17232
17233        if ProjectSettings::get_global(cx)
17234            .git
17235            .inline_blame_delay()
17236            .is_some()
17237        {
17238            self.start_inline_blame_timer(window, cx);
17239        } else {
17240            self.show_git_blame_inline = true
17241        }
17242    }
17243
17244    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17245        self.blame.as_ref()
17246    }
17247
17248    pub fn show_git_blame_gutter(&self) -> bool {
17249        self.show_git_blame_gutter
17250    }
17251
17252    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17253        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17254    }
17255
17256    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17257        self.show_git_blame_inline
17258            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17259            && !self.newest_selection_head_on_empty_line(cx)
17260            && self.has_blame_entries(cx)
17261    }
17262
17263    fn has_blame_entries(&self, cx: &App) -> bool {
17264        self.blame()
17265            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17266    }
17267
17268    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17269        let cursor_anchor = self.selections.newest_anchor().head();
17270
17271        let snapshot = self.buffer.read(cx).snapshot(cx);
17272        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17273
17274        snapshot.line_len(buffer_row) == 0
17275    }
17276
17277    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17278        let buffer_and_selection = maybe!({
17279            let selection = self.selections.newest::<Point>(cx);
17280            let selection_range = selection.range();
17281
17282            let multi_buffer = self.buffer().read(cx);
17283            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17284            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17285
17286            let (buffer, range, _) = if selection.reversed {
17287                buffer_ranges.first()
17288            } else {
17289                buffer_ranges.last()
17290            }?;
17291
17292            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17293                ..text::ToPoint::to_point(&range.end, &buffer).row;
17294            Some((
17295                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17296                selection,
17297            ))
17298        });
17299
17300        let Some((buffer, selection)) = buffer_and_selection else {
17301            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17302        };
17303
17304        let Some(project) = self.project.as_ref() else {
17305            return Task::ready(Err(anyhow!("editor does not have project")));
17306        };
17307
17308        project.update(cx, |project, cx| {
17309            project.get_permalink_to_line(&buffer, selection, cx)
17310        })
17311    }
17312
17313    pub fn copy_permalink_to_line(
17314        &mut self,
17315        _: &CopyPermalinkToLine,
17316        window: &mut Window,
17317        cx: &mut Context<Self>,
17318    ) {
17319        let permalink_task = self.get_permalink_to_line(cx);
17320        let workspace = self.workspace();
17321
17322        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17323            Ok(permalink) => {
17324                cx.update(|_, cx| {
17325                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17326                })
17327                .ok();
17328            }
17329            Err(err) => {
17330                let message = format!("Failed to copy permalink: {err}");
17331
17332                Err::<(), anyhow::Error>(err).log_err();
17333
17334                if let Some(workspace) = workspace {
17335                    workspace
17336                        .update_in(cx, |workspace, _, cx| {
17337                            struct CopyPermalinkToLine;
17338
17339                            workspace.show_toast(
17340                                Toast::new(
17341                                    NotificationId::unique::<CopyPermalinkToLine>(),
17342                                    message,
17343                                ),
17344                                cx,
17345                            )
17346                        })
17347                        .ok();
17348                }
17349            }
17350        })
17351        .detach();
17352    }
17353
17354    pub fn copy_file_location(
17355        &mut self,
17356        _: &CopyFileLocation,
17357        _: &mut Window,
17358        cx: &mut Context<Self>,
17359    ) {
17360        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17361        if let Some(file) = self.target_file(cx) {
17362            if let Some(path) = file.path().to_str() {
17363                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17364            }
17365        }
17366    }
17367
17368    pub fn open_permalink_to_line(
17369        &mut self,
17370        _: &OpenPermalinkToLine,
17371        window: &mut Window,
17372        cx: &mut Context<Self>,
17373    ) {
17374        let permalink_task = self.get_permalink_to_line(cx);
17375        let workspace = self.workspace();
17376
17377        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17378            Ok(permalink) => {
17379                cx.update(|_, cx| {
17380                    cx.open_url(permalink.as_ref());
17381                })
17382                .ok();
17383            }
17384            Err(err) => {
17385                let message = format!("Failed to open permalink: {err}");
17386
17387                Err::<(), anyhow::Error>(err).log_err();
17388
17389                if let Some(workspace) = workspace {
17390                    workspace
17391                        .update(cx, |workspace, cx| {
17392                            struct OpenPermalinkToLine;
17393
17394                            workspace.show_toast(
17395                                Toast::new(
17396                                    NotificationId::unique::<OpenPermalinkToLine>(),
17397                                    message,
17398                                ),
17399                                cx,
17400                            )
17401                        })
17402                        .ok();
17403                }
17404            }
17405        })
17406        .detach();
17407    }
17408
17409    pub fn insert_uuid_v4(
17410        &mut self,
17411        _: &InsertUuidV4,
17412        window: &mut Window,
17413        cx: &mut Context<Self>,
17414    ) {
17415        self.insert_uuid(UuidVersion::V4, window, cx);
17416    }
17417
17418    pub fn insert_uuid_v7(
17419        &mut self,
17420        _: &InsertUuidV7,
17421        window: &mut Window,
17422        cx: &mut Context<Self>,
17423    ) {
17424        self.insert_uuid(UuidVersion::V7, window, cx);
17425    }
17426
17427    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17428        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17429        self.transact(window, cx, |this, window, cx| {
17430            let edits = this
17431                .selections
17432                .all::<Point>(cx)
17433                .into_iter()
17434                .map(|selection| {
17435                    let uuid = match version {
17436                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17437                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17438                    };
17439
17440                    (selection.range(), uuid.to_string())
17441                });
17442            this.edit(edits, cx);
17443            this.refresh_inline_completion(true, false, window, cx);
17444        });
17445    }
17446
17447    pub fn open_selections_in_multibuffer(
17448        &mut self,
17449        _: &OpenSelectionsInMultibuffer,
17450        window: &mut Window,
17451        cx: &mut Context<Self>,
17452    ) {
17453        let multibuffer = self.buffer.read(cx);
17454
17455        let Some(buffer) = multibuffer.as_singleton() else {
17456            return;
17457        };
17458
17459        let Some(workspace) = self.workspace() else {
17460            return;
17461        };
17462
17463        let locations = self
17464            .selections
17465            .disjoint_anchors()
17466            .iter()
17467            .map(|range| Location {
17468                buffer: buffer.clone(),
17469                range: range.start.text_anchor..range.end.text_anchor,
17470            })
17471            .collect::<Vec<_>>();
17472
17473        let title = multibuffer.title(cx).to_string();
17474
17475        cx.spawn_in(window, async move |_, cx| {
17476            workspace.update_in(cx, |workspace, window, cx| {
17477                Self::open_locations_in_multibuffer(
17478                    workspace,
17479                    locations,
17480                    format!("Selections for '{title}'"),
17481                    false,
17482                    MultibufferSelectionMode::All,
17483                    window,
17484                    cx,
17485                );
17486            })
17487        })
17488        .detach();
17489    }
17490
17491    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17492    /// last highlight added will be used.
17493    ///
17494    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17495    pub fn highlight_rows<T: 'static>(
17496        &mut self,
17497        range: Range<Anchor>,
17498        color: Hsla,
17499        options: RowHighlightOptions,
17500        cx: &mut Context<Self>,
17501    ) {
17502        let snapshot = self.buffer().read(cx).snapshot(cx);
17503        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17504        let ix = row_highlights.binary_search_by(|highlight| {
17505            Ordering::Equal
17506                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17507                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17508        });
17509
17510        if let Err(mut ix) = ix {
17511            let index = post_inc(&mut self.highlight_order);
17512
17513            // If this range intersects with the preceding highlight, then merge it with
17514            // the preceding highlight. Otherwise insert a new highlight.
17515            let mut merged = false;
17516            if ix > 0 {
17517                let prev_highlight = &mut row_highlights[ix - 1];
17518                if prev_highlight
17519                    .range
17520                    .end
17521                    .cmp(&range.start, &snapshot)
17522                    .is_ge()
17523                {
17524                    ix -= 1;
17525                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17526                        prev_highlight.range.end = range.end;
17527                    }
17528                    merged = true;
17529                    prev_highlight.index = index;
17530                    prev_highlight.color = color;
17531                    prev_highlight.options = options;
17532                }
17533            }
17534
17535            if !merged {
17536                row_highlights.insert(
17537                    ix,
17538                    RowHighlight {
17539                        range: range.clone(),
17540                        index,
17541                        color,
17542                        options,
17543                        type_id: TypeId::of::<T>(),
17544                    },
17545                );
17546            }
17547
17548            // If any of the following highlights intersect with this one, merge them.
17549            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17550                let highlight = &row_highlights[ix];
17551                if next_highlight
17552                    .range
17553                    .start
17554                    .cmp(&highlight.range.end, &snapshot)
17555                    .is_le()
17556                {
17557                    if next_highlight
17558                        .range
17559                        .end
17560                        .cmp(&highlight.range.end, &snapshot)
17561                        .is_gt()
17562                    {
17563                        row_highlights[ix].range.end = next_highlight.range.end;
17564                    }
17565                    row_highlights.remove(ix + 1);
17566                } else {
17567                    break;
17568                }
17569            }
17570        }
17571    }
17572
17573    /// Remove any highlighted row ranges of the given type that intersect the
17574    /// given ranges.
17575    pub fn remove_highlighted_rows<T: 'static>(
17576        &mut self,
17577        ranges_to_remove: Vec<Range<Anchor>>,
17578        cx: &mut Context<Self>,
17579    ) {
17580        let snapshot = self.buffer().read(cx).snapshot(cx);
17581        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17582        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17583        row_highlights.retain(|highlight| {
17584            while let Some(range_to_remove) = ranges_to_remove.peek() {
17585                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17586                    Ordering::Less | Ordering::Equal => {
17587                        ranges_to_remove.next();
17588                    }
17589                    Ordering::Greater => {
17590                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17591                            Ordering::Less | Ordering::Equal => {
17592                                return false;
17593                            }
17594                            Ordering::Greater => break,
17595                        }
17596                    }
17597                }
17598            }
17599
17600            true
17601        })
17602    }
17603
17604    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17605    pub fn clear_row_highlights<T: 'static>(&mut self) {
17606        self.highlighted_rows.remove(&TypeId::of::<T>());
17607    }
17608
17609    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17610    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17611        self.highlighted_rows
17612            .get(&TypeId::of::<T>())
17613            .map_or(&[] as &[_], |vec| vec.as_slice())
17614            .iter()
17615            .map(|highlight| (highlight.range.clone(), highlight.color))
17616    }
17617
17618    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17619    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17620    /// Allows to ignore certain kinds of highlights.
17621    pub fn highlighted_display_rows(
17622        &self,
17623        window: &mut Window,
17624        cx: &mut App,
17625    ) -> BTreeMap<DisplayRow, LineHighlight> {
17626        let snapshot = self.snapshot(window, cx);
17627        let mut used_highlight_orders = HashMap::default();
17628        self.highlighted_rows
17629            .iter()
17630            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17631            .fold(
17632                BTreeMap::<DisplayRow, LineHighlight>::new(),
17633                |mut unique_rows, highlight| {
17634                    let start = highlight.range.start.to_display_point(&snapshot);
17635                    let end = highlight.range.end.to_display_point(&snapshot);
17636                    let start_row = start.row().0;
17637                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17638                        && end.column() == 0
17639                    {
17640                        end.row().0.saturating_sub(1)
17641                    } else {
17642                        end.row().0
17643                    };
17644                    for row in start_row..=end_row {
17645                        let used_index =
17646                            used_highlight_orders.entry(row).or_insert(highlight.index);
17647                        if highlight.index >= *used_index {
17648                            *used_index = highlight.index;
17649                            unique_rows.insert(
17650                                DisplayRow(row),
17651                                LineHighlight {
17652                                    include_gutter: highlight.options.include_gutter,
17653                                    border: None,
17654                                    background: highlight.color.into(),
17655                                    type_id: Some(highlight.type_id),
17656                                },
17657                            );
17658                        }
17659                    }
17660                    unique_rows
17661                },
17662            )
17663    }
17664
17665    pub fn highlighted_display_row_for_autoscroll(
17666        &self,
17667        snapshot: &DisplaySnapshot,
17668    ) -> Option<DisplayRow> {
17669        self.highlighted_rows
17670            .values()
17671            .flat_map(|highlighted_rows| highlighted_rows.iter())
17672            .filter_map(|highlight| {
17673                if highlight.options.autoscroll {
17674                    Some(highlight.range.start.to_display_point(snapshot).row())
17675                } else {
17676                    None
17677                }
17678            })
17679            .min()
17680    }
17681
17682    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17683        self.highlight_background::<SearchWithinRange>(
17684            ranges,
17685            |colors| colors.editor_document_highlight_read_background,
17686            cx,
17687        )
17688    }
17689
17690    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17691        self.breadcrumb_header = Some(new_header);
17692    }
17693
17694    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17695        self.clear_background_highlights::<SearchWithinRange>(cx);
17696    }
17697
17698    pub fn highlight_background<T: 'static>(
17699        &mut self,
17700        ranges: &[Range<Anchor>],
17701        color_fetcher: fn(&ThemeColors) -> Hsla,
17702        cx: &mut Context<Self>,
17703    ) {
17704        self.background_highlights
17705            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17706        self.scrollbar_marker_state.dirty = true;
17707        cx.notify();
17708    }
17709
17710    pub fn clear_background_highlights<T: 'static>(
17711        &mut self,
17712        cx: &mut Context<Self>,
17713    ) -> Option<BackgroundHighlight> {
17714        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17715        if !text_highlights.1.is_empty() {
17716            self.scrollbar_marker_state.dirty = true;
17717            cx.notify();
17718        }
17719        Some(text_highlights)
17720    }
17721
17722    pub fn highlight_gutter<T: 'static>(
17723        &mut self,
17724        ranges: &[Range<Anchor>],
17725        color_fetcher: fn(&App) -> Hsla,
17726        cx: &mut Context<Self>,
17727    ) {
17728        self.gutter_highlights
17729            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17730        cx.notify();
17731    }
17732
17733    pub fn clear_gutter_highlights<T: 'static>(
17734        &mut self,
17735        cx: &mut Context<Self>,
17736    ) -> Option<GutterHighlight> {
17737        cx.notify();
17738        self.gutter_highlights.remove(&TypeId::of::<T>())
17739    }
17740
17741    #[cfg(feature = "test-support")]
17742    pub fn all_text_background_highlights(
17743        &self,
17744        window: &mut Window,
17745        cx: &mut Context<Self>,
17746    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17747        let snapshot = self.snapshot(window, cx);
17748        let buffer = &snapshot.buffer_snapshot;
17749        let start = buffer.anchor_before(0);
17750        let end = buffer.anchor_after(buffer.len());
17751        let theme = cx.theme().colors();
17752        self.background_highlights_in_range(start..end, &snapshot, theme)
17753    }
17754
17755    #[cfg(feature = "test-support")]
17756    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17757        let snapshot = self.buffer().read(cx).snapshot(cx);
17758
17759        let highlights = self
17760            .background_highlights
17761            .get(&TypeId::of::<items::BufferSearchHighlights>());
17762
17763        if let Some((_color, ranges)) = highlights {
17764            ranges
17765                .iter()
17766                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17767                .collect_vec()
17768        } else {
17769            vec![]
17770        }
17771    }
17772
17773    fn document_highlights_for_position<'a>(
17774        &'a self,
17775        position: Anchor,
17776        buffer: &'a MultiBufferSnapshot,
17777    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17778        let read_highlights = self
17779            .background_highlights
17780            .get(&TypeId::of::<DocumentHighlightRead>())
17781            .map(|h| &h.1);
17782        let write_highlights = self
17783            .background_highlights
17784            .get(&TypeId::of::<DocumentHighlightWrite>())
17785            .map(|h| &h.1);
17786        let left_position = position.bias_left(buffer);
17787        let right_position = position.bias_right(buffer);
17788        read_highlights
17789            .into_iter()
17790            .chain(write_highlights)
17791            .flat_map(move |ranges| {
17792                let start_ix = match ranges.binary_search_by(|probe| {
17793                    let cmp = probe.end.cmp(&left_position, buffer);
17794                    if cmp.is_ge() {
17795                        Ordering::Greater
17796                    } else {
17797                        Ordering::Less
17798                    }
17799                }) {
17800                    Ok(i) | Err(i) => i,
17801                };
17802
17803                ranges[start_ix..]
17804                    .iter()
17805                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17806            })
17807    }
17808
17809    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17810        self.background_highlights
17811            .get(&TypeId::of::<T>())
17812            .map_or(false, |(_, highlights)| !highlights.is_empty())
17813    }
17814
17815    pub fn background_highlights_in_range(
17816        &self,
17817        search_range: Range<Anchor>,
17818        display_snapshot: &DisplaySnapshot,
17819        theme: &ThemeColors,
17820    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17821        let mut results = Vec::new();
17822        for (color_fetcher, ranges) in self.background_highlights.values() {
17823            let color = color_fetcher(theme);
17824            let start_ix = match ranges.binary_search_by(|probe| {
17825                let cmp = probe
17826                    .end
17827                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17828                if cmp.is_gt() {
17829                    Ordering::Greater
17830                } else {
17831                    Ordering::Less
17832                }
17833            }) {
17834                Ok(i) | Err(i) => i,
17835            };
17836            for range in &ranges[start_ix..] {
17837                if range
17838                    .start
17839                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17840                    .is_ge()
17841                {
17842                    break;
17843                }
17844
17845                let start = range.start.to_display_point(display_snapshot);
17846                let end = range.end.to_display_point(display_snapshot);
17847                results.push((start..end, color))
17848            }
17849        }
17850        results
17851    }
17852
17853    pub fn background_highlight_row_ranges<T: 'static>(
17854        &self,
17855        search_range: Range<Anchor>,
17856        display_snapshot: &DisplaySnapshot,
17857        count: usize,
17858    ) -> Vec<RangeInclusive<DisplayPoint>> {
17859        let mut results = Vec::new();
17860        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17861            return vec![];
17862        };
17863
17864        let start_ix = match ranges.binary_search_by(|probe| {
17865            let cmp = probe
17866                .end
17867                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17868            if cmp.is_gt() {
17869                Ordering::Greater
17870            } else {
17871                Ordering::Less
17872            }
17873        }) {
17874            Ok(i) | Err(i) => i,
17875        };
17876        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17877            if let (Some(start_display), Some(end_display)) = (start, end) {
17878                results.push(
17879                    start_display.to_display_point(display_snapshot)
17880                        ..=end_display.to_display_point(display_snapshot),
17881                );
17882            }
17883        };
17884        let mut start_row: Option<Point> = None;
17885        let mut end_row: Option<Point> = None;
17886        if ranges.len() > count {
17887            return Vec::new();
17888        }
17889        for range in &ranges[start_ix..] {
17890            if range
17891                .start
17892                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17893                .is_ge()
17894            {
17895                break;
17896            }
17897            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17898            if let Some(current_row) = &end_row {
17899                if end.row == current_row.row {
17900                    continue;
17901                }
17902            }
17903            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17904            if start_row.is_none() {
17905                assert_eq!(end_row, None);
17906                start_row = Some(start);
17907                end_row = Some(end);
17908                continue;
17909            }
17910            if let Some(current_end) = end_row.as_mut() {
17911                if start.row > current_end.row + 1 {
17912                    push_region(start_row, end_row);
17913                    start_row = Some(start);
17914                    end_row = Some(end);
17915                } else {
17916                    // Merge two hunks.
17917                    *current_end = end;
17918                }
17919            } else {
17920                unreachable!();
17921            }
17922        }
17923        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17924        push_region(start_row, end_row);
17925        results
17926    }
17927
17928    pub fn gutter_highlights_in_range(
17929        &self,
17930        search_range: Range<Anchor>,
17931        display_snapshot: &DisplaySnapshot,
17932        cx: &App,
17933    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17934        let mut results = Vec::new();
17935        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17936            let color = color_fetcher(cx);
17937            let start_ix = match ranges.binary_search_by(|probe| {
17938                let cmp = probe
17939                    .end
17940                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17941                if cmp.is_gt() {
17942                    Ordering::Greater
17943                } else {
17944                    Ordering::Less
17945                }
17946            }) {
17947                Ok(i) | Err(i) => i,
17948            };
17949            for range in &ranges[start_ix..] {
17950                if range
17951                    .start
17952                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17953                    .is_ge()
17954                {
17955                    break;
17956                }
17957
17958                let start = range.start.to_display_point(display_snapshot);
17959                let end = range.end.to_display_point(display_snapshot);
17960                results.push((start..end, color))
17961            }
17962        }
17963        results
17964    }
17965
17966    /// Get the text ranges corresponding to the redaction query
17967    pub fn redacted_ranges(
17968        &self,
17969        search_range: Range<Anchor>,
17970        display_snapshot: &DisplaySnapshot,
17971        cx: &App,
17972    ) -> Vec<Range<DisplayPoint>> {
17973        display_snapshot
17974            .buffer_snapshot
17975            .redacted_ranges(search_range, |file| {
17976                if let Some(file) = file {
17977                    file.is_private()
17978                        && EditorSettings::get(
17979                            Some(SettingsLocation {
17980                                worktree_id: file.worktree_id(cx),
17981                                path: file.path().as_ref(),
17982                            }),
17983                            cx,
17984                        )
17985                        .redact_private_values
17986                } else {
17987                    false
17988                }
17989            })
17990            .map(|range| {
17991                range.start.to_display_point(display_snapshot)
17992                    ..range.end.to_display_point(display_snapshot)
17993            })
17994            .collect()
17995    }
17996
17997    pub fn highlight_text<T: 'static>(
17998        &mut self,
17999        ranges: Vec<Range<Anchor>>,
18000        style: HighlightStyle,
18001        cx: &mut Context<Self>,
18002    ) {
18003        self.display_map.update(cx, |map, _| {
18004            map.highlight_text(TypeId::of::<T>(), ranges, style)
18005        });
18006        cx.notify();
18007    }
18008
18009    pub(crate) fn highlight_inlays<T: 'static>(
18010        &mut self,
18011        highlights: Vec<InlayHighlight>,
18012        style: HighlightStyle,
18013        cx: &mut Context<Self>,
18014    ) {
18015        self.display_map.update(cx, |map, _| {
18016            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18017        });
18018        cx.notify();
18019    }
18020
18021    pub fn text_highlights<'a, T: 'static>(
18022        &'a self,
18023        cx: &'a App,
18024    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18025        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18026    }
18027
18028    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18029        let cleared = self
18030            .display_map
18031            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18032        if cleared {
18033            cx.notify();
18034        }
18035    }
18036
18037    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18038        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18039            && self.focus_handle.is_focused(window)
18040    }
18041
18042    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18043        self.show_cursor_when_unfocused = is_enabled;
18044        cx.notify();
18045    }
18046
18047    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18048        cx.notify();
18049    }
18050
18051    fn on_debug_session_event(
18052        &mut self,
18053        _session: Entity<Session>,
18054        event: &SessionEvent,
18055        cx: &mut Context<Self>,
18056    ) {
18057        match event {
18058            SessionEvent::InvalidateInlineValue => {
18059                self.refresh_inline_values(cx);
18060            }
18061            _ => {}
18062        }
18063    }
18064
18065    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18066        let Some(project) = self.project.clone() else {
18067            return;
18068        };
18069
18070        if !self.inline_value_cache.enabled {
18071            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18072            self.splice_inlays(&inlays, Vec::new(), cx);
18073            return;
18074        }
18075
18076        let current_execution_position = self
18077            .highlighted_rows
18078            .get(&TypeId::of::<ActiveDebugLine>())
18079            .and_then(|lines| lines.last().map(|line| line.range.start));
18080
18081        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18082            let inline_values = editor
18083                .update(cx, |editor, cx| {
18084                    let Some(current_execution_position) = current_execution_position else {
18085                        return Some(Task::ready(Ok(Vec::new())));
18086                    };
18087
18088                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18089                        let snapshot = buffer.snapshot(cx);
18090
18091                        let excerpt = snapshot.excerpt_containing(
18092                            current_execution_position..current_execution_position,
18093                        )?;
18094
18095                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18096                    })?;
18097
18098                    let range =
18099                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18100
18101                    project.inline_values(buffer, range, cx)
18102                })
18103                .ok()
18104                .flatten()?
18105                .await
18106                .context("refreshing debugger inlays")
18107                .log_err()?;
18108
18109            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18110
18111            for (buffer_id, inline_value) in inline_values
18112                .into_iter()
18113                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18114            {
18115                buffer_inline_values
18116                    .entry(buffer_id)
18117                    .or_default()
18118                    .push(inline_value);
18119            }
18120
18121            editor
18122                .update(cx, |editor, cx| {
18123                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18124                    let mut new_inlays = Vec::default();
18125
18126                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18127                        let buffer_id = buffer_snapshot.remote_id();
18128                        buffer_inline_values
18129                            .get(&buffer_id)
18130                            .into_iter()
18131                            .flatten()
18132                            .for_each(|hint| {
18133                                let inlay = Inlay::debugger_hint(
18134                                    post_inc(&mut editor.next_inlay_id),
18135                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18136                                    hint.text(),
18137                                );
18138
18139                                new_inlays.push(inlay);
18140                            });
18141                    }
18142
18143                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18144                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18145
18146                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18147                })
18148                .ok()?;
18149            Some(())
18150        });
18151    }
18152
18153    fn on_buffer_event(
18154        &mut self,
18155        multibuffer: &Entity<MultiBuffer>,
18156        event: &multi_buffer::Event,
18157        window: &mut Window,
18158        cx: &mut Context<Self>,
18159    ) {
18160        match event {
18161            multi_buffer::Event::Edited {
18162                singleton_buffer_edited,
18163                edited_buffer: buffer_edited,
18164            } => {
18165                self.scrollbar_marker_state.dirty = true;
18166                self.active_indent_guides_state.dirty = true;
18167                self.refresh_active_diagnostics(cx);
18168                self.refresh_code_actions(window, cx);
18169                self.refresh_selected_text_highlights(true, window, cx);
18170                refresh_matching_bracket_highlights(self, window, cx);
18171                if self.has_active_inline_completion() {
18172                    self.update_visible_inline_completion(window, cx);
18173                }
18174                if let Some(buffer) = buffer_edited {
18175                    let buffer_id = buffer.read(cx).remote_id();
18176                    if !self.registered_buffers.contains_key(&buffer_id) {
18177                        if let Some(project) = self.project.as_ref() {
18178                            project.update(cx, |project, cx| {
18179                                self.registered_buffers.insert(
18180                                    buffer_id,
18181                                    project.register_buffer_with_language_servers(&buffer, cx),
18182                                );
18183                            })
18184                        }
18185                    }
18186                }
18187                cx.emit(EditorEvent::BufferEdited);
18188                cx.emit(SearchEvent::MatchesInvalidated);
18189                if *singleton_buffer_edited {
18190                    if let Some(project) = &self.project {
18191                        #[allow(clippy::mutable_key_type)]
18192                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18193                            multibuffer
18194                                .all_buffers()
18195                                .into_iter()
18196                                .filter_map(|buffer| {
18197                                    buffer.update(cx, |buffer, cx| {
18198                                        let language = buffer.language()?;
18199                                        let should_discard = project.update(cx, |project, cx| {
18200                                            project.is_local()
18201                                                && !project.has_language_servers_for(buffer, cx)
18202                                        });
18203                                        should_discard.not().then_some(language.clone())
18204                                    })
18205                                })
18206                                .collect::<HashSet<_>>()
18207                        });
18208                        if !languages_affected.is_empty() {
18209                            self.refresh_inlay_hints(
18210                                InlayHintRefreshReason::BufferEdited(languages_affected),
18211                                cx,
18212                            );
18213                        }
18214                    }
18215                }
18216
18217                let Some(project) = &self.project else { return };
18218                let (telemetry, is_via_ssh) = {
18219                    let project = project.read(cx);
18220                    let telemetry = project.client().telemetry().clone();
18221                    let is_via_ssh = project.is_via_ssh();
18222                    (telemetry, is_via_ssh)
18223                };
18224                refresh_linked_ranges(self, window, cx);
18225                telemetry.log_edit_event("editor", is_via_ssh);
18226            }
18227            multi_buffer::Event::ExcerptsAdded {
18228                buffer,
18229                predecessor,
18230                excerpts,
18231            } => {
18232                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18233                let buffer_id = buffer.read(cx).remote_id();
18234                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18235                    if let Some(project) = &self.project {
18236                        update_uncommitted_diff_for_buffer(
18237                            cx.entity(),
18238                            project,
18239                            [buffer.clone()],
18240                            self.buffer.clone(),
18241                            cx,
18242                        )
18243                        .detach();
18244                    }
18245                }
18246                cx.emit(EditorEvent::ExcerptsAdded {
18247                    buffer: buffer.clone(),
18248                    predecessor: *predecessor,
18249                    excerpts: excerpts.clone(),
18250                });
18251                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18252            }
18253            multi_buffer::Event::ExcerptsRemoved {
18254                ids,
18255                removed_buffer_ids,
18256            } => {
18257                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18258                let buffer = self.buffer.read(cx);
18259                self.registered_buffers
18260                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18261                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18262                cx.emit(EditorEvent::ExcerptsRemoved {
18263                    ids: ids.clone(),
18264                    removed_buffer_ids: removed_buffer_ids.clone(),
18265                })
18266            }
18267            multi_buffer::Event::ExcerptsEdited {
18268                excerpt_ids,
18269                buffer_ids,
18270            } => {
18271                self.display_map.update(cx, |map, cx| {
18272                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18273                });
18274                cx.emit(EditorEvent::ExcerptsEdited {
18275                    ids: excerpt_ids.clone(),
18276                })
18277            }
18278            multi_buffer::Event::ExcerptsExpanded { ids } => {
18279                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18280                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18281            }
18282            multi_buffer::Event::Reparsed(buffer_id) => {
18283                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18284                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18285
18286                cx.emit(EditorEvent::Reparsed(*buffer_id));
18287            }
18288            multi_buffer::Event::DiffHunksToggled => {
18289                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18290            }
18291            multi_buffer::Event::LanguageChanged(buffer_id) => {
18292                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18293                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18294                cx.emit(EditorEvent::Reparsed(*buffer_id));
18295                cx.notify();
18296            }
18297            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18298            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18299            multi_buffer::Event::FileHandleChanged
18300            | multi_buffer::Event::Reloaded
18301            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18302            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18303            multi_buffer::Event::DiagnosticsUpdated => {
18304                self.refresh_active_diagnostics(cx);
18305                self.refresh_inline_diagnostics(true, window, cx);
18306                self.scrollbar_marker_state.dirty = true;
18307                cx.notify();
18308            }
18309            _ => {}
18310        };
18311    }
18312
18313    pub fn start_temporary_diff_override(&mut self) {
18314        self.load_diff_task.take();
18315        self.temporary_diff_override = true;
18316    }
18317
18318    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18319        self.temporary_diff_override = false;
18320        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18321        self.buffer.update(cx, |buffer, cx| {
18322            buffer.set_all_diff_hunks_collapsed(cx);
18323        });
18324
18325        if let Some(project) = self.project.clone() {
18326            self.load_diff_task = Some(
18327                update_uncommitted_diff_for_buffer(
18328                    cx.entity(),
18329                    &project,
18330                    self.buffer.read(cx).all_buffers(),
18331                    self.buffer.clone(),
18332                    cx,
18333                )
18334                .shared(),
18335            );
18336        }
18337    }
18338
18339    fn on_display_map_changed(
18340        &mut self,
18341        _: Entity<DisplayMap>,
18342        _: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) {
18345        cx.notify();
18346    }
18347
18348    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18349        let new_severity = if self.diagnostics_enabled() {
18350            EditorSettings::get_global(cx)
18351                .diagnostics_max_severity
18352                .unwrap_or(DiagnosticSeverity::Hint)
18353        } else {
18354            DiagnosticSeverity::Off
18355        };
18356        self.set_max_diagnostics_severity(new_severity, cx);
18357        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18358        self.update_edit_prediction_settings(cx);
18359        self.refresh_inline_completion(true, false, window, cx);
18360        self.refresh_inlay_hints(
18361            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18362                self.selections.newest_anchor().head(),
18363                &self.buffer.read(cx).snapshot(cx),
18364                cx,
18365            )),
18366            cx,
18367        );
18368
18369        let old_cursor_shape = self.cursor_shape;
18370
18371        {
18372            let editor_settings = EditorSettings::get_global(cx);
18373            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18374            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18375            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18376            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18377        }
18378
18379        if old_cursor_shape != self.cursor_shape {
18380            cx.emit(EditorEvent::CursorShapeChanged);
18381        }
18382
18383        let project_settings = ProjectSettings::get_global(cx);
18384        self.serialize_dirty_buffers =
18385            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18386
18387        if self.mode.is_full() {
18388            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18389            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18390            if self.show_inline_diagnostics != show_inline_diagnostics {
18391                self.show_inline_diagnostics = show_inline_diagnostics;
18392                self.refresh_inline_diagnostics(false, window, cx);
18393            }
18394
18395            if self.git_blame_inline_enabled != inline_blame_enabled {
18396                self.toggle_git_blame_inline_internal(false, window, cx);
18397            }
18398
18399            let minimap_settings = EditorSettings::get_global(cx).minimap;
18400            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18401                self.set_minimap_visibility(
18402                    self.minimap_visibility.toggle_visibility(),
18403                    window,
18404                    cx,
18405                );
18406            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18407                minimap_entity.update(cx, |minimap_editor, cx| {
18408                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18409                })
18410            }
18411        }
18412
18413        cx.notify();
18414    }
18415
18416    pub fn set_searchable(&mut self, searchable: bool) {
18417        self.searchable = searchable;
18418    }
18419
18420    pub fn searchable(&self) -> bool {
18421        self.searchable
18422    }
18423
18424    fn open_proposed_changes_editor(
18425        &mut self,
18426        _: &OpenProposedChangesEditor,
18427        window: &mut Window,
18428        cx: &mut Context<Self>,
18429    ) {
18430        let Some(workspace) = self.workspace() else {
18431            cx.propagate();
18432            return;
18433        };
18434
18435        let selections = self.selections.all::<usize>(cx);
18436        let multi_buffer = self.buffer.read(cx);
18437        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18438        let mut new_selections_by_buffer = HashMap::default();
18439        for selection in selections {
18440            for (buffer, range, _) in
18441                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18442            {
18443                let mut range = range.to_point(buffer);
18444                range.start.column = 0;
18445                range.end.column = buffer.line_len(range.end.row);
18446                new_selections_by_buffer
18447                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18448                    .or_insert(Vec::new())
18449                    .push(range)
18450            }
18451        }
18452
18453        let proposed_changes_buffers = new_selections_by_buffer
18454            .into_iter()
18455            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18456            .collect::<Vec<_>>();
18457        let proposed_changes_editor = cx.new(|cx| {
18458            ProposedChangesEditor::new(
18459                "Proposed changes",
18460                proposed_changes_buffers,
18461                self.project.clone(),
18462                window,
18463                cx,
18464            )
18465        });
18466
18467        window.defer(cx, move |window, cx| {
18468            workspace.update(cx, |workspace, cx| {
18469                workspace.active_pane().update(cx, |pane, cx| {
18470                    pane.add_item(
18471                        Box::new(proposed_changes_editor),
18472                        true,
18473                        true,
18474                        None,
18475                        window,
18476                        cx,
18477                    );
18478                });
18479            });
18480        });
18481    }
18482
18483    pub fn open_excerpts_in_split(
18484        &mut self,
18485        _: &OpenExcerptsSplit,
18486        window: &mut Window,
18487        cx: &mut Context<Self>,
18488    ) {
18489        self.open_excerpts_common(None, true, window, cx)
18490    }
18491
18492    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18493        self.open_excerpts_common(None, false, window, cx)
18494    }
18495
18496    fn open_excerpts_common(
18497        &mut self,
18498        jump_data: Option<JumpData>,
18499        split: bool,
18500        window: &mut Window,
18501        cx: &mut Context<Self>,
18502    ) {
18503        let Some(workspace) = self.workspace() else {
18504            cx.propagate();
18505            return;
18506        };
18507
18508        if self.buffer.read(cx).is_singleton() {
18509            cx.propagate();
18510            return;
18511        }
18512
18513        let mut new_selections_by_buffer = HashMap::default();
18514        match &jump_data {
18515            Some(JumpData::MultiBufferPoint {
18516                excerpt_id,
18517                position,
18518                anchor,
18519                line_offset_from_top,
18520            }) => {
18521                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18522                if let Some(buffer) = multi_buffer_snapshot
18523                    .buffer_id_for_excerpt(*excerpt_id)
18524                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18525                {
18526                    let buffer_snapshot = buffer.read(cx).snapshot();
18527                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18528                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18529                    } else {
18530                        buffer_snapshot.clip_point(*position, Bias::Left)
18531                    };
18532                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18533                    new_selections_by_buffer.insert(
18534                        buffer,
18535                        (
18536                            vec![jump_to_offset..jump_to_offset],
18537                            Some(*line_offset_from_top),
18538                        ),
18539                    );
18540                }
18541            }
18542            Some(JumpData::MultiBufferRow {
18543                row,
18544                line_offset_from_top,
18545            }) => {
18546                let point = MultiBufferPoint::new(row.0, 0);
18547                if let Some((buffer, buffer_point, _)) =
18548                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18549                {
18550                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18551                    new_selections_by_buffer
18552                        .entry(buffer)
18553                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18554                        .0
18555                        .push(buffer_offset..buffer_offset)
18556                }
18557            }
18558            None => {
18559                let selections = self.selections.all::<usize>(cx);
18560                let multi_buffer = self.buffer.read(cx);
18561                for selection in selections {
18562                    for (snapshot, range, _, anchor) in multi_buffer
18563                        .snapshot(cx)
18564                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18565                    {
18566                        if let Some(anchor) = anchor {
18567                            // selection is in a deleted hunk
18568                            let Some(buffer_id) = anchor.buffer_id else {
18569                                continue;
18570                            };
18571                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18572                                continue;
18573                            };
18574                            let offset = text::ToOffset::to_offset(
18575                                &anchor.text_anchor,
18576                                &buffer_handle.read(cx).snapshot(),
18577                            );
18578                            let range = offset..offset;
18579                            new_selections_by_buffer
18580                                .entry(buffer_handle)
18581                                .or_insert((Vec::new(), None))
18582                                .0
18583                                .push(range)
18584                        } else {
18585                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18586                            else {
18587                                continue;
18588                            };
18589                            new_selections_by_buffer
18590                                .entry(buffer_handle)
18591                                .or_insert((Vec::new(), None))
18592                                .0
18593                                .push(range)
18594                        }
18595                    }
18596                }
18597            }
18598        }
18599
18600        new_selections_by_buffer
18601            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18602
18603        if new_selections_by_buffer.is_empty() {
18604            return;
18605        }
18606
18607        // We defer the pane interaction because we ourselves are a workspace item
18608        // and activating a new item causes the pane to call a method on us reentrantly,
18609        // which panics if we're on the stack.
18610        window.defer(cx, move |window, cx| {
18611            workspace.update(cx, |workspace, cx| {
18612                let pane = if split {
18613                    workspace.adjacent_pane(window, cx)
18614                } else {
18615                    workspace.active_pane().clone()
18616                };
18617
18618                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18619                    let editor = buffer
18620                        .read(cx)
18621                        .file()
18622                        .is_none()
18623                        .then(|| {
18624                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18625                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18626                            // Instead, we try to activate the existing editor in the pane first.
18627                            let (editor, pane_item_index) =
18628                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18629                                    let editor = item.downcast::<Editor>()?;
18630                                    let singleton_buffer =
18631                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18632                                    if singleton_buffer == buffer {
18633                                        Some((editor, i))
18634                                    } else {
18635                                        None
18636                                    }
18637                                })?;
18638                            pane.update(cx, |pane, cx| {
18639                                pane.activate_item(pane_item_index, true, true, window, cx)
18640                            });
18641                            Some(editor)
18642                        })
18643                        .flatten()
18644                        .unwrap_or_else(|| {
18645                            workspace.open_project_item::<Self>(
18646                                pane.clone(),
18647                                buffer,
18648                                true,
18649                                true,
18650                                window,
18651                                cx,
18652                            )
18653                        });
18654
18655                    editor.update(cx, |editor, cx| {
18656                        let autoscroll = match scroll_offset {
18657                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18658                            None => Autoscroll::newest(),
18659                        };
18660                        let nav_history = editor.nav_history.take();
18661                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18662                            s.select_ranges(ranges);
18663                        });
18664                        editor.nav_history = nav_history;
18665                    });
18666                }
18667            })
18668        });
18669    }
18670
18671    // For now, don't allow opening excerpts in buffers that aren't backed by
18672    // regular project files.
18673    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18674        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18675    }
18676
18677    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18678        let snapshot = self.buffer.read(cx).read(cx);
18679        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18680        Some(
18681            ranges
18682                .iter()
18683                .map(move |range| {
18684                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18685                })
18686                .collect(),
18687        )
18688    }
18689
18690    fn selection_replacement_ranges(
18691        &self,
18692        range: Range<OffsetUtf16>,
18693        cx: &mut App,
18694    ) -> Vec<Range<OffsetUtf16>> {
18695        let selections = self.selections.all::<OffsetUtf16>(cx);
18696        let newest_selection = selections
18697            .iter()
18698            .max_by_key(|selection| selection.id)
18699            .unwrap();
18700        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18701        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18702        let snapshot = self.buffer.read(cx).read(cx);
18703        selections
18704            .into_iter()
18705            .map(|mut selection| {
18706                selection.start.0 =
18707                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18708                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18709                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18710                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18711            })
18712            .collect()
18713    }
18714
18715    fn report_editor_event(
18716        &self,
18717        event_type: &'static str,
18718        file_extension: Option<String>,
18719        cx: &App,
18720    ) {
18721        if cfg!(any(test, feature = "test-support")) {
18722            return;
18723        }
18724
18725        let Some(project) = &self.project else { return };
18726
18727        // If None, we are in a file without an extension
18728        let file = self
18729            .buffer
18730            .read(cx)
18731            .as_singleton()
18732            .and_then(|b| b.read(cx).file());
18733        let file_extension = file_extension.or(file
18734            .as_ref()
18735            .and_then(|file| Path::new(file.file_name(cx)).extension())
18736            .and_then(|e| e.to_str())
18737            .map(|a| a.to_string()));
18738
18739        let vim_mode = vim_enabled(cx);
18740
18741        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18742        let copilot_enabled = edit_predictions_provider
18743            == language::language_settings::EditPredictionProvider::Copilot;
18744        let copilot_enabled_for_language = self
18745            .buffer
18746            .read(cx)
18747            .language_settings(cx)
18748            .show_edit_predictions;
18749
18750        let project = project.read(cx);
18751        telemetry::event!(
18752            event_type,
18753            file_extension,
18754            vim_mode,
18755            copilot_enabled,
18756            copilot_enabled_for_language,
18757            edit_predictions_provider,
18758            is_via_ssh = project.is_via_ssh(),
18759        );
18760    }
18761
18762    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18763    /// with each line being an array of {text, highlight} objects.
18764    fn copy_highlight_json(
18765        &mut self,
18766        _: &CopyHighlightJson,
18767        window: &mut Window,
18768        cx: &mut Context<Self>,
18769    ) {
18770        #[derive(Serialize)]
18771        struct Chunk<'a> {
18772            text: String,
18773            highlight: Option<&'a str>,
18774        }
18775
18776        let snapshot = self.buffer.read(cx).snapshot(cx);
18777        let range = self
18778            .selected_text_range(false, window, cx)
18779            .and_then(|selection| {
18780                if selection.range.is_empty() {
18781                    None
18782                } else {
18783                    Some(selection.range)
18784                }
18785            })
18786            .unwrap_or_else(|| 0..snapshot.len());
18787
18788        let chunks = snapshot.chunks(range, true);
18789        let mut lines = Vec::new();
18790        let mut line: VecDeque<Chunk> = VecDeque::new();
18791
18792        let Some(style) = self.style.as_ref() else {
18793            return;
18794        };
18795
18796        for chunk in chunks {
18797            let highlight = chunk
18798                .syntax_highlight_id
18799                .and_then(|id| id.name(&style.syntax));
18800            let mut chunk_lines = chunk.text.split('\n').peekable();
18801            while let Some(text) = chunk_lines.next() {
18802                let mut merged_with_last_token = false;
18803                if let Some(last_token) = line.back_mut() {
18804                    if last_token.highlight == highlight {
18805                        last_token.text.push_str(text);
18806                        merged_with_last_token = true;
18807                    }
18808                }
18809
18810                if !merged_with_last_token {
18811                    line.push_back(Chunk {
18812                        text: text.into(),
18813                        highlight,
18814                    });
18815                }
18816
18817                if chunk_lines.peek().is_some() {
18818                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18819                        line.pop_front();
18820                    }
18821                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18822                        line.pop_back();
18823                    }
18824
18825                    lines.push(mem::take(&mut line));
18826                }
18827            }
18828        }
18829
18830        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18831            return;
18832        };
18833        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18834    }
18835
18836    pub fn open_context_menu(
18837        &mut self,
18838        _: &OpenContextMenu,
18839        window: &mut Window,
18840        cx: &mut Context<Self>,
18841    ) {
18842        self.request_autoscroll(Autoscroll::newest(), cx);
18843        let position = self.selections.newest_display(cx).start;
18844        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18845    }
18846
18847    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18848        &self.inlay_hint_cache
18849    }
18850
18851    pub fn replay_insert_event(
18852        &mut self,
18853        text: &str,
18854        relative_utf16_range: Option<Range<isize>>,
18855        window: &mut Window,
18856        cx: &mut Context<Self>,
18857    ) {
18858        if !self.input_enabled {
18859            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18860            return;
18861        }
18862        if let Some(relative_utf16_range) = relative_utf16_range {
18863            let selections = self.selections.all::<OffsetUtf16>(cx);
18864            self.change_selections(None, window, cx, |s| {
18865                let new_ranges = selections.into_iter().map(|range| {
18866                    let start = OffsetUtf16(
18867                        range
18868                            .head()
18869                            .0
18870                            .saturating_add_signed(relative_utf16_range.start),
18871                    );
18872                    let end = OffsetUtf16(
18873                        range
18874                            .head()
18875                            .0
18876                            .saturating_add_signed(relative_utf16_range.end),
18877                    );
18878                    start..end
18879                });
18880                s.select_ranges(new_ranges);
18881            });
18882        }
18883
18884        self.handle_input(text, window, cx);
18885    }
18886
18887    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18888        let Some(provider) = self.semantics_provider.as_ref() else {
18889            return false;
18890        };
18891
18892        let mut supports = false;
18893        self.buffer().update(cx, |this, cx| {
18894            this.for_each_buffer(|buffer| {
18895                supports |= provider.supports_inlay_hints(buffer, cx);
18896            });
18897        });
18898
18899        supports
18900    }
18901
18902    pub fn is_focused(&self, window: &Window) -> bool {
18903        self.focus_handle.is_focused(window)
18904    }
18905
18906    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18907        cx.emit(EditorEvent::Focused);
18908
18909        if let Some(descendant) = self
18910            .last_focused_descendant
18911            .take()
18912            .and_then(|descendant| descendant.upgrade())
18913        {
18914            window.focus(&descendant);
18915        } else {
18916            if let Some(blame) = self.blame.as_ref() {
18917                blame.update(cx, GitBlame::focus)
18918            }
18919
18920            self.blink_manager.update(cx, BlinkManager::enable);
18921            self.show_cursor_names(window, cx);
18922            self.buffer.update(cx, |buffer, cx| {
18923                buffer.finalize_last_transaction(cx);
18924                if self.leader_id.is_none() {
18925                    buffer.set_active_selections(
18926                        &self.selections.disjoint_anchors(),
18927                        self.selections.line_mode,
18928                        self.cursor_shape,
18929                        cx,
18930                    );
18931                }
18932            });
18933        }
18934    }
18935
18936    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18937        cx.emit(EditorEvent::FocusedIn)
18938    }
18939
18940    fn handle_focus_out(
18941        &mut self,
18942        event: FocusOutEvent,
18943        _window: &mut Window,
18944        cx: &mut Context<Self>,
18945    ) {
18946        if event.blurred != self.focus_handle {
18947            self.last_focused_descendant = Some(event.blurred);
18948        }
18949        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18950    }
18951
18952    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18953        self.blink_manager.update(cx, BlinkManager::disable);
18954        self.buffer
18955            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18956
18957        if let Some(blame) = self.blame.as_ref() {
18958            blame.update(cx, GitBlame::blur)
18959        }
18960        if !self.hover_state.focused(window, cx) {
18961            hide_hover(self, cx);
18962        }
18963        if !self
18964            .context_menu
18965            .borrow()
18966            .as_ref()
18967            .is_some_and(|context_menu| context_menu.focused(window, cx))
18968        {
18969            self.hide_context_menu(window, cx);
18970        }
18971        self.discard_inline_completion(false, cx);
18972        cx.emit(EditorEvent::Blurred);
18973        cx.notify();
18974    }
18975
18976    pub fn register_action<A: Action>(
18977        &mut self,
18978        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
18979    ) -> Subscription {
18980        let id = self.next_editor_action_id.post_inc();
18981        let listener = Arc::new(listener);
18982        self.editor_actions.borrow_mut().insert(
18983            id,
18984            Box::new(move |window, _| {
18985                let listener = listener.clone();
18986                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
18987                    let action = action.downcast_ref().unwrap();
18988                    if phase == DispatchPhase::Bubble {
18989                        listener(action, window, cx)
18990                    }
18991                })
18992            }),
18993        );
18994
18995        let editor_actions = self.editor_actions.clone();
18996        Subscription::new(move || {
18997            editor_actions.borrow_mut().remove(&id);
18998        })
18999    }
19000
19001    pub fn file_header_size(&self) -> u32 {
19002        FILE_HEADER_HEIGHT
19003    }
19004
19005    pub fn restore(
19006        &mut self,
19007        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19008        window: &mut Window,
19009        cx: &mut Context<Self>,
19010    ) {
19011        let workspace = self.workspace();
19012        let project = self.project.as_ref();
19013        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19014            let mut tasks = Vec::new();
19015            for (buffer_id, changes) in revert_changes {
19016                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19017                    buffer.update(cx, |buffer, cx| {
19018                        buffer.edit(
19019                            changes
19020                                .into_iter()
19021                                .map(|(range, text)| (range, text.to_string())),
19022                            None,
19023                            cx,
19024                        );
19025                    });
19026
19027                    if let Some(project) =
19028                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19029                    {
19030                        project.update(cx, |project, cx| {
19031                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19032                        })
19033                    }
19034                }
19035            }
19036            tasks
19037        });
19038        cx.spawn_in(window, async move |_, cx| {
19039            for (buffer, task) in save_tasks {
19040                let result = task.await;
19041                if result.is_err() {
19042                    let Some(path) = buffer
19043                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19044                        .ok()
19045                    else {
19046                        continue;
19047                    };
19048                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19049                        let Some(task) = cx
19050                            .update_window_entity(&workspace, |workspace, window, cx| {
19051                                workspace
19052                                    .open_path_preview(path, None, false, false, false, window, cx)
19053                            })
19054                            .ok()
19055                        else {
19056                            continue;
19057                        };
19058                        task.await.log_err();
19059                    }
19060                }
19061            }
19062        })
19063        .detach();
19064        self.change_selections(None, window, cx, |selections| selections.refresh());
19065    }
19066
19067    pub fn to_pixel_point(
19068        &self,
19069        source: multi_buffer::Anchor,
19070        editor_snapshot: &EditorSnapshot,
19071        window: &mut Window,
19072    ) -> Option<gpui::Point<Pixels>> {
19073        let source_point = source.to_display_point(editor_snapshot);
19074        self.display_to_pixel_point(source_point, editor_snapshot, window)
19075    }
19076
19077    pub fn display_to_pixel_point(
19078        &self,
19079        source: DisplayPoint,
19080        editor_snapshot: &EditorSnapshot,
19081        window: &mut Window,
19082    ) -> Option<gpui::Point<Pixels>> {
19083        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19084        let text_layout_details = self.text_layout_details(window);
19085        let scroll_top = text_layout_details
19086            .scroll_anchor
19087            .scroll_position(editor_snapshot)
19088            .y;
19089
19090        if source.row().as_f32() < scroll_top.floor() {
19091            return None;
19092        }
19093        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19094        let source_y = line_height * (source.row().as_f32() - scroll_top);
19095        Some(gpui::Point::new(source_x, source_y))
19096    }
19097
19098    pub fn has_visible_completions_menu(&self) -> bool {
19099        !self.edit_prediction_preview_is_active()
19100            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19101                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19102            })
19103    }
19104
19105    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19106        if self.mode.is_minimap() {
19107            return;
19108        }
19109        self.addons
19110            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19111    }
19112
19113    pub fn unregister_addon<T: Addon>(&mut self) {
19114        self.addons.remove(&std::any::TypeId::of::<T>());
19115    }
19116
19117    pub fn addon<T: Addon>(&self) -> Option<&T> {
19118        let type_id = std::any::TypeId::of::<T>();
19119        self.addons
19120            .get(&type_id)
19121            .and_then(|item| item.to_any().downcast_ref::<T>())
19122    }
19123
19124    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19125        let type_id = std::any::TypeId::of::<T>();
19126        self.addons
19127            .get_mut(&type_id)
19128            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19129    }
19130
19131    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19132        let text_layout_details = self.text_layout_details(window);
19133        let style = &text_layout_details.editor_style;
19134        let font_id = window.text_system().resolve_font(&style.text.font());
19135        let font_size = style.text.font_size.to_pixels(window.rem_size());
19136        let line_height = style.text.line_height_in_pixels(window.rem_size());
19137        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19138
19139        gpui::Size::new(em_width, line_height)
19140    }
19141
19142    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19143        self.load_diff_task.clone()
19144    }
19145
19146    fn read_metadata_from_db(
19147        &mut self,
19148        item_id: u64,
19149        workspace_id: WorkspaceId,
19150        window: &mut Window,
19151        cx: &mut Context<Editor>,
19152    ) {
19153        if self.is_singleton(cx)
19154            && !self.mode.is_minimap()
19155            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19156        {
19157            let buffer_snapshot = OnceCell::new();
19158
19159            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19160                if !folds.is_empty() {
19161                    let snapshot =
19162                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19163                    self.fold_ranges(
19164                        folds
19165                            .into_iter()
19166                            .map(|(start, end)| {
19167                                snapshot.clip_offset(start, Bias::Left)
19168                                    ..snapshot.clip_offset(end, Bias::Right)
19169                            })
19170                            .collect(),
19171                        false,
19172                        window,
19173                        cx,
19174                    );
19175                }
19176            }
19177
19178            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19179                if !selections.is_empty() {
19180                    let snapshot =
19181                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19182                    self.change_selections(None, window, cx, |s| {
19183                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19184                            snapshot.clip_offset(start, Bias::Left)
19185                                ..snapshot.clip_offset(end, Bias::Right)
19186                        }));
19187                    });
19188                }
19189            };
19190        }
19191
19192        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19193    }
19194}
19195
19196fn vim_enabled(cx: &App) -> bool {
19197    cx.global::<SettingsStore>()
19198        .raw_user_settings()
19199        .get("vim_mode")
19200        == Some(&serde_json::Value::Bool(true))
19201}
19202
19203// Consider user intent and default settings
19204fn choose_completion_range(
19205    completion: &Completion,
19206    intent: CompletionIntent,
19207    buffer: &Entity<Buffer>,
19208    cx: &mut Context<Editor>,
19209) -> Range<usize> {
19210    fn should_replace(
19211        completion: &Completion,
19212        insert_range: &Range<text::Anchor>,
19213        intent: CompletionIntent,
19214        completion_mode_setting: LspInsertMode,
19215        buffer: &Buffer,
19216    ) -> bool {
19217        // specific actions take precedence over settings
19218        match intent {
19219            CompletionIntent::CompleteWithInsert => return false,
19220            CompletionIntent::CompleteWithReplace => return true,
19221            CompletionIntent::Complete | CompletionIntent::Compose => {}
19222        }
19223
19224        match completion_mode_setting {
19225            LspInsertMode::Insert => false,
19226            LspInsertMode::Replace => true,
19227            LspInsertMode::ReplaceSubsequence => {
19228                let mut text_to_replace = buffer.chars_for_range(
19229                    buffer.anchor_before(completion.replace_range.start)
19230                        ..buffer.anchor_after(completion.replace_range.end),
19231                );
19232                let mut completion_text = completion.new_text.chars();
19233
19234                // is `text_to_replace` a subsequence of `completion_text`
19235                text_to_replace
19236                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19237            }
19238            LspInsertMode::ReplaceSuffix => {
19239                let range_after_cursor = insert_range.end..completion.replace_range.end;
19240
19241                let text_after_cursor = buffer
19242                    .text_for_range(
19243                        buffer.anchor_before(range_after_cursor.start)
19244                            ..buffer.anchor_after(range_after_cursor.end),
19245                    )
19246                    .collect::<String>();
19247                completion.new_text.ends_with(&text_after_cursor)
19248            }
19249        }
19250    }
19251
19252    let buffer = buffer.read(cx);
19253
19254    if let CompletionSource::Lsp {
19255        insert_range: Some(insert_range),
19256        ..
19257    } = &completion.source
19258    {
19259        let completion_mode_setting =
19260            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19261                .completions
19262                .lsp_insert_mode;
19263
19264        if !should_replace(
19265            completion,
19266            &insert_range,
19267            intent,
19268            completion_mode_setting,
19269            buffer,
19270        ) {
19271            return insert_range.to_offset(buffer);
19272        }
19273    }
19274
19275    completion.replace_range.to_offset(buffer)
19276}
19277
19278fn insert_extra_newline_brackets(
19279    buffer: &MultiBufferSnapshot,
19280    range: Range<usize>,
19281    language: &language::LanguageScope,
19282) -> bool {
19283    let leading_whitespace_len = buffer
19284        .reversed_chars_at(range.start)
19285        .take_while(|c| c.is_whitespace() && *c != '\n')
19286        .map(|c| c.len_utf8())
19287        .sum::<usize>();
19288    let trailing_whitespace_len = buffer
19289        .chars_at(range.end)
19290        .take_while(|c| c.is_whitespace() && *c != '\n')
19291        .map(|c| c.len_utf8())
19292        .sum::<usize>();
19293    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19294
19295    language.brackets().any(|(pair, enabled)| {
19296        let pair_start = pair.start.trim_end();
19297        let pair_end = pair.end.trim_start();
19298
19299        enabled
19300            && pair.newline
19301            && buffer.contains_str_at(range.end, pair_end)
19302            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19303    })
19304}
19305
19306fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19307    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19308        [(buffer, range, _)] => (*buffer, range.clone()),
19309        _ => return false,
19310    };
19311    let pair = {
19312        let mut result: Option<BracketMatch> = None;
19313
19314        for pair in buffer
19315            .all_bracket_ranges(range.clone())
19316            .filter(move |pair| {
19317                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19318            })
19319        {
19320            let len = pair.close_range.end - pair.open_range.start;
19321
19322            if let Some(existing) = &result {
19323                let existing_len = existing.close_range.end - existing.open_range.start;
19324                if len > existing_len {
19325                    continue;
19326                }
19327            }
19328
19329            result = Some(pair);
19330        }
19331
19332        result
19333    };
19334    let Some(pair) = pair else {
19335        return false;
19336    };
19337    pair.newline_only
19338        && buffer
19339            .chars_for_range(pair.open_range.end..range.start)
19340            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19341            .all(|c| c.is_whitespace() && c != '\n')
19342}
19343
19344fn update_uncommitted_diff_for_buffer(
19345    editor: Entity<Editor>,
19346    project: &Entity<Project>,
19347    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19348    buffer: Entity<MultiBuffer>,
19349    cx: &mut App,
19350) -> Task<()> {
19351    let mut tasks = Vec::new();
19352    project.update(cx, |project, cx| {
19353        for buffer in buffers {
19354            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19355                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19356            }
19357        }
19358    });
19359    cx.spawn(async move |cx| {
19360        let diffs = future::join_all(tasks).await;
19361        if editor
19362            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19363            .unwrap_or(false)
19364        {
19365            return;
19366        }
19367
19368        buffer
19369            .update(cx, |buffer, cx| {
19370                for diff in diffs.into_iter().flatten() {
19371                    buffer.add_diff(diff, cx);
19372                }
19373            })
19374            .ok();
19375    })
19376}
19377
19378fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19379    let tab_size = tab_size.get() as usize;
19380    let mut width = offset;
19381
19382    for ch in text.chars() {
19383        width += if ch == '\t' {
19384            tab_size - (width % tab_size)
19385        } else {
19386            1
19387        };
19388    }
19389
19390    width - offset
19391}
19392
19393#[cfg(test)]
19394mod tests {
19395    use super::*;
19396
19397    #[test]
19398    fn test_string_size_with_expanded_tabs() {
19399        let nz = |val| NonZeroU32::new(val).unwrap();
19400        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19401        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19402        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19403        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19404        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19405        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19406        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19407        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19408    }
19409}
19410
19411/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19412struct WordBreakingTokenizer<'a> {
19413    input: &'a str,
19414}
19415
19416impl<'a> WordBreakingTokenizer<'a> {
19417    fn new(input: &'a str) -> Self {
19418        Self { input }
19419    }
19420}
19421
19422fn is_char_ideographic(ch: char) -> bool {
19423    use unicode_script::Script::*;
19424    use unicode_script::UnicodeScript;
19425    matches!(ch.script(), Han | Tangut | Yi)
19426}
19427
19428fn is_grapheme_ideographic(text: &str) -> bool {
19429    text.chars().any(is_char_ideographic)
19430}
19431
19432fn is_grapheme_whitespace(text: &str) -> bool {
19433    text.chars().any(|x| x.is_whitespace())
19434}
19435
19436fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19437    text.chars().next().map_or(false, |ch| {
19438        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19439    })
19440}
19441
19442#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19443enum WordBreakToken<'a> {
19444    Word { token: &'a str, grapheme_len: usize },
19445    InlineWhitespace { token: &'a str, grapheme_len: usize },
19446    Newline,
19447}
19448
19449impl<'a> Iterator for WordBreakingTokenizer<'a> {
19450    /// Yields a span, the count of graphemes in the token, and whether it was
19451    /// whitespace. Note that it also breaks at word boundaries.
19452    type Item = WordBreakToken<'a>;
19453
19454    fn next(&mut self) -> Option<Self::Item> {
19455        use unicode_segmentation::UnicodeSegmentation;
19456        if self.input.is_empty() {
19457            return None;
19458        }
19459
19460        let mut iter = self.input.graphemes(true).peekable();
19461        let mut offset = 0;
19462        let mut grapheme_len = 0;
19463        if let Some(first_grapheme) = iter.next() {
19464            let is_newline = first_grapheme == "\n";
19465            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19466            offset += first_grapheme.len();
19467            grapheme_len += 1;
19468            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19469                if let Some(grapheme) = iter.peek().copied() {
19470                    if should_stay_with_preceding_ideograph(grapheme) {
19471                        offset += grapheme.len();
19472                        grapheme_len += 1;
19473                    }
19474                }
19475            } else {
19476                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19477                let mut next_word_bound = words.peek().copied();
19478                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19479                    next_word_bound = words.next();
19480                }
19481                while let Some(grapheme) = iter.peek().copied() {
19482                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19483                        break;
19484                    };
19485                    if is_grapheme_whitespace(grapheme) != is_whitespace
19486                        || (grapheme == "\n") != is_newline
19487                    {
19488                        break;
19489                    };
19490                    offset += grapheme.len();
19491                    grapheme_len += 1;
19492                    iter.next();
19493                }
19494            }
19495            let token = &self.input[..offset];
19496            self.input = &self.input[offset..];
19497            if token == "\n" {
19498                Some(WordBreakToken::Newline)
19499            } else if is_whitespace {
19500                Some(WordBreakToken::InlineWhitespace {
19501                    token,
19502                    grapheme_len,
19503                })
19504            } else {
19505                Some(WordBreakToken::Word {
19506                    token,
19507                    grapheme_len,
19508                })
19509            }
19510        } else {
19511            None
19512        }
19513    }
19514}
19515
19516#[test]
19517fn test_word_breaking_tokenizer() {
19518    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19519        ("", &[]),
19520        ("  ", &[whitespace("  ", 2)]),
19521        ("Ʒ", &[word("Ʒ", 1)]),
19522        ("Ǽ", &[word("Ǽ", 1)]),
19523        ("", &[word("", 1)]),
19524        ("⋑⋑", &[word("⋑⋑", 2)]),
19525        (
19526            "原理,进而",
19527            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19528        ),
19529        (
19530            "hello world",
19531            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19532        ),
19533        (
19534            "hello, world",
19535            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19536        ),
19537        (
19538            "  hello world",
19539            &[
19540                whitespace("  ", 2),
19541                word("hello", 5),
19542                whitespace(" ", 1),
19543                word("world", 5),
19544            ],
19545        ),
19546        (
19547            "这是什么 \n 钢笔",
19548            &[
19549                word("", 1),
19550                word("", 1),
19551                word("", 1),
19552                word("", 1),
19553                whitespace(" ", 1),
19554                newline(),
19555                whitespace(" ", 1),
19556                word("", 1),
19557                word("", 1),
19558            ],
19559        ),
19560        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19561    ];
19562
19563    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19564        WordBreakToken::Word {
19565            token,
19566            grapheme_len,
19567        }
19568    }
19569
19570    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19571        WordBreakToken::InlineWhitespace {
19572            token,
19573            grapheme_len,
19574        }
19575    }
19576
19577    fn newline() -> WordBreakToken<'static> {
19578        WordBreakToken::Newline
19579    }
19580
19581    for (input, result) in tests {
19582        assert_eq!(
19583            WordBreakingTokenizer::new(input)
19584                .collect::<Vec<_>>()
19585                .as_slice(),
19586            *result,
19587        );
19588    }
19589}
19590
19591fn wrap_with_prefix(
19592    line_prefix: String,
19593    unwrapped_text: String,
19594    wrap_column: usize,
19595    tab_size: NonZeroU32,
19596    preserve_existing_whitespace: bool,
19597) -> String {
19598    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19599    let mut wrapped_text = String::new();
19600    let mut current_line = line_prefix.clone();
19601
19602    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19603    let mut current_line_len = line_prefix_len;
19604    let mut in_whitespace = false;
19605    for token in tokenizer {
19606        let have_preceding_whitespace = in_whitespace;
19607        match token {
19608            WordBreakToken::Word {
19609                token,
19610                grapheme_len,
19611            } => {
19612                in_whitespace = false;
19613                if current_line_len + grapheme_len > wrap_column
19614                    && current_line_len != line_prefix_len
19615                {
19616                    wrapped_text.push_str(current_line.trim_end());
19617                    wrapped_text.push('\n');
19618                    current_line.truncate(line_prefix.len());
19619                    current_line_len = line_prefix_len;
19620                }
19621                current_line.push_str(token);
19622                current_line_len += grapheme_len;
19623            }
19624            WordBreakToken::InlineWhitespace {
19625                mut token,
19626                mut grapheme_len,
19627            } => {
19628                in_whitespace = true;
19629                if have_preceding_whitespace && !preserve_existing_whitespace {
19630                    continue;
19631                }
19632                if !preserve_existing_whitespace {
19633                    token = " ";
19634                    grapheme_len = 1;
19635                }
19636                if current_line_len + grapheme_len > wrap_column {
19637                    wrapped_text.push_str(current_line.trim_end());
19638                    wrapped_text.push('\n');
19639                    current_line.truncate(line_prefix.len());
19640                    current_line_len = line_prefix_len;
19641                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19642                    current_line.push_str(token);
19643                    current_line_len += grapheme_len;
19644                }
19645            }
19646            WordBreakToken::Newline => {
19647                in_whitespace = true;
19648                if preserve_existing_whitespace {
19649                    wrapped_text.push_str(current_line.trim_end());
19650                    wrapped_text.push('\n');
19651                    current_line.truncate(line_prefix.len());
19652                    current_line_len = line_prefix_len;
19653                } else if have_preceding_whitespace {
19654                    continue;
19655                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19656                {
19657                    wrapped_text.push_str(current_line.trim_end());
19658                    wrapped_text.push('\n');
19659                    current_line.truncate(line_prefix.len());
19660                    current_line_len = line_prefix_len;
19661                } else if current_line_len != line_prefix_len {
19662                    current_line.push(' ');
19663                    current_line_len += 1;
19664                }
19665            }
19666        }
19667    }
19668
19669    if !current_line.is_empty() {
19670        wrapped_text.push_str(&current_line);
19671    }
19672    wrapped_text
19673}
19674
19675#[test]
19676fn test_wrap_with_prefix() {
19677    assert_eq!(
19678        wrap_with_prefix(
19679            "# ".to_string(),
19680            "abcdefg".to_string(),
19681            4,
19682            NonZeroU32::new(4).unwrap(),
19683            false,
19684        ),
19685        "# abcdefg"
19686    );
19687    assert_eq!(
19688        wrap_with_prefix(
19689            "".to_string(),
19690            "\thello world".to_string(),
19691            8,
19692            NonZeroU32::new(4).unwrap(),
19693            false,
19694        ),
19695        "hello\nworld"
19696    );
19697    assert_eq!(
19698        wrap_with_prefix(
19699            "// ".to_string(),
19700            "xx \nyy zz aa bb cc".to_string(),
19701            12,
19702            NonZeroU32::new(4).unwrap(),
19703            false,
19704        ),
19705        "// xx yy zz\n// aa bb cc"
19706    );
19707    assert_eq!(
19708        wrap_with_prefix(
19709            String::new(),
19710            "这是什么 \n 钢笔".to_string(),
19711            3,
19712            NonZeroU32::new(4).unwrap(),
19713            false,
19714        ),
19715        "这是什\n么 钢\n"
19716    );
19717}
19718
19719pub trait CollaborationHub {
19720    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19721    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19722    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19723}
19724
19725impl CollaborationHub for Entity<Project> {
19726    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19727        self.read(cx).collaborators()
19728    }
19729
19730    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19731        self.read(cx).user_store().read(cx).participant_indices()
19732    }
19733
19734    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19735        let this = self.read(cx);
19736        let user_ids = this.collaborators().values().map(|c| c.user_id);
19737        this.user_store().read_with(cx, |user_store, cx| {
19738            user_store.participant_names(user_ids, cx)
19739        })
19740    }
19741}
19742
19743pub trait SemanticsProvider {
19744    fn hover(
19745        &self,
19746        buffer: &Entity<Buffer>,
19747        position: text::Anchor,
19748        cx: &mut App,
19749    ) -> Option<Task<Vec<project::Hover>>>;
19750
19751    fn inline_values(
19752        &self,
19753        buffer_handle: Entity<Buffer>,
19754        range: Range<text::Anchor>,
19755        cx: &mut App,
19756    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19757
19758    fn inlay_hints(
19759        &self,
19760        buffer_handle: Entity<Buffer>,
19761        range: Range<text::Anchor>,
19762        cx: &mut App,
19763    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19764
19765    fn resolve_inlay_hint(
19766        &self,
19767        hint: InlayHint,
19768        buffer_handle: Entity<Buffer>,
19769        server_id: LanguageServerId,
19770        cx: &mut App,
19771    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19772
19773    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19774
19775    fn document_highlights(
19776        &self,
19777        buffer: &Entity<Buffer>,
19778        position: text::Anchor,
19779        cx: &mut App,
19780    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19781
19782    fn definitions(
19783        &self,
19784        buffer: &Entity<Buffer>,
19785        position: text::Anchor,
19786        kind: GotoDefinitionKind,
19787        cx: &mut App,
19788    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19789
19790    fn range_for_rename(
19791        &self,
19792        buffer: &Entity<Buffer>,
19793        position: text::Anchor,
19794        cx: &mut App,
19795    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19796
19797    fn perform_rename(
19798        &self,
19799        buffer: &Entity<Buffer>,
19800        position: text::Anchor,
19801        new_name: String,
19802        cx: &mut App,
19803    ) -> Option<Task<Result<ProjectTransaction>>>;
19804}
19805
19806pub trait CompletionProvider {
19807    fn completions(
19808        &self,
19809        excerpt_id: ExcerptId,
19810        buffer: &Entity<Buffer>,
19811        buffer_position: text::Anchor,
19812        trigger: CompletionContext,
19813        window: &mut Window,
19814        cx: &mut Context<Editor>,
19815    ) -> Task<Result<Option<Vec<Completion>>>>;
19816
19817    fn resolve_completions(
19818        &self,
19819        buffer: Entity<Buffer>,
19820        completion_indices: Vec<usize>,
19821        completions: Rc<RefCell<Box<[Completion]>>>,
19822        cx: &mut Context<Editor>,
19823    ) -> Task<Result<bool>>;
19824
19825    fn apply_additional_edits_for_completion(
19826        &self,
19827        _buffer: Entity<Buffer>,
19828        _completions: Rc<RefCell<Box<[Completion]>>>,
19829        _completion_index: usize,
19830        _push_to_history: bool,
19831        _cx: &mut Context<Editor>,
19832    ) -> Task<Result<Option<language::Transaction>>> {
19833        Task::ready(Ok(None))
19834    }
19835
19836    fn is_completion_trigger(
19837        &self,
19838        buffer: &Entity<Buffer>,
19839        position: language::Anchor,
19840        text: &str,
19841        trigger_in_words: bool,
19842        cx: &mut Context<Editor>,
19843    ) -> bool;
19844
19845    fn sort_completions(&self) -> bool {
19846        true
19847    }
19848
19849    fn filter_completions(&self) -> bool {
19850        true
19851    }
19852}
19853
19854pub trait CodeActionProvider {
19855    fn id(&self) -> Arc<str>;
19856
19857    fn code_actions(
19858        &self,
19859        buffer: &Entity<Buffer>,
19860        range: Range<text::Anchor>,
19861        window: &mut Window,
19862        cx: &mut App,
19863    ) -> Task<Result<Vec<CodeAction>>>;
19864
19865    fn apply_code_action(
19866        &self,
19867        buffer_handle: Entity<Buffer>,
19868        action: CodeAction,
19869        excerpt_id: ExcerptId,
19870        push_to_history: bool,
19871        window: &mut Window,
19872        cx: &mut App,
19873    ) -> Task<Result<ProjectTransaction>>;
19874}
19875
19876impl CodeActionProvider for Entity<Project> {
19877    fn id(&self) -> Arc<str> {
19878        "project".into()
19879    }
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        self.update(cx, |project, cx| {
19889            let code_lens = project.code_lens(buffer, range.clone(), cx);
19890            let code_actions = project.code_actions(buffer, range, None, cx);
19891            cx.background_spawn(async move {
19892                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19893                Ok(code_lens
19894                    .context("code lens fetch")?
19895                    .into_iter()
19896                    .chain(code_actions.context("code action fetch")?)
19897                    .collect())
19898            })
19899        })
19900    }
19901
19902    fn apply_code_action(
19903        &self,
19904        buffer_handle: Entity<Buffer>,
19905        action: CodeAction,
19906        _excerpt_id: ExcerptId,
19907        push_to_history: bool,
19908        _window: &mut Window,
19909        cx: &mut App,
19910    ) -> Task<Result<ProjectTransaction>> {
19911        self.update(cx, |project, cx| {
19912            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19913        })
19914    }
19915}
19916
19917fn snippet_completions(
19918    project: &Project,
19919    buffer: &Entity<Buffer>,
19920    buffer_position: text::Anchor,
19921    cx: &mut App,
19922) -> Task<Result<Vec<Completion>>> {
19923    let languages = buffer.read(cx).languages_at(buffer_position);
19924    let snippet_store = project.snippets().read(cx);
19925
19926    let scopes: Vec<_> = languages
19927        .iter()
19928        .filter_map(|language| {
19929            let language_name = language.lsp_id();
19930            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19931
19932            if snippets.is_empty() {
19933                None
19934            } else {
19935                Some((language.default_scope(), snippets))
19936            }
19937        })
19938        .collect();
19939
19940    if scopes.is_empty() {
19941        return Task::ready(Ok(vec![]));
19942    }
19943
19944    let snapshot = buffer.read(cx).text_snapshot();
19945    let chars: String = snapshot
19946        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19947        .collect();
19948    let executor = cx.background_executor().clone();
19949
19950    cx.background_spawn(async move {
19951        let mut all_results: Vec<Completion> = Vec::new();
19952        for (scope, snippets) in scopes.into_iter() {
19953            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19954            let mut last_word = chars
19955                .chars()
19956                .take_while(|c| classifier.is_word(*c))
19957                .collect::<String>();
19958            last_word = last_word.chars().rev().collect();
19959
19960            if last_word.is_empty() {
19961                return Ok(vec![]);
19962            }
19963
19964            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19965            let to_lsp = |point: &text::Anchor| {
19966                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19967                point_to_lsp(end)
19968            };
19969            let lsp_end = to_lsp(&buffer_position);
19970
19971            let candidates = snippets
19972                .iter()
19973                .enumerate()
19974                .flat_map(|(ix, snippet)| {
19975                    snippet
19976                        .prefix
19977                        .iter()
19978                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19979                })
19980                .collect::<Vec<StringMatchCandidate>>();
19981
19982            let mut matches = fuzzy::match_strings(
19983                &candidates,
19984                &last_word,
19985                last_word.chars().any(|c| c.is_uppercase()),
19986                100,
19987                &Default::default(),
19988                executor.clone(),
19989            )
19990            .await;
19991
19992            // Remove all candidates where the query's start does not match the start of any word in the candidate
19993            if let Some(query_start) = last_word.chars().next() {
19994                matches.retain(|string_match| {
19995                    split_words(&string_match.string).any(|word| {
19996                        // Check that the first codepoint of the word as lowercase matches the first
19997                        // codepoint of the query as lowercase
19998                        word.chars()
19999                            .flat_map(|codepoint| codepoint.to_lowercase())
20000                            .zip(query_start.to_lowercase())
20001                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20002                    })
20003                });
20004            }
20005
20006            let matched_strings = matches
20007                .into_iter()
20008                .map(|m| m.string)
20009                .collect::<HashSet<_>>();
20010
20011            let mut result: Vec<Completion> = snippets
20012                .iter()
20013                .filter_map(|snippet| {
20014                    let matching_prefix = snippet
20015                        .prefix
20016                        .iter()
20017                        .find(|prefix| matched_strings.contains(*prefix))?;
20018                    let start = as_offset - last_word.len();
20019                    let start = snapshot.anchor_before(start);
20020                    let range = start..buffer_position;
20021                    let lsp_start = to_lsp(&start);
20022                    let lsp_range = lsp::Range {
20023                        start: lsp_start,
20024                        end: lsp_end,
20025                    };
20026                    Some(Completion {
20027                        replace_range: range,
20028                        new_text: snippet.body.clone(),
20029                        source: CompletionSource::Lsp {
20030                            insert_range: None,
20031                            server_id: LanguageServerId(usize::MAX),
20032                            resolved: true,
20033                            lsp_completion: Box::new(lsp::CompletionItem {
20034                                label: snippet.prefix.first().unwrap().clone(),
20035                                kind: Some(CompletionItemKind::SNIPPET),
20036                                label_details: snippet.description.as_ref().map(|description| {
20037                                    lsp::CompletionItemLabelDetails {
20038                                        detail: Some(description.clone()),
20039                                        description: None,
20040                                    }
20041                                }),
20042                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20043                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20044                                    lsp::InsertReplaceEdit {
20045                                        new_text: snippet.body.clone(),
20046                                        insert: lsp_range,
20047                                        replace: lsp_range,
20048                                    },
20049                                )),
20050                                filter_text: Some(snippet.body.clone()),
20051                                sort_text: Some(char::MAX.to_string()),
20052                                ..lsp::CompletionItem::default()
20053                            }),
20054                            lsp_defaults: None,
20055                        },
20056                        label: CodeLabel {
20057                            text: matching_prefix.clone(),
20058                            runs: Vec::new(),
20059                            filter_range: 0..matching_prefix.len(),
20060                        },
20061                        icon_path: None,
20062                        documentation: Some(
20063                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20064                                single_line: snippet.name.clone().into(),
20065                                plain_text: snippet
20066                                    .description
20067                                    .clone()
20068                                    .map(|description| description.into()),
20069                            },
20070                        ),
20071                        insert_text_mode: None,
20072                        confirm: None,
20073                    })
20074                })
20075                .collect();
20076
20077            all_results.append(&mut result);
20078        }
20079
20080        Ok(all_results)
20081    })
20082}
20083
20084impl CompletionProvider for Entity<Project> {
20085    fn completions(
20086        &self,
20087        _excerpt_id: ExcerptId,
20088        buffer: &Entity<Buffer>,
20089        buffer_position: text::Anchor,
20090        options: CompletionContext,
20091        _window: &mut Window,
20092        cx: &mut Context<Editor>,
20093    ) -> Task<Result<Option<Vec<Completion>>>> {
20094        self.update(cx, |project, cx| {
20095            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20096            let project_completions = project.completions(buffer, buffer_position, options, cx);
20097            cx.background_spawn(async move {
20098                let snippets_completions = snippets.await?;
20099                match project_completions.await? {
20100                    Some(mut completions) => {
20101                        completions.extend(snippets_completions);
20102                        Ok(Some(completions))
20103                    }
20104                    None => {
20105                        if snippets_completions.is_empty() {
20106                            Ok(None)
20107                        } else {
20108                            Ok(Some(snippets_completions))
20109                        }
20110                    }
20111                }
20112            })
20113        })
20114    }
20115
20116    fn resolve_completions(
20117        &self,
20118        buffer: Entity<Buffer>,
20119        completion_indices: Vec<usize>,
20120        completions: Rc<RefCell<Box<[Completion]>>>,
20121        cx: &mut Context<Editor>,
20122    ) -> Task<Result<bool>> {
20123        self.update(cx, |project, cx| {
20124            project.lsp_store().update(cx, |lsp_store, cx| {
20125                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20126            })
20127        })
20128    }
20129
20130    fn apply_additional_edits_for_completion(
20131        &self,
20132        buffer: Entity<Buffer>,
20133        completions: Rc<RefCell<Box<[Completion]>>>,
20134        completion_index: usize,
20135        push_to_history: bool,
20136        cx: &mut Context<Editor>,
20137    ) -> Task<Result<Option<language::Transaction>>> {
20138        self.update(cx, |project, cx| {
20139            project.lsp_store().update(cx, |lsp_store, cx| {
20140                lsp_store.apply_additional_edits_for_completion(
20141                    buffer,
20142                    completions,
20143                    completion_index,
20144                    push_to_history,
20145                    cx,
20146                )
20147            })
20148        })
20149    }
20150
20151    fn is_completion_trigger(
20152        &self,
20153        buffer: &Entity<Buffer>,
20154        position: language::Anchor,
20155        text: &str,
20156        trigger_in_words: bool,
20157        cx: &mut Context<Editor>,
20158    ) -> bool {
20159        let mut chars = text.chars();
20160        let char = if let Some(char) = chars.next() {
20161            char
20162        } else {
20163            return false;
20164        };
20165        if chars.next().is_some() {
20166            return false;
20167        }
20168
20169        let buffer = buffer.read(cx);
20170        let snapshot = buffer.snapshot();
20171        if !snapshot.settings_at(position, cx).show_completions_on_input {
20172            return false;
20173        }
20174        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20175        if trigger_in_words && classifier.is_word(char) {
20176            return true;
20177        }
20178
20179        buffer.completion_triggers().contains(text)
20180    }
20181}
20182
20183impl SemanticsProvider for Entity<Project> {
20184    fn hover(
20185        &self,
20186        buffer: &Entity<Buffer>,
20187        position: text::Anchor,
20188        cx: &mut App,
20189    ) -> Option<Task<Vec<project::Hover>>> {
20190        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20191    }
20192
20193    fn document_highlights(
20194        &self,
20195        buffer: &Entity<Buffer>,
20196        position: text::Anchor,
20197        cx: &mut App,
20198    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20199        Some(self.update(cx, |project, cx| {
20200            project.document_highlights(buffer, position, cx)
20201        }))
20202    }
20203
20204    fn definitions(
20205        &self,
20206        buffer: &Entity<Buffer>,
20207        position: text::Anchor,
20208        kind: GotoDefinitionKind,
20209        cx: &mut App,
20210    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20211        Some(self.update(cx, |project, cx| match kind {
20212            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20213            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20214            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20215            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20216        }))
20217    }
20218
20219    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20220        // TODO: make this work for remote projects
20221        self.update(cx, |project, cx| {
20222            if project
20223                .active_debug_session(cx)
20224                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20225            {
20226                return true;
20227            }
20228
20229            buffer.update(cx, |buffer, cx| {
20230                project.any_language_server_supports_inlay_hints(buffer, cx)
20231            })
20232        })
20233    }
20234
20235    fn inline_values(
20236        &self,
20237        buffer_handle: Entity<Buffer>,
20238        range: Range<text::Anchor>,
20239        cx: &mut App,
20240    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20241        self.update(cx, |project, cx| {
20242            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20243
20244            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20245        })
20246    }
20247
20248    fn inlay_hints(
20249        &self,
20250        buffer_handle: Entity<Buffer>,
20251        range: Range<text::Anchor>,
20252        cx: &mut App,
20253    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20254        Some(self.update(cx, |project, cx| {
20255            project.inlay_hints(buffer_handle, range, cx)
20256        }))
20257    }
20258
20259    fn resolve_inlay_hint(
20260        &self,
20261        hint: InlayHint,
20262        buffer_handle: Entity<Buffer>,
20263        server_id: LanguageServerId,
20264        cx: &mut App,
20265    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20266        Some(self.update(cx, |project, cx| {
20267            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20268        }))
20269    }
20270
20271    fn range_for_rename(
20272        &self,
20273        buffer: &Entity<Buffer>,
20274        position: text::Anchor,
20275        cx: &mut App,
20276    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20277        Some(self.update(cx, |project, cx| {
20278            let buffer = buffer.clone();
20279            let task = project.prepare_rename(buffer.clone(), position, cx);
20280            cx.spawn(async move |_, cx| {
20281                Ok(match task.await? {
20282                    PrepareRenameResponse::Success(range) => Some(range),
20283                    PrepareRenameResponse::InvalidPosition => None,
20284                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20285                        // Fallback on using TreeSitter info to determine identifier range
20286                        buffer.update(cx, |buffer, _| {
20287                            let snapshot = buffer.snapshot();
20288                            let (range, kind) = snapshot.surrounding_word(position);
20289                            if kind != Some(CharKind::Word) {
20290                                return None;
20291                            }
20292                            Some(
20293                                snapshot.anchor_before(range.start)
20294                                    ..snapshot.anchor_after(range.end),
20295                            )
20296                        })?
20297                    }
20298                })
20299            })
20300        }))
20301    }
20302
20303    fn perform_rename(
20304        &self,
20305        buffer: &Entity<Buffer>,
20306        position: text::Anchor,
20307        new_name: String,
20308        cx: &mut App,
20309    ) -> Option<Task<Result<ProjectTransaction>>> {
20310        Some(self.update(cx, |project, cx| {
20311            project.perform_rename(buffer.clone(), position, new_name, cx)
20312        }))
20313    }
20314}
20315
20316fn inlay_hint_settings(
20317    location: Anchor,
20318    snapshot: &MultiBufferSnapshot,
20319    cx: &mut Context<Editor>,
20320) -> InlayHintSettings {
20321    let file = snapshot.file_at(location);
20322    let language = snapshot.language_at(location).map(|l| l.name());
20323    language_settings(language, file, cx).inlay_hints
20324}
20325
20326fn consume_contiguous_rows(
20327    contiguous_row_selections: &mut Vec<Selection<Point>>,
20328    selection: &Selection<Point>,
20329    display_map: &DisplaySnapshot,
20330    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20331) -> (MultiBufferRow, MultiBufferRow) {
20332    contiguous_row_selections.push(selection.clone());
20333    let start_row = MultiBufferRow(selection.start.row);
20334    let mut end_row = ending_row(selection, display_map);
20335
20336    while let Some(next_selection) = selections.peek() {
20337        if next_selection.start.row <= end_row.0 {
20338            end_row = ending_row(next_selection, display_map);
20339            contiguous_row_selections.push(selections.next().unwrap().clone());
20340        } else {
20341            break;
20342        }
20343    }
20344    (start_row, end_row)
20345}
20346
20347fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20348    if next_selection.end.column > 0 || next_selection.is_empty() {
20349        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20350    } else {
20351        MultiBufferRow(next_selection.end.row)
20352    }
20353}
20354
20355impl EditorSnapshot {
20356    pub fn remote_selections_in_range<'a>(
20357        &'a self,
20358        range: &'a Range<Anchor>,
20359        collaboration_hub: &dyn CollaborationHub,
20360        cx: &'a App,
20361    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20362        let participant_names = collaboration_hub.user_names(cx);
20363        let participant_indices = collaboration_hub.user_participant_indices(cx);
20364        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20365        let collaborators_by_replica_id = collaborators_by_peer_id
20366            .values()
20367            .map(|collaborator| (collaborator.replica_id, collaborator))
20368            .collect::<HashMap<_, _>>();
20369        self.buffer_snapshot
20370            .selections_in_range(range, false)
20371            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20372                if replica_id == AGENT_REPLICA_ID {
20373                    Some(RemoteSelection {
20374                        replica_id,
20375                        selection,
20376                        cursor_shape,
20377                        line_mode,
20378                        collaborator_id: CollaboratorId::Agent,
20379                        user_name: Some("Agent".into()),
20380                        color: cx.theme().players().agent(),
20381                    })
20382                } else {
20383                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20384                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20385                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20386                    Some(RemoteSelection {
20387                        replica_id,
20388                        selection,
20389                        cursor_shape,
20390                        line_mode,
20391                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20392                        user_name,
20393                        color: if let Some(index) = participant_index {
20394                            cx.theme().players().color_for_participant(index.0)
20395                        } else {
20396                            cx.theme().players().absent()
20397                        },
20398                    })
20399                }
20400            })
20401    }
20402
20403    pub fn hunks_for_ranges(
20404        &self,
20405        ranges: impl IntoIterator<Item = Range<Point>>,
20406    ) -> Vec<MultiBufferDiffHunk> {
20407        let mut hunks = Vec::new();
20408        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20409            HashMap::default();
20410        for query_range in ranges {
20411            let query_rows =
20412                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20413            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20414                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20415            ) {
20416                // Include deleted hunks that are adjacent to the query range, because
20417                // otherwise they would be missed.
20418                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20419                if hunk.status().is_deleted() {
20420                    intersects_range |= hunk.row_range.start == query_rows.end;
20421                    intersects_range |= hunk.row_range.end == query_rows.start;
20422                }
20423                if intersects_range {
20424                    if !processed_buffer_rows
20425                        .entry(hunk.buffer_id)
20426                        .or_default()
20427                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20428                    {
20429                        continue;
20430                    }
20431                    hunks.push(hunk);
20432                }
20433            }
20434        }
20435
20436        hunks
20437    }
20438
20439    fn display_diff_hunks_for_rows<'a>(
20440        &'a self,
20441        display_rows: Range<DisplayRow>,
20442        folded_buffers: &'a HashSet<BufferId>,
20443    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20444        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20445        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20446
20447        self.buffer_snapshot
20448            .diff_hunks_in_range(buffer_start..buffer_end)
20449            .filter_map(|hunk| {
20450                if folded_buffers.contains(&hunk.buffer_id) {
20451                    return None;
20452                }
20453
20454                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20455                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20456
20457                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20458                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20459
20460                let display_hunk = if hunk_display_start.column() != 0 {
20461                    DisplayDiffHunk::Folded {
20462                        display_row: hunk_display_start.row(),
20463                    }
20464                } else {
20465                    let mut end_row = hunk_display_end.row();
20466                    if hunk_display_end.column() > 0 {
20467                        end_row.0 += 1;
20468                    }
20469                    let is_created_file = hunk.is_created_file();
20470                    DisplayDiffHunk::Unfolded {
20471                        status: hunk.status(),
20472                        diff_base_byte_range: hunk.diff_base_byte_range,
20473                        display_row_range: hunk_display_start.row()..end_row,
20474                        multi_buffer_range: Anchor::range_in_buffer(
20475                            hunk.excerpt_id,
20476                            hunk.buffer_id,
20477                            hunk.buffer_range,
20478                        ),
20479                        is_created_file,
20480                    }
20481                };
20482
20483                Some(display_hunk)
20484            })
20485    }
20486
20487    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20488        self.display_snapshot.buffer_snapshot.language_at(position)
20489    }
20490
20491    pub fn is_focused(&self) -> bool {
20492        self.is_focused
20493    }
20494
20495    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20496        self.placeholder_text.as_ref()
20497    }
20498
20499    pub fn scroll_position(&self) -> gpui::Point<f32> {
20500        self.scroll_anchor.scroll_position(&self.display_snapshot)
20501    }
20502
20503    fn gutter_dimensions(
20504        &self,
20505        font_id: FontId,
20506        font_size: Pixels,
20507        max_line_number_width: Pixels,
20508        cx: &App,
20509    ) -> Option<GutterDimensions> {
20510        if !self.show_gutter {
20511            return None;
20512        }
20513
20514        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20515        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20516
20517        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20518            matches!(
20519                ProjectSettings::get_global(cx).git.git_gutter,
20520                Some(GitGutterSetting::TrackedFiles)
20521            )
20522        });
20523        let gutter_settings = EditorSettings::get_global(cx).gutter;
20524        let show_line_numbers = self
20525            .show_line_numbers
20526            .unwrap_or(gutter_settings.line_numbers);
20527        let line_gutter_width = if show_line_numbers {
20528            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20529            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20530            max_line_number_width.max(min_width_for_number_on_gutter)
20531        } else {
20532            0.0.into()
20533        };
20534
20535        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20536        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20537
20538        let git_blame_entries_width =
20539            self.git_blame_gutter_max_author_length
20540                .map(|max_author_length| {
20541                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20542                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20543
20544                    /// The number of characters to dedicate to gaps and margins.
20545                    const SPACING_WIDTH: usize = 4;
20546
20547                    let max_char_count = max_author_length.min(renderer.max_author_length())
20548                        + ::git::SHORT_SHA_LENGTH
20549                        + MAX_RELATIVE_TIMESTAMP.len()
20550                        + SPACING_WIDTH;
20551
20552                    em_advance * max_char_count
20553                });
20554
20555        let is_singleton = self.buffer_snapshot.is_singleton();
20556
20557        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20558        left_padding += if !is_singleton {
20559            em_width * 4.0
20560        } else if show_runnables || show_breakpoints {
20561            em_width * 3.0
20562        } else if show_git_gutter && show_line_numbers {
20563            em_width * 2.0
20564        } else if show_git_gutter || show_line_numbers {
20565            em_width
20566        } else {
20567            px(0.)
20568        };
20569
20570        let shows_folds = is_singleton && gutter_settings.folds;
20571
20572        let right_padding = if shows_folds && show_line_numbers {
20573            em_width * 4.0
20574        } else if shows_folds || (!is_singleton && show_line_numbers) {
20575            em_width * 3.0
20576        } else if show_line_numbers {
20577            em_width
20578        } else {
20579            px(0.)
20580        };
20581
20582        Some(GutterDimensions {
20583            left_padding,
20584            right_padding,
20585            width: line_gutter_width + left_padding + right_padding,
20586            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20587            git_blame_entries_width,
20588        })
20589    }
20590
20591    pub fn render_crease_toggle(
20592        &self,
20593        buffer_row: MultiBufferRow,
20594        row_contains_cursor: bool,
20595        editor: Entity<Editor>,
20596        window: &mut Window,
20597        cx: &mut App,
20598    ) -> Option<AnyElement> {
20599        let folded = self.is_line_folded(buffer_row);
20600        let mut is_foldable = false;
20601
20602        if let Some(crease) = self
20603            .crease_snapshot
20604            .query_row(buffer_row, &self.buffer_snapshot)
20605        {
20606            is_foldable = true;
20607            match crease {
20608                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20609                    if let Some(render_toggle) = render_toggle {
20610                        let toggle_callback =
20611                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20612                                if folded {
20613                                    editor.update(cx, |editor, cx| {
20614                                        editor.fold_at(buffer_row, window, cx)
20615                                    });
20616                                } else {
20617                                    editor.update(cx, |editor, cx| {
20618                                        editor.unfold_at(buffer_row, window, cx)
20619                                    });
20620                                }
20621                            });
20622                        return Some((render_toggle)(
20623                            buffer_row,
20624                            folded,
20625                            toggle_callback,
20626                            window,
20627                            cx,
20628                        ));
20629                    }
20630                }
20631            }
20632        }
20633
20634        is_foldable |= self.starts_indent(buffer_row);
20635
20636        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20637            Some(
20638                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20639                    .toggle_state(folded)
20640                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20641                        if folded {
20642                            this.unfold_at(buffer_row, window, cx);
20643                        } else {
20644                            this.fold_at(buffer_row, window, cx);
20645                        }
20646                    }))
20647                    .into_any_element(),
20648            )
20649        } else {
20650            None
20651        }
20652    }
20653
20654    pub fn render_crease_trailer(
20655        &self,
20656        buffer_row: MultiBufferRow,
20657        window: &mut Window,
20658        cx: &mut App,
20659    ) -> Option<AnyElement> {
20660        let folded = self.is_line_folded(buffer_row);
20661        if let Crease::Inline { render_trailer, .. } = self
20662            .crease_snapshot
20663            .query_row(buffer_row, &self.buffer_snapshot)?
20664        {
20665            let render_trailer = render_trailer.as_ref()?;
20666            Some(render_trailer(buffer_row, folded, window, cx))
20667        } else {
20668            None
20669        }
20670    }
20671}
20672
20673impl Deref for EditorSnapshot {
20674    type Target = DisplaySnapshot;
20675
20676    fn deref(&self) -> &Self::Target {
20677        &self.display_snapshot
20678    }
20679}
20680
20681#[derive(Clone, Debug, PartialEq, Eq)]
20682pub enum EditorEvent {
20683    InputIgnored {
20684        text: Arc<str>,
20685    },
20686    InputHandled {
20687        utf16_range_to_replace: Option<Range<isize>>,
20688        text: Arc<str>,
20689    },
20690    ExcerptsAdded {
20691        buffer: Entity<Buffer>,
20692        predecessor: ExcerptId,
20693        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20694    },
20695    ExcerptsRemoved {
20696        ids: Vec<ExcerptId>,
20697        removed_buffer_ids: Vec<BufferId>,
20698    },
20699    BufferFoldToggled {
20700        ids: Vec<ExcerptId>,
20701        folded: bool,
20702    },
20703    ExcerptsEdited {
20704        ids: Vec<ExcerptId>,
20705    },
20706    ExcerptsExpanded {
20707        ids: Vec<ExcerptId>,
20708    },
20709    BufferEdited,
20710    Edited {
20711        transaction_id: clock::Lamport,
20712    },
20713    Reparsed(BufferId),
20714    Focused,
20715    FocusedIn,
20716    Blurred,
20717    DirtyChanged,
20718    Saved,
20719    TitleChanged,
20720    DiffBaseChanged,
20721    SelectionsChanged {
20722        local: bool,
20723    },
20724    ScrollPositionChanged {
20725        local: bool,
20726        autoscroll: bool,
20727    },
20728    Closed,
20729    TransactionUndone {
20730        transaction_id: clock::Lamport,
20731    },
20732    TransactionBegun {
20733        transaction_id: clock::Lamport,
20734    },
20735    Reloaded,
20736    CursorShapeChanged,
20737    PushedToNavHistory {
20738        anchor: Anchor,
20739        is_deactivate: bool,
20740    },
20741}
20742
20743impl EventEmitter<EditorEvent> for Editor {}
20744
20745impl Focusable for Editor {
20746    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20747        self.focus_handle.clone()
20748    }
20749}
20750
20751impl Render for Editor {
20752    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20753        let settings = ThemeSettings::get_global(cx);
20754
20755        let mut text_style = match self.mode {
20756            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20757                color: cx.theme().colors().editor_foreground,
20758                font_family: settings.ui_font.family.clone(),
20759                font_features: settings.ui_font.features.clone(),
20760                font_fallbacks: settings.ui_font.fallbacks.clone(),
20761                font_size: rems(0.875).into(),
20762                font_weight: settings.ui_font.weight,
20763                line_height: relative(settings.buffer_line_height.value()),
20764                ..Default::default()
20765            },
20766            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20767                color: cx.theme().colors().editor_foreground,
20768                font_family: settings.buffer_font.family.clone(),
20769                font_features: settings.buffer_font.features.clone(),
20770                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20771                font_size: settings.buffer_font_size(cx).into(),
20772                font_weight: settings.buffer_font.weight,
20773                line_height: relative(settings.buffer_line_height.value()),
20774                ..Default::default()
20775            },
20776        };
20777        if let Some(text_style_refinement) = &self.text_style_refinement {
20778            text_style.refine(text_style_refinement)
20779        }
20780
20781        let background = match self.mode {
20782            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20783            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20784            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20785            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20786        };
20787
20788        EditorElement::new(
20789            &cx.entity(),
20790            EditorStyle {
20791                background,
20792                local_player: cx.theme().players().local(),
20793                text: text_style,
20794                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20795                syntax: cx.theme().syntax().clone(),
20796                status: cx.theme().status().clone(),
20797                inlay_hints_style: make_inlay_hints_style(cx),
20798                inline_completion_styles: make_suggestion_styles(cx),
20799                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20800                show_underlines: !self.mode.is_minimap(),
20801            },
20802        )
20803    }
20804}
20805
20806impl EntityInputHandler for Editor {
20807    fn text_for_range(
20808        &mut self,
20809        range_utf16: Range<usize>,
20810        adjusted_range: &mut Option<Range<usize>>,
20811        _: &mut Window,
20812        cx: &mut Context<Self>,
20813    ) -> Option<String> {
20814        let snapshot = self.buffer.read(cx).read(cx);
20815        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20816        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20817        if (start.0..end.0) != range_utf16 {
20818            adjusted_range.replace(start.0..end.0);
20819        }
20820        Some(snapshot.text_for_range(start..end).collect())
20821    }
20822
20823    fn selected_text_range(
20824        &mut self,
20825        ignore_disabled_input: bool,
20826        _: &mut Window,
20827        cx: &mut Context<Self>,
20828    ) -> Option<UTF16Selection> {
20829        // Prevent the IME menu from appearing when holding down an alphabetic key
20830        // while input is disabled.
20831        if !ignore_disabled_input && !self.input_enabled {
20832            return None;
20833        }
20834
20835        let selection = self.selections.newest::<OffsetUtf16>(cx);
20836        let range = selection.range();
20837
20838        Some(UTF16Selection {
20839            range: range.start.0..range.end.0,
20840            reversed: selection.reversed,
20841        })
20842    }
20843
20844    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20845        let snapshot = self.buffer.read(cx).read(cx);
20846        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20847        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20848    }
20849
20850    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20851        self.clear_highlights::<InputComposition>(cx);
20852        self.ime_transaction.take();
20853    }
20854
20855    fn replace_text_in_range(
20856        &mut self,
20857        range_utf16: Option<Range<usize>>,
20858        text: &str,
20859        window: &mut Window,
20860        cx: &mut Context<Self>,
20861    ) {
20862        if !self.input_enabled {
20863            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20864            return;
20865        }
20866
20867        self.transact(window, cx, |this, window, cx| {
20868            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20869                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20870                Some(this.selection_replacement_ranges(range_utf16, cx))
20871            } else {
20872                this.marked_text_ranges(cx)
20873            };
20874
20875            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20876                let newest_selection_id = this.selections.newest_anchor().id;
20877                this.selections
20878                    .all::<OffsetUtf16>(cx)
20879                    .iter()
20880                    .zip(ranges_to_replace.iter())
20881                    .find_map(|(selection, range)| {
20882                        if selection.id == newest_selection_id {
20883                            Some(
20884                                (range.start.0 as isize - selection.head().0 as isize)
20885                                    ..(range.end.0 as isize - selection.head().0 as isize),
20886                            )
20887                        } else {
20888                            None
20889                        }
20890                    })
20891            });
20892
20893            cx.emit(EditorEvent::InputHandled {
20894                utf16_range_to_replace: range_to_replace,
20895                text: text.into(),
20896            });
20897
20898            if let Some(new_selected_ranges) = new_selected_ranges {
20899                this.change_selections(None, window, cx, |selections| {
20900                    selections.select_ranges(new_selected_ranges)
20901                });
20902                this.backspace(&Default::default(), window, cx);
20903            }
20904
20905            this.handle_input(text, window, cx);
20906        });
20907
20908        if let Some(transaction) = self.ime_transaction {
20909            self.buffer.update(cx, |buffer, cx| {
20910                buffer.group_until_transaction(transaction, cx);
20911            });
20912        }
20913
20914        self.unmark_text(window, cx);
20915    }
20916
20917    fn replace_and_mark_text_in_range(
20918        &mut self,
20919        range_utf16: Option<Range<usize>>,
20920        text: &str,
20921        new_selected_range_utf16: Option<Range<usize>>,
20922        window: &mut Window,
20923        cx: &mut Context<Self>,
20924    ) {
20925        if !self.input_enabled {
20926            return;
20927        }
20928
20929        let transaction = self.transact(window, cx, |this, window, cx| {
20930            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20931                let snapshot = this.buffer.read(cx).read(cx);
20932                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20933                    for marked_range in &mut marked_ranges {
20934                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20935                        marked_range.start.0 += relative_range_utf16.start;
20936                        marked_range.start =
20937                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20938                        marked_range.end =
20939                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20940                    }
20941                }
20942                Some(marked_ranges)
20943            } else if let Some(range_utf16) = range_utf16 {
20944                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20945                Some(this.selection_replacement_ranges(range_utf16, cx))
20946            } else {
20947                None
20948            };
20949
20950            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20951                let newest_selection_id = this.selections.newest_anchor().id;
20952                this.selections
20953                    .all::<OffsetUtf16>(cx)
20954                    .iter()
20955                    .zip(ranges_to_replace.iter())
20956                    .find_map(|(selection, range)| {
20957                        if selection.id == newest_selection_id {
20958                            Some(
20959                                (range.start.0 as isize - selection.head().0 as isize)
20960                                    ..(range.end.0 as isize - selection.head().0 as isize),
20961                            )
20962                        } else {
20963                            None
20964                        }
20965                    })
20966            });
20967
20968            cx.emit(EditorEvent::InputHandled {
20969                utf16_range_to_replace: range_to_replace,
20970                text: text.into(),
20971            });
20972
20973            if let Some(ranges) = ranges_to_replace {
20974                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20975            }
20976
20977            let marked_ranges = {
20978                let snapshot = this.buffer.read(cx).read(cx);
20979                this.selections
20980                    .disjoint_anchors()
20981                    .iter()
20982                    .map(|selection| {
20983                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20984                    })
20985                    .collect::<Vec<_>>()
20986            };
20987
20988            if text.is_empty() {
20989                this.unmark_text(window, cx);
20990            } else {
20991                this.highlight_text::<InputComposition>(
20992                    marked_ranges.clone(),
20993                    HighlightStyle {
20994                        underline: Some(UnderlineStyle {
20995                            thickness: px(1.),
20996                            color: None,
20997                            wavy: false,
20998                        }),
20999                        ..Default::default()
21000                    },
21001                    cx,
21002                );
21003            }
21004
21005            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21006            let use_autoclose = this.use_autoclose;
21007            let use_auto_surround = this.use_auto_surround;
21008            this.set_use_autoclose(false);
21009            this.set_use_auto_surround(false);
21010            this.handle_input(text, window, cx);
21011            this.set_use_autoclose(use_autoclose);
21012            this.set_use_auto_surround(use_auto_surround);
21013
21014            if let Some(new_selected_range) = new_selected_range_utf16 {
21015                let snapshot = this.buffer.read(cx).read(cx);
21016                let new_selected_ranges = marked_ranges
21017                    .into_iter()
21018                    .map(|marked_range| {
21019                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21020                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21021                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21022                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21023                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21024                    })
21025                    .collect::<Vec<_>>();
21026
21027                drop(snapshot);
21028                this.change_selections(None, window, cx, |selections| {
21029                    selections.select_ranges(new_selected_ranges)
21030                });
21031            }
21032        });
21033
21034        self.ime_transaction = self.ime_transaction.or(transaction);
21035        if let Some(transaction) = self.ime_transaction {
21036            self.buffer.update(cx, |buffer, cx| {
21037                buffer.group_until_transaction(transaction, cx);
21038            });
21039        }
21040
21041        if self.text_highlights::<InputComposition>(cx).is_none() {
21042            self.ime_transaction.take();
21043        }
21044    }
21045
21046    fn bounds_for_range(
21047        &mut self,
21048        range_utf16: Range<usize>,
21049        element_bounds: gpui::Bounds<Pixels>,
21050        window: &mut Window,
21051        cx: &mut Context<Self>,
21052    ) -> Option<gpui::Bounds<Pixels>> {
21053        let text_layout_details = self.text_layout_details(window);
21054        let gpui::Size {
21055            width: em_width,
21056            height: line_height,
21057        } = self.character_size(window);
21058
21059        let snapshot = self.snapshot(window, cx);
21060        let scroll_position = snapshot.scroll_position();
21061        let scroll_left = scroll_position.x * em_width;
21062
21063        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21064        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21065            + self.gutter_dimensions.width
21066            + self.gutter_dimensions.margin;
21067        let y = line_height * (start.row().as_f32() - scroll_position.y);
21068
21069        Some(Bounds {
21070            origin: element_bounds.origin + point(x, y),
21071            size: size(em_width, line_height),
21072        })
21073    }
21074
21075    fn character_index_for_point(
21076        &mut self,
21077        point: gpui::Point<Pixels>,
21078        _window: &mut Window,
21079        _cx: &mut Context<Self>,
21080    ) -> Option<usize> {
21081        let position_map = self.last_position_map.as_ref()?;
21082        if !position_map.text_hitbox.contains(&point) {
21083            return None;
21084        }
21085        let display_point = position_map.point_for_position(point).previous_valid;
21086        let anchor = position_map
21087            .snapshot
21088            .display_point_to_anchor(display_point, Bias::Left);
21089        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21090        Some(utf16_offset.0)
21091    }
21092}
21093
21094trait SelectionExt {
21095    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21096    fn spanned_rows(
21097        &self,
21098        include_end_if_at_line_start: bool,
21099        map: &DisplaySnapshot,
21100    ) -> Range<MultiBufferRow>;
21101}
21102
21103impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21104    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21105        let start = self
21106            .start
21107            .to_point(&map.buffer_snapshot)
21108            .to_display_point(map);
21109        let end = self
21110            .end
21111            .to_point(&map.buffer_snapshot)
21112            .to_display_point(map);
21113        if self.reversed {
21114            end..start
21115        } else {
21116            start..end
21117        }
21118    }
21119
21120    fn spanned_rows(
21121        &self,
21122        include_end_if_at_line_start: bool,
21123        map: &DisplaySnapshot,
21124    ) -> Range<MultiBufferRow> {
21125        let start = self.start.to_point(&map.buffer_snapshot);
21126        let mut end = self.end.to_point(&map.buffer_snapshot);
21127        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21128            end.row -= 1;
21129        }
21130
21131        let buffer_start = map.prev_line_boundary(start).0;
21132        let buffer_end = map.next_line_boundary(end).0;
21133        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21134    }
21135}
21136
21137impl<T: InvalidationRegion> InvalidationStack<T> {
21138    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21139    where
21140        S: Clone + ToOffset,
21141    {
21142        while let Some(region) = self.last() {
21143            let all_selections_inside_invalidation_ranges =
21144                if selections.len() == region.ranges().len() {
21145                    selections
21146                        .iter()
21147                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21148                        .all(|(selection, invalidation_range)| {
21149                            let head = selection.head().to_offset(buffer);
21150                            invalidation_range.start <= head && invalidation_range.end >= head
21151                        })
21152                } else {
21153                    false
21154                };
21155
21156            if all_selections_inside_invalidation_ranges {
21157                break;
21158            } else {
21159                self.pop();
21160            }
21161        }
21162    }
21163}
21164
21165impl<T> Default for InvalidationStack<T> {
21166    fn default() -> Self {
21167        Self(Default::default())
21168    }
21169}
21170
21171impl<T> Deref for InvalidationStack<T> {
21172    type Target = Vec<T>;
21173
21174    fn deref(&self) -> &Self::Target {
21175        &self.0
21176    }
21177}
21178
21179impl<T> DerefMut for InvalidationStack<T> {
21180    fn deref_mut(&mut self) -> &mut Self::Target {
21181        &mut self.0
21182    }
21183}
21184
21185impl InvalidationRegion for SnippetState {
21186    fn ranges(&self) -> &[Range<Anchor>] {
21187        &self.ranges[self.active_index]
21188    }
21189}
21190
21191fn inline_completion_edit_text(
21192    current_snapshot: &BufferSnapshot,
21193    edits: &[(Range<Anchor>, String)],
21194    edit_preview: &EditPreview,
21195    include_deletions: bool,
21196    cx: &App,
21197) -> HighlightedText {
21198    let edits = edits
21199        .iter()
21200        .map(|(anchor, text)| {
21201            (
21202                anchor.start.text_anchor..anchor.end.text_anchor,
21203                text.clone(),
21204            )
21205        })
21206        .collect::<Vec<_>>();
21207
21208    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21209}
21210
21211pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21212    match severity {
21213        lsp::DiagnosticSeverity::ERROR => colors.error,
21214        lsp::DiagnosticSeverity::WARNING => colors.warning,
21215        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21216        lsp::DiagnosticSeverity::HINT => colors.info,
21217        _ => colors.ignored,
21218    }
21219}
21220
21221pub fn styled_runs_for_code_label<'a>(
21222    label: &'a CodeLabel,
21223    syntax_theme: &'a theme::SyntaxTheme,
21224) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21225    let fade_out = HighlightStyle {
21226        fade_out: Some(0.35),
21227        ..Default::default()
21228    };
21229
21230    let mut prev_end = label.filter_range.end;
21231    label
21232        .runs
21233        .iter()
21234        .enumerate()
21235        .flat_map(move |(ix, (range, highlight_id))| {
21236            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21237                style
21238            } else {
21239                return Default::default();
21240            };
21241            let mut muted_style = style;
21242            muted_style.highlight(fade_out);
21243
21244            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21245            if range.start >= label.filter_range.end {
21246                if range.start > prev_end {
21247                    runs.push((prev_end..range.start, fade_out));
21248                }
21249                runs.push((range.clone(), muted_style));
21250            } else if range.end <= label.filter_range.end {
21251                runs.push((range.clone(), style));
21252            } else {
21253                runs.push((range.start..label.filter_range.end, style));
21254                runs.push((label.filter_range.end..range.end, muted_style));
21255            }
21256            prev_end = cmp::max(prev_end, range.end);
21257
21258            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21259                runs.push((prev_end..label.text.len(), fade_out));
21260            }
21261
21262            runs
21263        })
21264}
21265
21266pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21267    let mut prev_index = 0;
21268    let mut prev_codepoint: Option<char> = None;
21269    text.char_indices()
21270        .chain([(text.len(), '\0')])
21271        .filter_map(move |(index, codepoint)| {
21272            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21273            let is_boundary = index == text.len()
21274                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21275                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21276            if is_boundary {
21277                let chunk = &text[prev_index..index];
21278                prev_index = index;
21279                Some(chunk)
21280            } else {
21281                None
21282            }
21283        })
21284}
21285
21286pub trait RangeToAnchorExt: Sized {
21287    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21288
21289    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21290        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21291        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21292    }
21293}
21294
21295impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21296    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21297        let start_offset = self.start.to_offset(snapshot);
21298        let end_offset = self.end.to_offset(snapshot);
21299        if start_offset == end_offset {
21300            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21301        } else {
21302            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21303        }
21304    }
21305}
21306
21307pub trait RowExt {
21308    fn as_f32(&self) -> f32;
21309
21310    fn next_row(&self) -> Self;
21311
21312    fn previous_row(&self) -> Self;
21313
21314    fn minus(&self, other: Self) -> u32;
21315}
21316
21317impl RowExt for DisplayRow {
21318    fn as_f32(&self) -> f32 {
21319        self.0 as f32
21320    }
21321
21322    fn next_row(&self) -> Self {
21323        Self(self.0 + 1)
21324    }
21325
21326    fn previous_row(&self) -> Self {
21327        Self(self.0.saturating_sub(1))
21328    }
21329
21330    fn minus(&self, other: Self) -> u32 {
21331        self.0 - other.0
21332    }
21333}
21334
21335impl RowExt for MultiBufferRow {
21336    fn as_f32(&self) -> f32 {
21337        self.0 as f32
21338    }
21339
21340    fn next_row(&self) -> Self {
21341        Self(self.0 + 1)
21342    }
21343
21344    fn previous_row(&self) -> Self {
21345        Self(self.0.saturating_sub(1))
21346    }
21347
21348    fn minus(&self, other: Self) -> u32 {
21349        self.0 - other.0
21350    }
21351}
21352
21353trait RowRangeExt {
21354    type Row;
21355
21356    fn len(&self) -> usize;
21357
21358    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21359}
21360
21361impl RowRangeExt for Range<MultiBufferRow> {
21362    type Row = MultiBufferRow;
21363
21364    fn len(&self) -> usize {
21365        (self.end.0 - self.start.0) as usize
21366    }
21367
21368    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21369        (self.start.0..self.end.0).map(MultiBufferRow)
21370    }
21371}
21372
21373impl RowRangeExt for Range<DisplayRow> {
21374    type Row = DisplayRow;
21375
21376    fn len(&self) -> usize {
21377        (self.end.0 - self.start.0) as usize
21378    }
21379
21380    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21381        (self.start.0..self.end.0).map(DisplayRow)
21382    }
21383}
21384
21385/// If select range has more than one line, we
21386/// just point the cursor to range.start.
21387fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21388    if range.start.row == range.end.row {
21389        range
21390    } else {
21391        range.start..range.start
21392    }
21393}
21394pub struct KillRing(ClipboardItem);
21395impl Global for KillRing {}
21396
21397const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21398
21399enum BreakpointPromptEditAction {
21400    Log,
21401    Condition,
21402    HitCondition,
21403}
21404
21405struct BreakpointPromptEditor {
21406    pub(crate) prompt: Entity<Editor>,
21407    editor: WeakEntity<Editor>,
21408    breakpoint_anchor: Anchor,
21409    breakpoint: Breakpoint,
21410    edit_action: BreakpointPromptEditAction,
21411    block_ids: HashSet<CustomBlockId>,
21412    editor_margins: Arc<Mutex<EditorMargins>>,
21413    _subscriptions: Vec<Subscription>,
21414}
21415
21416impl BreakpointPromptEditor {
21417    const MAX_LINES: u8 = 4;
21418
21419    fn new(
21420        editor: WeakEntity<Editor>,
21421        breakpoint_anchor: Anchor,
21422        breakpoint: Breakpoint,
21423        edit_action: BreakpointPromptEditAction,
21424        window: &mut Window,
21425        cx: &mut Context<Self>,
21426    ) -> Self {
21427        let base_text = match edit_action {
21428            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21429            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21430            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21431        }
21432        .map(|msg| msg.to_string())
21433        .unwrap_or_default();
21434
21435        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21436        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21437
21438        let prompt = cx.new(|cx| {
21439            let mut prompt = Editor::new(
21440                EditorMode::AutoHeight {
21441                    max_lines: Self::MAX_LINES as usize,
21442                },
21443                buffer,
21444                None,
21445                window,
21446                cx,
21447            );
21448            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21449            prompt.set_show_cursor_when_unfocused(false, cx);
21450            prompt.set_placeholder_text(
21451                match edit_action {
21452                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21453                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21454                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21455                },
21456                cx,
21457            );
21458
21459            prompt
21460        });
21461
21462        Self {
21463            prompt,
21464            editor,
21465            breakpoint_anchor,
21466            breakpoint,
21467            edit_action,
21468            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21469            block_ids: Default::default(),
21470            _subscriptions: vec![],
21471        }
21472    }
21473
21474    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21475        self.block_ids.extend(block_ids)
21476    }
21477
21478    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21479        if let Some(editor) = self.editor.upgrade() {
21480            let message = self
21481                .prompt
21482                .read(cx)
21483                .buffer
21484                .read(cx)
21485                .as_singleton()
21486                .expect("A multi buffer in breakpoint prompt isn't possible")
21487                .read(cx)
21488                .as_rope()
21489                .to_string();
21490
21491            editor.update(cx, |editor, cx| {
21492                editor.edit_breakpoint_at_anchor(
21493                    self.breakpoint_anchor,
21494                    self.breakpoint.clone(),
21495                    match self.edit_action {
21496                        BreakpointPromptEditAction::Log => {
21497                            BreakpointEditAction::EditLogMessage(message.into())
21498                        }
21499                        BreakpointPromptEditAction::Condition => {
21500                            BreakpointEditAction::EditCondition(message.into())
21501                        }
21502                        BreakpointPromptEditAction::HitCondition => {
21503                            BreakpointEditAction::EditHitCondition(message.into())
21504                        }
21505                    },
21506                    cx,
21507                );
21508
21509                editor.remove_blocks(self.block_ids.clone(), None, cx);
21510                cx.focus_self(window);
21511            });
21512        }
21513    }
21514
21515    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21516        self.editor
21517            .update(cx, |editor, cx| {
21518                editor.remove_blocks(self.block_ids.clone(), None, cx);
21519                window.focus(&editor.focus_handle);
21520            })
21521            .log_err();
21522    }
21523
21524    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21525        let settings = ThemeSettings::get_global(cx);
21526        let text_style = TextStyle {
21527            color: if self.prompt.read(cx).read_only(cx) {
21528                cx.theme().colors().text_disabled
21529            } else {
21530                cx.theme().colors().text
21531            },
21532            font_family: settings.buffer_font.family.clone(),
21533            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21534            font_size: settings.buffer_font_size(cx).into(),
21535            font_weight: settings.buffer_font.weight,
21536            line_height: relative(settings.buffer_line_height.value()),
21537            ..Default::default()
21538        };
21539        EditorElement::new(
21540            &self.prompt,
21541            EditorStyle {
21542                background: cx.theme().colors().editor_background,
21543                local_player: cx.theme().players().local(),
21544                text: text_style,
21545                ..Default::default()
21546            },
21547        )
21548    }
21549}
21550
21551impl Render for BreakpointPromptEditor {
21552    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21553        let editor_margins = *self.editor_margins.lock();
21554        let gutter_dimensions = editor_margins.gutter;
21555        h_flex()
21556            .key_context("Editor")
21557            .bg(cx.theme().colors().editor_background)
21558            .border_y_1()
21559            .border_color(cx.theme().status().info_border)
21560            .size_full()
21561            .py(window.line_height() / 2.5)
21562            .on_action(cx.listener(Self::confirm))
21563            .on_action(cx.listener(Self::cancel))
21564            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21565            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21566    }
21567}
21568
21569impl Focusable for BreakpointPromptEditor {
21570    fn focus_handle(&self, cx: &App) -> FocusHandle {
21571        self.prompt.focus_handle(cx)
21572    }
21573}
21574
21575fn all_edits_insertions_or_deletions(
21576    edits: &Vec<(Range<Anchor>, String)>,
21577    snapshot: &MultiBufferSnapshot,
21578) -> bool {
21579    let mut all_insertions = true;
21580    let mut all_deletions = true;
21581
21582    for (range, new_text) in edits.iter() {
21583        let range_is_empty = range.to_offset(&snapshot).is_empty();
21584        let text_is_empty = new_text.is_empty();
21585
21586        if range_is_empty != text_is_empty {
21587            if range_is_empty {
21588                all_deletions = false;
21589            } else {
21590                all_insertions = false;
21591            }
21592        } else {
21593            return false;
21594        }
21595
21596        if !all_insertions && !all_deletions {
21597            return false;
21598        }
21599    }
21600    all_insertions || all_deletions
21601}
21602
21603struct MissingEditPredictionKeybindingTooltip;
21604
21605impl Render for MissingEditPredictionKeybindingTooltip {
21606    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21607        ui::tooltip_container(window, cx, |container, _, cx| {
21608            container
21609                .flex_shrink_0()
21610                .max_w_80()
21611                .min_h(rems_from_px(124.))
21612                .justify_between()
21613                .child(
21614                    v_flex()
21615                        .flex_1()
21616                        .text_ui_sm(cx)
21617                        .child(Label::new("Conflict with Accept Keybinding"))
21618                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21619                )
21620                .child(
21621                    h_flex()
21622                        .pb_1()
21623                        .gap_1()
21624                        .items_end()
21625                        .w_full()
21626                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21627                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21628                        }))
21629                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21630                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21631                        })),
21632                )
21633        })
21634    }
21635}
21636
21637#[derive(Debug, Clone, Copy, PartialEq)]
21638pub struct LineHighlight {
21639    pub background: Background,
21640    pub border: Option<gpui::Hsla>,
21641    pub include_gutter: bool,
21642    pub type_id: Option<TypeId>,
21643}
21644
21645fn render_diff_hunk_controls(
21646    row: u32,
21647    status: &DiffHunkStatus,
21648    hunk_range: Range<Anchor>,
21649    is_created_file: bool,
21650    line_height: Pixels,
21651    editor: &Entity<Editor>,
21652    _window: &mut Window,
21653    cx: &mut App,
21654) -> AnyElement {
21655    h_flex()
21656        .h(line_height)
21657        .mr_1()
21658        .gap_1()
21659        .px_0p5()
21660        .pb_1()
21661        .border_x_1()
21662        .border_b_1()
21663        .border_color(cx.theme().colors().border_variant)
21664        .rounded_b_lg()
21665        .bg(cx.theme().colors().editor_background)
21666        .gap_1()
21667        .occlude()
21668        .shadow_md()
21669        .child(if status.has_secondary_hunk() {
21670            Button::new(("stage", row as u64), "Stage")
21671                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21672                .tooltip({
21673                    let focus_handle = editor.focus_handle(cx);
21674                    move |window, cx| {
21675                        Tooltip::for_action_in(
21676                            "Stage Hunk",
21677                            &::git::ToggleStaged,
21678                            &focus_handle,
21679                            window,
21680                            cx,
21681                        )
21682                    }
21683                })
21684                .on_click({
21685                    let editor = editor.clone();
21686                    move |_event, _window, cx| {
21687                        editor.update(cx, |editor, cx| {
21688                            editor.stage_or_unstage_diff_hunks(
21689                                true,
21690                                vec![hunk_range.start..hunk_range.start],
21691                                cx,
21692                            );
21693                        });
21694                    }
21695                })
21696        } else {
21697            Button::new(("unstage", row as u64), "Unstage")
21698                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21699                .tooltip({
21700                    let focus_handle = editor.focus_handle(cx);
21701                    move |window, cx| {
21702                        Tooltip::for_action_in(
21703                            "Unstage Hunk",
21704                            &::git::ToggleStaged,
21705                            &focus_handle,
21706                            window,
21707                            cx,
21708                        )
21709                    }
21710                })
21711                .on_click({
21712                    let editor = editor.clone();
21713                    move |_event, _window, cx| {
21714                        editor.update(cx, |editor, cx| {
21715                            editor.stage_or_unstage_diff_hunks(
21716                                false,
21717                                vec![hunk_range.start..hunk_range.start],
21718                                cx,
21719                            );
21720                        });
21721                    }
21722                })
21723        })
21724        .child(
21725            Button::new(("restore", row as u64), "Restore")
21726                .tooltip({
21727                    let focus_handle = editor.focus_handle(cx);
21728                    move |window, cx| {
21729                        Tooltip::for_action_in(
21730                            "Restore Hunk",
21731                            &::git::Restore,
21732                            &focus_handle,
21733                            window,
21734                            cx,
21735                        )
21736                    }
21737                })
21738                .on_click({
21739                    let editor = editor.clone();
21740                    move |_event, window, cx| {
21741                        editor.update(cx, |editor, cx| {
21742                            let snapshot = editor.snapshot(window, cx);
21743                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21744                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21745                        });
21746                    }
21747                })
21748                .disabled(is_created_file),
21749        )
21750        .when(
21751            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21752            |el| {
21753                el.child(
21754                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21755                        .shape(IconButtonShape::Square)
21756                        .icon_size(IconSize::Small)
21757                        // .disabled(!has_multiple_hunks)
21758                        .tooltip({
21759                            let focus_handle = editor.focus_handle(cx);
21760                            move |window, cx| {
21761                                Tooltip::for_action_in(
21762                                    "Next Hunk",
21763                                    &GoToHunk,
21764                                    &focus_handle,
21765                                    window,
21766                                    cx,
21767                                )
21768                            }
21769                        })
21770                        .on_click({
21771                            let editor = editor.clone();
21772                            move |_event, window, cx| {
21773                                editor.update(cx, |editor, cx| {
21774                                    let snapshot = editor.snapshot(window, cx);
21775                                    let position =
21776                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21777                                    editor.go_to_hunk_before_or_after_position(
21778                                        &snapshot,
21779                                        position,
21780                                        Direction::Next,
21781                                        window,
21782                                        cx,
21783                                    );
21784                                    editor.expand_selected_diff_hunks(cx);
21785                                });
21786                            }
21787                        }),
21788                )
21789                .child(
21790                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21791                        .shape(IconButtonShape::Square)
21792                        .icon_size(IconSize::Small)
21793                        // .disabled(!has_multiple_hunks)
21794                        .tooltip({
21795                            let focus_handle = editor.focus_handle(cx);
21796                            move |window, cx| {
21797                                Tooltip::for_action_in(
21798                                    "Previous Hunk",
21799                                    &GoToPreviousHunk,
21800                                    &focus_handle,
21801                                    window,
21802                                    cx,
21803                                )
21804                            }
21805                        })
21806                        .on_click({
21807                            let editor = editor.clone();
21808                            move |_event, window, cx| {
21809                                editor.update(cx, |editor, cx| {
21810                                    let snapshot = editor.snapshot(window, cx);
21811                                    let point =
21812                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21813                                    editor.go_to_hunk_before_or_after_position(
21814                                        &snapshot,
21815                                        point,
21816                                        Direction::Prev,
21817                                        window,
21818                                        cx,
21819                                    );
21820                                    editor.expand_selected_diff_hunks(cx);
21821                                });
21822                            }
21823                        }),
21824                )
21825            },
21826        )
21827        .into_any_element()
21828}