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                        crate::hover_popover::hide_hover(editor, cx);
 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                            crate::hover_popover::hide_hover(editor, cx);
 5516                            *editor.context_menu.borrow_mut() =
 5517                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5518                                    buffer,
 5519                                    actions: CodeActionContents::new(
 5520                                        resolved_tasks,
 5521                                        code_actions,
 5522                                        debug_scenarios,
 5523                                        task_context.unwrap_or_default(),
 5524                                    ),
 5525                                    selected_item: Default::default(),
 5526                                    scroll_handle: UniformListScrollHandle::default(),
 5527                                    deployed_from_indicator,
 5528                                }));
 5529                            if spawn_straight_away {
 5530                                if let Some(task) = editor.confirm_code_action(
 5531                                    &ConfirmCodeAction { item_ix: Some(0) },
 5532                                    window,
 5533                                    cx,
 5534                                ) {
 5535                                    cx.notify();
 5536                                    return task;
 5537                                }
 5538                            }
 5539                            cx.notify();
 5540                            Task::ready(Ok(()))
 5541                        }) {
 5542                            task.await
 5543                        } else {
 5544                            Ok(())
 5545                        }
 5546                    }))
 5547                } else {
 5548                    Some(Task::ready(Ok(())))
 5549                }
 5550            })?;
 5551            if let Some(task) = spawned_test_task {
 5552                task.await?;
 5553            }
 5554
 5555            anyhow::Ok(())
 5556        })
 5557        .detach_and_log_err(cx);
 5558    }
 5559
 5560    pub fn confirm_code_action(
 5561        &mut self,
 5562        action: &ConfirmCodeAction,
 5563        window: &mut Window,
 5564        cx: &mut Context<Self>,
 5565    ) -> Option<Task<Result<()>>> {
 5566        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5567
 5568        let actions_menu =
 5569            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5570                menu
 5571            } else {
 5572                return None;
 5573            };
 5574
 5575        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5576        let action = actions_menu.actions.get(action_ix)?;
 5577        let title = action.label();
 5578        let buffer = actions_menu.buffer;
 5579        let workspace = self.workspace()?;
 5580
 5581        match action {
 5582            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5583                workspace.update(cx, |workspace, cx| {
 5584                    workspace.schedule_resolved_task(
 5585                        task_source_kind,
 5586                        resolved_task,
 5587                        false,
 5588                        window,
 5589                        cx,
 5590                    );
 5591
 5592                    Some(Task::ready(Ok(())))
 5593                })
 5594            }
 5595            CodeActionsItem::CodeAction {
 5596                excerpt_id,
 5597                action,
 5598                provider,
 5599            } => {
 5600                let apply_code_action =
 5601                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5602                let workspace = workspace.downgrade();
 5603                Some(cx.spawn_in(window, async move |editor, cx| {
 5604                    let project_transaction = apply_code_action.await?;
 5605                    Self::open_project_transaction(
 5606                        &editor,
 5607                        workspace,
 5608                        project_transaction,
 5609                        title,
 5610                        cx,
 5611                    )
 5612                    .await
 5613                }))
 5614            }
 5615            CodeActionsItem::DebugScenario(scenario) => {
 5616                let context = actions_menu.actions.context.clone();
 5617
 5618                workspace.update(cx, |workspace, cx| {
 5619                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5620                });
 5621                Some(Task::ready(Ok(())))
 5622            }
 5623        }
 5624    }
 5625
 5626    pub async fn open_project_transaction(
 5627        this: &WeakEntity<Editor>,
 5628        workspace: WeakEntity<Workspace>,
 5629        transaction: ProjectTransaction,
 5630        title: String,
 5631        cx: &mut AsyncWindowContext,
 5632    ) -> Result<()> {
 5633        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5634        cx.update(|_, cx| {
 5635            entries.sort_unstable_by_key(|(buffer, _)| {
 5636                buffer.read(cx).file().map(|f| f.path().clone())
 5637            });
 5638        })?;
 5639
 5640        // If the project transaction's edits are all contained within this editor, then
 5641        // avoid opening a new editor to display them.
 5642
 5643        if let Some((buffer, transaction)) = entries.first() {
 5644            if entries.len() == 1 {
 5645                let excerpt = this.update(cx, |editor, cx| {
 5646                    editor
 5647                        .buffer()
 5648                        .read(cx)
 5649                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5650                })?;
 5651                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5652                    if excerpted_buffer == *buffer {
 5653                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5654                            let excerpt_range = excerpt_range.to_offset(buffer);
 5655                            buffer
 5656                                .edited_ranges_for_transaction::<usize>(transaction)
 5657                                .all(|range| {
 5658                                    excerpt_range.start <= range.start
 5659                                        && excerpt_range.end >= range.end
 5660                                })
 5661                        })?;
 5662
 5663                        if all_edits_within_excerpt {
 5664                            return Ok(());
 5665                        }
 5666                    }
 5667                }
 5668            }
 5669        } else {
 5670            return Ok(());
 5671        }
 5672
 5673        let mut ranges_to_highlight = Vec::new();
 5674        let excerpt_buffer = cx.new(|cx| {
 5675            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5676            for (buffer_handle, transaction) in &entries {
 5677                let edited_ranges = buffer_handle
 5678                    .read(cx)
 5679                    .edited_ranges_for_transaction::<Point>(transaction)
 5680                    .collect::<Vec<_>>();
 5681                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5682                    PathKey::for_buffer(buffer_handle, cx),
 5683                    buffer_handle.clone(),
 5684                    edited_ranges,
 5685                    DEFAULT_MULTIBUFFER_CONTEXT,
 5686                    cx,
 5687                );
 5688
 5689                ranges_to_highlight.extend(ranges);
 5690            }
 5691            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5692            multibuffer
 5693        })?;
 5694
 5695        workspace.update_in(cx, |workspace, window, cx| {
 5696            let project = workspace.project().clone();
 5697            let editor =
 5698                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5699            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5700            editor.update(cx, |editor, cx| {
 5701                editor.highlight_background::<Self>(
 5702                    &ranges_to_highlight,
 5703                    |theme| theme.editor_highlighted_line_background,
 5704                    cx,
 5705                );
 5706            });
 5707        })?;
 5708
 5709        Ok(())
 5710    }
 5711
 5712    pub fn clear_code_action_providers(&mut self) {
 5713        self.code_action_providers.clear();
 5714        self.available_code_actions.take();
 5715    }
 5716
 5717    pub fn add_code_action_provider(
 5718        &mut self,
 5719        provider: Rc<dyn CodeActionProvider>,
 5720        window: &mut Window,
 5721        cx: &mut Context<Self>,
 5722    ) {
 5723        if self
 5724            .code_action_providers
 5725            .iter()
 5726            .any(|existing_provider| existing_provider.id() == provider.id())
 5727        {
 5728            return;
 5729        }
 5730
 5731        self.code_action_providers.push(provider);
 5732        self.refresh_code_actions(window, cx);
 5733    }
 5734
 5735    pub fn remove_code_action_provider(
 5736        &mut self,
 5737        id: Arc<str>,
 5738        window: &mut Window,
 5739        cx: &mut Context<Self>,
 5740    ) {
 5741        self.code_action_providers
 5742            .retain(|provider| provider.id() != id);
 5743        self.refresh_code_actions(window, cx);
 5744    }
 5745
 5746    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5747        let newest_selection = self.selections.newest_anchor().clone();
 5748        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5749        let buffer = self.buffer.read(cx);
 5750        if newest_selection.head().diff_base_anchor.is_some() {
 5751            return None;
 5752        }
 5753        let (start_buffer, start) =
 5754            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5755        let (end_buffer, end) =
 5756            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5757        if start_buffer != end_buffer {
 5758            return None;
 5759        }
 5760
 5761        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5762            cx.background_executor()
 5763                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5764                .await;
 5765
 5766            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5767                let providers = this.code_action_providers.clone();
 5768                let tasks = this
 5769                    .code_action_providers
 5770                    .iter()
 5771                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5772                    .collect::<Vec<_>>();
 5773                (providers, tasks)
 5774            })?;
 5775
 5776            let mut actions = Vec::new();
 5777            for (provider, provider_actions) in
 5778                providers.into_iter().zip(future::join_all(tasks).await)
 5779            {
 5780                if let Some(provider_actions) = provider_actions.log_err() {
 5781                    actions.extend(provider_actions.into_iter().map(|action| {
 5782                        AvailableCodeAction {
 5783                            excerpt_id: newest_selection.start.excerpt_id,
 5784                            action,
 5785                            provider: provider.clone(),
 5786                        }
 5787                    }));
 5788                }
 5789            }
 5790
 5791            this.update(cx, |this, cx| {
 5792                this.available_code_actions = if actions.is_empty() {
 5793                    None
 5794                } else {
 5795                    Some((
 5796                        Location {
 5797                            buffer: start_buffer,
 5798                            range: start..end,
 5799                        },
 5800                        actions.into(),
 5801                    ))
 5802                };
 5803                cx.notify();
 5804            })
 5805        }));
 5806        None
 5807    }
 5808
 5809    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5810        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5811            self.show_git_blame_inline = false;
 5812
 5813            self.show_git_blame_inline_delay_task =
 5814                Some(cx.spawn_in(window, async move |this, cx| {
 5815                    cx.background_executor().timer(delay).await;
 5816
 5817                    this.update(cx, |this, cx| {
 5818                        this.show_git_blame_inline = true;
 5819                        cx.notify();
 5820                    })
 5821                    .log_err();
 5822                }));
 5823        }
 5824    }
 5825
 5826    fn show_blame_popover(
 5827        &mut self,
 5828        blame_entry: &BlameEntry,
 5829        position: gpui::Point<Pixels>,
 5830        cx: &mut Context<Self>,
 5831    ) {
 5832        if let Some(state) = &mut self.inline_blame_popover {
 5833            state.hide_task.take();
 5834            cx.notify();
 5835        } else {
 5836            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5837            let show_task = cx.spawn(async move |editor, cx| {
 5838                cx.background_executor()
 5839                    .timer(std::time::Duration::from_millis(delay))
 5840                    .await;
 5841                editor
 5842                    .update(cx, |editor, cx| {
 5843                        if let Some(state) = &mut editor.inline_blame_popover {
 5844                            state.show_task = None;
 5845                            cx.notify();
 5846                        }
 5847                    })
 5848                    .ok();
 5849            });
 5850            let Some(blame) = self.blame.as_ref() else {
 5851                return;
 5852            };
 5853            let blame = blame.read(cx);
 5854            let details = blame.details_for_entry(&blame_entry);
 5855            let markdown = cx.new(|cx| {
 5856                Markdown::new(
 5857                    details
 5858                        .as_ref()
 5859                        .map(|message| message.message.clone())
 5860                        .unwrap_or_default(),
 5861                    None,
 5862                    None,
 5863                    cx,
 5864                )
 5865            });
 5866            self.inline_blame_popover = Some(InlineBlamePopover {
 5867                position,
 5868                show_task: Some(show_task),
 5869                hide_task: None,
 5870                popover_bounds: None,
 5871                popover_state: InlineBlamePopoverState {
 5872                    scroll_handle: ScrollHandle::new(),
 5873                    commit_message: details,
 5874                    markdown,
 5875                },
 5876            });
 5877        }
 5878    }
 5879
 5880    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5881        if let Some(state) = &mut self.inline_blame_popover {
 5882            if state.show_task.is_some() {
 5883                self.inline_blame_popover.take();
 5884                cx.notify();
 5885            } else {
 5886                let hide_task = cx.spawn(async move |editor, cx| {
 5887                    cx.background_executor()
 5888                        .timer(std::time::Duration::from_millis(100))
 5889                        .await;
 5890                    editor
 5891                        .update(cx, |editor, cx| {
 5892                            editor.inline_blame_popover.take();
 5893                            cx.notify();
 5894                        })
 5895                        .ok();
 5896                });
 5897                state.hide_task = Some(hide_task);
 5898            }
 5899        }
 5900    }
 5901
 5902    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5903        if self.pending_rename.is_some() {
 5904            return None;
 5905        }
 5906
 5907        let provider = self.semantics_provider.clone()?;
 5908        let buffer = self.buffer.read(cx);
 5909        let newest_selection = self.selections.newest_anchor().clone();
 5910        let cursor_position = newest_selection.head();
 5911        let (cursor_buffer, cursor_buffer_position) =
 5912            buffer.text_anchor_for_position(cursor_position, cx)?;
 5913        let (tail_buffer, tail_buffer_position) =
 5914            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5915        if cursor_buffer != tail_buffer {
 5916            return None;
 5917        }
 5918
 5919        let snapshot = cursor_buffer.read(cx).snapshot();
 5920        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5921        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5922        if start_word_range != end_word_range {
 5923            self.document_highlights_task.take();
 5924            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5925            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5926            return None;
 5927        }
 5928
 5929        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5930        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5931            cx.background_executor()
 5932                .timer(Duration::from_millis(debounce))
 5933                .await;
 5934
 5935            let highlights = if let Some(highlights) = cx
 5936                .update(|cx| {
 5937                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5938                })
 5939                .ok()
 5940                .flatten()
 5941            {
 5942                highlights.await.log_err()
 5943            } else {
 5944                None
 5945            };
 5946
 5947            if let Some(highlights) = highlights {
 5948                this.update(cx, |this, cx| {
 5949                    if this.pending_rename.is_some() {
 5950                        return;
 5951                    }
 5952
 5953                    let buffer_id = cursor_position.buffer_id;
 5954                    let buffer = this.buffer.read(cx);
 5955                    if !buffer
 5956                        .text_anchor_for_position(cursor_position, cx)
 5957                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5958                    {
 5959                        return;
 5960                    }
 5961
 5962                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5963                    let mut write_ranges = Vec::new();
 5964                    let mut read_ranges = Vec::new();
 5965                    for highlight in highlights {
 5966                        for (excerpt_id, excerpt_range) in
 5967                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5968                        {
 5969                            let start = highlight
 5970                                .range
 5971                                .start
 5972                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5973                            let end = highlight
 5974                                .range
 5975                                .end
 5976                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5977                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5978                                continue;
 5979                            }
 5980
 5981                            let range = Anchor {
 5982                                buffer_id,
 5983                                excerpt_id,
 5984                                text_anchor: start,
 5985                                diff_base_anchor: None,
 5986                            }..Anchor {
 5987                                buffer_id,
 5988                                excerpt_id,
 5989                                text_anchor: end,
 5990                                diff_base_anchor: None,
 5991                            };
 5992                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5993                                write_ranges.push(range);
 5994                            } else {
 5995                                read_ranges.push(range);
 5996                            }
 5997                        }
 5998                    }
 5999
 6000                    this.highlight_background::<DocumentHighlightRead>(
 6001                        &read_ranges,
 6002                        |theme| theme.editor_document_highlight_read_background,
 6003                        cx,
 6004                    );
 6005                    this.highlight_background::<DocumentHighlightWrite>(
 6006                        &write_ranges,
 6007                        |theme| theme.editor_document_highlight_write_background,
 6008                        cx,
 6009                    );
 6010                    cx.notify();
 6011                })
 6012                .log_err();
 6013            }
 6014        }));
 6015        None
 6016    }
 6017
 6018    fn prepare_highlight_query_from_selection(
 6019        &mut self,
 6020        cx: &mut Context<Editor>,
 6021    ) -> Option<(String, Range<Anchor>)> {
 6022        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6023            return None;
 6024        }
 6025        if !EditorSettings::get_global(cx).selection_highlight {
 6026            return None;
 6027        }
 6028        if self.selections.count() != 1 || self.selections.line_mode {
 6029            return None;
 6030        }
 6031        let selection = self.selections.newest::<Point>(cx);
 6032        if selection.is_empty() || selection.start.row != selection.end.row {
 6033            return None;
 6034        }
 6035        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6036        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6037        let query = multi_buffer_snapshot
 6038            .text_for_range(selection_anchor_range.clone())
 6039            .collect::<String>();
 6040        if query.trim().is_empty() {
 6041            return None;
 6042        }
 6043        Some((query, selection_anchor_range))
 6044    }
 6045
 6046    fn update_selection_occurrence_highlights(
 6047        &mut self,
 6048        query_text: String,
 6049        query_range: Range<Anchor>,
 6050        multi_buffer_range_to_query: Range<Point>,
 6051        use_debounce: bool,
 6052        window: &mut Window,
 6053        cx: &mut Context<Editor>,
 6054    ) -> Task<()> {
 6055        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6056        cx.spawn_in(window, async move |editor, cx| {
 6057            if use_debounce {
 6058                cx.background_executor()
 6059                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6060                    .await;
 6061            }
 6062            let match_task = cx.background_spawn(async move {
 6063                let buffer_ranges = multi_buffer_snapshot
 6064                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6065                    .into_iter()
 6066                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6067                let mut match_ranges = Vec::new();
 6068                let Ok(regex) = project::search::SearchQuery::text(
 6069                    query_text.clone(),
 6070                    false,
 6071                    false,
 6072                    false,
 6073                    Default::default(),
 6074                    Default::default(),
 6075                    false,
 6076                    None,
 6077                ) else {
 6078                    return Vec::default();
 6079                };
 6080                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6081                    match_ranges.extend(
 6082                        regex
 6083                            .search(&buffer_snapshot, Some(search_range.clone()))
 6084                            .await
 6085                            .into_iter()
 6086                            .filter_map(|match_range| {
 6087                                let match_start = buffer_snapshot
 6088                                    .anchor_after(search_range.start + match_range.start);
 6089                                let match_end = buffer_snapshot
 6090                                    .anchor_before(search_range.start + match_range.end);
 6091                                let match_anchor_range = Anchor::range_in_buffer(
 6092                                    excerpt_id,
 6093                                    buffer_snapshot.remote_id(),
 6094                                    match_start..match_end,
 6095                                );
 6096                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6097                            }),
 6098                    );
 6099                }
 6100                match_ranges
 6101            });
 6102            let match_ranges = match_task.await;
 6103            editor
 6104                .update_in(cx, |editor, _, cx| {
 6105                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6106                    if !match_ranges.is_empty() {
 6107                        editor.highlight_background::<SelectedTextHighlight>(
 6108                            &match_ranges,
 6109                            |theme| theme.editor_document_highlight_bracket_background,
 6110                            cx,
 6111                        )
 6112                    }
 6113                })
 6114                .log_err();
 6115        })
 6116    }
 6117
 6118    fn refresh_selected_text_highlights(
 6119        &mut self,
 6120        on_buffer_edit: bool,
 6121        window: &mut Window,
 6122        cx: &mut Context<Editor>,
 6123    ) {
 6124        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6125        else {
 6126            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6127            self.quick_selection_highlight_task.take();
 6128            self.debounced_selection_highlight_task.take();
 6129            return;
 6130        };
 6131        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6132        if on_buffer_edit
 6133            || self
 6134                .quick_selection_highlight_task
 6135                .as_ref()
 6136                .map_or(true, |(prev_anchor_range, _)| {
 6137                    prev_anchor_range != &query_range
 6138                })
 6139        {
 6140            let multi_buffer_visible_start = self
 6141                .scroll_manager
 6142                .anchor()
 6143                .anchor
 6144                .to_point(&multi_buffer_snapshot);
 6145            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6146                multi_buffer_visible_start
 6147                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6148                Bias::Left,
 6149            );
 6150            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6151            self.quick_selection_highlight_task = Some((
 6152                query_range.clone(),
 6153                self.update_selection_occurrence_highlights(
 6154                    query_text.clone(),
 6155                    query_range.clone(),
 6156                    multi_buffer_visible_range,
 6157                    false,
 6158                    window,
 6159                    cx,
 6160                ),
 6161            ));
 6162        }
 6163        if on_buffer_edit
 6164            || self
 6165                .debounced_selection_highlight_task
 6166                .as_ref()
 6167                .map_or(true, |(prev_anchor_range, _)| {
 6168                    prev_anchor_range != &query_range
 6169                })
 6170        {
 6171            let multi_buffer_start = multi_buffer_snapshot
 6172                .anchor_before(0)
 6173                .to_point(&multi_buffer_snapshot);
 6174            let multi_buffer_end = multi_buffer_snapshot
 6175                .anchor_after(multi_buffer_snapshot.len())
 6176                .to_point(&multi_buffer_snapshot);
 6177            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6178            self.debounced_selection_highlight_task = Some((
 6179                query_range.clone(),
 6180                self.update_selection_occurrence_highlights(
 6181                    query_text,
 6182                    query_range,
 6183                    multi_buffer_full_range,
 6184                    true,
 6185                    window,
 6186                    cx,
 6187                ),
 6188            ));
 6189        }
 6190    }
 6191
 6192    pub fn refresh_inline_completion(
 6193        &mut self,
 6194        debounce: bool,
 6195        user_requested: bool,
 6196        window: &mut Window,
 6197        cx: &mut Context<Self>,
 6198    ) -> Option<()> {
 6199        let provider = self.edit_prediction_provider()?;
 6200        let cursor = self.selections.newest_anchor().head();
 6201        let (buffer, cursor_buffer_position) =
 6202            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6203
 6204        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6205            self.discard_inline_completion(false, cx);
 6206            return None;
 6207        }
 6208
 6209        if !user_requested
 6210            && (!self.should_show_edit_predictions()
 6211                || !self.is_focused(window)
 6212                || buffer.read(cx).is_empty())
 6213        {
 6214            self.discard_inline_completion(false, cx);
 6215            return None;
 6216        }
 6217
 6218        self.update_visible_inline_completion(window, cx);
 6219        provider.refresh(
 6220            self.project.clone(),
 6221            buffer,
 6222            cursor_buffer_position,
 6223            debounce,
 6224            cx,
 6225        );
 6226        Some(())
 6227    }
 6228
 6229    fn show_edit_predictions_in_menu(&self) -> bool {
 6230        match self.edit_prediction_settings {
 6231            EditPredictionSettings::Disabled => false,
 6232            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6233        }
 6234    }
 6235
 6236    pub fn edit_predictions_enabled(&self) -> bool {
 6237        match self.edit_prediction_settings {
 6238            EditPredictionSettings::Disabled => false,
 6239            EditPredictionSettings::Enabled { .. } => true,
 6240        }
 6241    }
 6242
 6243    fn edit_prediction_requires_modifier(&self) -> bool {
 6244        match self.edit_prediction_settings {
 6245            EditPredictionSettings::Disabled => false,
 6246            EditPredictionSettings::Enabled {
 6247                preview_requires_modifier,
 6248                ..
 6249            } => preview_requires_modifier,
 6250        }
 6251    }
 6252
 6253    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6254        if self.edit_prediction_provider.is_none() {
 6255            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6256        } else {
 6257            let selection = self.selections.newest_anchor();
 6258            let cursor = selection.head();
 6259
 6260            if let Some((buffer, cursor_buffer_position)) =
 6261                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6262            {
 6263                self.edit_prediction_settings =
 6264                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6265            }
 6266        }
 6267    }
 6268
 6269    fn edit_prediction_settings_at_position(
 6270        &self,
 6271        buffer: &Entity<Buffer>,
 6272        buffer_position: language::Anchor,
 6273        cx: &App,
 6274    ) -> EditPredictionSettings {
 6275        if !self.mode.is_full()
 6276            || !self.show_inline_completions_override.unwrap_or(true)
 6277            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6278        {
 6279            return EditPredictionSettings::Disabled;
 6280        }
 6281
 6282        let buffer = buffer.read(cx);
 6283
 6284        let file = buffer.file();
 6285
 6286        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6287            return EditPredictionSettings::Disabled;
 6288        };
 6289
 6290        let by_provider = matches!(
 6291            self.menu_inline_completions_policy,
 6292            MenuInlineCompletionsPolicy::ByProvider
 6293        );
 6294
 6295        let show_in_menu = by_provider
 6296            && self
 6297                .edit_prediction_provider
 6298                .as_ref()
 6299                .map_or(false, |provider| {
 6300                    provider.provider.show_completions_in_menu()
 6301                });
 6302
 6303        let preview_requires_modifier =
 6304            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6305
 6306        EditPredictionSettings::Enabled {
 6307            show_in_menu,
 6308            preview_requires_modifier,
 6309        }
 6310    }
 6311
 6312    fn should_show_edit_predictions(&self) -> bool {
 6313        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6314    }
 6315
 6316    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6317        matches!(
 6318            self.edit_prediction_preview,
 6319            EditPredictionPreview::Active { .. }
 6320        )
 6321    }
 6322
 6323    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6324        let cursor = self.selections.newest_anchor().head();
 6325        if let Some((buffer, cursor_position)) =
 6326            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6327        {
 6328            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6329        } else {
 6330            false
 6331        }
 6332    }
 6333
 6334    pub fn supports_minimap(&self, cx: &App) -> bool {
 6335        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6336    }
 6337
 6338    fn edit_predictions_enabled_in_buffer(
 6339        &self,
 6340        buffer: &Entity<Buffer>,
 6341        buffer_position: language::Anchor,
 6342        cx: &App,
 6343    ) -> bool {
 6344        maybe!({
 6345            if self.read_only(cx) {
 6346                return Some(false);
 6347            }
 6348            let provider = self.edit_prediction_provider()?;
 6349            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6350                return Some(false);
 6351            }
 6352            let buffer = buffer.read(cx);
 6353            let Some(file) = buffer.file() else {
 6354                return Some(true);
 6355            };
 6356            let settings = all_language_settings(Some(file), cx);
 6357            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6358        })
 6359        .unwrap_or(false)
 6360    }
 6361
 6362    fn cycle_inline_completion(
 6363        &mut self,
 6364        direction: Direction,
 6365        window: &mut Window,
 6366        cx: &mut Context<Self>,
 6367    ) -> Option<()> {
 6368        let provider = self.edit_prediction_provider()?;
 6369        let cursor = self.selections.newest_anchor().head();
 6370        let (buffer, cursor_buffer_position) =
 6371            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6372        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6373            return None;
 6374        }
 6375
 6376        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6377        self.update_visible_inline_completion(window, cx);
 6378
 6379        Some(())
 6380    }
 6381
 6382    pub fn show_inline_completion(
 6383        &mut self,
 6384        _: &ShowEditPrediction,
 6385        window: &mut Window,
 6386        cx: &mut Context<Self>,
 6387    ) {
 6388        if !self.has_active_inline_completion() {
 6389            self.refresh_inline_completion(false, true, window, cx);
 6390            return;
 6391        }
 6392
 6393        self.update_visible_inline_completion(window, cx);
 6394    }
 6395
 6396    pub fn display_cursor_names(
 6397        &mut self,
 6398        _: &DisplayCursorNames,
 6399        window: &mut Window,
 6400        cx: &mut Context<Self>,
 6401    ) {
 6402        self.show_cursor_names(window, cx);
 6403    }
 6404
 6405    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6406        self.show_cursor_names = true;
 6407        cx.notify();
 6408        cx.spawn_in(window, async move |this, cx| {
 6409            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6410            this.update(cx, |this, cx| {
 6411                this.show_cursor_names = false;
 6412                cx.notify()
 6413            })
 6414            .ok()
 6415        })
 6416        .detach();
 6417    }
 6418
 6419    pub fn next_edit_prediction(
 6420        &mut self,
 6421        _: &NextEditPrediction,
 6422        window: &mut Window,
 6423        cx: &mut Context<Self>,
 6424    ) {
 6425        if self.has_active_inline_completion() {
 6426            self.cycle_inline_completion(Direction::Next, window, cx);
 6427        } else {
 6428            let is_copilot_disabled = self
 6429                .refresh_inline_completion(false, true, window, cx)
 6430                .is_none();
 6431            if is_copilot_disabled {
 6432                cx.propagate();
 6433            }
 6434        }
 6435    }
 6436
 6437    pub fn previous_edit_prediction(
 6438        &mut self,
 6439        _: &PreviousEditPrediction,
 6440        window: &mut Window,
 6441        cx: &mut Context<Self>,
 6442    ) {
 6443        if self.has_active_inline_completion() {
 6444            self.cycle_inline_completion(Direction::Prev, window, cx);
 6445        } else {
 6446            let is_copilot_disabled = self
 6447                .refresh_inline_completion(false, true, window, cx)
 6448                .is_none();
 6449            if is_copilot_disabled {
 6450                cx.propagate();
 6451            }
 6452        }
 6453    }
 6454
 6455    pub fn accept_edit_prediction(
 6456        &mut self,
 6457        _: &AcceptEditPrediction,
 6458        window: &mut Window,
 6459        cx: &mut Context<Self>,
 6460    ) {
 6461        if self.show_edit_predictions_in_menu() {
 6462            self.hide_context_menu(window, cx);
 6463        }
 6464
 6465        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6466            return;
 6467        };
 6468
 6469        self.report_inline_completion_event(
 6470            active_inline_completion.completion_id.clone(),
 6471            true,
 6472            cx,
 6473        );
 6474
 6475        match &active_inline_completion.completion {
 6476            InlineCompletion::Move { target, .. } => {
 6477                let target = *target;
 6478
 6479                if let Some(position_map) = &self.last_position_map {
 6480                    if position_map
 6481                        .visible_row_range
 6482                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6483                        || !self.edit_prediction_requires_modifier()
 6484                    {
 6485                        self.unfold_ranges(&[target..target], true, false, cx);
 6486                        // Note that this is also done in vim's handler of the Tab action.
 6487                        self.change_selections(
 6488                            Some(Autoscroll::newest()),
 6489                            window,
 6490                            cx,
 6491                            |selections| {
 6492                                selections.select_anchor_ranges([target..target]);
 6493                            },
 6494                        );
 6495                        self.clear_row_highlights::<EditPredictionPreview>();
 6496
 6497                        self.edit_prediction_preview
 6498                            .set_previous_scroll_position(None);
 6499                    } else {
 6500                        self.edit_prediction_preview
 6501                            .set_previous_scroll_position(Some(
 6502                                position_map.snapshot.scroll_anchor,
 6503                            ));
 6504
 6505                        self.highlight_rows::<EditPredictionPreview>(
 6506                            target..target,
 6507                            cx.theme().colors().editor_highlighted_line_background,
 6508                            RowHighlightOptions {
 6509                                autoscroll: true,
 6510                                ..Default::default()
 6511                            },
 6512                            cx,
 6513                        );
 6514                        self.request_autoscroll(Autoscroll::fit(), cx);
 6515                    }
 6516                }
 6517            }
 6518            InlineCompletion::Edit { edits, .. } => {
 6519                if let Some(provider) = self.edit_prediction_provider() {
 6520                    provider.accept(cx);
 6521                }
 6522
 6523                let snapshot = self.buffer.read(cx).snapshot(cx);
 6524                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6525
 6526                self.buffer.update(cx, |buffer, cx| {
 6527                    buffer.edit(edits.iter().cloned(), None, cx)
 6528                });
 6529
 6530                self.change_selections(None, window, cx, |s| {
 6531                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 6532                });
 6533
 6534                self.update_visible_inline_completion(window, cx);
 6535                if self.active_inline_completion.is_none() {
 6536                    self.refresh_inline_completion(true, true, window, cx);
 6537                }
 6538
 6539                cx.notify();
 6540            }
 6541        }
 6542
 6543        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6544    }
 6545
 6546    pub fn accept_partial_inline_completion(
 6547        &mut self,
 6548        _: &AcceptPartialEditPrediction,
 6549        window: &mut Window,
 6550        cx: &mut Context<Self>,
 6551    ) {
 6552        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6553            return;
 6554        };
 6555        if self.selections.count() != 1 {
 6556            return;
 6557        }
 6558
 6559        self.report_inline_completion_event(
 6560            active_inline_completion.completion_id.clone(),
 6561            true,
 6562            cx,
 6563        );
 6564
 6565        match &active_inline_completion.completion {
 6566            InlineCompletion::Move { target, .. } => {
 6567                let target = *target;
 6568                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6569                    selections.select_anchor_ranges([target..target]);
 6570                });
 6571            }
 6572            InlineCompletion::Edit { edits, .. } => {
 6573                // Find an insertion that starts at the cursor position.
 6574                let snapshot = self.buffer.read(cx).snapshot(cx);
 6575                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6576                let insertion = edits.iter().find_map(|(range, text)| {
 6577                    let range = range.to_offset(&snapshot);
 6578                    if range.is_empty() && range.start == cursor_offset {
 6579                        Some(text)
 6580                    } else {
 6581                        None
 6582                    }
 6583                });
 6584
 6585                if let Some(text) = insertion {
 6586                    let mut partial_completion = text
 6587                        .chars()
 6588                        .by_ref()
 6589                        .take_while(|c| c.is_alphabetic())
 6590                        .collect::<String>();
 6591                    if partial_completion.is_empty() {
 6592                        partial_completion = text
 6593                            .chars()
 6594                            .by_ref()
 6595                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6596                            .collect::<String>();
 6597                    }
 6598
 6599                    cx.emit(EditorEvent::InputHandled {
 6600                        utf16_range_to_replace: None,
 6601                        text: partial_completion.clone().into(),
 6602                    });
 6603
 6604                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6605
 6606                    self.refresh_inline_completion(true, true, window, cx);
 6607                    cx.notify();
 6608                } else {
 6609                    self.accept_edit_prediction(&Default::default(), window, cx);
 6610                }
 6611            }
 6612        }
 6613    }
 6614
 6615    fn discard_inline_completion(
 6616        &mut self,
 6617        should_report_inline_completion_event: bool,
 6618        cx: &mut Context<Self>,
 6619    ) -> bool {
 6620        if should_report_inline_completion_event {
 6621            let completion_id = self
 6622                .active_inline_completion
 6623                .as_ref()
 6624                .and_then(|active_completion| active_completion.completion_id.clone());
 6625
 6626            self.report_inline_completion_event(completion_id, false, cx);
 6627        }
 6628
 6629        if let Some(provider) = self.edit_prediction_provider() {
 6630            provider.discard(cx);
 6631        }
 6632
 6633        self.take_active_inline_completion(cx)
 6634    }
 6635
 6636    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6637        let Some(provider) = self.edit_prediction_provider() else {
 6638            return;
 6639        };
 6640
 6641        let Some((_, buffer, _)) = self
 6642            .buffer
 6643            .read(cx)
 6644            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6645        else {
 6646            return;
 6647        };
 6648
 6649        let extension = buffer
 6650            .read(cx)
 6651            .file()
 6652            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6653
 6654        let event_type = match accepted {
 6655            true => "Edit Prediction Accepted",
 6656            false => "Edit Prediction Discarded",
 6657        };
 6658        telemetry::event!(
 6659            event_type,
 6660            provider = provider.name(),
 6661            prediction_id = id,
 6662            suggestion_accepted = accepted,
 6663            file_extension = extension,
 6664        );
 6665    }
 6666
 6667    pub fn has_active_inline_completion(&self) -> bool {
 6668        self.active_inline_completion.is_some()
 6669    }
 6670
 6671    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6672        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6673            return false;
 6674        };
 6675
 6676        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6677        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6678        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6679        true
 6680    }
 6681
 6682    /// Returns true when we're displaying the edit prediction popover below the cursor
 6683    /// like we are not previewing and the LSP autocomplete menu is visible
 6684    /// or we are in `when_holding_modifier` mode.
 6685    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6686        if self.edit_prediction_preview_is_active()
 6687            || !self.show_edit_predictions_in_menu()
 6688            || !self.edit_predictions_enabled()
 6689        {
 6690            return false;
 6691        }
 6692
 6693        if self.has_visible_completions_menu() {
 6694            return true;
 6695        }
 6696
 6697        has_completion && self.edit_prediction_requires_modifier()
 6698    }
 6699
 6700    fn handle_modifiers_changed(
 6701        &mut self,
 6702        modifiers: Modifiers,
 6703        position_map: &PositionMap,
 6704        window: &mut Window,
 6705        cx: &mut Context<Self>,
 6706    ) {
 6707        if self.show_edit_predictions_in_menu() {
 6708            self.update_edit_prediction_preview(&modifiers, window, cx);
 6709        }
 6710
 6711        self.update_selection_mode(&modifiers, position_map, window, cx);
 6712
 6713        let mouse_position = window.mouse_position();
 6714        if !position_map.text_hitbox.is_hovered(window) {
 6715            return;
 6716        }
 6717
 6718        self.update_hovered_link(
 6719            position_map.point_for_position(mouse_position),
 6720            &position_map.snapshot,
 6721            modifiers,
 6722            window,
 6723            cx,
 6724        )
 6725    }
 6726
 6727    fn update_selection_mode(
 6728        &mut self,
 6729        modifiers: &Modifiers,
 6730        position_map: &PositionMap,
 6731        window: &mut Window,
 6732        cx: &mut Context<Self>,
 6733    ) {
 6734        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6735            return;
 6736        }
 6737
 6738        let mouse_position = window.mouse_position();
 6739        let point_for_position = position_map.point_for_position(mouse_position);
 6740        let position = point_for_position.previous_valid;
 6741
 6742        self.select(
 6743            SelectPhase::BeginColumnar {
 6744                position,
 6745                reset: false,
 6746                goal_column: point_for_position.exact_unclipped.column(),
 6747            },
 6748            window,
 6749            cx,
 6750        );
 6751    }
 6752
 6753    fn update_edit_prediction_preview(
 6754        &mut self,
 6755        modifiers: &Modifiers,
 6756        window: &mut Window,
 6757        cx: &mut Context<Self>,
 6758    ) {
 6759        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6760        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6761            return;
 6762        };
 6763
 6764        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6765            if matches!(
 6766                self.edit_prediction_preview,
 6767                EditPredictionPreview::Inactive { .. }
 6768            ) {
 6769                self.edit_prediction_preview = EditPredictionPreview::Active {
 6770                    previous_scroll_position: None,
 6771                    since: Instant::now(),
 6772                };
 6773
 6774                self.update_visible_inline_completion(window, cx);
 6775                cx.notify();
 6776            }
 6777        } else if let EditPredictionPreview::Active {
 6778            previous_scroll_position,
 6779            since,
 6780        } = self.edit_prediction_preview
 6781        {
 6782            if let (Some(previous_scroll_position), Some(position_map)) =
 6783                (previous_scroll_position, self.last_position_map.as_ref())
 6784            {
 6785                self.set_scroll_position(
 6786                    previous_scroll_position
 6787                        .scroll_position(&position_map.snapshot.display_snapshot),
 6788                    window,
 6789                    cx,
 6790                );
 6791            }
 6792
 6793            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6794                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6795            };
 6796            self.clear_row_highlights::<EditPredictionPreview>();
 6797            self.update_visible_inline_completion(window, cx);
 6798            cx.notify();
 6799        }
 6800    }
 6801
 6802    fn update_visible_inline_completion(
 6803        &mut self,
 6804        _window: &mut Window,
 6805        cx: &mut Context<Self>,
 6806    ) -> Option<()> {
 6807        let selection = self.selections.newest_anchor();
 6808        let cursor = selection.head();
 6809        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6810        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6811        let excerpt_id = cursor.excerpt_id;
 6812
 6813        let show_in_menu = self.show_edit_predictions_in_menu();
 6814        let completions_menu_has_precedence = !show_in_menu
 6815            && (self.context_menu.borrow().is_some()
 6816                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6817
 6818        if completions_menu_has_precedence
 6819            || !offset_selection.is_empty()
 6820            || self
 6821                .active_inline_completion
 6822                .as_ref()
 6823                .map_or(false, |completion| {
 6824                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6825                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6826                    !invalidation_range.contains(&offset_selection.head())
 6827                })
 6828        {
 6829            self.discard_inline_completion(false, cx);
 6830            return None;
 6831        }
 6832
 6833        self.take_active_inline_completion(cx);
 6834        let Some(provider) = self.edit_prediction_provider() else {
 6835            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6836            return None;
 6837        };
 6838
 6839        let (buffer, cursor_buffer_position) =
 6840            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6841
 6842        self.edit_prediction_settings =
 6843            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6844
 6845        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6846
 6847        if self.edit_prediction_indent_conflict {
 6848            let cursor_point = cursor.to_point(&multibuffer);
 6849
 6850            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6851
 6852            if let Some((_, indent)) = indents.iter().next() {
 6853                if indent.len == cursor_point.column {
 6854                    self.edit_prediction_indent_conflict = false;
 6855                }
 6856            }
 6857        }
 6858
 6859        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6860        let edits = inline_completion
 6861            .edits
 6862            .into_iter()
 6863            .flat_map(|(range, new_text)| {
 6864                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6865                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6866                Some((start..end, new_text))
 6867            })
 6868            .collect::<Vec<_>>();
 6869        if edits.is_empty() {
 6870            return None;
 6871        }
 6872
 6873        let first_edit_start = edits.first().unwrap().0.start;
 6874        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6875        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6876
 6877        let last_edit_end = edits.last().unwrap().0.end;
 6878        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6879        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6880
 6881        let cursor_row = cursor.to_point(&multibuffer).row;
 6882
 6883        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6884
 6885        let mut inlay_ids = Vec::new();
 6886        let invalidation_row_range;
 6887        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6888            Some(cursor_row..edit_end_row)
 6889        } else if cursor_row > edit_end_row {
 6890            Some(edit_start_row..cursor_row)
 6891        } else {
 6892            None
 6893        };
 6894        let is_move =
 6895            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6896        let completion = if is_move {
 6897            invalidation_row_range =
 6898                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6899            let target = first_edit_start;
 6900            InlineCompletion::Move { target, snapshot }
 6901        } else {
 6902            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6903                && !self.inline_completions_hidden_for_vim_mode;
 6904
 6905            if show_completions_in_buffer {
 6906                if edits
 6907                    .iter()
 6908                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6909                {
 6910                    let mut inlays = Vec::new();
 6911                    for (range, new_text) in &edits {
 6912                        let inlay = Inlay::inline_completion(
 6913                            post_inc(&mut self.next_inlay_id),
 6914                            range.start,
 6915                            new_text.as_str(),
 6916                        );
 6917                        inlay_ids.push(inlay.id);
 6918                        inlays.push(inlay);
 6919                    }
 6920
 6921                    self.splice_inlays(&[], inlays, cx);
 6922                } else {
 6923                    let background_color = cx.theme().status().deleted_background;
 6924                    self.highlight_text::<InlineCompletionHighlight>(
 6925                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6926                        HighlightStyle {
 6927                            background_color: Some(background_color),
 6928                            ..Default::default()
 6929                        },
 6930                        cx,
 6931                    );
 6932                }
 6933            }
 6934
 6935            invalidation_row_range = edit_start_row..edit_end_row;
 6936
 6937            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6938                if provider.show_tab_accept_marker() {
 6939                    EditDisplayMode::TabAccept
 6940                } else {
 6941                    EditDisplayMode::Inline
 6942                }
 6943            } else {
 6944                EditDisplayMode::DiffPopover
 6945            };
 6946
 6947            InlineCompletion::Edit {
 6948                edits,
 6949                edit_preview: inline_completion.edit_preview,
 6950                display_mode,
 6951                snapshot,
 6952            }
 6953        };
 6954
 6955        let invalidation_range = multibuffer
 6956            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6957            ..multibuffer.anchor_after(Point::new(
 6958                invalidation_row_range.end,
 6959                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6960            ));
 6961
 6962        self.stale_inline_completion_in_menu = None;
 6963        self.active_inline_completion = Some(InlineCompletionState {
 6964            inlay_ids,
 6965            completion,
 6966            completion_id: inline_completion.id,
 6967            invalidation_range,
 6968        });
 6969
 6970        cx.notify();
 6971
 6972        Some(())
 6973    }
 6974
 6975    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6976        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6977    }
 6978
 6979    fn clear_tasks(&mut self) {
 6980        self.tasks.clear()
 6981    }
 6982
 6983    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6984        if self.tasks.insert(key, value).is_some() {
 6985            // This case should hopefully be rare, but just in case...
 6986            log::error!(
 6987                "multiple different run targets found on a single line, only the last target will be rendered"
 6988            )
 6989        }
 6990    }
 6991
 6992    /// Get all display points of breakpoints that will be rendered within editor
 6993    ///
 6994    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 6995    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 6996    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 6997    fn active_breakpoints(
 6998        &self,
 6999        range: Range<DisplayRow>,
 7000        window: &mut Window,
 7001        cx: &mut Context<Self>,
 7002    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7003        let mut breakpoint_display_points = HashMap::default();
 7004
 7005        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7006            return breakpoint_display_points;
 7007        };
 7008
 7009        let snapshot = self.snapshot(window, cx);
 7010
 7011        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7012        let Some(project) = self.project.as_ref() else {
 7013            return breakpoint_display_points;
 7014        };
 7015
 7016        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7017            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7018
 7019        for (buffer_snapshot, range, excerpt_id) in
 7020            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7021        {
 7022            let Some(buffer) = project.read_with(cx, |this, cx| {
 7023                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7024            }) else {
 7025                continue;
 7026            };
 7027            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7028                &buffer,
 7029                Some(
 7030                    buffer_snapshot.anchor_before(range.start)
 7031                        ..buffer_snapshot.anchor_after(range.end),
 7032                ),
 7033                buffer_snapshot,
 7034                cx,
 7035            );
 7036            for (breakpoint, state) in breakpoints {
 7037                let multi_buffer_anchor =
 7038                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7039                let position = multi_buffer_anchor
 7040                    .to_point(&multi_buffer_snapshot)
 7041                    .to_display_point(&snapshot);
 7042
 7043                breakpoint_display_points.insert(
 7044                    position.row(),
 7045                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7046                );
 7047            }
 7048        }
 7049
 7050        breakpoint_display_points
 7051    }
 7052
 7053    fn breakpoint_context_menu(
 7054        &self,
 7055        anchor: Anchor,
 7056        window: &mut Window,
 7057        cx: &mut Context<Self>,
 7058    ) -> Entity<ui::ContextMenu> {
 7059        let weak_editor = cx.weak_entity();
 7060        let focus_handle = self.focus_handle(cx);
 7061
 7062        let row = self
 7063            .buffer
 7064            .read(cx)
 7065            .snapshot(cx)
 7066            .summary_for_anchor::<Point>(&anchor)
 7067            .row;
 7068
 7069        let breakpoint = self
 7070            .breakpoint_at_row(row, window, cx)
 7071            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7072
 7073        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7074            "Edit Log Breakpoint"
 7075        } else {
 7076            "Set Log Breakpoint"
 7077        };
 7078
 7079        let condition_breakpoint_msg = if breakpoint
 7080            .as_ref()
 7081            .is_some_and(|bp| bp.1.condition.is_some())
 7082        {
 7083            "Edit Condition Breakpoint"
 7084        } else {
 7085            "Set Condition Breakpoint"
 7086        };
 7087
 7088        let hit_condition_breakpoint_msg = if breakpoint
 7089            .as_ref()
 7090            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7091        {
 7092            "Edit Hit Condition Breakpoint"
 7093        } else {
 7094            "Set Hit Condition Breakpoint"
 7095        };
 7096
 7097        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7098            "Unset Breakpoint"
 7099        } else {
 7100            "Set Breakpoint"
 7101        };
 7102
 7103        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7104            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7105
 7106        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7107            BreakpointState::Enabled => Some("Disable"),
 7108            BreakpointState::Disabled => Some("Enable"),
 7109        });
 7110
 7111        let (anchor, breakpoint) =
 7112            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7113
 7114        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7115            menu.on_blur_subscription(Subscription::new(|| {}))
 7116                .context(focus_handle)
 7117                .when(run_to_cursor, |this| {
 7118                    let weak_editor = weak_editor.clone();
 7119                    this.entry("Run to cursor", None, move |window, cx| {
 7120                        weak_editor
 7121                            .update(cx, |editor, cx| {
 7122                                editor.change_selections(None, window, cx, |s| {
 7123                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7124                                });
 7125                            })
 7126                            .ok();
 7127
 7128                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7129                    })
 7130                    .separator()
 7131                })
 7132                .when_some(toggle_state_msg, |this, msg| {
 7133                    this.entry(msg, None, {
 7134                        let weak_editor = weak_editor.clone();
 7135                        let breakpoint = breakpoint.clone();
 7136                        move |_window, cx| {
 7137                            weak_editor
 7138                                .update(cx, |this, cx| {
 7139                                    this.edit_breakpoint_at_anchor(
 7140                                        anchor,
 7141                                        breakpoint.as_ref().clone(),
 7142                                        BreakpointEditAction::InvertState,
 7143                                        cx,
 7144                                    );
 7145                                })
 7146                                .log_err();
 7147                        }
 7148                    })
 7149                })
 7150                .entry(set_breakpoint_msg, None, {
 7151                    let weak_editor = weak_editor.clone();
 7152                    let breakpoint = breakpoint.clone();
 7153                    move |_window, cx| {
 7154                        weak_editor
 7155                            .update(cx, |this, cx| {
 7156                                this.edit_breakpoint_at_anchor(
 7157                                    anchor,
 7158                                    breakpoint.as_ref().clone(),
 7159                                    BreakpointEditAction::Toggle,
 7160                                    cx,
 7161                                );
 7162                            })
 7163                            .log_err();
 7164                    }
 7165                })
 7166                .entry(log_breakpoint_msg, None, {
 7167                    let breakpoint = breakpoint.clone();
 7168                    let weak_editor = weak_editor.clone();
 7169                    move |window, cx| {
 7170                        weak_editor
 7171                            .update(cx, |this, cx| {
 7172                                this.add_edit_breakpoint_block(
 7173                                    anchor,
 7174                                    breakpoint.as_ref(),
 7175                                    BreakpointPromptEditAction::Log,
 7176                                    window,
 7177                                    cx,
 7178                                );
 7179                            })
 7180                            .log_err();
 7181                    }
 7182                })
 7183                .entry(condition_breakpoint_msg, None, {
 7184                    let breakpoint = breakpoint.clone();
 7185                    let weak_editor = weak_editor.clone();
 7186                    move |window, cx| {
 7187                        weak_editor
 7188                            .update(cx, |this, cx| {
 7189                                this.add_edit_breakpoint_block(
 7190                                    anchor,
 7191                                    breakpoint.as_ref(),
 7192                                    BreakpointPromptEditAction::Condition,
 7193                                    window,
 7194                                    cx,
 7195                                );
 7196                            })
 7197                            .log_err();
 7198                    }
 7199                })
 7200                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7201                    weak_editor
 7202                        .update(cx, |this, cx| {
 7203                            this.add_edit_breakpoint_block(
 7204                                anchor,
 7205                                breakpoint.as_ref(),
 7206                                BreakpointPromptEditAction::HitCondition,
 7207                                window,
 7208                                cx,
 7209                            );
 7210                        })
 7211                        .log_err();
 7212                })
 7213        })
 7214    }
 7215
 7216    fn render_breakpoint(
 7217        &self,
 7218        position: Anchor,
 7219        row: DisplayRow,
 7220        breakpoint: &Breakpoint,
 7221        state: Option<BreakpointSessionState>,
 7222        cx: &mut Context<Self>,
 7223    ) -> IconButton {
 7224        let is_rejected = state.is_some_and(|s| !s.verified);
 7225        // Is it a breakpoint that shows up when hovering over gutter?
 7226        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7227            (false, false),
 7228            |PhantomBreakpointIndicator {
 7229                 is_active,
 7230                 display_row,
 7231                 collides_with_existing_breakpoint,
 7232             }| {
 7233                (
 7234                    is_active && display_row == row,
 7235                    collides_with_existing_breakpoint,
 7236                )
 7237            },
 7238        );
 7239
 7240        let (color, icon) = {
 7241            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7242                (false, false) => ui::IconName::DebugBreakpoint,
 7243                (true, false) => ui::IconName::DebugLogBreakpoint,
 7244                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7245                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7246            };
 7247
 7248            let color = if is_phantom {
 7249                Color::Hint
 7250            } else if is_rejected {
 7251                Color::Disabled
 7252            } else {
 7253                Color::Debugger
 7254            };
 7255
 7256            (color, icon)
 7257        };
 7258
 7259        let breakpoint = Arc::from(breakpoint.clone());
 7260
 7261        let alt_as_text = gpui::Keystroke {
 7262            modifiers: Modifiers::secondary_key(),
 7263            ..Default::default()
 7264        };
 7265        let primary_action_text = if breakpoint.is_disabled() {
 7266            "enable"
 7267        } else if is_phantom && !collides_with_existing {
 7268            "set"
 7269        } else {
 7270            "unset"
 7271        };
 7272        let mut primary_text = format!("Click to {primary_action_text}");
 7273        if collides_with_existing && !breakpoint.is_disabled() {
 7274            use std::fmt::Write;
 7275            write!(primary_text, ", {alt_as_text}-click to disable").ok();
 7276        }
 7277        let primary_text = SharedString::from(primary_text);
 7278        let focus_handle = self.focus_handle.clone();
 7279
 7280        let meta = if is_rejected {
 7281            "No executable code is associated with this line."
 7282        } else {
 7283            "Right-click for more options."
 7284        };
 7285        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7286            .icon_size(IconSize::XSmall)
 7287            .size(ui::ButtonSize::None)
 7288            .when(is_rejected, |this| {
 7289                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7290            })
 7291            .icon_color(color)
 7292            .style(ButtonStyle::Transparent)
 7293            .on_click(cx.listener({
 7294                let breakpoint = breakpoint.clone();
 7295
 7296                move |editor, event: &ClickEvent, window, cx| {
 7297                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7298                        BreakpointEditAction::InvertState
 7299                    } else {
 7300                        BreakpointEditAction::Toggle
 7301                    };
 7302
 7303                    window.focus(&editor.focus_handle(cx));
 7304                    editor.edit_breakpoint_at_anchor(
 7305                        position,
 7306                        breakpoint.as_ref().clone(),
 7307                        edit_action,
 7308                        cx,
 7309                    );
 7310                }
 7311            }))
 7312            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7313                editor.set_breakpoint_context_menu(
 7314                    row,
 7315                    Some(position),
 7316                    event.down.position,
 7317                    window,
 7318                    cx,
 7319                );
 7320            }))
 7321            .tooltip(move |window, cx| {
 7322                Tooltip::with_meta_in(primary_text.clone(), None, meta, &focus_handle, window, cx)
 7323            })
 7324    }
 7325
 7326    fn build_tasks_context(
 7327        project: &Entity<Project>,
 7328        buffer: &Entity<Buffer>,
 7329        buffer_row: u32,
 7330        tasks: &Arc<RunnableTasks>,
 7331        cx: &mut Context<Self>,
 7332    ) -> Task<Option<task::TaskContext>> {
 7333        let position = Point::new(buffer_row, tasks.column);
 7334        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7335        let location = Location {
 7336            buffer: buffer.clone(),
 7337            range: range_start..range_start,
 7338        };
 7339        // Fill in the environmental variables from the tree-sitter captures
 7340        let mut captured_task_variables = TaskVariables::default();
 7341        for (capture_name, value) in tasks.extra_variables.clone() {
 7342            captured_task_variables.insert(
 7343                task::VariableName::Custom(capture_name.into()),
 7344                value.clone(),
 7345            );
 7346        }
 7347        project.update(cx, |project, cx| {
 7348            project.task_store().update(cx, |task_store, cx| {
 7349                task_store.task_context_for_location(captured_task_variables, location, cx)
 7350            })
 7351        })
 7352    }
 7353
 7354    pub fn spawn_nearest_task(
 7355        &mut self,
 7356        action: &SpawnNearestTask,
 7357        window: &mut Window,
 7358        cx: &mut Context<Self>,
 7359    ) {
 7360        let Some((workspace, _)) = self.workspace.clone() else {
 7361            return;
 7362        };
 7363        let Some(project) = self.project.clone() else {
 7364            return;
 7365        };
 7366
 7367        // Try to find a closest, enclosing node using tree-sitter that has a
 7368        // task
 7369        let Some((buffer, buffer_row, tasks)) = self
 7370            .find_enclosing_node_task(cx)
 7371            // Or find the task that's closest in row-distance.
 7372            .or_else(|| self.find_closest_task(cx))
 7373        else {
 7374            return;
 7375        };
 7376
 7377        let reveal_strategy = action.reveal;
 7378        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7379        cx.spawn_in(window, async move |_, cx| {
 7380            let context = task_context.await?;
 7381            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7382
 7383            let resolved = &mut resolved_task.resolved;
 7384            resolved.reveal = reveal_strategy;
 7385
 7386            workspace
 7387                .update_in(cx, |workspace, window, cx| {
 7388                    workspace.schedule_resolved_task(
 7389                        task_source_kind,
 7390                        resolved_task,
 7391                        false,
 7392                        window,
 7393                        cx,
 7394                    );
 7395                })
 7396                .ok()
 7397        })
 7398        .detach();
 7399    }
 7400
 7401    fn find_closest_task(
 7402        &mut self,
 7403        cx: &mut Context<Self>,
 7404    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7405        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7406
 7407        let ((buffer_id, row), tasks) = self
 7408            .tasks
 7409            .iter()
 7410            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7411
 7412        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7413        let tasks = Arc::new(tasks.to_owned());
 7414        Some((buffer, *row, tasks))
 7415    }
 7416
 7417    fn find_enclosing_node_task(
 7418        &mut self,
 7419        cx: &mut Context<Self>,
 7420    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7421        let snapshot = self.buffer.read(cx).snapshot(cx);
 7422        let offset = self.selections.newest::<usize>(cx).head();
 7423        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7424        let buffer_id = excerpt.buffer().remote_id();
 7425
 7426        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7427        let mut cursor = layer.node().walk();
 7428
 7429        while cursor.goto_first_child_for_byte(offset).is_some() {
 7430            if cursor.node().end_byte() == offset {
 7431                cursor.goto_next_sibling();
 7432            }
 7433        }
 7434
 7435        // Ascend to the smallest ancestor that contains the range and has a task.
 7436        loop {
 7437            let node = cursor.node();
 7438            let node_range = node.byte_range();
 7439            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7440
 7441            // Check if this node contains our offset
 7442            if node_range.start <= offset && node_range.end >= offset {
 7443                // If it contains offset, check for task
 7444                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7445                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7446                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7447                }
 7448            }
 7449
 7450            if !cursor.goto_parent() {
 7451                break;
 7452            }
 7453        }
 7454        None
 7455    }
 7456
 7457    fn render_run_indicator(
 7458        &self,
 7459        _style: &EditorStyle,
 7460        is_active: bool,
 7461        row: DisplayRow,
 7462        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7463        cx: &mut Context<Self>,
 7464    ) -> IconButton {
 7465        let color = Color::Muted;
 7466        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7467
 7468        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7469            .shape(ui::IconButtonShape::Square)
 7470            .icon_size(IconSize::XSmall)
 7471            .icon_color(color)
 7472            .toggle_state(is_active)
 7473            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7474                let quick_launch = e.down.button == MouseButton::Left;
 7475                window.focus(&editor.focus_handle(cx));
 7476                editor.toggle_code_actions(
 7477                    &ToggleCodeActions {
 7478                        deployed_from_indicator: Some(row),
 7479                        quick_launch,
 7480                    },
 7481                    window,
 7482                    cx,
 7483                );
 7484            }))
 7485            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7486                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7487            }))
 7488    }
 7489
 7490    pub fn context_menu_visible(&self) -> bool {
 7491        !self.edit_prediction_preview_is_active()
 7492            && self
 7493                .context_menu
 7494                .borrow()
 7495                .as_ref()
 7496                .map_or(false, |menu| menu.visible())
 7497    }
 7498
 7499    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7500        self.context_menu
 7501            .borrow()
 7502            .as_ref()
 7503            .map(|menu| menu.origin())
 7504    }
 7505
 7506    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7507        self.context_menu_options = Some(options);
 7508    }
 7509
 7510    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7511    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7512
 7513    fn render_edit_prediction_popover(
 7514        &mut self,
 7515        text_bounds: &Bounds<Pixels>,
 7516        content_origin: gpui::Point<Pixels>,
 7517        right_margin: Pixels,
 7518        editor_snapshot: &EditorSnapshot,
 7519        visible_row_range: Range<DisplayRow>,
 7520        scroll_top: f32,
 7521        scroll_bottom: f32,
 7522        line_layouts: &[LineWithInvisibles],
 7523        line_height: Pixels,
 7524        scroll_pixel_position: gpui::Point<Pixels>,
 7525        newest_selection_head: Option<DisplayPoint>,
 7526        editor_width: Pixels,
 7527        style: &EditorStyle,
 7528        window: &mut Window,
 7529        cx: &mut App,
 7530    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7531        if self.mode().is_minimap() {
 7532            return None;
 7533        }
 7534        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7535
 7536        if self.edit_prediction_visible_in_cursor_popover(true) {
 7537            return None;
 7538        }
 7539
 7540        match &active_inline_completion.completion {
 7541            InlineCompletion::Move { target, .. } => {
 7542                let target_display_point = target.to_display_point(editor_snapshot);
 7543
 7544                if self.edit_prediction_requires_modifier() {
 7545                    if !self.edit_prediction_preview_is_active() {
 7546                        return None;
 7547                    }
 7548
 7549                    self.render_edit_prediction_modifier_jump_popover(
 7550                        text_bounds,
 7551                        content_origin,
 7552                        visible_row_range,
 7553                        line_layouts,
 7554                        line_height,
 7555                        scroll_pixel_position,
 7556                        newest_selection_head,
 7557                        target_display_point,
 7558                        window,
 7559                        cx,
 7560                    )
 7561                } else {
 7562                    self.render_edit_prediction_eager_jump_popover(
 7563                        text_bounds,
 7564                        content_origin,
 7565                        editor_snapshot,
 7566                        visible_row_range,
 7567                        scroll_top,
 7568                        scroll_bottom,
 7569                        line_height,
 7570                        scroll_pixel_position,
 7571                        target_display_point,
 7572                        editor_width,
 7573                        window,
 7574                        cx,
 7575                    )
 7576                }
 7577            }
 7578            InlineCompletion::Edit {
 7579                display_mode: EditDisplayMode::Inline,
 7580                ..
 7581            } => None,
 7582            InlineCompletion::Edit {
 7583                display_mode: EditDisplayMode::TabAccept,
 7584                edits,
 7585                ..
 7586            } => {
 7587                let range = &edits.first()?.0;
 7588                let target_display_point = range.end.to_display_point(editor_snapshot);
 7589
 7590                self.render_edit_prediction_end_of_line_popover(
 7591                    "Accept",
 7592                    editor_snapshot,
 7593                    visible_row_range,
 7594                    target_display_point,
 7595                    line_height,
 7596                    scroll_pixel_position,
 7597                    content_origin,
 7598                    editor_width,
 7599                    window,
 7600                    cx,
 7601                )
 7602            }
 7603            InlineCompletion::Edit {
 7604                edits,
 7605                edit_preview,
 7606                display_mode: EditDisplayMode::DiffPopover,
 7607                snapshot,
 7608            } => self.render_edit_prediction_diff_popover(
 7609                text_bounds,
 7610                content_origin,
 7611                right_margin,
 7612                editor_snapshot,
 7613                visible_row_range,
 7614                line_layouts,
 7615                line_height,
 7616                scroll_pixel_position,
 7617                newest_selection_head,
 7618                editor_width,
 7619                style,
 7620                edits,
 7621                edit_preview,
 7622                snapshot,
 7623                window,
 7624                cx,
 7625            ),
 7626        }
 7627    }
 7628
 7629    fn render_edit_prediction_modifier_jump_popover(
 7630        &mut self,
 7631        text_bounds: &Bounds<Pixels>,
 7632        content_origin: gpui::Point<Pixels>,
 7633        visible_row_range: Range<DisplayRow>,
 7634        line_layouts: &[LineWithInvisibles],
 7635        line_height: Pixels,
 7636        scroll_pixel_position: gpui::Point<Pixels>,
 7637        newest_selection_head: Option<DisplayPoint>,
 7638        target_display_point: DisplayPoint,
 7639        window: &mut Window,
 7640        cx: &mut App,
 7641    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7642        let scrolled_content_origin =
 7643            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7644
 7645        const SCROLL_PADDING_Y: Pixels = px(12.);
 7646
 7647        if target_display_point.row() < visible_row_range.start {
 7648            return self.render_edit_prediction_scroll_popover(
 7649                |_| SCROLL_PADDING_Y,
 7650                IconName::ArrowUp,
 7651                visible_row_range,
 7652                line_layouts,
 7653                newest_selection_head,
 7654                scrolled_content_origin,
 7655                window,
 7656                cx,
 7657            );
 7658        } else if target_display_point.row() >= visible_row_range.end {
 7659            return self.render_edit_prediction_scroll_popover(
 7660                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7661                IconName::ArrowDown,
 7662                visible_row_range,
 7663                line_layouts,
 7664                newest_selection_head,
 7665                scrolled_content_origin,
 7666                window,
 7667                cx,
 7668            );
 7669        }
 7670
 7671        const POLE_WIDTH: Pixels = px(2.);
 7672
 7673        let line_layout =
 7674            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7675        let target_column = target_display_point.column() as usize;
 7676
 7677        let target_x = line_layout.x_for_index(target_column);
 7678        let target_y =
 7679            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7680
 7681        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7682
 7683        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7684        border_color.l += 0.001;
 7685
 7686        let mut element = v_flex()
 7687            .items_end()
 7688            .when(flag_on_right, |el| el.items_start())
 7689            .child(if flag_on_right {
 7690                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7691                    .rounded_bl(px(0.))
 7692                    .rounded_tl(px(0.))
 7693                    .border_l_2()
 7694                    .border_color(border_color)
 7695            } else {
 7696                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7697                    .rounded_br(px(0.))
 7698                    .rounded_tr(px(0.))
 7699                    .border_r_2()
 7700                    .border_color(border_color)
 7701            })
 7702            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7703            .into_any();
 7704
 7705        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7706
 7707        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7708            - point(
 7709                if flag_on_right {
 7710                    POLE_WIDTH
 7711                } else {
 7712                    size.width - POLE_WIDTH
 7713                },
 7714                size.height - line_height,
 7715            );
 7716
 7717        origin.x = origin.x.max(content_origin.x);
 7718
 7719        element.prepaint_at(origin, window, cx);
 7720
 7721        Some((element, origin))
 7722    }
 7723
 7724    fn render_edit_prediction_scroll_popover(
 7725        &mut self,
 7726        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7727        scroll_icon: IconName,
 7728        visible_row_range: Range<DisplayRow>,
 7729        line_layouts: &[LineWithInvisibles],
 7730        newest_selection_head: Option<DisplayPoint>,
 7731        scrolled_content_origin: gpui::Point<Pixels>,
 7732        window: &mut Window,
 7733        cx: &mut App,
 7734    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7735        let mut element = self
 7736            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7737            .into_any();
 7738
 7739        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7740
 7741        let cursor = newest_selection_head?;
 7742        let cursor_row_layout =
 7743            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7744        let cursor_column = cursor.column() as usize;
 7745
 7746        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7747
 7748        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7749
 7750        element.prepaint_at(origin, window, cx);
 7751        Some((element, origin))
 7752    }
 7753
 7754    fn render_edit_prediction_eager_jump_popover(
 7755        &mut self,
 7756        text_bounds: &Bounds<Pixels>,
 7757        content_origin: gpui::Point<Pixels>,
 7758        editor_snapshot: &EditorSnapshot,
 7759        visible_row_range: Range<DisplayRow>,
 7760        scroll_top: f32,
 7761        scroll_bottom: f32,
 7762        line_height: Pixels,
 7763        scroll_pixel_position: gpui::Point<Pixels>,
 7764        target_display_point: DisplayPoint,
 7765        editor_width: Pixels,
 7766        window: &mut Window,
 7767        cx: &mut App,
 7768    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7769        if target_display_point.row().as_f32() < scroll_top {
 7770            let mut element = self
 7771                .render_edit_prediction_line_popover(
 7772                    "Jump to Edit",
 7773                    Some(IconName::ArrowUp),
 7774                    window,
 7775                    cx,
 7776                )?
 7777                .into_any();
 7778
 7779            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7780            let offset = point(
 7781                (text_bounds.size.width - size.width) / 2.,
 7782                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7783            );
 7784
 7785            let origin = text_bounds.origin + offset;
 7786            element.prepaint_at(origin, window, cx);
 7787            Some((element, origin))
 7788        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7789            let mut element = self
 7790                .render_edit_prediction_line_popover(
 7791                    "Jump to Edit",
 7792                    Some(IconName::ArrowDown),
 7793                    window,
 7794                    cx,
 7795                )?
 7796                .into_any();
 7797
 7798            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7799            let offset = point(
 7800                (text_bounds.size.width - size.width) / 2.,
 7801                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7802            );
 7803
 7804            let origin = text_bounds.origin + offset;
 7805            element.prepaint_at(origin, window, cx);
 7806            Some((element, origin))
 7807        } else {
 7808            self.render_edit_prediction_end_of_line_popover(
 7809                "Jump to Edit",
 7810                editor_snapshot,
 7811                visible_row_range,
 7812                target_display_point,
 7813                line_height,
 7814                scroll_pixel_position,
 7815                content_origin,
 7816                editor_width,
 7817                window,
 7818                cx,
 7819            )
 7820        }
 7821    }
 7822
 7823    fn render_edit_prediction_end_of_line_popover(
 7824        self: &mut Editor,
 7825        label: &'static str,
 7826        editor_snapshot: &EditorSnapshot,
 7827        visible_row_range: Range<DisplayRow>,
 7828        target_display_point: DisplayPoint,
 7829        line_height: Pixels,
 7830        scroll_pixel_position: gpui::Point<Pixels>,
 7831        content_origin: gpui::Point<Pixels>,
 7832        editor_width: Pixels,
 7833        window: &mut Window,
 7834        cx: &mut App,
 7835    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7836        let target_line_end = DisplayPoint::new(
 7837            target_display_point.row(),
 7838            editor_snapshot.line_len(target_display_point.row()),
 7839        );
 7840
 7841        let mut element = self
 7842            .render_edit_prediction_line_popover(label, None, window, cx)?
 7843            .into_any();
 7844
 7845        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7846
 7847        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7848
 7849        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7850        let mut origin = start_point
 7851            + line_origin
 7852            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7853        origin.x = origin.x.max(content_origin.x);
 7854
 7855        let max_x = content_origin.x + editor_width - size.width;
 7856
 7857        if origin.x > max_x {
 7858            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7859
 7860            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7861                origin.y += offset;
 7862                IconName::ArrowUp
 7863            } else {
 7864                origin.y -= offset;
 7865                IconName::ArrowDown
 7866            };
 7867
 7868            element = self
 7869                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7870                .into_any();
 7871
 7872            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7873
 7874            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7875        }
 7876
 7877        element.prepaint_at(origin, window, cx);
 7878        Some((element, origin))
 7879    }
 7880
 7881    fn render_edit_prediction_diff_popover(
 7882        self: &Editor,
 7883        text_bounds: &Bounds<Pixels>,
 7884        content_origin: gpui::Point<Pixels>,
 7885        right_margin: Pixels,
 7886        editor_snapshot: &EditorSnapshot,
 7887        visible_row_range: Range<DisplayRow>,
 7888        line_layouts: &[LineWithInvisibles],
 7889        line_height: Pixels,
 7890        scroll_pixel_position: gpui::Point<Pixels>,
 7891        newest_selection_head: Option<DisplayPoint>,
 7892        editor_width: Pixels,
 7893        style: &EditorStyle,
 7894        edits: &Vec<(Range<Anchor>, String)>,
 7895        edit_preview: &Option<language::EditPreview>,
 7896        snapshot: &language::BufferSnapshot,
 7897        window: &mut Window,
 7898        cx: &mut App,
 7899    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7900        let edit_start = edits
 7901            .first()
 7902            .unwrap()
 7903            .0
 7904            .start
 7905            .to_display_point(editor_snapshot);
 7906        let edit_end = edits
 7907            .last()
 7908            .unwrap()
 7909            .0
 7910            .end
 7911            .to_display_point(editor_snapshot);
 7912
 7913        let is_visible = visible_row_range.contains(&edit_start.row())
 7914            || visible_row_range.contains(&edit_end.row());
 7915        if !is_visible {
 7916            return None;
 7917        }
 7918
 7919        let highlighted_edits =
 7920            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7921
 7922        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7923        let line_count = highlighted_edits.text.lines().count();
 7924
 7925        const BORDER_WIDTH: Pixels = px(1.);
 7926
 7927        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7928        let has_keybind = keybind.is_some();
 7929
 7930        let mut element = h_flex()
 7931            .items_start()
 7932            .child(
 7933                h_flex()
 7934                    .bg(cx.theme().colors().editor_background)
 7935                    .border(BORDER_WIDTH)
 7936                    .shadow_sm()
 7937                    .border_color(cx.theme().colors().border)
 7938                    .rounded_l_lg()
 7939                    .when(line_count > 1, |el| el.rounded_br_lg())
 7940                    .pr_1()
 7941                    .child(styled_text),
 7942            )
 7943            .child(
 7944                h_flex()
 7945                    .h(line_height + BORDER_WIDTH * 2.)
 7946                    .px_1p5()
 7947                    .gap_1()
 7948                    // Workaround: For some reason, there's a gap if we don't do this
 7949                    .ml(-BORDER_WIDTH)
 7950                    .shadow(smallvec![gpui::BoxShadow {
 7951                        color: gpui::black().opacity(0.05),
 7952                        offset: point(px(1.), px(1.)),
 7953                        blur_radius: px(2.),
 7954                        spread_radius: px(0.),
 7955                    }])
 7956                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7957                    .border(BORDER_WIDTH)
 7958                    .border_color(cx.theme().colors().border)
 7959                    .rounded_r_lg()
 7960                    .id("edit_prediction_diff_popover_keybind")
 7961                    .when(!has_keybind, |el| {
 7962                        let status_colors = cx.theme().status();
 7963
 7964                        el.bg(status_colors.error_background)
 7965                            .border_color(status_colors.error.opacity(0.6))
 7966                            .child(Icon::new(IconName::Info).color(Color::Error))
 7967                            .cursor_default()
 7968                            .hoverable_tooltip(move |_window, cx| {
 7969                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7970                            })
 7971                    })
 7972                    .children(keybind),
 7973            )
 7974            .into_any();
 7975
 7976        let longest_row =
 7977            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7978        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7979            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7980        } else {
 7981            layout_line(
 7982                longest_row,
 7983                editor_snapshot,
 7984                style,
 7985                editor_width,
 7986                |_| false,
 7987                window,
 7988                cx,
 7989            )
 7990            .width
 7991        };
 7992
 7993        let viewport_bounds =
 7994            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 7995                right: -right_margin,
 7996                ..Default::default()
 7997            });
 7998
 7999        let x_after_longest =
 8000            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8001                - scroll_pixel_position.x;
 8002
 8003        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8004
 8005        // Fully visible if it can be displayed within the window (allow overlapping other
 8006        // panes). However, this is only allowed if the popover starts within text_bounds.
 8007        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8008            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8009
 8010        let mut origin = if can_position_to_the_right {
 8011            point(
 8012                x_after_longest,
 8013                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8014                    - scroll_pixel_position.y,
 8015            )
 8016        } else {
 8017            let cursor_row = newest_selection_head.map(|head| head.row());
 8018            let above_edit = edit_start
 8019                .row()
 8020                .0
 8021                .checked_sub(line_count as u32)
 8022                .map(DisplayRow);
 8023            let below_edit = Some(edit_end.row() + 1);
 8024            let above_cursor =
 8025                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8026            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8027
 8028            // Place the edit popover adjacent to the edit if there is a location
 8029            // available that is onscreen and does not obscure the cursor. Otherwise,
 8030            // place it adjacent to the cursor.
 8031            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8032                .into_iter()
 8033                .flatten()
 8034                .find(|&start_row| {
 8035                    let end_row = start_row + line_count as u32;
 8036                    visible_row_range.contains(&start_row)
 8037                        && visible_row_range.contains(&end_row)
 8038                        && cursor_row.map_or(true, |cursor_row| {
 8039                            !((start_row..end_row).contains(&cursor_row))
 8040                        })
 8041                })?;
 8042
 8043            content_origin
 8044                + point(
 8045                    -scroll_pixel_position.x,
 8046                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8047                )
 8048        };
 8049
 8050        origin.x -= BORDER_WIDTH;
 8051
 8052        window.defer_draw(element, origin, 1);
 8053
 8054        // Do not return an element, since it will already be drawn due to defer_draw.
 8055        None
 8056    }
 8057
 8058    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8059        px(30.)
 8060    }
 8061
 8062    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8063        if self.read_only(cx) {
 8064            cx.theme().players().read_only()
 8065        } else {
 8066            self.style.as_ref().unwrap().local_player
 8067        }
 8068    }
 8069
 8070    fn render_edit_prediction_accept_keybind(
 8071        &self,
 8072        window: &mut Window,
 8073        cx: &App,
 8074    ) -> Option<AnyElement> {
 8075        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8076        let accept_keystroke = accept_binding.keystroke()?;
 8077
 8078        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8079
 8080        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8081            Color::Accent
 8082        } else {
 8083            Color::Muted
 8084        };
 8085
 8086        h_flex()
 8087            .px_0p5()
 8088            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8089            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8090            .text_size(TextSize::XSmall.rems(cx))
 8091            .child(h_flex().children(ui::render_modifiers(
 8092                &accept_keystroke.modifiers,
 8093                PlatformStyle::platform(),
 8094                Some(modifiers_color),
 8095                Some(IconSize::XSmall.rems().into()),
 8096                true,
 8097            )))
 8098            .when(is_platform_style_mac, |parent| {
 8099                parent.child(accept_keystroke.key.clone())
 8100            })
 8101            .when(!is_platform_style_mac, |parent| {
 8102                parent.child(
 8103                    Key::new(
 8104                        util::capitalize(&accept_keystroke.key),
 8105                        Some(Color::Default),
 8106                    )
 8107                    .size(Some(IconSize::XSmall.rems().into())),
 8108                )
 8109            })
 8110            .into_any()
 8111            .into()
 8112    }
 8113
 8114    fn render_edit_prediction_line_popover(
 8115        &self,
 8116        label: impl Into<SharedString>,
 8117        icon: Option<IconName>,
 8118        window: &mut Window,
 8119        cx: &App,
 8120    ) -> Option<Stateful<Div>> {
 8121        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8122
 8123        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8124        let has_keybind = keybind.is_some();
 8125
 8126        let result = h_flex()
 8127            .id("ep-line-popover")
 8128            .py_0p5()
 8129            .pl_1()
 8130            .pr(padding_right)
 8131            .gap_1()
 8132            .rounded_md()
 8133            .border_1()
 8134            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8135            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8136            .shadow_sm()
 8137            .when(!has_keybind, |el| {
 8138                let status_colors = cx.theme().status();
 8139
 8140                el.bg(status_colors.error_background)
 8141                    .border_color(status_colors.error.opacity(0.6))
 8142                    .pl_2()
 8143                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8144                    .cursor_default()
 8145                    .hoverable_tooltip(move |_window, cx| {
 8146                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8147                    })
 8148            })
 8149            .children(keybind)
 8150            .child(
 8151                Label::new(label)
 8152                    .size(LabelSize::Small)
 8153                    .when(!has_keybind, |el| {
 8154                        el.color(cx.theme().status().error.into()).strikethrough()
 8155                    }),
 8156            )
 8157            .when(!has_keybind, |el| {
 8158                el.child(
 8159                    h_flex().ml_1().child(
 8160                        Icon::new(IconName::Info)
 8161                            .size(IconSize::Small)
 8162                            .color(cx.theme().status().error.into()),
 8163                    ),
 8164                )
 8165            })
 8166            .when_some(icon, |element, icon| {
 8167                element.child(
 8168                    div()
 8169                        .mt(px(1.5))
 8170                        .child(Icon::new(icon).size(IconSize::Small)),
 8171                )
 8172            });
 8173
 8174        Some(result)
 8175    }
 8176
 8177    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8178        let accent_color = cx.theme().colors().text_accent;
 8179        let editor_bg_color = cx.theme().colors().editor_background;
 8180        editor_bg_color.blend(accent_color.opacity(0.1))
 8181    }
 8182
 8183    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8184        let accent_color = cx.theme().colors().text_accent;
 8185        let editor_bg_color = cx.theme().colors().editor_background;
 8186        editor_bg_color.blend(accent_color.opacity(0.6))
 8187    }
 8188
 8189    fn render_edit_prediction_cursor_popover(
 8190        &self,
 8191        min_width: Pixels,
 8192        max_width: Pixels,
 8193        cursor_point: Point,
 8194        style: &EditorStyle,
 8195        accept_keystroke: Option<&gpui::Keystroke>,
 8196        _window: &Window,
 8197        cx: &mut Context<Editor>,
 8198    ) -> Option<AnyElement> {
 8199        let provider = self.edit_prediction_provider.as_ref()?;
 8200
 8201        if provider.provider.needs_terms_acceptance(cx) {
 8202            return Some(
 8203                h_flex()
 8204                    .min_w(min_width)
 8205                    .flex_1()
 8206                    .px_2()
 8207                    .py_1()
 8208                    .gap_3()
 8209                    .elevation_2(cx)
 8210                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8211                    .id("accept-terms")
 8212                    .cursor_pointer()
 8213                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8214                    .on_click(cx.listener(|this, _event, window, cx| {
 8215                        cx.stop_propagation();
 8216                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8217                        window.dispatch_action(
 8218                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8219                            cx,
 8220                        );
 8221                    }))
 8222                    .child(
 8223                        h_flex()
 8224                            .flex_1()
 8225                            .gap_2()
 8226                            .child(Icon::new(IconName::ZedPredict))
 8227                            .child(Label::new("Accept Terms of Service"))
 8228                            .child(div().w_full())
 8229                            .child(
 8230                                Icon::new(IconName::ArrowUpRight)
 8231                                    .color(Color::Muted)
 8232                                    .size(IconSize::Small),
 8233                            )
 8234                            .into_any_element(),
 8235                    )
 8236                    .into_any(),
 8237            );
 8238        }
 8239
 8240        let is_refreshing = provider.provider.is_refreshing(cx);
 8241
 8242        fn pending_completion_container() -> Div {
 8243            h_flex()
 8244                .h_full()
 8245                .flex_1()
 8246                .gap_2()
 8247                .child(Icon::new(IconName::ZedPredict))
 8248        }
 8249
 8250        let completion = match &self.active_inline_completion {
 8251            Some(prediction) => {
 8252                if !self.has_visible_completions_menu() {
 8253                    const RADIUS: Pixels = px(6.);
 8254                    const BORDER_WIDTH: Pixels = px(1.);
 8255
 8256                    return Some(
 8257                        h_flex()
 8258                            .elevation_2(cx)
 8259                            .border(BORDER_WIDTH)
 8260                            .border_color(cx.theme().colors().border)
 8261                            .when(accept_keystroke.is_none(), |el| {
 8262                                el.border_color(cx.theme().status().error)
 8263                            })
 8264                            .rounded(RADIUS)
 8265                            .rounded_tl(px(0.))
 8266                            .overflow_hidden()
 8267                            .child(div().px_1p5().child(match &prediction.completion {
 8268                                InlineCompletion::Move { target, snapshot } => {
 8269                                    use text::ToPoint as _;
 8270                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8271                                    {
 8272                                        Icon::new(IconName::ZedPredictDown)
 8273                                    } else {
 8274                                        Icon::new(IconName::ZedPredictUp)
 8275                                    }
 8276                                }
 8277                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8278                            }))
 8279                            .child(
 8280                                h_flex()
 8281                                    .gap_1()
 8282                                    .py_1()
 8283                                    .px_2()
 8284                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8285                                    .border_l_1()
 8286                                    .border_color(cx.theme().colors().border)
 8287                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8288                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8289                                        el.child(
 8290                                            Label::new("Hold")
 8291                                                .size(LabelSize::Small)
 8292                                                .when(accept_keystroke.is_none(), |el| {
 8293                                                    el.strikethrough()
 8294                                                })
 8295                                                .line_height_style(LineHeightStyle::UiLabel),
 8296                                        )
 8297                                    })
 8298                                    .id("edit_prediction_cursor_popover_keybind")
 8299                                    .when(accept_keystroke.is_none(), |el| {
 8300                                        let status_colors = cx.theme().status();
 8301
 8302                                        el.bg(status_colors.error_background)
 8303                                            .border_color(status_colors.error.opacity(0.6))
 8304                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8305                                            .cursor_default()
 8306                                            .hoverable_tooltip(move |_window, cx| {
 8307                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8308                                                    .into()
 8309                                            })
 8310                                    })
 8311                                    .when_some(
 8312                                        accept_keystroke.as_ref(),
 8313                                        |el, accept_keystroke| {
 8314                                            el.child(h_flex().children(ui::render_modifiers(
 8315                                                &accept_keystroke.modifiers,
 8316                                                PlatformStyle::platform(),
 8317                                                Some(Color::Default),
 8318                                                Some(IconSize::XSmall.rems().into()),
 8319                                                false,
 8320                                            )))
 8321                                        },
 8322                                    ),
 8323                            )
 8324                            .into_any(),
 8325                    );
 8326                }
 8327
 8328                self.render_edit_prediction_cursor_popover_preview(
 8329                    prediction,
 8330                    cursor_point,
 8331                    style,
 8332                    cx,
 8333                )?
 8334            }
 8335
 8336            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8337                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8338                    stale_completion,
 8339                    cursor_point,
 8340                    style,
 8341                    cx,
 8342                )?,
 8343
 8344                None => {
 8345                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8346                }
 8347            },
 8348
 8349            None => pending_completion_container().child(Label::new("No Prediction")),
 8350        };
 8351
 8352        let completion = if is_refreshing {
 8353            completion
 8354                .with_animation(
 8355                    "loading-completion",
 8356                    Animation::new(Duration::from_secs(2))
 8357                        .repeat()
 8358                        .with_easing(pulsating_between(0.4, 0.8)),
 8359                    |label, delta| label.opacity(delta),
 8360                )
 8361                .into_any_element()
 8362        } else {
 8363            completion.into_any_element()
 8364        };
 8365
 8366        let has_completion = self.active_inline_completion.is_some();
 8367
 8368        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8369        Some(
 8370            h_flex()
 8371                .min_w(min_width)
 8372                .max_w(max_width)
 8373                .flex_1()
 8374                .elevation_2(cx)
 8375                .border_color(cx.theme().colors().border)
 8376                .child(
 8377                    div()
 8378                        .flex_1()
 8379                        .py_1()
 8380                        .px_2()
 8381                        .overflow_hidden()
 8382                        .child(completion),
 8383                )
 8384                .when_some(accept_keystroke, |el, accept_keystroke| {
 8385                    if !accept_keystroke.modifiers.modified() {
 8386                        return el;
 8387                    }
 8388
 8389                    el.child(
 8390                        h_flex()
 8391                            .h_full()
 8392                            .border_l_1()
 8393                            .rounded_r_lg()
 8394                            .border_color(cx.theme().colors().border)
 8395                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8396                            .gap_1()
 8397                            .py_1()
 8398                            .px_2()
 8399                            .child(
 8400                                h_flex()
 8401                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8402                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8403                                    .child(h_flex().children(ui::render_modifiers(
 8404                                        &accept_keystroke.modifiers,
 8405                                        PlatformStyle::platform(),
 8406                                        Some(if !has_completion {
 8407                                            Color::Muted
 8408                                        } else {
 8409                                            Color::Default
 8410                                        }),
 8411                                        None,
 8412                                        false,
 8413                                    ))),
 8414                            )
 8415                            .child(Label::new("Preview").into_any_element())
 8416                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8417                    )
 8418                })
 8419                .into_any(),
 8420        )
 8421    }
 8422
 8423    fn render_edit_prediction_cursor_popover_preview(
 8424        &self,
 8425        completion: &InlineCompletionState,
 8426        cursor_point: Point,
 8427        style: &EditorStyle,
 8428        cx: &mut Context<Editor>,
 8429    ) -> Option<Div> {
 8430        use text::ToPoint as _;
 8431
 8432        fn render_relative_row_jump(
 8433            prefix: impl Into<String>,
 8434            current_row: u32,
 8435            target_row: u32,
 8436        ) -> Div {
 8437            let (row_diff, arrow) = if target_row < current_row {
 8438                (current_row - target_row, IconName::ArrowUp)
 8439            } else {
 8440                (target_row - current_row, IconName::ArrowDown)
 8441            };
 8442
 8443            h_flex()
 8444                .child(
 8445                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8446                        .color(Color::Muted)
 8447                        .size(LabelSize::Small),
 8448                )
 8449                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8450        }
 8451
 8452        match &completion.completion {
 8453            InlineCompletion::Move {
 8454                target, snapshot, ..
 8455            } => Some(
 8456                h_flex()
 8457                    .px_2()
 8458                    .gap_2()
 8459                    .flex_1()
 8460                    .child(
 8461                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8462                            Icon::new(IconName::ZedPredictDown)
 8463                        } else {
 8464                            Icon::new(IconName::ZedPredictUp)
 8465                        },
 8466                    )
 8467                    .child(Label::new("Jump to Edit")),
 8468            ),
 8469
 8470            InlineCompletion::Edit {
 8471                edits,
 8472                edit_preview,
 8473                snapshot,
 8474                display_mode: _,
 8475            } => {
 8476                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8477
 8478                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8479                    &snapshot,
 8480                    &edits,
 8481                    edit_preview.as_ref()?,
 8482                    true,
 8483                    cx,
 8484                )
 8485                .first_line_preview();
 8486
 8487                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8488                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8489
 8490                let preview = h_flex()
 8491                    .gap_1()
 8492                    .min_w_16()
 8493                    .child(styled_text)
 8494                    .when(has_more_lines, |parent| parent.child(""));
 8495
 8496                let left = if first_edit_row != cursor_point.row {
 8497                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8498                        .into_any_element()
 8499                } else {
 8500                    Icon::new(IconName::ZedPredict).into_any_element()
 8501                };
 8502
 8503                Some(
 8504                    h_flex()
 8505                        .h_full()
 8506                        .flex_1()
 8507                        .gap_2()
 8508                        .pr_1()
 8509                        .overflow_x_hidden()
 8510                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8511                        .child(left)
 8512                        .child(preview),
 8513                )
 8514            }
 8515        }
 8516    }
 8517
 8518    fn render_context_menu(
 8519        &self,
 8520        style: &EditorStyle,
 8521        max_height_in_lines: u32,
 8522        window: &mut Window,
 8523        cx: &mut Context<Editor>,
 8524    ) -> Option<AnyElement> {
 8525        let menu = self.context_menu.borrow();
 8526        let menu = menu.as_ref()?;
 8527        if !menu.visible() {
 8528            return None;
 8529        };
 8530        Some(menu.render(style, max_height_in_lines, window, cx))
 8531    }
 8532
 8533    fn render_context_menu_aside(
 8534        &mut self,
 8535        max_size: Size<Pixels>,
 8536        window: &mut Window,
 8537        cx: &mut Context<Editor>,
 8538    ) -> Option<AnyElement> {
 8539        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8540            if menu.visible() {
 8541                menu.render_aside(self, max_size, window, cx)
 8542            } else {
 8543                None
 8544            }
 8545        })
 8546    }
 8547
 8548    fn hide_context_menu(
 8549        &mut self,
 8550        window: &mut Window,
 8551        cx: &mut Context<Self>,
 8552    ) -> Option<CodeContextMenu> {
 8553        cx.notify();
 8554        self.completion_tasks.clear();
 8555        let context_menu = self.context_menu.borrow_mut().take();
 8556        self.stale_inline_completion_in_menu.take();
 8557        self.update_visible_inline_completion(window, cx);
 8558        context_menu
 8559    }
 8560
 8561    fn show_snippet_choices(
 8562        &mut self,
 8563        choices: &Vec<String>,
 8564        selection: Range<Anchor>,
 8565        cx: &mut Context<Self>,
 8566    ) {
 8567        if selection.start.buffer_id.is_none() {
 8568            return;
 8569        }
 8570        let buffer_id = selection.start.buffer_id.unwrap();
 8571        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8572        let id = post_inc(&mut self.next_completion_id);
 8573        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8574
 8575        if let Some(buffer) = buffer {
 8576            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8577                CompletionsMenu::new_snippet_choices(
 8578                    id,
 8579                    true,
 8580                    choices,
 8581                    selection,
 8582                    buffer,
 8583                    snippet_sort_order,
 8584                ),
 8585            ));
 8586        }
 8587    }
 8588
 8589    pub fn insert_snippet(
 8590        &mut self,
 8591        insertion_ranges: &[Range<usize>],
 8592        snippet: Snippet,
 8593        window: &mut Window,
 8594        cx: &mut Context<Self>,
 8595    ) -> Result<()> {
 8596        struct Tabstop<T> {
 8597            is_end_tabstop: bool,
 8598            ranges: Vec<Range<T>>,
 8599            choices: Option<Vec<String>>,
 8600        }
 8601
 8602        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8603            let snippet_text: Arc<str> = snippet.text.clone().into();
 8604            let edits = insertion_ranges
 8605                .iter()
 8606                .cloned()
 8607                .map(|range| (range, snippet_text.clone()));
 8608            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8609
 8610            let snapshot = &*buffer.read(cx);
 8611            let snippet = &snippet;
 8612            snippet
 8613                .tabstops
 8614                .iter()
 8615                .map(|tabstop| {
 8616                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8617                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8618                    });
 8619                    let mut tabstop_ranges = tabstop
 8620                        .ranges
 8621                        .iter()
 8622                        .flat_map(|tabstop_range| {
 8623                            let mut delta = 0_isize;
 8624                            insertion_ranges.iter().map(move |insertion_range| {
 8625                                let insertion_start = insertion_range.start as isize + delta;
 8626                                delta +=
 8627                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8628
 8629                                let start = ((insertion_start + tabstop_range.start) as usize)
 8630                                    .min(snapshot.len());
 8631                                let end = ((insertion_start + tabstop_range.end) as usize)
 8632                                    .min(snapshot.len());
 8633                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8634                            })
 8635                        })
 8636                        .collect::<Vec<_>>();
 8637                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8638
 8639                    Tabstop {
 8640                        is_end_tabstop,
 8641                        ranges: tabstop_ranges,
 8642                        choices: tabstop.choices.clone(),
 8643                    }
 8644                })
 8645                .collect::<Vec<_>>()
 8646        });
 8647        if let Some(tabstop) = tabstops.first() {
 8648            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8649                s.select_ranges(tabstop.ranges.iter().cloned());
 8650            });
 8651
 8652            if let Some(choices) = &tabstop.choices {
 8653                if let Some(selection) = tabstop.ranges.first() {
 8654                    self.show_snippet_choices(choices, selection.clone(), cx)
 8655                }
 8656            }
 8657
 8658            // If we're already at the last tabstop and it's at the end of the snippet,
 8659            // we're done, we don't need to keep the state around.
 8660            if !tabstop.is_end_tabstop {
 8661                let choices = tabstops
 8662                    .iter()
 8663                    .map(|tabstop| tabstop.choices.clone())
 8664                    .collect();
 8665
 8666                let ranges = tabstops
 8667                    .into_iter()
 8668                    .map(|tabstop| tabstop.ranges)
 8669                    .collect::<Vec<_>>();
 8670
 8671                self.snippet_stack.push(SnippetState {
 8672                    active_index: 0,
 8673                    ranges,
 8674                    choices,
 8675                });
 8676            }
 8677
 8678            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8679            if self.autoclose_regions.is_empty() {
 8680                let snapshot = self.buffer.read(cx).snapshot(cx);
 8681                for selection in &mut self.selections.all::<Point>(cx) {
 8682                    let selection_head = selection.head();
 8683                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8684                        continue;
 8685                    };
 8686
 8687                    let mut bracket_pair = None;
 8688                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8689                    let prev_chars = snapshot
 8690                        .reversed_chars_at(selection_head)
 8691                        .collect::<String>();
 8692                    for (pair, enabled) in scope.brackets() {
 8693                        if enabled
 8694                            && pair.close
 8695                            && prev_chars.starts_with(pair.start.as_str())
 8696                            && next_chars.starts_with(pair.end.as_str())
 8697                        {
 8698                            bracket_pair = Some(pair.clone());
 8699                            break;
 8700                        }
 8701                    }
 8702                    if let Some(pair) = bracket_pair {
 8703                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8704                        let autoclose_enabled =
 8705                            self.use_autoclose && snapshot_settings.use_autoclose;
 8706                        if autoclose_enabled {
 8707                            let start = snapshot.anchor_after(selection_head);
 8708                            let end = snapshot.anchor_after(selection_head);
 8709                            self.autoclose_regions.push(AutocloseRegion {
 8710                                selection_id: selection.id,
 8711                                range: start..end,
 8712                                pair,
 8713                            });
 8714                        }
 8715                    }
 8716                }
 8717            }
 8718        }
 8719        Ok(())
 8720    }
 8721
 8722    pub fn move_to_next_snippet_tabstop(
 8723        &mut self,
 8724        window: &mut Window,
 8725        cx: &mut Context<Self>,
 8726    ) -> bool {
 8727        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8728    }
 8729
 8730    pub fn move_to_prev_snippet_tabstop(
 8731        &mut self,
 8732        window: &mut Window,
 8733        cx: &mut Context<Self>,
 8734    ) -> bool {
 8735        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8736    }
 8737
 8738    pub fn move_to_snippet_tabstop(
 8739        &mut self,
 8740        bias: Bias,
 8741        window: &mut Window,
 8742        cx: &mut Context<Self>,
 8743    ) -> bool {
 8744        if let Some(mut snippet) = self.snippet_stack.pop() {
 8745            match bias {
 8746                Bias::Left => {
 8747                    if snippet.active_index > 0 {
 8748                        snippet.active_index -= 1;
 8749                    } else {
 8750                        self.snippet_stack.push(snippet);
 8751                        return false;
 8752                    }
 8753                }
 8754                Bias::Right => {
 8755                    if snippet.active_index + 1 < snippet.ranges.len() {
 8756                        snippet.active_index += 1;
 8757                    } else {
 8758                        self.snippet_stack.push(snippet);
 8759                        return false;
 8760                    }
 8761                }
 8762            }
 8763            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8764                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8765                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8766                });
 8767
 8768                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8769                    if let Some(selection) = current_ranges.first() {
 8770                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8771                    }
 8772                }
 8773
 8774                // If snippet state is not at the last tabstop, push it back on the stack
 8775                if snippet.active_index + 1 < snippet.ranges.len() {
 8776                    self.snippet_stack.push(snippet);
 8777                }
 8778                return true;
 8779            }
 8780        }
 8781
 8782        false
 8783    }
 8784
 8785    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8786        self.transact(window, cx, |this, window, cx| {
 8787            this.select_all(&SelectAll, window, cx);
 8788            this.insert("", window, cx);
 8789        });
 8790    }
 8791
 8792    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8793        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8794        self.transact(window, cx, |this, window, cx| {
 8795            this.select_autoclose_pair(window, cx);
 8796            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8797            if !this.linked_edit_ranges.is_empty() {
 8798                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8799                let snapshot = this.buffer.read(cx).snapshot(cx);
 8800
 8801                for selection in selections.iter() {
 8802                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8803                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8804                    if selection_start.buffer_id != selection_end.buffer_id {
 8805                        continue;
 8806                    }
 8807                    if let Some(ranges) =
 8808                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8809                    {
 8810                        for (buffer, entries) in ranges {
 8811                            linked_ranges.entry(buffer).or_default().extend(entries);
 8812                        }
 8813                    }
 8814                }
 8815            }
 8816
 8817            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8818            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8819            for selection in &mut selections {
 8820                if selection.is_empty() {
 8821                    let old_head = selection.head();
 8822                    let mut new_head =
 8823                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8824                            .to_point(&display_map);
 8825                    if let Some((buffer, line_buffer_range)) = display_map
 8826                        .buffer_snapshot
 8827                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8828                    {
 8829                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8830                        let indent_len = match indent_size.kind {
 8831                            IndentKind::Space => {
 8832                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8833                            }
 8834                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8835                        };
 8836                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8837                            let indent_len = indent_len.get();
 8838                            new_head = cmp::min(
 8839                                new_head,
 8840                                MultiBufferPoint::new(
 8841                                    old_head.row,
 8842                                    ((old_head.column - 1) / indent_len) * indent_len,
 8843                                ),
 8844                            );
 8845                        }
 8846                    }
 8847
 8848                    selection.set_head(new_head, SelectionGoal::None);
 8849                }
 8850            }
 8851
 8852            this.signature_help_state.set_backspace_pressed(true);
 8853            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8854                s.select(selections)
 8855            });
 8856            this.insert("", window, cx);
 8857            let empty_str: Arc<str> = Arc::from("");
 8858            for (buffer, edits) in linked_ranges {
 8859                let snapshot = buffer.read(cx).snapshot();
 8860                use text::ToPoint as TP;
 8861
 8862                let edits = edits
 8863                    .into_iter()
 8864                    .map(|range| {
 8865                        let end_point = TP::to_point(&range.end, &snapshot);
 8866                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8867
 8868                        if end_point == start_point {
 8869                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8870                                .saturating_sub(1);
 8871                            start_point =
 8872                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8873                        };
 8874
 8875                        (start_point..end_point, empty_str.clone())
 8876                    })
 8877                    .sorted_by_key(|(range, _)| range.start)
 8878                    .collect::<Vec<_>>();
 8879                buffer.update(cx, |this, cx| {
 8880                    this.edit(edits, None, cx);
 8881                })
 8882            }
 8883            this.refresh_inline_completion(true, false, window, cx);
 8884            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8885        });
 8886    }
 8887
 8888    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8889        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8890        self.transact(window, cx, |this, window, cx| {
 8891            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8892                s.move_with(|map, selection| {
 8893                    if selection.is_empty() {
 8894                        let cursor = movement::right(map, selection.head());
 8895                        selection.end = cursor;
 8896                        selection.reversed = true;
 8897                        selection.goal = SelectionGoal::None;
 8898                    }
 8899                })
 8900            });
 8901            this.insert("", window, cx);
 8902            this.refresh_inline_completion(true, false, window, cx);
 8903        });
 8904    }
 8905
 8906    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8907        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8908        if self.move_to_prev_snippet_tabstop(window, cx) {
 8909            return;
 8910        }
 8911        self.outdent(&Outdent, window, cx);
 8912    }
 8913
 8914    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8915        if self.move_to_next_snippet_tabstop(window, cx) {
 8916            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8917            return;
 8918        }
 8919        if self.read_only(cx) {
 8920            return;
 8921        }
 8922        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8923        let mut selections = self.selections.all_adjusted(cx);
 8924        let buffer = self.buffer.read(cx);
 8925        let snapshot = buffer.snapshot(cx);
 8926        let rows_iter = selections.iter().map(|s| s.head().row);
 8927        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8928
 8929        let has_some_cursor_in_whitespace = selections
 8930            .iter()
 8931            .filter(|selection| selection.is_empty())
 8932            .any(|selection| {
 8933                let cursor = selection.head();
 8934                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8935                cursor.column < current_indent.len
 8936            });
 8937
 8938        let mut edits = Vec::new();
 8939        let mut prev_edited_row = 0;
 8940        let mut row_delta = 0;
 8941        for selection in &mut selections {
 8942            if selection.start.row != prev_edited_row {
 8943                row_delta = 0;
 8944            }
 8945            prev_edited_row = selection.end.row;
 8946
 8947            // If the selection is non-empty, then increase the indentation of the selected lines.
 8948            if !selection.is_empty() {
 8949                row_delta =
 8950                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8951                continue;
 8952            }
 8953
 8954            let cursor = selection.head();
 8955            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8956            if let Some(suggested_indent) =
 8957                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8958            {
 8959                // Don't do anything if already at suggested indent
 8960                // and there is any other cursor which is not
 8961                if has_some_cursor_in_whitespace
 8962                    && cursor.column == current_indent.len
 8963                    && current_indent.len == suggested_indent.len
 8964                {
 8965                    continue;
 8966                }
 8967
 8968                // Adjust line and move cursor to suggested indent
 8969                // if cursor is not at suggested indent
 8970                if cursor.column < suggested_indent.len
 8971                    && cursor.column <= current_indent.len
 8972                    && current_indent.len <= suggested_indent.len
 8973                {
 8974                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8975                    selection.end = selection.start;
 8976                    if row_delta == 0 {
 8977                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8978                            cursor.row,
 8979                            current_indent,
 8980                            suggested_indent,
 8981                        ));
 8982                        row_delta = suggested_indent.len - current_indent.len;
 8983                    }
 8984                    continue;
 8985                }
 8986
 8987                // If current indent is more than suggested indent
 8988                // only move cursor to current indent and skip indent
 8989                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 8990                    selection.start = Point::new(cursor.row, current_indent.len);
 8991                    selection.end = selection.start;
 8992                    continue;
 8993                }
 8994            }
 8995
 8996            // Otherwise, insert a hard or soft tab.
 8997            let settings = buffer.language_settings_at(cursor, cx);
 8998            let tab_size = if settings.hard_tabs {
 8999                IndentSize::tab()
 9000            } else {
 9001                let tab_size = settings.tab_size.get();
 9002                let indent_remainder = snapshot
 9003                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9004                    .flat_map(str::chars)
 9005                    .fold(row_delta % tab_size, |counter: u32, c| {
 9006                        if c == '\t' {
 9007                            0
 9008                        } else {
 9009                            (counter + 1) % tab_size
 9010                        }
 9011                    });
 9012
 9013                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9014                IndentSize::spaces(chars_to_next_tab_stop)
 9015            };
 9016            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9017            selection.end = selection.start;
 9018            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9019            row_delta += tab_size.len;
 9020        }
 9021
 9022        self.transact(window, cx, |this, window, cx| {
 9023            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9024            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9025                s.select(selections)
 9026            });
 9027            this.refresh_inline_completion(true, false, window, cx);
 9028        });
 9029    }
 9030
 9031    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9032        if self.read_only(cx) {
 9033            return;
 9034        }
 9035        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9036        let mut selections = self.selections.all::<Point>(cx);
 9037        let mut prev_edited_row = 0;
 9038        let mut row_delta = 0;
 9039        let mut edits = Vec::new();
 9040        let buffer = self.buffer.read(cx);
 9041        let snapshot = buffer.snapshot(cx);
 9042        for selection in &mut selections {
 9043            if selection.start.row != prev_edited_row {
 9044                row_delta = 0;
 9045            }
 9046            prev_edited_row = selection.end.row;
 9047
 9048            row_delta =
 9049                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9050        }
 9051
 9052        self.transact(window, cx, |this, window, cx| {
 9053            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9054            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9055                s.select(selections)
 9056            });
 9057        });
 9058    }
 9059
 9060    fn indent_selection(
 9061        buffer: &MultiBuffer,
 9062        snapshot: &MultiBufferSnapshot,
 9063        selection: &mut Selection<Point>,
 9064        edits: &mut Vec<(Range<Point>, String)>,
 9065        delta_for_start_row: u32,
 9066        cx: &App,
 9067    ) -> u32 {
 9068        let settings = buffer.language_settings_at(selection.start, cx);
 9069        let tab_size = settings.tab_size.get();
 9070        let indent_kind = if settings.hard_tabs {
 9071            IndentKind::Tab
 9072        } else {
 9073            IndentKind::Space
 9074        };
 9075        let mut start_row = selection.start.row;
 9076        let mut end_row = selection.end.row + 1;
 9077
 9078        // If a selection ends at the beginning of a line, don't indent
 9079        // that last line.
 9080        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9081            end_row -= 1;
 9082        }
 9083
 9084        // Avoid re-indenting a row that has already been indented by a
 9085        // previous selection, but still update this selection's column
 9086        // to reflect that indentation.
 9087        if delta_for_start_row > 0 {
 9088            start_row += 1;
 9089            selection.start.column += delta_for_start_row;
 9090            if selection.end.row == selection.start.row {
 9091                selection.end.column += delta_for_start_row;
 9092            }
 9093        }
 9094
 9095        let mut delta_for_end_row = 0;
 9096        let has_multiple_rows = start_row + 1 != end_row;
 9097        for row in start_row..end_row {
 9098            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9099            let indent_delta = match (current_indent.kind, indent_kind) {
 9100                (IndentKind::Space, IndentKind::Space) => {
 9101                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9102                    IndentSize::spaces(columns_to_next_tab_stop)
 9103                }
 9104                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9105                (_, IndentKind::Tab) => IndentSize::tab(),
 9106            };
 9107
 9108            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9109                0
 9110            } else {
 9111                selection.start.column
 9112            };
 9113            let row_start = Point::new(row, start);
 9114            edits.push((
 9115                row_start..row_start,
 9116                indent_delta.chars().collect::<String>(),
 9117            ));
 9118
 9119            // Update this selection's endpoints to reflect the indentation.
 9120            if row == selection.start.row {
 9121                selection.start.column += indent_delta.len;
 9122            }
 9123            if row == selection.end.row {
 9124                selection.end.column += indent_delta.len;
 9125                delta_for_end_row = indent_delta.len;
 9126            }
 9127        }
 9128
 9129        if selection.start.row == selection.end.row {
 9130            delta_for_start_row + delta_for_end_row
 9131        } else {
 9132            delta_for_end_row
 9133        }
 9134    }
 9135
 9136    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9137        if self.read_only(cx) {
 9138            return;
 9139        }
 9140        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9141        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9142        let selections = self.selections.all::<Point>(cx);
 9143        let mut deletion_ranges = Vec::new();
 9144        let mut last_outdent = None;
 9145        {
 9146            let buffer = self.buffer.read(cx);
 9147            let snapshot = buffer.snapshot(cx);
 9148            for selection in &selections {
 9149                let settings = buffer.language_settings_at(selection.start, cx);
 9150                let tab_size = settings.tab_size.get();
 9151                let mut rows = selection.spanned_rows(false, &display_map);
 9152
 9153                // Avoid re-outdenting a row that has already been outdented by a
 9154                // previous selection.
 9155                if let Some(last_row) = last_outdent {
 9156                    if last_row == rows.start {
 9157                        rows.start = rows.start.next_row();
 9158                    }
 9159                }
 9160                let has_multiple_rows = rows.len() > 1;
 9161                for row in rows.iter_rows() {
 9162                    let indent_size = snapshot.indent_size_for_line(row);
 9163                    if indent_size.len > 0 {
 9164                        let deletion_len = match indent_size.kind {
 9165                            IndentKind::Space => {
 9166                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9167                                if columns_to_prev_tab_stop == 0 {
 9168                                    tab_size
 9169                                } else {
 9170                                    columns_to_prev_tab_stop
 9171                                }
 9172                            }
 9173                            IndentKind::Tab => 1,
 9174                        };
 9175                        let start = if has_multiple_rows
 9176                            || deletion_len > selection.start.column
 9177                            || indent_size.len < selection.start.column
 9178                        {
 9179                            0
 9180                        } else {
 9181                            selection.start.column - deletion_len
 9182                        };
 9183                        deletion_ranges.push(
 9184                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9185                        );
 9186                        last_outdent = Some(row);
 9187                    }
 9188                }
 9189            }
 9190        }
 9191
 9192        self.transact(window, cx, |this, window, cx| {
 9193            this.buffer.update(cx, |buffer, cx| {
 9194                let empty_str: Arc<str> = Arc::default();
 9195                buffer.edit(
 9196                    deletion_ranges
 9197                        .into_iter()
 9198                        .map(|range| (range, empty_str.clone())),
 9199                    None,
 9200                    cx,
 9201                );
 9202            });
 9203            let selections = this.selections.all::<usize>(cx);
 9204            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9205                s.select(selections)
 9206            });
 9207        });
 9208    }
 9209
 9210    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9211        if self.read_only(cx) {
 9212            return;
 9213        }
 9214        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9215        let selections = self
 9216            .selections
 9217            .all::<usize>(cx)
 9218            .into_iter()
 9219            .map(|s| s.range());
 9220
 9221        self.transact(window, cx, |this, window, cx| {
 9222            this.buffer.update(cx, |buffer, cx| {
 9223                buffer.autoindent_ranges(selections, cx);
 9224            });
 9225            let selections = this.selections.all::<usize>(cx);
 9226            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9227                s.select(selections)
 9228            });
 9229        });
 9230    }
 9231
 9232    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9233        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9234        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9235        let selections = self.selections.all::<Point>(cx);
 9236
 9237        let mut new_cursors = Vec::new();
 9238        let mut edit_ranges = Vec::new();
 9239        let mut selections = selections.iter().peekable();
 9240        while let Some(selection) = selections.next() {
 9241            let mut rows = selection.spanned_rows(false, &display_map);
 9242            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9243
 9244            // Accumulate contiguous regions of rows that we want to delete.
 9245            while let Some(next_selection) = selections.peek() {
 9246                let next_rows = next_selection.spanned_rows(false, &display_map);
 9247                if next_rows.start <= rows.end {
 9248                    rows.end = next_rows.end;
 9249                    selections.next().unwrap();
 9250                } else {
 9251                    break;
 9252                }
 9253            }
 9254
 9255            let buffer = &display_map.buffer_snapshot;
 9256            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9257            let edit_end;
 9258            let cursor_buffer_row;
 9259            if buffer.max_point().row >= rows.end.0 {
 9260                // If there's a line after the range, delete the \n from the end of the row range
 9261                // and position the cursor on the next line.
 9262                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9263                cursor_buffer_row = rows.end;
 9264            } else {
 9265                // If there isn't a line after the range, delete the \n from the line before the
 9266                // start of the row range and position the cursor there.
 9267                edit_start = edit_start.saturating_sub(1);
 9268                edit_end = buffer.len();
 9269                cursor_buffer_row = rows.start.previous_row();
 9270            }
 9271
 9272            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9273            *cursor.column_mut() =
 9274                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9275
 9276            new_cursors.push((
 9277                selection.id,
 9278                buffer.anchor_after(cursor.to_point(&display_map)),
 9279            ));
 9280            edit_ranges.push(edit_start..edit_end);
 9281        }
 9282
 9283        self.transact(window, cx, |this, window, cx| {
 9284            let buffer = this.buffer.update(cx, |buffer, cx| {
 9285                let empty_str: Arc<str> = Arc::default();
 9286                buffer.edit(
 9287                    edit_ranges
 9288                        .into_iter()
 9289                        .map(|range| (range, empty_str.clone())),
 9290                    None,
 9291                    cx,
 9292                );
 9293                buffer.snapshot(cx)
 9294            });
 9295            let new_selections = new_cursors
 9296                .into_iter()
 9297                .map(|(id, cursor)| {
 9298                    let cursor = cursor.to_point(&buffer);
 9299                    Selection {
 9300                        id,
 9301                        start: cursor,
 9302                        end: cursor,
 9303                        reversed: false,
 9304                        goal: SelectionGoal::None,
 9305                    }
 9306                })
 9307                .collect();
 9308
 9309            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9310                s.select(new_selections);
 9311            });
 9312        });
 9313    }
 9314
 9315    pub fn join_lines_impl(
 9316        &mut self,
 9317        insert_whitespace: bool,
 9318        window: &mut Window,
 9319        cx: &mut Context<Self>,
 9320    ) {
 9321        if self.read_only(cx) {
 9322            return;
 9323        }
 9324        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9325        for selection in self.selections.all::<Point>(cx) {
 9326            let start = MultiBufferRow(selection.start.row);
 9327            // Treat single line selections as if they include the next line. Otherwise this action
 9328            // would do nothing for single line selections individual cursors.
 9329            let end = if selection.start.row == selection.end.row {
 9330                MultiBufferRow(selection.start.row + 1)
 9331            } else {
 9332                MultiBufferRow(selection.end.row)
 9333            };
 9334
 9335            if let Some(last_row_range) = row_ranges.last_mut() {
 9336                if start <= last_row_range.end {
 9337                    last_row_range.end = end;
 9338                    continue;
 9339                }
 9340            }
 9341            row_ranges.push(start..end);
 9342        }
 9343
 9344        let snapshot = self.buffer.read(cx).snapshot(cx);
 9345        let mut cursor_positions = Vec::new();
 9346        for row_range in &row_ranges {
 9347            let anchor = snapshot.anchor_before(Point::new(
 9348                row_range.end.previous_row().0,
 9349                snapshot.line_len(row_range.end.previous_row()),
 9350            ));
 9351            cursor_positions.push(anchor..anchor);
 9352        }
 9353
 9354        self.transact(window, cx, |this, window, cx| {
 9355            for row_range in row_ranges.into_iter().rev() {
 9356                for row in row_range.iter_rows().rev() {
 9357                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9358                    let next_line_row = row.next_row();
 9359                    let indent = snapshot.indent_size_for_line(next_line_row);
 9360                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9361
 9362                    let replace =
 9363                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9364                            " "
 9365                        } else {
 9366                            ""
 9367                        };
 9368
 9369                    this.buffer.update(cx, |buffer, cx| {
 9370                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9371                    });
 9372                }
 9373            }
 9374
 9375            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9376                s.select_anchor_ranges(cursor_positions)
 9377            });
 9378        });
 9379    }
 9380
 9381    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9382        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9383        self.join_lines_impl(true, window, cx);
 9384    }
 9385
 9386    pub fn sort_lines_case_sensitive(
 9387        &mut self,
 9388        _: &SortLinesCaseSensitive,
 9389        window: &mut Window,
 9390        cx: &mut Context<Self>,
 9391    ) {
 9392        self.manipulate_lines(window, cx, |lines| lines.sort())
 9393    }
 9394
 9395    pub fn sort_lines_case_insensitive(
 9396        &mut self,
 9397        _: &SortLinesCaseInsensitive,
 9398        window: &mut Window,
 9399        cx: &mut Context<Self>,
 9400    ) {
 9401        self.manipulate_lines(window, cx, |lines| {
 9402            lines.sort_by_key(|line| line.to_lowercase())
 9403        })
 9404    }
 9405
 9406    pub fn unique_lines_case_insensitive(
 9407        &mut self,
 9408        _: &UniqueLinesCaseInsensitive,
 9409        window: &mut Window,
 9410        cx: &mut Context<Self>,
 9411    ) {
 9412        self.manipulate_lines(window, cx, |lines| {
 9413            let mut seen = HashSet::default();
 9414            lines.retain(|line| seen.insert(line.to_lowercase()));
 9415        })
 9416    }
 9417
 9418    pub fn unique_lines_case_sensitive(
 9419        &mut self,
 9420        _: &UniqueLinesCaseSensitive,
 9421        window: &mut Window,
 9422        cx: &mut Context<Self>,
 9423    ) {
 9424        self.manipulate_lines(window, cx, |lines| {
 9425            let mut seen = HashSet::default();
 9426            lines.retain(|line| seen.insert(*line));
 9427        })
 9428    }
 9429
 9430    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9431        let Some(project) = self.project.clone() else {
 9432            return;
 9433        };
 9434        self.reload(project, window, cx)
 9435            .detach_and_notify_err(window, cx);
 9436    }
 9437
 9438    pub fn restore_file(
 9439        &mut self,
 9440        _: &::git::RestoreFile,
 9441        window: &mut Window,
 9442        cx: &mut Context<Self>,
 9443    ) {
 9444        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9445        let mut buffer_ids = HashSet::default();
 9446        let snapshot = self.buffer().read(cx).snapshot(cx);
 9447        for selection in self.selections.all::<usize>(cx) {
 9448            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9449        }
 9450
 9451        let buffer = self.buffer().read(cx);
 9452        let ranges = buffer_ids
 9453            .into_iter()
 9454            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9455            .collect::<Vec<_>>();
 9456
 9457        self.restore_hunks_in_ranges(ranges, window, cx);
 9458    }
 9459
 9460    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9461        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9462        let selections = self
 9463            .selections
 9464            .all(cx)
 9465            .into_iter()
 9466            .map(|s| s.range())
 9467            .collect();
 9468        self.restore_hunks_in_ranges(selections, window, cx);
 9469    }
 9470
 9471    pub fn restore_hunks_in_ranges(
 9472        &mut self,
 9473        ranges: Vec<Range<Point>>,
 9474        window: &mut Window,
 9475        cx: &mut Context<Editor>,
 9476    ) {
 9477        let mut revert_changes = HashMap::default();
 9478        let chunk_by = self
 9479            .snapshot(window, cx)
 9480            .hunks_for_ranges(ranges)
 9481            .into_iter()
 9482            .chunk_by(|hunk| hunk.buffer_id);
 9483        for (buffer_id, hunks) in &chunk_by {
 9484            let hunks = hunks.collect::<Vec<_>>();
 9485            for hunk in &hunks {
 9486                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9487            }
 9488            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9489        }
 9490        drop(chunk_by);
 9491        if !revert_changes.is_empty() {
 9492            self.transact(window, cx, |editor, window, cx| {
 9493                editor.restore(revert_changes, window, cx);
 9494            });
 9495        }
 9496    }
 9497
 9498    pub fn open_active_item_in_terminal(
 9499        &mut self,
 9500        _: &OpenInTerminal,
 9501        window: &mut Window,
 9502        cx: &mut Context<Self>,
 9503    ) {
 9504        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9505            let project_path = buffer.read(cx).project_path(cx)?;
 9506            let project = self.project.as_ref()?.read(cx);
 9507            let entry = project.entry_for_path(&project_path, cx)?;
 9508            let parent = match &entry.canonical_path {
 9509                Some(canonical_path) => canonical_path.to_path_buf(),
 9510                None => project.absolute_path(&project_path, cx)?,
 9511            }
 9512            .parent()?
 9513            .to_path_buf();
 9514            Some(parent)
 9515        }) {
 9516            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9517        }
 9518    }
 9519
 9520    fn set_breakpoint_context_menu(
 9521        &mut self,
 9522        display_row: DisplayRow,
 9523        position: Option<Anchor>,
 9524        clicked_point: gpui::Point<Pixels>,
 9525        window: &mut Window,
 9526        cx: &mut Context<Self>,
 9527    ) {
 9528        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9529            return;
 9530        }
 9531        let source = self
 9532            .buffer
 9533            .read(cx)
 9534            .snapshot(cx)
 9535            .anchor_before(Point::new(display_row.0, 0u32));
 9536
 9537        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9538
 9539        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9540            self,
 9541            source,
 9542            clicked_point,
 9543            context_menu,
 9544            window,
 9545            cx,
 9546        );
 9547    }
 9548
 9549    fn add_edit_breakpoint_block(
 9550        &mut self,
 9551        anchor: Anchor,
 9552        breakpoint: &Breakpoint,
 9553        edit_action: BreakpointPromptEditAction,
 9554        window: &mut Window,
 9555        cx: &mut Context<Self>,
 9556    ) {
 9557        let weak_editor = cx.weak_entity();
 9558        let bp_prompt = cx.new(|cx| {
 9559            BreakpointPromptEditor::new(
 9560                weak_editor,
 9561                anchor,
 9562                breakpoint.clone(),
 9563                edit_action,
 9564                window,
 9565                cx,
 9566            )
 9567        });
 9568
 9569        let height = bp_prompt.update(cx, |this, cx| {
 9570            this.prompt
 9571                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9572        });
 9573        let cloned_prompt = bp_prompt.clone();
 9574        let blocks = vec![BlockProperties {
 9575            style: BlockStyle::Sticky,
 9576            placement: BlockPlacement::Above(anchor),
 9577            height: Some(height),
 9578            render: Arc::new(move |cx| {
 9579                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9580                cloned_prompt.clone().into_any_element()
 9581            }),
 9582            priority: 0,
 9583            render_in_minimap: true,
 9584        }];
 9585
 9586        let focus_handle = bp_prompt.focus_handle(cx);
 9587        window.focus(&focus_handle);
 9588
 9589        let block_ids = self.insert_blocks(blocks, None, cx);
 9590        bp_prompt.update(cx, |prompt, _| {
 9591            prompt.add_block_ids(block_ids);
 9592        });
 9593    }
 9594
 9595    pub(crate) fn breakpoint_at_row(
 9596        &self,
 9597        row: u32,
 9598        window: &mut Window,
 9599        cx: &mut Context<Self>,
 9600    ) -> Option<(Anchor, Breakpoint)> {
 9601        let snapshot = self.snapshot(window, cx);
 9602        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9603
 9604        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9605    }
 9606
 9607    pub(crate) fn breakpoint_at_anchor(
 9608        &self,
 9609        breakpoint_position: Anchor,
 9610        snapshot: &EditorSnapshot,
 9611        cx: &mut Context<Self>,
 9612    ) -> Option<(Anchor, Breakpoint)> {
 9613        let project = self.project.clone()?;
 9614
 9615        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9616            snapshot
 9617                .buffer_snapshot
 9618                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9619        })?;
 9620
 9621        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9622        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9623        let buffer_snapshot = buffer.read(cx).snapshot();
 9624
 9625        let row = buffer_snapshot
 9626            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9627            .row;
 9628
 9629        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9630        let anchor_end = snapshot
 9631            .buffer_snapshot
 9632            .anchor_after(Point::new(row, line_len));
 9633
 9634        let bp = self
 9635            .breakpoint_store
 9636            .as_ref()?
 9637            .read_with(cx, |breakpoint_store, cx| {
 9638                breakpoint_store
 9639                    .breakpoints(
 9640                        &buffer,
 9641                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9642                        &buffer_snapshot,
 9643                        cx,
 9644                    )
 9645                    .next()
 9646                    .and_then(|(bp, _)| {
 9647                        let breakpoint_row = buffer_snapshot
 9648                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9649                            .row;
 9650
 9651                        if breakpoint_row == row {
 9652                            snapshot
 9653                                .buffer_snapshot
 9654                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9655                                .map(|position| (position, bp.bp.clone()))
 9656                        } else {
 9657                            None
 9658                        }
 9659                    })
 9660            });
 9661        bp
 9662    }
 9663
 9664    pub fn edit_log_breakpoint(
 9665        &mut self,
 9666        _: &EditLogBreakpoint,
 9667        window: &mut Window,
 9668        cx: &mut Context<Self>,
 9669    ) {
 9670        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9671            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9672                message: None,
 9673                state: BreakpointState::Enabled,
 9674                condition: None,
 9675                hit_condition: None,
 9676            });
 9677
 9678            self.add_edit_breakpoint_block(
 9679                anchor,
 9680                &breakpoint,
 9681                BreakpointPromptEditAction::Log,
 9682                window,
 9683                cx,
 9684            );
 9685        }
 9686    }
 9687
 9688    fn breakpoints_at_cursors(
 9689        &self,
 9690        window: &mut Window,
 9691        cx: &mut Context<Self>,
 9692    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9693        let snapshot = self.snapshot(window, cx);
 9694        let cursors = self
 9695            .selections
 9696            .disjoint_anchors()
 9697            .into_iter()
 9698            .map(|selection| {
 9699                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9700
 9701                let breakpoint_position = self
 9702                    .breakpoint_at_row(cursor_position.row, window, cx)
 9703                    .map(|bp| bp.0)
 9704                    .unwrap_or_else(|| {
 9705                        snapshot
 9706                            .display_snapshot
 9707                            .buffer_snapshot
 9708                            .anchor_after(Point::new(cursor_position.row, 0))
 9709                    });
 9710
 9711                let breakpoint = self
 9712                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9713                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9714
 9715                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9716            })
 9717            // 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.
 9718            .collect::<HashMap<Anchor, _>>();
 9719
 9720        cursors.into_iter().collect()
 9721    }
 9722
 9723    pub fn enable_breakpoint(
 9724        &mut self,
 9725        _: &crate::actions::EnableBreakpoint,
 9726        window: &mut Window,
 9727        cx: &mut Context<Self>,
 9728    ) {
 9729        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9730            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9731                continue;
 9732            };
 9733            self.edit_breakpoint_at_anchor(
 9734                anchor,
 9735                breakpoint,
 9736                BreakpointEditAction::InvertState,
 9737                cx,
 9738            );
 9739        }
 9740    }
 9741
 9742    pub fn disable_breakpoint(
 9743        &mut self,
 9744        _: &crate::actions::DisableBreakpoint,
 9745        window: &mut Window,
 9746        cx: &mut Context<Self>,
 9747    ) {
 9748        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9749            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9750                continue;
 9751            };
 9752            self.edit_breakpoint_at_anchor(
 9753                anchor,
 9754                breakpoint,
 9755                BreakpointEditAction::InvertState,
 9756                cx,
 9757            );
 9758        }
 9759    }
 9760
 9761    pub fn toggle_breakpoint(
 9762        &mut self,
 9763        _: &crate::actions::ToggleBreakpoint,
 9764        window: &mut Window,
 9765        cx: &mut Context<Self>,
 9766    ) {
 9767        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9768            if let Some(breakpoint) = breakpoint {
 9769                self.edit_breakpoint_at_anchor(
 9770                    anchor,
 9771                    breakpoint,
 9772                    BreakpointEditAction::Toggle,
 9773                    cx,
 9774                );
 9775            } else {
 9776                self.edit_breakpoint_at_anchor(
 9777                    anchor,
 9778                    Breakpoint::new_standard(),
 9779                    BreakpointEditAction::Toggle,
 9780                    cx,
 9781                );
 9782            }
 9783        }
 9784    }
 9785
 9786    pub fn edit_breakpoint_at_anchor(
 9787        &mut self,
 9788        breakpoint_position: Anchor,
 9789        breakpoint: Breakpoint,
 9790        edit_action: BreakpointEditAction,
 9791        cx: &mut Context<Self>,
 9792    ) {
 9793        let Some(breakpoint_store) = &self.breakpoint_store else {
 9794            return;
 9795        };
 9796
 9797        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9798            if breakpoint_position == Anchor::min() {
 9799                self.buffer()
 9800                    .read(cx)
 9801                    .excerpt_buffer_ids()
 9802                    .into_iter()
 9803                    .next()
 9804            } else {
 9805                None
 9806            }
 9807        }) else {
 9808            return;
 9809        };
 9810
 9811        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9812            return;
 9813        };
 9814
 9815        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9816            breakpoint_store.toggle_breakpoint(
 9817                buffer,
 9818                BreakpointWithPosition {
 9819                    position: breakpoint_position.text_anchor,
 9820                    bp: breakpoint,
 9821                },
 9822                edit_action,
 9823                cx,
 9824            );
 9825        });
 9826
 9827        cx.notify();
 9828    }
 9829
 9830    #[cfg(any(test, feature = "test-support"))]
 9831    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9832        self.breakpoint_store.clone()
 9833    }
 9834
 9835    pub fn prepare_restore_change(
 9836        &self,
 9837        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9838        hunk: &MultiBufferDiffHunk,
 9839        cx: &mut App,
 9840    ) -> Option<()> {
 9841        if hunk.is_created_file() {
 9842            return None;
 9843        }
 9844        let buffer = self.buffer.read(cx);
 9845        let diff = buffer.diff_for(hunk.buffer_id)?;
 9846        let buffer = buffer.buffer(hunk.buffer_id)?;
 9847        let buffer = buffer.read(cx);
 9848        let original_text = diff
 9849            .read(cx)
 9850            .base_text()
 9851            .as_rope()
 9852            .slice(hunk.diff_base_byte_range.clone());
 9853        let buffer_snapshot = buffer.snapshot();
 9854        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9855        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9856            probe
 9857                .0
 9858                .start
 9859                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9860                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9861        }) {
 9862            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9863            Some(())
 9864        } else {
 9865            None
 9866        }
 9867    }
 9868
 9869    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9870        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9871    }
 9872
 9873    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9874        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9875    }
 9876
 9877    fn manipulate_lines<Fn>(
 9878        &mut self,
 9879        window: &mut Window,
 9880        cx: &mut Context<Self>,
 9881        mut callback: Fn,
 9882    ) where
 9883        Fn: FnMut(&mut Vec<&str>),
 9884    {
 9885        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9886
 9887        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9888        let buffer = self.buffer.read(cx).snapshot(cx);
 9889
 9890        let mut edits = Vec::new();
 9891
 9892        let selections = self.selections.all::<Point>(cx);
 9893        let mut selections = selections.iter().peekable();
 9894        let mut contiguous_row_selections = Vec::new();
 9895        let mut new_selections = Vec::new();
 9896        let mut added_lines = 0;
 9897        let mut removed_lines = 0;
 9898
 9899        while let Some(selection) = selections.next() {
 9900            let (start_row, end_row) = consume_contiguous_rows(
 9901                &mut contiguous_row_selections,
 9902                selection,
 9903                &display_map,
 9904                &mut selections,
 9905            );
 9906
 9907            let start_point = Point::new(start_row.0, 0);
 9908            let end_point = Point::new(
 9909                end_row.previous_row().0,
 9910                buffer.line_len(end_row.previous_row()),
 9911            );
 9912            let text = buffer
 9913                .text_for_range(start_point..end_point)
 9914                .collect::<String>();
 9915
 9916            let mut lines = text.split('\n').collect_vec();
 9917
 9918            let lines_before = lines.len();
 9919            callback(&mut lines);
 9920            let lines_after = lines.len();
 9921
 9922            edits.push((start_point..end_point, lines.join("\n")));
 9923
 9924            // Selections must change based on added and removed line count
 9925            let start_row =
 9926                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9927            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9928            new_selections.push(Selection {
 9929                id: selection.id,
 9930                start: start_row,
 9931                end: end_row,
 9932                goal: SelectionGoal::None,
 9933                reversed: selection.reversed,
 9934            });
 9935
 9936            if lines_after > lines_before {
 9937                added_lines += lines_after - lines_before;
 9938            } else if lines_before > lines_after {
 9939                removed_lines += lines_before - lines_after;
 9940            }
 9941        }
 9942
 9943        self.transact(window, cx, |this, window, cx| {
 9944            let buffer = this.buffer.update(cx, |buffer, cx| {
 9945                buffer.edit(edits, None, cx);
 9946                buffer.snapshot(cx)
 9947            });
 9948
 9949            // Recalculate offsets on newly edited buffer
 9950            let new_selections = new_selections
 9951                .iter()
 9952                .map(|s| {
 9953                    let start_point = Point::new(s.start.0, 0);
 9954                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9955                    Selection {
 9956                        id: s.id,
 9957                        start: buffer.point_to_offset(start_point),
 9958                        end: buffer.point_to_offset(end_point),
 9959                        goal: s.goal,
 9960                        reversed: s.reversed,
 9961                    }
 9962                })
 9963                .collect();
 9964
 9965            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9966                s.select(new_selections);
 9967            });
 9968
 9969            this.request_autoscroll(Autoscroll::fit(), cx);
 9970        });
 9971    }
 9972
 9973    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9974        self.manipulate_text(window, cx, |text| {
 9975            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9976            if has_upper_case_characters {
 9977                text.to_lowercase()
 9978            } else {
 9979                text.to_uppercase()
 9980            }
 9981        })
 9982    }
 9983
 9984    pub fn convert_to_upper_case(
 9985        &mut self,
 9986        _: &ConvertToUpperCase,
 9987        window: &mut Window,
 9988        cx: &mut Context<Self>,
 9989    ) {
 9990        self.manipulate_text(window, cx, |text| text.to_uppercase())
 9991    }
 9992
 9993    pub fn convert_to_lower_case(
 9994        &mut self,
 9995        _: &ConvertToLowerCase,
 9996        window: &mut Window,
 9997        cx: &mut Context<Self>,
 9998    ) {
 9999        self.manipulate_text(window, cx, |text| text.to_lowercase())
10000    }
10001
10002    pub fn convert_to_title_case(
10003        &mut self,
10004        _: &ConvertToTitleCase,
10005        window: &mut Window,
10006        cx: &mut Context<Self>,
10007    ) {
10008        self.manipulate_text(window, cx, |text| {
10009            text.split('\n')
10010                .map(|line| line.to_case(Case::Title))
10011                .join("\n")
10012        })
10013    }
10014
10015    pub fn convert_to_snake_case(
10016        &mut self,
10017        _: &ConvertToSnakeCase,
10018        window: &mut Window,
10019        cx: &mut Context<Self>,
10020    ) {
10021        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10022    }
10023
10024    pub fn convert_to_kebab_case(
10025        &mut self,
10026        _: &ConvertToKebabCase,
10027        window: &mut Window,
10028        cx: &mut Context<Self>,
10029    ) {
10030        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10031    }
10032
10033    pub fn convert_to_upper_camel_case(
10034        &mut self,
10035        _: &ConvertToUpperCamelCase,
10036        window: &mut Window,
10037        cx: &mut Context<Self>,
10038    ) {
10039        self.manipulate_text(window, cx, |text| {
10040            text.split('\n')
10041                .map(|line| line.to_case(Case::UpperCamel))
10042                .join("\n")
10043        })
10044    }
10045
10046    pub fn convert_to_lower_camel_case(
10047        &mut self,
10048        _: &ConvertToLowerCamelCase,
10049        window: &mut Window,
10050        cx: &mut Context<Self>,
10051    ) {
10052        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10053    }
10054
10055    pub fn convert_to_opposite_case(
10056        &mut self,
10057        _: &ConvertToOppositeCase,
10058        window: &mut Window,
10059        cx: &mut Context<Self>,
10060    ) {
10061        self.manipulate_text(window, cx, |text| {
10062            text.chars()
10063                .fold(String::with_capacity(text.len()), |mut t, c| {
10064                    if c.is_uppercase() {
10065                        t.extend(c.to_lowercase());
10066                    } else {
10067                        t.extend(c.to_uppercase());
10068                    }
10069                    t
10070                })
10071        })
10072    }
10073
10074    pub fn convert_to_rot13(
10075        &mut self,
10076        _: &ConvertToRot13,
10077        window: &mut Window,
10078        cx: &mut Context<Self>,
10079    ) {
10080        self.manipulate_text(window, cx, |text| {
10081            text.chars()
10082                .map(|c| match c {
10083                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10084                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10085                    _ => c,
10086                })
10087                .collect()
10088        })
10089    }
10090
10091    pub fn convert_to_rot47(
10092        &mut self,
10093        _: &ConvertToRot47,
10094        window: &mut Window,
10095        cx: &mut Context<Self>,
10096    ) {
10097        self.manipulate_text(window, cx, |text| {
10098            text.chars()
10099                .map(|c| {
10100                    let code_point = c as u32;
10101                    if code_point >= 33 && code_point <= 126 {
10102                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10103                    }
10104                    c
10105                })
10106                .collect()
10107        })
10108    }
10109
10110    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10111    where
10112        Fn: FnMut(&str) -> String,
10113    {
10114        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10115        let buffer = self.buffer.read(cx).snapshot(cx);
10116
10117        let mut new_selections = Vec::new();
10118        let mut edits = Vec::new();
10119        let mut selection_adjustment = 0i32;
10120
10121        for selection in self.selections.all::<usize>(cx) {
10122            let selection_is_empty = selection.is_empty();
10123
10124            let (start, end) = if selection_is_empty {
10125                let word_range = movement::surrounding_word(
10126                    &display_map,
10127                    selection.start.to_display_point(&display_map),
10128                );
10129                let start = word_range.start.to_offset(&display_map, Bias::Left);
10130                let end = word_range.end.to_offset(&display_map, Bias::Left);
10131                (start, end)
10132            } else {
10133                (selection.start, selection.end)
10134            };
10135
10136            let text = buffer.text_for_range(start..end).collect::<String>();
10137            let old_length = text.len() as i32;
10138            let text = callback(&text);
10139
10140            new_selections.push(Selection {
10141                start: (start as i32 - selection_adjustment) as usize,
10142                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10143                goal: SelectionGoal::None,
10144                ..selection
10145            });
10146
10147            selection_adjustment += old_length - text.len() as i32;
10148
10149            edits.push((start..end, text));
10150        }
10151
10152        self.transact(window, cx, |this, window, cx| {
10153            this.buffer.update(cx, |buffer, cx| {
10154                buffer.edit(edits, None, cx);
10155            });
10156
10157            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10158                s.select(new_selections);
10159            });
10160
10161            this.request_autoscroll(Autoscroll::fit(), cx);
10162        });
10163    }
10164
10165    pub fn duplicate(
10166        &mut self,
10167        upwards: bool,
10168        whole_lines: bool,
10169        window: &mut Window,
10170        cx: &mut Context<Self>,
10171    ) {
10172        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10173
10174        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10175        let buffer = &display_map.buffer_snapshot;
10176        let selections = self.selections.all::<Point>(cx);
10177
10178        let mut edits = Vec::new();
10179        let mut selections_iter = selections.iter().peekable();
10180        while let Some(selection) = selections_iter.next() {
10181            let mut rows = selection.spanned_rows(false, &display_map);
10182            // duplicate line-wise
10183            if whole_lines || selection.start == selection.end {
10184                // Avoid duplicating the same lines twice.
10185                while let Some(next_selection) = selections_iter.peek() {
10186                    let next_rows = next_selection.spanned_rows(false, &display_map);
10187                    if next_rows.start < rows.end {
10188                        rows.end = next_rows.end;
10189                        selections_iter.next().unwrap();
10190                    } else {
10191                        break;
10192                    }
10193                }
10194
10195                // Copy the text from the selected row region and splice it either at the start
10196                // or end of the region.
10197                let start = Point::new(rows.start.0, 0);
10198                let end = Point::new(
10199                    rows.end.previous_row().0,
10200                    buffer.line_len(rows.end.previous_row()),
10201                );
10202                let text = buffer
10203                    .text_for_range(start..end)
10204                    .chain(Some("\n"))
10205                    .collect::<String>();
10206                let insert_location = if upwards {
10207                    Point::new(rows.end.0, 0)
10208                } else {
10209                    start
10210                };
10211                edits.push((insert_location..insert_location, text));
10212            } else {
10213                // duplicate character-wise
10214                let start = selection.start;
10215                let end = selection.end;
10216                let text = buffer.text_for_range(start..end).collect::<String>();
10217                edits.push((selection.end..selection.end, text));
10218            }
10219        }
10220
10221        self.transact(window, cx, |this, _, cx| {
10222            this.buffer.update(cx, |buffer, cx| {
10223                buffer.edit(edits, None, cx);
10224            });
10225
10226            this.request_autoscroll(Autoscroll::fit(), cx);
10227        });
10228    }
10229
10230    pub fn duplicate_line_up(
10231        &mut self,
10232        _: &DuplicateLineUp,
10233        window: &mut Window,
10234        cx: &mut Context<Self>,
10235    ) {
10236        self.duplicate(true, true, window, cx);
10237    }
10238
10239    pub fn duplicate_line_down(
10240        &mut self,
10241        _: &DuplicateLineDown,
10242        window: &mut Window,
10243        cx: &mut Context<Self>,
10244    ) {
10245        self.duplicate(false, true, window, cx);
10246    }
10247
10248    pub fn duplicate_selection(
10249        &mut self,
10250        _: &DuplicateSelection,
10251        window: &mut Window,
10252        cx: &mut Context<Self>,
10253    ) {
10254        self.duplicate(false, false, window, cx);
10255    }
10256
10257    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10258        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10259
10260        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10261        let buffer = self.buffer.read(cx).snapshot(cx);
10262
10263        let mut edits = Vec::new();
10264        let mut unfold_ranges = Vec::new();
10265        let mut refold_creases = Vec::new();
10266
10267        let selections = self.selections.all::<Point>(cx);
10268        let mut selections = selections.iter().peekable();
10269        let mut contiguous_row_selections = Vec::new();
10270        let mut new_selections = Vec::new();
10271
10272        while let Some(selection) = selections.next() {
10273            // Find all the selections that span a contiguous row range
10274            let (start_row, end_row) = consume_contiguous_rows(
10275                &mut contiguous_row_selections,
10276                selection,
10277                &display_map,
10278                &mut selections,
10279            );
10280
10281            // Move the text spanned by the row range to be before the line preceding the row range
10282            if start_row.0 > 0 {
10283                let range_to_move = Point::new(
10284                    start_row.previous_row().0,
10285                    buffer.line_len(start_row.previous_row()),
10286                )
10287                    ..Point::new(
10288                        end_row.previous_row().0,
10289                        buffer.line_len(end_row.previous_row()),
10290                    );
10291                let insertion_point = display_map
10292                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10293                    .0;
10294
10295                // Don't move lines across excerpts
10296                if buffer
10297                    .excerpt_containing(insertion_point..range_to_move.end)
10298                    .is_some()
10299                {
10300                    let text = buffer
10301                        .text_for_range(range_to_move.clone())
10302                        .flat_map(|s| s.chars())
10303                        .skip(1)
10304                        .chain(['\n'])
10305                        .collect::<String>();
10306
10307                    edits.push((
10308                        buffer.anchor_after(range_to_move.start)
10309                            ..buffer.anchor_before(range_to_move.end),
10310                        String::new(),
10311                    ));
10312                    let insertion_anchor = buffer.anchor_after(insertion_point);
10313                    edits.push((insertion_anchor..insertion_anchor, text));
10314
10315                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10316
10317                    // Move selections up
10318                    new_selections.extend(contiguous_row_selections.drain(..).map(
10319                        |mut selection| {
10320                            selection.start.row -= row_delta;
10321                            selection.end.row -= row_delta;
10322                            selection
10323                        },
10324                    ));
10325
10326                    // Move folds up
10327                    unfold_ranges.push(range_to_move.clone());
10328                    for fold in display_map.folds_in_range(
10329                        buffer.anchor_before(range_to_move.start)
10330                            ..buffer.anchor_after(range_to_move.end),
10331                    ) {
10332                        let mut start = fold.range.start.to_point(&buffer);
10333                        let mut end = fold.range.end.to_point(&buffer);
10334                        start.row -= row_delta;
10335                        end.row -= row_delta;
10336                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10337                    }
10338                }
10339            }
10340
10341            // If we didn't move line(s), preserve the existing selections
10342            new_selections.append(&mut contiguous_row_selections);
10343        }
10344
10345        self.transact(window, cx, |this, window, cx| {
10346            this.unfold_ranges(&unfold_ranges, true, true, cx);
10347            this.buffer.update(cx, |buffer, cx| {
10348                for (range, text) in edits {
10349                    buffer.edit([(range, text)], None, cx);
10350                }
10351            });
10352            this.fold_creases(refold_creases, true, window, cx);
10353            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10354                s.select(new_selections);
10355            })
10356        });
10357    }
10358
10359    pub fn move_line_down(
10360        &mut self,
10361        _: &MoveLineDown,
10362        window: &mut Window,
10363        cx: &mut Context<Self>,
10364    ) {
10365        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10366
10367        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10368        let buffer = self.buffer.read(cx).snapshot(cx);
10369
10370        let mut edits = Vec::new();
10371        let mut unfold_ranges = Vec::new();
10372        let mut refold_creases = Vec::new();
10373
10374        let selections = self.selections.all::<Point>(cx);
10375        let mut selections = selections.iter().peekable();
10376        let mut contiguous_row_selections = Vec::new();
10377        let mut new_selections = Vec::new();
10378
10379        while let Some(selection) = selections.next() {
10380            // Find all the selections that span a contiguous row range
10381            let (start_row, end_row) = consume_contiguous_rows(
10382                &mut contiguous_row_selections,
10383                selection,
10384                &display_map,
10385                &mut selections,
10386            );
10387
10388            // Move the text spanned by the row range to be after the last line of the row range
10389            if end_row.0 <= buffer.max_point().row {
10390                let range_to_move =
10391                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10392                let insertion_point = display_map
10393                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10394                    .0;
10395
10396                // Don't move lines across excerpt boundaries
10397                if buffer
10398                    .excerpt_containing(range_to_move.start..insertion_point)
10399                    .is_some()
10400                {
10401                    let mut text = String::from("\n");
10402                    text.extend(buffer.text_for_range(range_to_move.clone()));
10403                    text.pop(); // Drop trailing newline
10404                    edits.push((
10405                        buffer.anchor_after(range_to_move.start)
10406                            ..buffer.anchor_before(range_to_move.end),
10407                        String::new(),
10408                    ));
10409                    let insertion_anchor = buffer.anchor_after(insertion_point);
10410                    edits.push((insertion_anchor..insertion_anchor, text));
10411
10412                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10413
10414                    // Move selections down
10415                    new_selections.extend(contiguous_row_selections.drain(..).map(
10416                        |mut selection| {
10417                            selection.start.row += row_delta;
10418                            selection.end.row += row_delta;
10419                            selection
10420                        },
10421                    ));
10422
10423                    // Move folds down
10424                    unfold_ranges.push(range_to_move.clone());
10425                    for fold in display_map.folds_in_range(
10426                        buffer.anchor_before(range_to_move.start)
10427                            ..buffer.anchor_after(range_to_move.end),
10428                    ) {
10429                        let mut start = fold.range.start.to_point(&buffer);
10430                        let mut end = fold.range.end.to_point(&buffer);
10431                        start.row += row_delta;
10432                        end.row += row_delta;
10433                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10434                    }
10435                }
10436            }
10437
10438            // If we didn't move line(s), preserve the existing selections
10439            new_selections.append(&mut contiguous_row_selections);
10440        }
10441
10442        self.transact(window, cx, |this, window, cx| {
10443            this.unfold_ranges(&unfold_ranges, true, true, cx);
10444            this.buffer.update(cx, |buffer, cx| {
10445                for (range, text) in edits {
10446                    buffer.edit([(range, text)], None, cx);
10447                }
10448            });
10449            this.fold_creases(refold_creases, true, window, cx);
10450            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10451                s.select(new_selections)
10452            });
10453        });
10454    }
10455
10456    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10457        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10458        let text_layout_details = &self.text_layout_details(window);
10459        self.transact(window, cx, |this, window, cx| {
10460            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10461                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10462                s.move_with(|display_map, selection| {
10463                    if !selection.is_empty() {
10464                        return;
10465                    }
10466
10467                    let mut head = selection.head();
10468                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10469                    if head.column() == display_map.line_len(head.row()) {
10470                        transpose_offset = display_map
10471                            .buffer_snapshot
10472                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10473                    }
10474
10475                    if transpose_offset == 0 {
10476                        return;
10477                    }
10478
10479                    *head.column_mut() += 1;
10480                    head = display_map.clip_point(head, Bias::Right);
10481                    let goal = SelectionGoal::HorizontalPosition(
10482                        display_map
10483                            .x_for_display_point(head, text_layout_details)
10484                            .into(),
10485                    );
10486                    selection.collapse_to(head, goal);
10487
10488                    let transpose_start = display_map
10489                        .buffer_snapshot
10490                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10491                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10492                        let transpose_end = display_map
10493                            .buffer_snapshot
10494                            .clip_offset(transpose_offset + 1, Bias::Right);
10495                        if let Some(ch) =
10496                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10497                        {
10498                            edits.push((transpose_start..transpose_offset, String::new()));
10499                            edits.push((transpose_end..transpose_end, ch.to_string()));
10500                        }
10501                    }
10502                });
10503                edits
10504            });
10505            this.buffer
10506                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10507            let selections = this.selections.all::<usize>(cx);
10508            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10509                s.select(selections);
10510            });
10511        });
10512    }
10513
10514    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10515        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10516        self.rewrap_impl(RewrapOptions::default(), cx)
10517    }
10518
10519    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10520        let buffer = self.buffer.read(cx).snapshot(cx);
10521        let selections = self.selections.all::<Point>(cx);
10522        let mut selections = selections.iter().peekable();
10523
10524        let mut edits = Vec::new();
10525        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10526
10527        while let Some(selection) = selections.next() {
10528            let mut start_row = selection.start.row;
10529            let mut end_row = selection.end.row;
10530
10531            // Skip selections that overlap with a range that has already been rewrapped.
10532            let selection_range = start_row..end_row;
10533            if rewrapped_row_ranges
10534                .iter()
10535                .any(|range| range.overlaps(&selection_range))
10536            {
10537                continue;
10538            }
10539
10540            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10541
10542            // Since not all lines in the selection may be at the same indent
10543            // level, choose the indent size that is the most common between all
10544            // of the lines.
10545            //
10546            // If there is a tie, we use the deepest indent.
10547            let (indent_size, indent_end) = {
10548                let mut indent_size_occurrences = HashMap::default();
10549                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10550
10551                for row in start_row..=end_row {
10552                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10553                    rows_by_indent_size.entry(indent).or_default().push(row);
10554                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10555                }
10556
10557                let indent_size = indent_size_occurrences
10558                    .into_iter()
10559                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10560                    .map(|(indent, _)| indent)
10561                    .unwrap_or_default();
10562                let row = rows_by_indent_size[&indent_size][0];
10563                let indent_end = Point::new(row, indent_size.len);
10564
10565                (indent_size, indent_end)
10566            };
10567
10568            let mut line_prefix = indent_size.chars().collect::<String>();
10569
10570            let mut inside_comment = false;
10571            if let Some(comment_prefix) =
10572                buffer
10573                    .language_scope_at(selection.head())
10574                    .and_then(|language| {
10575                        language
10576                            .line_comment_prefixes()
10577                            .iter()
10578                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10579                            .cloned()
10580                    })
10581            {
10582                line_prefix.push_str(&comment_prefix);
10583                inside_comment = true;
10584            }
10585
10586            let language_settings = buffer.language_settings_at(selection.head(), cx);
10587            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10588                RewrapBehavior::InComments => inside_comment,
10589                RewrapBehavior::InSelections => !selection.is_empty(),
10590                RewrapBehavior::Anywhere => true,
10591            };
10592
10593            let should_rewrap = options.override_language_settings
10594                || allow_rewrap_based_on_language
10595                || self.hard_wrap.is_some();
10596            if !should_rewrap {
10597                continue;
10598            }
10599
10600            if selection.is_empty() {
10601                'expand_upwards: while start_row > 0 {
10602                    let prev_row = start_row - 1;
10603                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10604                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10605                    {
10606                        start_row = prev_row;
10607                    } else {
10608                        break 'expand_upwards;
10609                    }
10610                }
10611
10612                'expand_downwards: while end_row < buffer.max_point().row {
10613                    let next_row = end_row + 1;
10614                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10615                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10616                    {
10617                        end_row = next_row;
10618                    } else {
10619                        break 'expand_downwards;
10620                    }
10621                }
10622            }
10623
10624            let start = Point::new(start_row, 0);
10625            let start_offset = start.to_offset(&buffer);
10626            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10627            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10628            let Some(lines_without_prefixes) = selection_text
10629                .lines()
10630                .map(|line| {
10631                    line.strip_prefix(&line_prefix)
10632                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10633                        .with_context(|| {
10634                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10635                        })
10636                })
10637                .collect::<Result<Vec<_>, _>>()
10638                .log_err()
10639            else {
10640                continue;
10641            };
10642
10643            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10644                buffer
10645                    .language_settings_at(Point::new(start_row, 0), cx)
10646                    .preferred_line_length as usize
10647            });
10648            let wrapped_text = wrap_with_prefix(
10649                line_prefix,
10650                lines_without_prefixes.join("\n"),
10651                wrap_column,
10652                tab_size,
10653                options.preserve_existing_whitespace,
10654            );
10655
10656            // TODO: should always use char-based diff while still supporting cursor behavior that
10657            // matches vim.
10658            let mut diff_options = DiffOptions::default();
10659            if options.override_language_settings {
10660                diff_options.max_word_diff_len = 0;
10661                diff_options.max_word_diff_line_count = 0;
10662            } else {
10663                diff_options.max_word_diff_len = usize::MAX;
10664                diff_options.max_word_diff_line_count = usize::MAX;
10665            }
10666
10667            for (old_range, new_text) in
10668                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10669            {
10670                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10671                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10672                edits.push((edit_start..edit_end, new_text));
10673            }
10674
10675            rewrapped_row_ranges.push(start_row..=end_row);
10676        }
10677
10678        self.buffer
10679            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10680    }
10681
10682    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10683        let mut text = String::new();
10684        let buffer = self.buffer.read(cx).snapshot(cx);
10685        let mut selections = self.selections.all::<Point>(cx);
10686        let mut clipboard_selections = Vec::with_capacity(selections.len());
10687        {
10688            let max_point = buffer.max_point();
10689            let mut is_first = true;
10690            for selection in &mut selections {
10691                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10692                if is_entire_line {
10693                    selection.start = Point::new(selection.start.row, 0);
10694                    if !selection.is_empty() && selection.end.column == 0 {
10695                        selection.end = cmp::min(max_point, selection.end);
10696                    } else {
10697                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10698                    }
10699                    selection.goal = SelectionGoal::None;
10700                }
10701                if is_first {
10702                    is_first = false;
10703                } else {
10704                    text += "\n";
10705                }
10706                let mut len = 0;
10707                for chunk in buffer.text_for_range(selection.start..selection.end) {
10708                    text.push_str(chunk);
10709                    len += chunk.len();
10710                }
10711                clipboard_selections.push(ClipboardSelection {
10712                    len,
10713                    is_entire_line,
10714                    first_line_indent: buffer
10715                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10716                        .len,
10717                });
10718            }
10719        }
10720
10721        self.transact(window, cx, |this, window, cx| {
10722            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10723                s.select(selections);
10724            });
10725            this.insert("", window, cx);
10726        });
10727        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10728    }
10729
10730    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10731        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10732        let item = self.cut_common(window, cx);
10733        cx.write_to_clipboard(item);
10734    }
10735
10736    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10737        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10738        self.change_selections(None, window, cx, |s| {
10739            s.move_with(|snapshot, sel| {
10740                if sel.is_empty() {
10741                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10742                }
10743            });
10744        });
10745        let item = self.cut_common(window, cx);
10746        cx.set_global(KillRing(item))
10747    }
10748
10749    pub fn kill_ring_yank(
10750        &mut self,
10751        _: &KillRingYank,
10752        window: &mut Window,
10753        cx: &mut Context<Self>,
10754    ) {
10755        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10756        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10757            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10758                (kill_ring.text().to_string(), kill_ring.metadata_json())
10759            } else {
10760                return;
10761            }
10762        } else {
10763            return;
10764        };
10765        self.do_paste(&text, metadata, false, window, cx);
10766    }
10767
10768    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10769        self.do_copy(true, cx);
10770    }
10771
10772    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10773        self.do_copy(false, cx);
10774    }
10775
10776    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10777        let selections = self.selections.all::<Point>(cx);
10778        let buffer = self.buffer.read(cx).read(cx);
10779        let mut text = String::new();
10780
10781        let mut clipboard_selections = Vec::with_capacity(selections.len());
10782        {
10783            let max_point = buffer.max_point();
10784            let mut is_first = true;
10785            for selection in &selections {
10786                let mut start = selection.start;
10787                let mut end = selection.end;
10788                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10789                if is_entire_line {
10790                    start = Point::new(start.row, 0);
10791                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10792                }
10793
10794                let mut trimmed_selections = Vec::new();
10795                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10796                    let row = MultiBufferRow(start.row);
10797                    let first_indent = buffer.indent_size_for_line(row);
10798                    if first_indent.len == 0 || start.column > first_indent.len {
10799                        trimmed_selections.push(start..end);
10800                    } else {
10801                        trimmed_selections.push(
10802                            Point::new(row.0, first_indent.len)
10803                                ..Point::new(row.0, buffer.line_len(row)),
10804                        );
10805                        for row in start.row + 1..=end.row {
10806                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10807                            if row == end.row {
10808                                line_len = end.column;
10809                            }
10810                            if line_len == 0 {
10811                                trimmed_selections
10812                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10813                                continue;
10814                            }
10815                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10816                            if row_indent_size.len >= first_indent.len {
10817                                trimmed_selections.push(
10818                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10819                                );
10820                            } else {
10821                                trimmed_selections.clear();
10822                                trimmed_selections.push(start..end);
10823                                break;
10824                            }
10825                        }
10826                    }
10827                } else {
10828                    trimmed_selections.push(start..end);
10829                }
10830
10831                for trimmed_range in trimmed_selections {
10832                    if is_first {
10833                        is_first = false;
10834                    } else {
10835                        text += "\n";
10836                    }
10837                    let mut len = 0;
10838                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10839                        text.push_str(chunk);
10840                        len += chunk.len();
10841                    }
10842                    clipboard_selections.push(ClipboardSelection {
10843                        len,
10844                        is_entire_line,
10845                        first_line_indent: buffer
10846                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10847                            .len,
10848                    });
10849                }
10850            }
10851        }
10852
10853        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10854            text,
10855            clipboard_selections,
10856        ));
10857    }
10858
10859    pub fn do_paste(
10860        &mut self,
10861        text: &String,
10862        clipboard_selections: Option<Vec<ClipboardSelection>>,
10863        handle_entire_lines: bool,
10864        window: &mut Window,
10865        cx: &mut Context<Self>,
10866    ) {
10867        if self.read_only(cx) {
10868            return;
10869        }
10870
10871        let clipboard_text = Cow::Borrowed(text);
10872
10873        self.transact(window, cx, |this, window, cx| {
10874            if let Some(mut clipboard_selections) = clipboard_selections {
10875                let old_selections = this.selections.all::<usize>(cx);
10876                let all_selections_were_entire_line =
10877                    clipboard_selections.iter().all(|s| s.is_entire_line);
10878                let first_selection_indent_column =
10879                    clipboard_selections.first().map(|s| s.first_line_indent);
10880                if clipboard_selections.len() != old_selections.len() {
10881                    clipboard_selections.drain(..);
10882                }
10883                let cursor_offset = this.selections.last::<usize>(cx).head();
10884                let mut auto_indent_on_paste = true;
10885
10886                this.buffer.update(cx, |buffer, cx| {
10887                    let snapshot = buffer.read(cx);
10888                    auto_indent_on_paste = snapshot
10889                        .language_settings_at(cursor_offset, cx)
10890                        .auto_indent_on_paste;
10891
10892                    let mut start_offset = 0;
10893                    let mut edits = Vec::new();
10894                    let mut original_indent_columns = Vec::new();
10895                    for (ix, selection) in old_selections.iter().enumerate() {
10896                        let to_insert;
10897                        let entire_line;
10898                        let original_indent_column;
10899                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10900                            let end_offset = start_offset + clipboard_selection.len;
10901                            to_insert = &clipboard_text[start_offset..end_offset];
10902                            entire_line = clipboard_selection.is_entire_line;
10903                            start_offset = end_offset + 1;
10904                            original_indent_column = Some(clipboard_selection.first_line_indent);
10905                        } else {
10906                            to_insert = clipboard_text.as_str();
10907                            entire_line = all_selections_were_entire_line;
10908                            original_indent_column = first_selection_indent_column
10909                        }
10910
10911                        // If the corresponding selection was empty when this slice of the
10912                        // clipboard text was written, then the entire line containing the
10913                        // selection was copied. If this selection is also currently empty,
10914                        // then paste the line before the current line of the buffer.
10915                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10916                            let column = selection.start.to_point(&snapshot).column as usize;
10917                            let line_start = selection.start - column;
10918                            line_start..line_start
10919                        } else {
10920                            selection.range()
10921                        };
10922
10923                        edits.push((range, to_insert));
10924                        original_indent_columns.push(original_indent_column);
10925                    }
10926                    drop(snapshot);
10927
10928                    buffer.edit(
10929                        edits,
10930                        if auto_indent_on_paste {
10931                            Some(AutoindentMode::Block {
10932                                original_indent_columns,
10933                            })
10934                        } else {
10935                            None
10936                        },
10937                        cx,
10938                    );
10939                });
10940
10941                let selections = this.selections.all::<usize>(cx);
10942                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10943                    s.select(selections)
10944                });
10945            } else {
10946                this.insert(&clipboard_text, window, cx);
10947            }
10948        });
10949    }
10950
10951    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10952        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10953        if let Some(item) = cx.read_from_clipboard() {
10954            let entries = item.entries();
10955
10956            match entries.first() {
10957                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10958                // of all the pasted entries.
10959                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10960                    .do_paste(
10961                        clipboard_string.text(),
10962                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10963                        true,
10964                        window,
10965                        cx,
10966                    ),
10967                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10968            }
10969        }
10970    }
10971
10972    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10973        if self.read_only(cx) {
10974            return;
10975        }
10976
10977        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10978
10979        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10980            if let Some((selections, _)) =
10981                self.selection_history.transaction(transaction_id).cloned()
10982            {
10983                self.change_selections(None, window, cx, |s| {
10984                    s.select_anchors(selections.to_vec());
10985                });
10986            } else {
10987                log::error!(
10988                    "No entry in selection_history found for undo. \
10989                     This may correspond to a bug where undo does not update the selection. \
10990                     If this is occurring, please add details to \
10991                     https://github.com/zed-industries/zed/issues/22692"
10992                );
10993            }
10994            self.request_autoscroll(Autoscroll::fit(), cx);
10995            self.unmark_text(window, cx);
10996            self.refresh_inline_completion(true, false, window, cx);
10997            cx.emit(EditorEvent::Edited { transaction_id });
10998            cx.emit(EditorEvent::TransactionUndone { transaction_id });
10999        }
11000    }
11001
11002    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11003        if self.read_only(cx) {
11004            return;
11005        }
11006
11007        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11008
11009        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11010            if let Some((_, Some(selections))) =
11011                self.selection_history.transaction(transaction_id).cloned()
11012            {
11013                self.change_selections(None, window, cx, |s| {
11014                    s.select_anchors(selections.to_vec());
11015                });
11016            } else {
11017                log::error!(
11018                    "No entry in selection_history found for redo. \
11019                     This may correspond to a bug where undo does not update the selection. \
11020                     If this is occurring, please add details to \
11021                     https://github.com/zed-industries/zed/issues/22692"
11022                );
11023            }
11024            self.request_autoscroll(Autoscroll::fit(), cx);
11025            self.unmark_text(window, cx);
11026            self.refresh_inline_completion(true, false, window, cx);
11027            cx.emit(EditorEvent::Edited { transaction_id });
11028        }
11029    }
11030
11031    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11032        self.buffer
11033            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11034    }
11035
11036    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11037        self.buffer
11038            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11039    }
11040
11041    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11042        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11043        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11044            s.move_with(|map, selection| {
11045                let cursor = if selection.is_empty() {
11046                    movement::left(map, selection.start)
11047                } else {
11048                    selection.start
11049                };
11050                selection.collapse_to(cursor, SelectionGoal::None);
11051            });
11052        })
11053    }
11054
11055    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11056        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11057        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11058            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11059        })
11060    }
11061
11062    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11063        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11064        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11065            s.move_with(|map, selection| {
11066                let cursor = if selection.is_empty() {
11067                    movement::right(map, selection.end)
11068                } else {
11069                    selection.end
11070                };
11071                selection.collapse_to(cursor, SelectionGoal::None)
11072            });
11073        })
11074    }
11075
11076    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11077        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11078        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11079            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11080        })
11081    }
11082
11083    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11084        if self.take_rename(true, window, cx).is_some() {
11085            return;
11086        }
11087
11088        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11089            cx.propagate();
11090            return;
11091        }
11092
11093        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11094
11095        let text_layout_details = &self.text_layout_details(window);
11096        let selection_count = self.selections.count();
11097        let first_selection = self.selections.first_anchor();
11098
11099        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11100            s.move_with(|map, selection| {
11101                if !selection.is_empty() {
11102                    selection.goal = SelectionGoal::None;
11103                }
11104                let (cursor, goal) = movement::up(
11105                    map,
11106                    selection.start,
11107                    selection.goal,
11108                    false,
11109                    text_layout_details,
11110                );
11111                selection.collapse_to(cursor, goal);
11112            });
11113        });
11114
11115        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11116        {
11117            cx.propagate();
11118        }
11119    }
11120
11121    pub fn move_up_by_lines(
11122        &mut self,
11123        action: &MoveUpByLines,
11124        window: &mut Window,
11125        cx: &mut Context<Self>,
11126    ) {
11127        if self.take_rename(true, window, cx).is_some() {
11128            return;
11129        }
11130
11131        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11132            cx.propagate();
11133            return;
11134        }
11135
11136        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11137
11138        let text_layout_details = &self.text_layout_details(window);
11139
11140        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11141            s.move_with(|map, selection| {
11142                if !selection.is_empty() {
11143                    selection.goal = SelectionGoal::None;
11144                }
11145                let (cursor, goal) = movement::up_by_rows(
11146                    map,
11147                    selection.start,
11148                    action.lines,
11149                    selection.goal,
11150                    false,
11151                    text_layout_details,
11152                );
11153                selection.collapse_to(cursor, goal);
11154            });
11155        })
11156    }
11157
11158    pub fn move_down_by_lines(
11159        &mut self,
11160        action: &MoveDownByLines,
11161        window: &mut Window,
11162        cx: &mut Context<Self>,
11163    ) {
11164        if self.take_rename(true, window, cx).is_some() {
11165            return;
11166        }
11167
11168        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11169            cx.propagate();
11170            return;
11171        }
11172
11173        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11174
11175        let text_layout_details = &self.text_layout_details(window);
11176
11177        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11178            s.move_with(|map, selection| {
11179                if !selection.is_empty() {
11180                    selection.goal = SelectionGoal::None;
11181                }
11182                let (cursor, goal) = movement::down_by_rows(
11183                    map,
11184                    selection.start,
11185                    action.lines,
11186                    selection.goal,
11187                    false,
11188                    text_layout_details,
11189                );
11190                selection.collapse_to(cursor, goal);
11191            });
11192        })
11193    }
11194
11195    pub fn select_down_by_lines(
11196        &mut self,
11197        action: &SelectDownByLines,
11198        window: &mut Window,
11199        cx: &mut Context<Self>,
11200    ) {
11201        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11202        let text_layout_details = &self.text_layout_details(window);
11203        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11204            s.move_heads_with(|map, head, goal| {
11205                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11206            })
11207        })
11208    }
11209
11210    pub fn select_up_by_lines(
11211        &mut self,
11212        action: &SelectUpByLines,
11213        window: &mut Window,
11214        cx: &mut Context<Self>,
11215    ) {
11216        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11217        let text_layout_details = &self.text_layout_details(window);
11218        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11219            s.move_heads_with(|map, head, goal| {
11220                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11221            })
11222        })
11223    }
11224
11225    pub fn select_page_up(
11226        &mut self,
11227        _: &SelectPageUp,
11228        window: &mut Window,
11229        cx: &mut Context<Self>,
11230    ) {
11231        let Some(row_count) = self.visible_row_count() else {
11232            return;
11233        };
11234
11235        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11236
11237        let text_layout_details = &self.text_layout_details(window);
11238
11239        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11240            s.move_heads_with(|map, head, goal| {
11241                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11242            })
11243        })
11244    }
11245
11246    pub fn move_page_up(
11247        &mut self,
11248        action: &MovePageUp,
11249        window: &mut Window,
11250        cx: &mut Context<Self>,
11251    ) {
11252        if self.take_rename(true, window, cx).is_some() {
11253            return;
11254        }
11255
11256        if self
11257            .context_menu
11258            .borrow_mut()
11259            .as_mut()
11260            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11261            .unwrap_or(false)
11262        {
11263            return;
11264        }
11265
11266        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11267            cx.propagate();
11268            return;
11269        }
11270
11271        let Some(row_count) = self.visible_row_count() else {
11272            return;
11273        };
11274
11275        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11276
11277        let autoscroll = if action.center_cursor {
11278            Autoscroll::center()
11279        } else {
11280            Autoscroll::fit()
11281        };
11282
11283        let text_layout_details = &self.text_layout_details(window);
11284
11285        self.change_selections(Some(autoscroll), window, cx, |s| {
11286            s.move_with(|map, selection| {
11287                if !selection.is_empty() {
11288                    selection.goal = SelectionGoal::None;
11289                }
11290                let (cursor, goal) = movement::up_by_rows(
11291                    map,
11292                    selection.end,
11293                    row_count,
11294                    selection.goal,
11295                    false,
11296                    text_layout_details,
11297                );
11298                selection.collapse_to(cursor, goal);
11299            });
11300        });
11301    }
11302
11303    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11304        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11305        let text_layout_details = &self.text_layout_details(window);
11306        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11307            s.move_heads_with(|map, head, goal| {
11308                movement::up(map, head, goal, false, text_layout_details)
11309            })
11310        })
11311    }
11312
11313    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11314        self.take_rename(true, window, cx);
11315
11316        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11317            cx.propagate();
11318            return;
11319        }
11320
11321        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11322
11323        let text_layout_details = &self.text_layout_details(window);
11324        let selection_count = self.selections.count();
11325        let first_selection = self.selections.first_anchor();
11326
11327        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11328            s.move_with(|map, selection| {
11329                if !selection.is_empty() {
11330                    selection.goal = SelectionGoal::None;
11331                }
11332                let (cursor, goal) = movement::down(
11333                    map,
11334                    selection.end,
11335                    selection.goal,
11336                    false,
11337                    text_layout_details,
11338                );
11339                selection.collapse_to(cursor, goal);
11340            });
11341        });
11342
11343        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11344        {
11345            cx.propagate();
11346        }
11347    }
11348
11349    pub fn select_page_down(
11350        &mut self,
11351        _: &SelectPageDown,
11352        window: &mut Window,
11353        cx: &mut Context<Self>,
11354    ) {
11355        let Some(row_count) = self.visible_row_count() else {
11356            return;
11357        };
11358
11359        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11360
11361        let text_layout_details = &self.text_layout_details(window);
11362
11363        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11364            s.move_heads_with(|map, head, goal| {
11365                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11366            })
11367        })
11368    }
11369
11370    pub fn move_page_down(
11371        &mut self,
11372        action: &MovePageDown,
11373        window: &mut Window,
11374        cx: &mut Context<Self>,
11375    ) {
11376        if self.take_rename(true, window, cx).is_some() {
11377            return;
11378        }
11379
11380        if self
11381            .context_menu
11382            .borrow_mut()
11383            .as_mut()
11384            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11385            .unwrap_or(false)
11386        {
11387            return;
11388        }
11389
11390        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11391            cx.propagate();
11392            return;
11393        }
11394
11395        let Some(row_count) = self.visible_row_count() else {
11396            return;
11397        };
11398
11399        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11400
11401        let autoscroll = if action.center_cursor {
11402            Autoscroll::center()
11403        } else {
11404            Autoscroll::fit()
11405        };
11406
11407        let text_layout_details = &self.text_layout_details(window);
11408        self.change_selections(Some(autoscroll), window, cx, |s| {
11409            s.move_with(|map, selection| {
11410                if !selection.is_empty() {
11411                    selection.goal = SelectionGoal::None;
11412                }
11413                let (cursor, goal) = movement::down_by_rows(
11414                    map,
11415                    selection.end,
11416                    row_count,
11417                    selection.goal,
11418                    false,
11419                    text_layout_details,
11420                );
11421                selection.collapse_to(cursor, goal);
11422            });
11423        });
11424    }
11425
11426    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11427        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11428        let text_layout_details = &self.text_layout_details(window);
11429        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11430            s.move_heads_with(|map, head, goal| {
11431                movement::down(map, head, goal, false, text_layout_details)
11432            })
11433        });
11434    }
11435
11436    pub fn context_menu_first(
11437        &mut self,
11438        _: &ContextMenuFirst,
11439        _window: &mut Window,
11440        cx: &mut Context<Self>,
11441    ) {
11442        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11443            context_menu.select_first(self.completion_provider.as_deref(), cx);
11444        }
11445    }
11446
11447    pub fn context_menu_prev(
11448        &mut self,
11449        _: &ContextMenuPrevious,
11450        _window: &mut Window,
11451        cx: &mut Context<Self>,
11452    ) {
11453        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11454            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11455        }
11456    }
11457
11458    pub fn context_menu_next(
11459        &mut self,
11460        _: &ContextMenuNext,
11461        _window: &mut Window,
11462        cx: &mut Context<Self>,
11463    ) {
11464        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11465            context_menu.select_next(self.completion_provider.as_deref(), cx);
11466        }
11467    }
11468
11469    pub fn context_menu_last(
11470        &mut self,
11471        _: &ContextMenuLast,
11472        _window: &mut Window,
11473        cx: &mut Context<Self>,
11474    ) {
11475        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11476            context_menu.select_last(self.completion_provider.as_deref(), cx);
11477        }
11478    }
11479
11480    pub fn move_to_previous_word_start(
11481        &mut self,
11482        _: &MoveToPreviousWordStart,
11483        window: &mut Window,
11484        cx: &mut Context<Self>,
11485    ) {
11486        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11487        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11488            s.move_cursors_with(|map, head, _| {
11489                (
11490                    movement::previous_word_start(map, head),
11491                    SelectionGoal::None,
11492                )
11493            });
11494        })
11495    }
11496
11497    pub fn move_to_previous_subword_start(
11498        &mut self,
11499        _: &MoveToPreviousSubwordStart,
11500        window: &mut Window,
11501        cx: &mut Context<Self>,
11502    ) {
11503        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11504        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11505            s.move_cursors_with(|map, head, _| {
11506                (
11507                    movement::previous_subword_start(map, head),
11508                    SelectionGoal::None,
11509                )
11510            });
11511        })
11512    }
11513
11514    pub fn select_to_previous_word_start(
11515        &mut self,
11516        _: &SelectToPreviousWordStart,
11517        window: &mut Window,
11518        cx: &mut Context<Self>,
11519    ) {
11520        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11521        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11522            s.move_heads_with(|map, head, _| {
11523                (
11524                    movement::previous_word_start(map, head),
11525                    SelectionGoal::None,
11526                )
11527            });
11528        })
11529    }
11530
11531    pub fn select_to_previous_subword_start(
11532        &mut self,
11533        _: &SelectToPreviousSubwordStart,
11534        window: &mut Window,
11535        cx: &mut Context<Self>,
11536    ) {
11537        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11538        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11539            s.move_heads_with(|map, head, _| {
11540                (
11541                    movement::previous_subword_start(map, head),
11542                    SelectionGoal::None,
11543                )
11544            });
11545        })
11546    }
11547
11548    pub fn delete_to_previous_word_start(
11549        &mut self,
11550        action: &DeleteToPreviousWordStart,
11551        window: &mut Window,
11552        cx: &mut Context<Self>,
11553    ) {
11554        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11555        self.transact(window, cx, |this, window, cx| {
11556            this.select_autoclose_pair(window, cx);
11557            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11558                s.move_with(|map, selection| {
11559                    if selection.is_empty() {
11560                        let cursor = if action.ignore_newlines {
11561                            movement::previous_word_start(map, selection.head())
11562                        } else {
11563                            movement::previous_word_start_or_newline(map, selection.head())
11564                        };
11565                        selection.set_head(cursor, SelectionGoal::None);
11566                    }
11567                });
11568            });
11569            this.insert("", window, cx);
11570        });
11571    }
11572
11573    pub fn delete_to_previous_subword_start(
11574        &mut self,
11575        _: &DeleteToPreviousSubwordStart,
11576        window: &mut Window,
11577        cx: &mut Context<Self>,
11578    ) {
11579        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11580        self.transact(window, cx, |this, window, cx| {
11581            this.select_autoclose_pair(window, cx);
11582            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11583                s.move_with(|map, selection| {
11584                    if selection.is_empty() {
11585                        let cursor = movement::previous_subword_start(map, selection.head());
11586                        selection.set_head(cursor, SelectionGoal::None);
11587                    }
11588                });
11589            });
11590            this.insert("", window, cx);
11591        });
11592    }
11593
11594    pub fn move_to_next_word_end(
11595        &mut self,
11596        _: &MoveToNextWordEnd,
11597        window: &mut Window,
11598        cx: &mut Context<Self>,
11599    ) {
11600        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11601        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11602            s.move_cursors_with(|map, head, _| {
11603                (movement::next_word_end(map, head), SelectionGoal::None)
11604            });
11605        })
11606    }
11607
11608    pub fn move_to_next_subword_end(
11609        &mut self,
11610        _: &MoveToNextSubwordEnd,
11611        window: &mut Window,
11612        cx: &mut Context<Self>,
11613    ) {
11614        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11615        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11616            s.move_cursors_with(|map, head, _| {
11617                (movement::next_subword_end(map, head), SelectionGoal::None)
11618            });
11619        })
11620    }
11621
11622    pub fn select_to_next_word_end(
11623        &mut self,
11624        _: &SelectToNextWordEnd,
11625        window: &mut Window,
11626        cx: &mut Context<Self>,
11627    ) {
11628        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11629        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11630            s.move_heads_with(|map, head, _| {
11631                (movement::next_word_end(map, head), SelectionGoal::None)
11632            });
11633        })
11634    }
11635
11636    pub fn select_to_next_subword_end(
11637        &mut self,
11638        _: &SelectToNextSubwordEnd,
11639        window: &mut Window,
11640        cx: &mut Context<Self>,
11641    ) {
11642        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11643        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11644            s.move_heads_with(|map, head, _| {
11645                (movement::next_subword_end(map, head), SelectionGoal::None)
11646            });
11647        })
11648    }
11649
11650    pub fn delete_to_next_word_end(
11651        &mut self,
11652        action: &DeleteToNextWordEnd,
11653        window: &mut Window,
11654        cx: &mut Context<Self>,
11655    ) {
11656        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11657        self.transact(window, cx, |this, window, cx| {
11658            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11659                s.move_with(|map, selection| {
11660                    if selection.is_empty() {
11661                        let cursor = if action.ignore_newlines {
11662                            movement::next_word_end(map, selection.head())
11663                        } else {
11664                            movement::next_word_end_or_newline(map, selection.head())
11665                        };
11666                        selection.set_head(cursor, SelectionGoal::None);
11667                    }
11668                });
11669            });
11670            this.insert("", window, cx);
11671        });
11672    }
11673
11674    pub fn delete_to_next_subword_end(
11675        &mut self,
11676        _: &DeleteToNextSubwordEnd,
11677        window: &mut Window,
11678        cx: &mut Context<Self>,
11679    ) {
11680        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11681        self.transact(window, cx, |this, window, cx| {
11682            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11683                s.move_with(|map, selection| {
11684                    if selection.is_empty() {
11685                        let cursor = movement::next_subword_end(map, selection.head());
11686                        selection.set_head(cursor, SelectionGoal::None);
11687                    }
11688                });
11689            });
11690            this.insert("", window, cx);
11691        });
11692    }
11693
11694    pub fn move_to_beginning_of_line(
11695        &mut self,
11696        action: &MoveToBeginningOfLine,
11697        window: &mut Window,
11698        cx: &mut Context<Self>,
11699    ) {
11700        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11701        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11702            s.move_cursors_with(|map, head, _| {
11703                (
11704                    movement::indented_line_beginning(
11705                        map,
11706                        head,
11707                        action.stop_at_soft_wraps,
11708                        action.stop_at_indent,
11709                    ),
11710                    SelectionGoal::None,
11711                )
11712            });
11713        })
11714    }
11715
11716    pub fn select_to_beginning_of_line(
11717        &mut self,
11718        action: &SelectToBeginningOfLine,
11719        window: &mut Window,
11720        cx: &mut Context<Self>,
11721    ) {
11722        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11723        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11724            s.move_heads_with(|map, head, _| {
11725                (
11726                    movement::indented_line_beginning(
11727                        map,
11728                        head,
11729                        action.stop_at_soft_wraps,
11730                        action.stop_at_indent,
11731                    ),
11732                    SelectionGoal::None,
11733                )
11734            });
11735        });
11736    }
11737
11738    pub fn delete_to_beginning_of_line(
11739        &mut self,
11740        action: &DeleteToBeginningOfLine,
11741        window: &mut Window,
11742        cx: &mut Context<Self>,
11743    ) {
11744        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11745        self.transact(window, cx, |this, window, cx| {
11746            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11747                s.move_with(|_, selection| {
11748                    selection.reversed = true;
11749                });
11750            });
11751
11752            this.select_to_beginning_of_line(
11753                &SelectToBeginningOfLine {
11754                    stop_at_soft_wraps: false,
11755                    stop_at_indent: action.stop_at_indent,
11756                },
11757                window,
11758                cx,
11759            );
11760            this.backspace(&Backspace, window, cx);
11761        });
11762    }
11763
11764    pub fn move_to_end_of_line(
11765        &mut self,
11766        action: &MoveToEndOfLine,
11767        window: &mut Window,
11768        cx: &mut Context<Self>,
11769    ) {
11770        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11771        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11772            s.move_cursors_with(|map, head, _| {
11773                (
11774                    movement::line_end(map, head, action.stop_at_soft_wraps),
11775                    SelectionGoal::None,
11776                )
11777            });
11778        })
11779    }
11780
11781    pub fn select_to_end_of_line(
11782        &mut self,
11783        action: &SelectToEndOfLine,
11784        window: &mut Window,
11785        cx: &mut Context<Self>,
11786    ) {
11787        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11788        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11789            s.move_heads_with(|map, head, _| {
11790                (
11791                    movement::line_end(map, head, action.stop_at_soft_wraps),
11792                    SelectionGoal::None,
11793                )
11794            });
11795        })
11796    }
11797
11798    pub fn delete_to_end_of_line(
11799        &mut self,
11800        _: &DeleteToEndOfLine,
11801        window: &mut Window,
11802        cx: &mut Context<Self>,
11803    ) {
11804        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11805        self.transact(window, cx, |this, window, cx| {
11806            this.select_to_end_of_line(
11807                &SelectToEndOfLine {
11808                    stop_at_soft_wraps: false,
11809                },
11810                window,
11811                cx,
11812            );
11813            this.delete(&Delete, window, cx);
11814        });
11815    }
11816
11817    pub fn cut_to_end_of_line(
11818        &mut self,
11819        _: &CutToEndOfLine,
11820        window: &mut Window,
11821        cx: &mut Context<Self>,
11822    ) {
11823        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11824        self.transact(window, cx, |this, window, cx| {
11825            this.select_to_end_of_line(
11826                &SelectToEndOfLine {
11827                    stop_at_soft_wraps: false,
11828                },
11829                window,
11830                cx,
11831            );
11832            this.cut(&Cut, window, cx);
11833        });
11834    }
11835
11836    pub fn move_to_start_of_paragraph(
11837        &mut self,
11838        _: &MoveToStartOfParagraph,
11839        window: &mut Window,
11840        cx: &mut Context<Self>,
11841    ) {
11842        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11843            cx.propagate();
11844            return;
11845        }
11846        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11847        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11848            s.move_with(|map, selection| {
11849                selection.collapse_to(
11850                    movement::start_of_paragraph(map, selection.head(), 1),
11851                    SelectionGoal::None,
11852                )
11853            });
11854        })
11855    }
11856
11857    pub fn move_to_end_of_paragraph(
11858        &mut self,
11859        _: &MoveToEndOfParagraph,
11860        window: &mut Window,
11861        cx: &mut Context<Self>,
11862    ) {
11863        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11864            cx.propagate();
11865            return;
11866        }
11867        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11868        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11869            s.move_with(|map, selection| {
11870                selection.collapse_to(
11871                    movement::end_of_paragraph(map, selection.head(), 1),
11872                    SelectionGoal::None,
11873                )
11874            });
11875        })
11876    }
11877
11878    pub fn select_to_start_of_paragraph(
11879        &mut self,
11880        _: &SelectToStartOfParagraph,
11881        window: &mut Window,
11882        cx: &mut Context<Self>,
11883    ) {
11884        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11885            cx.propagate();
11886            return;
11887        }
11888        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11889        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11890            s.move_heads_with(|map, head, _| {
11891                (
11892                    movement::start_of_paragraph(map, head, 1),
11893                    SelectionGoal::None,
11894                )
11895            });
11896        })
11897    }
11898
11899    pub fn select_to_end_of_paragraph(
11900        &mut self,
11901        _: &SelectToEndOfParagraph,
11902        window: &mut Window,
11903        cx: &mut Context<Self>,
11904    ) {
11905        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11906            cx.propagate();
11907            return;
11908        }
11909        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11910        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11911            s.move_heads_with(|map, head, _| {
11912                (
11913                    movement::end_of_paragraph(map, head, 1),
11914                    SelectionGoal::None,
11915                )
11916            });
11917        })
11918    }
11919
11920    pub fn move_to_start_of_excerpt(
11921        &mut self,
11922        _: &MoveToStartOfExcerpt,
11923        window: &mut Window,
11924        cx: &mut Context<Self>,
11925    ) {
11926        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11927            cx.propagate();
11928            return;
11929        }
11930        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11931        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11932            s.move_with(|map, selection| {
11933                selection.collapse_to(
11934                    movement::start_of_excerpt(
11935                        map,
11936                        selection.head(),
11937                        workspace::searchable::Direction::Prev,
11938                    ),
11939                    SelectionGoal::None,
11940                )
11941            });
11942        })
11943    }
11944
11945    pub fn move_to_start_of_next_excerpt(
11946        &mut self,
11947        _: &MoveToStartOfNextExcerpt,
11948        window: &mut Window,
11949        cx: &mut Context<Self>,
11950    ) {
11951        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11952            cx.propagate();
11953            return;
11954        }
11955
11956        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11957            s.move_with(|map, selection| {
11958                selection.collapse_to(
11959                    movement::start_of_excerpt(
11960                        map,
11961                        selection.head(),
11962                        workspace::searchable::Direction::Next,
11963                    ),
11964                    SelectionGoal::None,
11965                )
11966            });
11967        })
11968    }
11969
11970    pub fn move_to_end_of_excerpt(
11971        &mut self,
11972        _: &MoveToEndOfExcerpt,
11973        window: &mut Window,
11974        cx: &mut Context<Self>,
11975    ) {
11976        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11977            cx.propagate();
11978            return;
11979        }
11980        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11981        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11982            s.move_with(|map, selection| {
11983                selection.collapse_to(
11984                    movement::end_of_excerpt(
11985                        map,
11986                        selection.head(),
11987                        workspace::searchable::Direction::Next,
11988                    ),
11989                    SelectionGoal::None,
11990                )
11991            });
11992        })
11993    }
11994
11995    pub fn move_to_end_of_previous_excerpt(
11996        &mut self,
11997        _: &MoveToEndOfPreviousExcerpt,
11998        window: &mut Window,
11999        cx: &mut Context<Self>,
12000    ) {
12001        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12002            cx.propagate();
12003            return;
12004        }
12005        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12006        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12007            s.move_with(|map, selection| {
12008                selection.collapse_to(
12009                    movement::end_of_excerpt(
12010                        map,
12011                        selection.head(),
12012                        workspace::searchable::Direction::Prev,
12013                    ),
12014                    SelectionGoal::None,
12015                )
12016            });
12017        })
12018    }
12019
12020    pub fn select_to_start_of_excerpt(
12021        &mut self,
12022        _: &SelectToStartOfExcerpt,
12023        window: &mut Window,
12024        cx: &mut Context<Self>,
12025    ) {
12026        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12027            cx.propagate();
12028            return;
12029        }
12030        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12031        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12032            s.move_heads_with(|map, head, _| {
12033                (
12034                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12035                    SelectionGoal::None,
12036                )
12037            });
12038        })
12039    }
12040
12041    pub fn select_to_start_of_next_excerpt(
12042        &mut self,
12043        _: &SelectToStartOfNextExcerpt,
12044        window: &mut Window,
12045        cx: &mut Context<Self>,
12046    ) {
12047        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12048            cx.propagate();
12049            return;
12050        }
12051        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12052        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12053            s.move_heads_with(|map, head, _| {
12054                (
12055                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12056                    SelectionGoal::None,
12057                )
12058            });
12059        })
12060    }
12061
12062    pub fn select_to_end_of_excerpt(
12063        &mut self,
12064        _: &SelectToEndOfExcerpt,
12065        window: &mut Window,
12066        cx: &mut Context<Self>,
12067    ) {
12068        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12069            cx.propagate();
12070            return;
12071        }
12072        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12073        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12074            s.move_heads_with(|map, head, _| {
12075                (
12076                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12077                    SelectionGoal::None,
12078                )
12079            });
12080        })
12081    }
12082
12083    pub fn select_to_end_of_previous_excerpt(
12084        &mut self,
12085        _: &SelectToEndOfPreviousExcerpt,
12086        window: &mut Window,
12087        cx: &mut Context<Self>,
12088    ) {
12089        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12090            cx.propagate();
12091            return;
12092        }
12093        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12094        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12095            s.move_heads_with(|map, head, _| {
12096                (
12097                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12098                    SelectionGoal::None,
12099                )
12100            });
12101        })
12102    }
12103
12104    pub fn move_to_beginning(
12105        &mut self,
12106        _: &MoveToBeginning,
12107        window: &mut Window,
12108        cx: &mut Context<Self>,
12109    ) {
12110        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12111            cx.propagate();
12112            return;
12113        }
12114        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12115        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12116            s.select_ranges(vec![0..0]);
12117        });
12118    }
12119
12120    pub fn select_to_beginning(
12121        &mut self,
12122        _: &SelectToBeginning,
12123        window: &mut Window,
12124        cx: &mut Context<Self>,
12125    ) {
12126        let mut selection = self.selections.last::<Point>(cx);
12127        selection.set_head(Point::zero(), SelectionGoal::None);
12128        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12129        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12130            s.select(vec![selection]);
12131        });
12132    }
12133
12134    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12135        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12136            cx.propagate();
12137            return;
12138        }
12139        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12140        let cursor = self.buffer.read(cx).read(cx).len();
12141        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12142            s.select_ranges(vec![cursor..cursor])
12143        });
12144    }
12145
12146    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12147        self.nav_history = nav_history;
12148    }
12149
12150    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12151        self.nav_history.as_ref()
12152    }
12153
12154    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12155        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12156    }
12157
12158    fn push_to_nav_history(
12159        &mut self,
12160        cursor_anchor: Anchor,
12161        new_position: Option<Point>,
12162        is_deactivate: bool,
12163        cx: &mut Context<Self>,
12164    ) {
12165        if let Some(nav_history) = self.nav_history.as_mut() {
12166            let buffer = self.buffer.read(cx).read(cx);
12167            let cursor_position = cursor_anchor.to_point(&buffer);
12168            let scroll_state = self.scroll_manager.anchor();
12169            let scroll_top_row = scroll_state.top_row(&buffer);
12170            drop(buffer);
12171
12172            if let Some(new_position) = new_position {
12173                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12174                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12175                    return;
12176                }
12177            }
12178
12179            nav_history.push(
12180                Some(NavigationData {
12181                    cursor_anchor,
12182                    cursor_position,
12183                    scroll_anchor: scroll_state,
12184                    scroll_top_row,
12185                }),
12186                cx,
12187            );
12188            cx.emit(EditorEvent::PushedToNavHistory {
12189                anchor: cursor_anchor,
12190                is_deactivate,
12191            })
12192        }
12193    }
12194
12195    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12196        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12197        let buffer = self.buffer.read(cx).snapshot(cx);
12198        let mut selection = self.selections.first::<usize>(cx);
12199        selection.set_head(buffer.len(), SelectionGoal::None);
12200        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12201            s.select(vec![selection]);
12202        });
12203    }
12204
12205    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12206        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12207        let end = self.buffer.read(cx).read(cx).len();
12208        self.change_selections(None, window, cx, |s| {
12209            s.select_ranges(vec![0..end]);
12210        });
12211    }
12212
12213    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12214        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12215        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12216        let mut selections = self.selections.all::<Point>(cx);
12217        let max_point = display_map.buffer_snapshot.max_point();
12218        for selection in &mut selections {
12219            let rows = selection.spanned_rows(true, &display_map);
12220            selection.start = Point::new(rows.start.0, 0);
12221            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12222            selection.reversed = false;
12223        }
12224        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12225            s.select(selections);
12226        });
12227    }
12228
12229    pub fn split_selection_into_lines(
12230        &mut self,
12231        _: &SplitSelectionIntoLines,
12232        window: &mut Window,
12233        cx: &mut Context<Self>,
12234    ) {
12235        let selections = self
12236            .selections
12237            .all::<Point>(cx)
12238            .into_iter()
12239            .map(|selection| selection.start..selection.end)
12240            .collect::<Vec<_>>();
12241        self.unfold_ranges(&selections, true, true, cx);
12242
12243        let mut new_selection_ranges = Vec::new();
12244        {
12245            let buffer = self.buffer.read(cx).read(cx);
12246            for selection in selections {
12247                for row in selection.start.row..selection.end.row {
12248                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12249                    new_selection_ranges.push(cursor..cursor);
12250                }
12251
12252                let is_multiline_selection = selection.start.row != selection.end.row;
12253                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12254                // so this action feels more ergonomic when paired with other selection operations
12255                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12256                if !should_skip_last {
12257                    new_selection_ranges.push(selection.end..selection.end);
12258                }
12259            }
12260        }
12261        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12262            s.select_ranges(new_selection_ranges);
12263        });
12264    }
12265
12266    pub fn add_selection_above(
12267        &mut self,
12268        _: &AddSelectionAbove,
12269        window: &mut Window,
12270        cx: &mut Context<Self>,
12271    ) {
12272        self.add_selection(true, window, cx);
12273    }
12274
12275    pub fn add_selection_below(
12276        &mut self,
12277        _: &AddSelectionBelow,
12278        window: &mut Window,
12279        cx: &mut Context<Self>,
12280    ) {
12281        self.add_selection(false, window, cx);
12282    }
12283
12284    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12285        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12286
12287        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12288        let mut selections = self.selections.all::<Point>(cx);
12289        let text_layout_details = self.text_layout_details(window);
12290        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12291            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12292            let range = oldest_selection.display_range(&display_map).sorted();
12293
12294            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12295            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12296            let positions = start_x.min(end_x)..start_x.max(end_x);
12297
12298            selections.clear();
12299            let mut stack = Vec::new();
12300            for row in range.start.row().0..=range.end.row().0 {
12301                if let Some(selection) = self.selections.build_columnar_selection(
12302                    &display_map,
12303                    DisplayRow(row),
12304                    &positions,
12305                    oldest_selection.reversed,
12306                    &text_layout_details,
12307                ) {
12308                    stack.push(selection.id);
12309                    selections.push(selection);
12310                }
12311            }
12312
12313            if above {
12314                stack.reverse();
12315            }
12316
12317            AddSelectionsState { above, stack }
12318        });
12319
12320        let last_added_selection = *state.stack.last().unwrap();
12321        let mut new_selections = Vec::new();
12322        if above == state.above {
12323            let end_row = if above {
12324                DisplayRow(0)
12325            } else {
12326                display_map.max_point().row()
12327            };
12328
12329            'outer: for selection in selections {
12330                if selection.id == last_added_selection {
12331                    let range = selection.display_range(&display_map).sorted();
12332                    debug_assert_eq!(range.start.row(), range.end.row());
12333                    let mut row = range.start.row();
12334                    let positions =
12335                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12336                            px(start)..px(end)
12337                        } else {
12338                            let start_x =
12339                                display_map.x_for_display_point(range.start, &text_layout_details);
12340                            let end_x =
12341                                display_map.x_for_display_point(range.end, &text_layout_details);
12342                            start_x.min(end_x)..start_x.max(end_x)
12343                        };
12344
12345                    while row != end_row {
12346                        if above {
12347                            row.0 -= 1;
12348                        } else {
12349                            row.0 += 1;
12350                        }
12351
12352                        if let Some(new_selection) = self.selections.build_columnar_selection(
12353                            &display_map,
12354                            row,
12355                            &positions,
12356                            selection.reversed,
12357                            &text_layout_details,
12358                        ) {
12359                            state.stack.push(new_selection.id);
12360                            if above {
12361                                new_selections.push(new_selection);
12362                                new_selections.push(selection);
12363                            } else {
12364                                new_selections.push(selection);
12365                                new_selections.push(new_selection);
12366                            }
12367
12368                            continue 'outer;
12369                        }
12370                    }
12371                }
12372
12373                new_selections.push(selection);
12374            }
12375        } else {
12376            new_selections = selections;
12377            new_selections.retain(|s| s.id != last_added_selection);
12378            state.stack.pop();
12379        }
12380
12381        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12382            s.select(new_selections);
12383        });
12384        if state.stack.len() > 1 {
12385            self.add_selections_state = Some(state);
12386        }
12387    }
12388
12389    fn select_match_ranges(
12390        &mut self,
12391        range: Range<usize>,
12392        reversed: bool,
12393        replace_newest: bool,
12394        auto_scroll: Option<Autoscroll>,
12395        window: &mut Window,
12396        cx: &mut Context<Editor>,
12397    ) {
12398        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12399        self.change_selections(auto_scroll, window, cx, |s| {
12400            if replace_newest {
12401                s.delete(s.newest_anchor().id);
12402            }
12403            if reversed {
12404                s.insert_range(range.end..range.start);
12405            } else {
12406                s.insert_range(range);
12407            }
12408        });
12409    }
12410
12411    pub fn select_next_match_internal(
12412        &mut self,
12413        display_map: &DisplaySnapshot,
12414        replace_newest: bool,
12415        autoscroll: Option<Autoscroll>,
12416        window: &mut Window,
12417        cx: &mut Context<Self>,
12418    ) -> Result<()> {
12419        let buffer = &display_map.buffer_snapshot;
12420        let mut selections = self.selections.all::<usize>(cx);
12421        if let Some(mut select_next_state) = self.select_next_state.take() {
12422            let query = &select_next_state.query;
12423            if !select_next_state.done {
12424                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12425                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12426                let mut next_selected_range = None;
12427
12428                let bytes_after_last_selection =
12429                    buffer.bytes_in_range(last_selection.end..buffer.len());
12430                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12431                let query_matches = query
12432                    .stream_find_iter(bytes_after_last_selection)
12433                    .map(|result| (last_selection.end, result))
12434                    .chain(
12435                        query
12436                            .stream_find_iter(bytes_before_first_selection)
12437                            .map(|result| (0, result)),
12438                    );
12439
12440                for (start_offset, query_match) in query_matches {
12441                    let query_match = query_match.unwrap(); // can only fail due to I/O
12442                    let offset_range =
12443                        start_offset + query_match.start()..start_offset + query_match.end();
12444                    let display_range = offset_range.start.to_display_point(display_map)
12445                        ..offset_range.end.to_display_point(display_map);
12446
12447                    if !select_next_state.wordwise
12448                        || (!movement::is_inside_word(display_map, display_range.start)
12449                            && !movement::is_inside_word(display_map, display_range.end))
12450                    {
12451                        // TODO: This is n^2, because we might check all the selections
12452                        if !selections
12453                            .iter()
12454                            .any(|selection| selection.range().overlaps(&offset_range))
12455                        {
12456                            next_selected_range = Some(offset_range);
12457                            break;
12458                        }
12459                    }
12460                }
12461
12462                if let Some(next_selected_range) = next_selected_range {
12463                    self.select_match_ranges(
12464                        next_selected_range,
12465                        last_selection.reversed,
12466                        replace_newest,
12467                        autoscroll,
12468                        window,
12469                        cx,
12470                    );
12471                } else {
12472                    select_next_state.done = true;
12473                }
12474            }
12475
12476            self.select_next_state = Some(select_next_state);
12477        } else {
12478            let mut only_carets = true;
12479            let mut same_text_selected = true;
12480            let mut selected_text = None;
12481
12482            let mut selections_iter = selections.iter().peekable();
12483            while let Some(selection) = selections_iter.next() {
12484                if selection.start != selection.end {
12485                    only_carets = false;
12486                }
12487
12488                if same_text_selected {
12489                    if selected_text.is_none() {
12490                        selected_text =
12491                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12492                    }
12493
12494                    if let Some(next_selection) = selections_iter.peek() {
12495                        if next_selection.range().len() == selection.range().len() {
12496                            let next_selected_text = buffer
12497                                .text_for_range(next_selection.range())
12498                                .collect::<String>();
12499                            if Some(next_selected_text) != selected_text {
12500                                same_text_selected = false;
12501                                selected_text = None;
12502                            }
12503                        } else {
12504                            same_text_selected = false;
12505                            selected_text = None;
12506                        }
12507                    }
12508                }
12509            }
12510
12511            if only_carets {
12512                for selection in &mut selections {
12513                    let word_range = movement::surrounding_word(
12514                        display_map,
12515                        selection.start.to_display_point(display_map),
12516                    );
12517                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12518                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12519                    selection.goal = SelectionGoal::None;
12520                    selection.reversed = false;
12521                    self.select_match_ranges(
12522                        selection.start..selection.end,
12523                        selection.reversed,
12524                        replace_newest,
12525                        autoscroll,
12526                        window,
12527                        cx,
12528                    );
12529                }
12530
12531                if selections.len() == 1 {
12532                    let selection = selections
12533                        .last()
12534                        .expect("ensured that there's only one selection");
12535                    let query = buffer
12536                        .text_for_range(selection.start..selection.end)
12537                        .collect::<String>();
12538                    let is_empty = query.is_empty();
12539                    let select_state = SelectNextState {
12540                        query: AhoCorasick::new(&[query])?,
12541                        wordwise: true,
12542                        done: is_empty,
12543                    };
12544                    self.select_next_state = Some(select_state);
12545                } else {
12546                    self.select_next_state = None;
12547                }
12548            } else if let Some(selected_text) = selected_text {
12549                self.select_next_state = Some(SelectNextState {
12550                    query: AhoCorasick::new(&[selected_text])?,
12551                    wordwise: false,
12552                    done: false,
12553                });
12554                self.select_next_match_internal(
12555                    display_map,
12556                    replace_newest,
12557                    autoscroll,
12558                    window,
12559                    cx,
12560                )?;
12561            }
12562        }
12563        Ok(())
12564    }
12565
12566    pub fn select_all_matches(
12567        &mut self,
12568        _action: &SelectAllMatches,
12569        window: &mut Window,
12570        cx: &mut Context<Self>,
12571    ) -> Result<()> {
12572        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12573
12574        self.push_to_selection_history();
12575        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12576
12577        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12578        let Some(select_next_state) = self.select_next_state.as_mut() else {
12579            return Ok(());
12580        };
12581        if select_next_state.done {
12582            return Ok(());
12583        }
12584
12585        let mut new_selections = Vec::new();
12586
12587        let reversed = self.selections.oldest::<usize>(cx).reversed;
12588        let buffer = &display_map.buffer_snapshot;
12589        let query_matches = select_next_state
12590            .query
12591            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12592
12593        for query_match in query_matches.into_iter() {
12594            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12595            let offset_range = if reversed {
12596                query_match.end()..query_match.start()
12597            } else {
12598                query_match.start()..query_match.end()
12599            };
12600            let display_range = offset_range.start.to_display_point(&display_map)
12601                ..offset_range.end.to_display_point(&display_map);
12602
12603            if !select_next_state.wordwise
12604                || (!movement::is_inside_word(&display_map, display_range.start)
12605                    && !movement::is_inside_word(&display_map, display_range.end))
12606            {
12607                new_selections.push(offset_range.start..offset_range.end);
12608            }
12609        }
12610
12611        select_next_state.done = true;
12612        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12613        self.change_selections(None, window, cx, |selections| {
12614            selections.select_ranges(new_selections)
12615        });
12616
12617        Ok(())
12618    }
12619
12620    pub fn select_next(
12621        &mut self,
12622        action: &SelectNext,
12623        window: &mut Window,
12624        cx: &mut Context<Self>,
12625    ) -> Result<()> {
12626        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12627        self.push_to_selection_history();
12628        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12629        self.select_next_match_internal(
12630            &display_map,
12631            action.replace_newest,
12632            Some(Autoscroll::newest()),
12633            window,
12634            cx,
12635        )?;
12636        Ok(())
12637    }
12638
12639    pub fn select_previous(
12640        &mut self,
12641        action: &SelectPrevious,
12642        window: &mut Window,
12643        cx: &mut Context<Self>,
12644    ) -> Result<()> {
12645        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12646        self.push_to_selection_history();
12647        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12648        let buffer = &display_map.buffer_snapshot;
12649        let mut selections = self.selections.all::<usize>(cx);
12650        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12651            let query = &select_prev_state.query;
12652            if !select_prev_state.done {
12653                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12654                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12655                let mut next_selected_range = None;
12656                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12657                let bytes_before_last_selection =
12658                    buffer.reversed_bytes_in_range(0..last_selection.start);
12659                let bytes_after_first_selection =
12660                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12661                let query_matches = query
12662                    .stream_find_iter(bytes_before_last_selection)
12663                    .map(|result| (last_selection.start, result))
12664                    .chain(
12665                        query
12666                            .stream_find_iter(bytes_after_first_selection)
12667                            .map(|result| (buffer.len(), result)),
12668                    );
12669                for (end_offset, query_match) in query_matches {
12670                    let query_match = query_match.unwrap(); // can only fail due to I/O
12671                    let offset_range =
12672                        end_offset - query_match.end()..end_offset - query_match.start();
12673                    let display_range = offset_range.start.to_display_point(&display_map)
12674                        ..offset_range.end.to_display_point(&display_map);
12675
12676                    if !select_prev_state.wordwise
12677                        || (!movement::is_inside_word(&display_map, display_range.start)
12678                            && !movement::is_inside_word(&display_map, display_range.end))
12679                    {
12680                        next_selected_range = Some(offset_range);
12681                        break;
12682                    }
12683                }
12684
12685                if let Some(next_selected_range) = next_selected_range {
12686                    self.select_match_ranges(
12687                        next_selected_range,
12688                        last_selection.reversed,
12689                        action.replace_newest,
12690                        Some(Autoscroll::newest()),
12691                        window,
12692                        cx,
12693                    );
12694                } else {
12695                    select_prev_state.done = true;
12696                }
12697            }
12698
12699            self.select_prev_state = Some(select_prev_state);
12700        } else {
12701            let mut only_carets = true;
12702            let mut same_text_selected = true;
12703            let mut selected_text = None;
12704
12705            let mut selections_iter = selections.iter().peekable();
12706            while let Some(selection) = selections_iter.next() {
12707                if selection.start != selection.end {
12708                    only_carets = false;
12709                }
12710
12711                if same_text_selected {
12712                    if selected_text.is_none() {
12713                        selected_text =
12714                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12715                    }
12716
12717                    if let Some(next_selection) = selections_iter.peek() {
12718                        if next_selection.range().len() == selection.range().len() {
12719                            let next_selected_text = buffer
12720                                .text_for_range(next_selection.range())
12721                                .collect::<String>();
12722                            if Some(next_selected_text) != selected_text {
12723                                same_text_selected = false;
12724                                selected_text = None;
12725                            }
12726                        } else {
12727                            same_text_selected = false;
12728                            selected_text = None;
12729                        }
12730                    }
12731                }
12732            }
12733
12734            if only_carets {
12735                for selection in &mut selections {
12736                    let word_range = movement::surrounding_word(
12737                        &display_map,
12738                        selection.start.to_display_point(&display_map),
12739                    );
12740                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12741                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12742                    selection.goal = SelectionGoal::None;
12743                    selection.reversed = false;
12744                    self.select_match_ranges(
12745                        selection.start..selection.end,
12746                        selection.reversed,
12747                        action.replace_newest,
12748                        Some(Autoscroll::newest()),
12749                        window,
12750                        cx,
12751                    );
12752                }
12753                if selections.len() == 1 {
12754                    let selection = selections
12755                        .last()
12756                        .expect("ensured that there's only one selection");
12757                    let query = buffer
12758                        .text_for_range(selection.start..selection.end)
12759                        .collect::<String>();
12760                    let is_empty = query.is_empty();
12761                    let select_state = SelectNextState {
12762                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12763                        wordwise: true,
12764                        done: is_empty,
12765                    };
12766                    self.select_prev_state = Some(select_state);
12767                } else {
12768                    self.select_prev_state = None;
12769                }
12770            } else if let Some(selected_text) = selected_text {
12771                self.select_prev_state = Some(SelectNextState {
12772                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12773                    wordwise: false,
12774                    done: false,
12775                });
12776                self.select_previous(action, window, cx)?;
12777            }
12778        }
12779        Ok(())
12780    }
12781
12782    pub fn find_next_match(
12783        &mut self,
12784        _: &FindNextMatch,
12785        window: &mut Window,
12786        cx: &mut Context<Self>,
12787    ) -> Result<()> {
12788        let selections = self.selections.disjoint_anchors();
12789        match selections.first() {
12790            Some(first) if selections.len() >= 2 => {
12791                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12792                    s.select_ranges([first.range()]);
12793                });
12794            }
12795            _ => self.select_next(
12796                &SelectNext {
12797                    replace_newest: true,
12798                },
12799                window,
12800                cx,
12801            )?,
12802        }
12803        Ok(())
12804    }
12805
12806    pub fn find_previous_match(
12807        &mut self,
12808        _: &FindPreviousMatch,
12809        window: &mut Window,
12810        cx: &mut Context<Self>,
12811    ) -> Result<()> {
12812        let selections = self.selections.disjoint_anchors();
12813        match selections.last() {
12814            Some(last) if selections.len() >= 2 => {
12815                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12816                    s.select_ranges([last.range()]);
12817                });
12818            }
12819            _ => self.select_previous(
12820                &SelectPrevious {
12821                    replace_newest: true,
12822                },
12823                window,
12824                cx,
12825            )?,
12826        }
12827        Ok(())
12828    }
12829
12830    pub fn toggle_comments(
12831        &mut self,
12832        action: &ToggleComments,
12833        window: &mut Window,
12834        cx: &mut Context<Self>,
12835    ) {
12836        if self.read_only(cx) {
12837            return;
12838        }
12839        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12840        let text_layout_details = &self.text_layout_details(window);
12841        self.transact(window, cx, |this, window, cx| {
12842            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12843            let mut edits = Vec::new();
12844            let mut selection_edit_ranges = Vec::new();
12845            let mut last_toggled_row = None;
12846            let snapshot = this.buffer.read(cx).read(cx);
12847            let empty_str: Arc<str> = Arc::default();
12848            let mut suffixes_inserted = Vec::new();
12849            let ignore_indent = action.ignore_indent;
12850
12851            fn comment_prefix_range(
12852                snapshot: &MultiBufferSnapshot,
12853                row: MultiBufferRow,
12854                comment_prefix: &str,
12855                comment_prefix_whitespace: &str,
12856                ignore_indent: bool,
12857            ) -> Range<Point> {
12858                let indent_size = if ignore_indent {
12859                    0
12860                } else {
12861                    snapshot.indent_size_for_line(row).len
12862                };
12863
12864                let start = Point::new(row.0, indent_size);
12865
12866                let mut line_bytes = snapshot
12867                    .bytes_in_range(start..snapshot.max_point())
12868                    .flatten()
12869                    .copied();
12870
12871                // If this line currently begins with the line comment prefix, then record
12872                // the range containing the prefix.
12873                if line_bytes
12874                    .by_ref()
12875                    .take(comment_prefix.len())
12876                    .eq(comment_prefix.bytes())
12877                {
12878                    // Include any whitespace that matches the comment prefix.
12879                    let matching_whitespace_len = line_bytes
12880                        .zip(comment_prefix_whitespace.bytes())
12881                        .take_while(|(a, b)| a == b)
12882                        .count() as u32;
12883                    let end = Point::new(
12884                        start.row,
12885                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12886                    );
12887                    start..end
12888                } else {
12889                    start..start
12890                }
12891            }
12892
12893            fn comment_suffix_range(
12894                snapshot: &MultiBufferSnapshot,
12895                row: MultiBufferRow,
12896                comment_suffix: &str,
12897                comment_suffix_has_leading_space: bool,
12898            ) -> Range<Point> {
12899                let end = Point::new(row.0, snapshot.line_len(row));
12900                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12901
12902                let mut line_end_bytes = snapshot
12903                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12904                    .flatten()
12905                    .copied();
12906
12907                let leading_space_len = if suffix_start_column > 0
12908                    && line_end_bytes.next() == Some(b' ')
12909                    && comment_suffix_has_leading_space
12910                {
12911                    1
12912                } else {
12913                    0
12914                };
12915
12916                // If this line currently begins with the line comment prefix, then record
12917                // the range containing the prefix.
12918                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12919                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12920                    start..end
12921                } else {
12922                    end..end
12923                }
12924            }
12925
12926            // TODO: Handle selections that cross excerpts
12927            for selection in &mut selections {
12928                let start_column = snapshot
12929                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12930                    .len;
12931                let language = if let Some(language) =
12932                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12933                {
12934                    language
12935                } else {
12936                    continue;
12937                };
12938
12939                selection_edit_ranges.clear();
12940
12941                // If multiple selections contain a given row, avoid processing that
12942                // row more than once.
12943                let mut start_row = MultiBufferRow(selection.start.row);
12944                if last_toggled_row == Some(start_row) {
12945                    start_row = start_row.next_row();
12946                }
12947                let end_row =
12948                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12949                        MultiBufferRow(selection.end.row - 1)
12950                    } else {
12951                        MultiBufferRow(selection.end.row)
12952                    };
12953                last_toggled_row = Some(end_row);
12954
12955                if start_row > end_row {
12956                    continue;
12957                }
12958
12959                // If the language has line comments, toggle those.
12960                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12961
12962                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12963                if ignore_indent {
12964                    full_comment_prefixes = full_comment_prefixes
12965                        .into_iter()
12966                        .map(|s| Arc::from(s.trim_end()))
12967                        .collect();
12968                }
12969
12970                if !full_comment_prefixes.is_empty() {
12971                    let first_prefix = full_comment_prefixes
12972                        .first()
12973                        .expect("prefixes is non-empty");
12974                    let prefix_trimmed_lengths = full_comment_prefixes
12975                        .iter()
12976                        .map(|p| p.trim_end_matches(' ').len())
12977                        .collect::<SmallVec<[usize; 4]>>();
12978
12979                    let mut all_selection_lines_are_comments = true;
12980
12981                    for row in start_row.0..=end_row.0 {
12982                        let row = MultiBufferRow(row);
12983                        if start_row < end_row && snapshot.is_line_blank(row) {
12984                            continue;
12985                        }
12986
12987                        let prefix_range = full_comment_prefixes
12988                            .iter()
12989                            .zip(prefix_trimmed_lengths.iter().copied())
12990                            .map(|(prefix, trimmed_prefix_len)| {
12991                                comment_prefix_range(
12992                                    snapshot.deref(),
12993                                    row,
12994                                    &prefix[..trimmed_prefix_len],
12995                                    &prefix[trimmed_prefix_len..],
12996                                    ignore_indent,
12997                                )
12998                            })
12999                            .max_by_key(|range| range.end.column - range.start.column)
13000                            .expect("prefixes is non-empty");
13001
13002                        if prefix_range.is_empty() {
13003                            all_selection_lines_are_comments = false;
13004                        }
13005
13006                        selection_edit_ranges.push(prefix_range);
13007                    }
13008
13009                    if all_selection_lines_are_comments {
13010                        edits.extend(
13011                            selection_edit_ranges
13012                                .iter()
13013                                .cloned()
13014                                .map(|range| (range, empty_str.clone())),
13015                        );
13016                    } else {
13017                        let min_column = selection_edit_ranges
13018                            .iter()
13019                            .map(|range| range.start.column)
13020                            .min()
13021                            .unwrap_or(0);
13022                        edits.extend(selection_edit_ranges.iter().map(|range| {
13023                            let position = Point::new(range.start.row, min_column);
13024                            (position..position, first_prefix.clone())
13025                        }));
13026                    }
13027                } else if let Some((full_comment_prefix, comment_suffix)) =
13028                    language.block_comment_delimiters()
13029                {
13030                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13031                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13032                    let prefix_range = comment_prefix_range(
13033                        snapshot.deref(),
13034                        start_row,
13035                        comment_prefix,
13036                        comment_prefix_whitespace,
13037                        ignore_indent,
13038                    );
13039                    let suffix_range = comment_suffix_range(
13040                        snapshot.deref(),
13041                        end_row,
13042                        comment_suffix.trim_start_matches(' '),
13043                        comment_suffix.starts_with(' '),
13044                    );
13045
13046                    if prefix_range.is_empty() || suffix_range.is_empty() {
13047                        edits.push((
13048                            prefix_range.start..prefix_range.start,
13049                            full_comment_prefix.clone(),
13050                        ));
13051                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13052                        suffixes_inserted.push((end_row, comment_suffix.len()));
13053                    } else {
13054                        edits.push((prefix_range, empty_str.clone()));
13055                        edits.push((suffix_range, empty_str.clone()));
13056                    }
13057                } else {
13058                    continue;
13059                }
13060            }
13061
13062            drop(snapshot);
13063            this.buffer.update(cx, |buffer, cx| {
13064                buffer.edit(edits, None, cx);
13065            });
13066
13067            // Adjust selections so that they end before any comment suffixes that
13068            // were inserted.
13069            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13070            let mut selections = this.selections.all::<Point>(cx);
13071            let snapshot = this.buffer.read(cx).read(cx);
13072            for selection in &mut selections {
13073                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13074                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13075                        Ordering::Less => {
13076                            suffixes_inserted.next();
13077                            continue;
13078                        }
13079                        Ordering::Greater => break,
13080                        Ordering::Equal => {
13081                            if selection.end.column == snapshot.line_len(row) {
13082                                if selection.is_empty() {
13083                                    selection.start.column -= suffix_len as u32;
13084                                }
13085                                selection.end.column -= suffix_len as u32;
13086                            }
13087                            break;
13088                        }
13089                    }
13090                }
13091            }
13092
13093            drop(snapshot);
13094            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13095                s.select(selections)
13096            });
13097
13098            let selections = this.selections.all::<Point>(cx);
13099            let selections_on_single_row = selections.windows(2).all(|selections| {
13100                selections[0].start.row == selections[1].start.row
13101                    && selections[0].end.row == selections[1].end.row
13102                    && selections[0].start.row == selections[0].end.row
13103            });
13104            let selections_selecting = selections
13105                .iter()
13106                .any(|selection| selection.start != selection.end);
13107            let advance_downwards = action.advance_downwards
13108                && selections_on_single_row
13109                && !selections_selecting
13110                && !matches!(this.mode, EditorMode::SingleLine { .. });
13111
13112            if advance_downwards {
13113                let snapshot = this.buffer.read(cx).snapshot(cx);
13114
13115                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13116                    s.move_cursors_with(|display_snapshot, display_point, _| {
13117                        let mut point = display_point.to_point(display_snapshot);
13118                        point.row += 1;
13119                        point = snapshot.clip_point(point, Bias::Left);
13120                        let display_point = point.to_display_point(display_snapshot);
13121                        let goal = SelectionGoal::HorizontalPosition(
13122                            display_snapshot
13123                                .x_for_display_point(display_point, text_layout_details)
13124                                .into(),
13125                        );
13126                        (display_point, goal)
13127                    })
13128                });
13129            }
13130        });
13131    }
13132
13133    pub fn select_enclosing_symbol(
13134        &mut self,
13135        _: &SelectEnclosingSymbol,
13136        window: &mut Window,
13137        cx: &mut Context<Self>,
13138    ) {
13139        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13140
13141        let buffer = self.buffer.read(cx).snapshot(cx);
13142        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13143
13144        fn update_selection(
13145            selection: &Selection<usize>,
13146            buffer_snap: &MultiBufferSnapshot,
13147        ) -> Option<Selection<usize>> {
13148            let cursor = selection.head();
13149            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13150            for symbol in symbols.iter().rev() {
13151                let start = symbol.range.start.to_offset(buffer_snap);
13152                let end = symbol.range.end.to_offset(buffer_snap);
13153                let new_range = start..end;
13154                if start < selection.start || end > selection.end {
13155                    return Some(Selection {
13156                        id: selection.id,
13157                        start: new_range.start,
13158                        end: new_range.end,
13159                        goal: SelectionGoal::None,
13160                        reversed: selection.reversed,
13161                    });
13162                }
13163            }
13164            None
13165        }
13166
13167        let mut selected_larger_symbol = false;
13168        let new_selections = old_selections
13169            .iter()
13170            .map(|selection| match update_selection(selection, &buffer) {
13171                Some(new_selection) => {
13172                    if new_selection.range() != selection.range() {
13173                        selected_larger_symbol = true;
13174                    }
13175                    new_selection
13176                }
13177                None => selection.clone(),
13178            })
13179            .collect::<Vec<_>>();
13180
13181        if selected_larger_symbol {
13182            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13183                s.select(new_selections);
13184            });
13185        }
13186    }
13187
13188    pub fn select_larger_syntax_node(
13189        &mut self,
13190        _: &SelectLargerSyntaxNode,
13191        window: &mut Window,
13192        cx: &mut Context<Self>,
13193    ) {
13194        let Some(visible_row_count) = self.visible_row_count() else {
13195            return;
13196        };
13197        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13198        if old_selections.is_empty() {
13199            return;
13200        }
13201
13202        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13203
13204        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13205        let buffer = self.buffer.read(cx).snapshot(cx);
13206
13207        let mut selected_larger_node = false;
13208        let mut new_selections = old_selections
13209            .iter()
13210            .map(|selection| {
13211                let old_range = selection.start..selection.end;
13212
13213                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13214                    // manually select word at selection
13215                    if ["string_content", "inline"].contains(&node.kind()) {
13216                        let word_range = {
13217                            let display_point = buffer
13218                                .offset_to_point(old_range.start)
13219                                .to_display_point(&display_map);
13220                            let Range { start, end } =
13221                                movement::surrounding_word(&display_map, display_point);
13222                            start.to_point(&display_map).to_offset(&buffer)
13223                                ..end.to_point(&display_map).to_offset(&buffer)
13224                        };
13225                        // ignore if word is already selected
13226                        if !word_range.is_empty() && old_range != word_range {
13227                            let last_word_range = {
13228                                let display_point = buffer
13229                                    .offset_to_point(old_range.end)
13230                                    .to_display_point(&display_map);
13231                                let Range { start, end } =
13232                                    movement::surrounding_word(&display_map, display_point);
13233                                start.to_point(&display_map).to_offset(&buffer)
13234                                    ..end.to_point(&display_map).to_offset(&buffer)
13235                            };
13236                            // only select word if start and end point belongs to same word
13237                            if word_range == last_word_range {
13238                                selected_larger_node = true;
13239                                return Selection {
13240                                    id: selection.id,
13241                                    start: word_range.start,
13242                                    end: word_range.end,
13243                                    goal: SelectionGoal::None,
13244                                    reversed: selection.reversed,
13245                                };
13246                            }
13247                        }
13248                    }
13249                }
13250
13251                let mut new_range = old_range.clone();
13252                while let Some((_node, containing_range)) =
13253                    buffer.syntax_ancestor(new_range.clone())
13254                {
13255                    new_range = match containing_range {
13256                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13257                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13258                    };
13259                    if !display_map.intersects_fold(new_range.start)
13260                        && !display_map.intersects_fold(new_range.end)
13261                    {
13262                        break;
13263                    }
13264                }
13265
13266                selected_larger_node |= new_range != old_range;
13267                Selection {
13268                    id: selection.id,
13269                    start: new_range.start,
13270                    end: new_range.end,
13271                    goal: SelectionGoal::None,
13272                    reversed: selection.reversed,
13273                }
13274            })
13275            .collect::<Vec<_>>();
13276
13277        if !selected_larger_node {
13278            return; // don't put this call in the history
13279        }
13280
13281        // scroll based on transformation done to the last selection created by the user
13282        let (last_old, last_new) = old_selections
13283            .last()
13284            .zip(new_selections.last().cloned())
13285            .expect("old_selections isn't empty");
13286
13287        // revert selection
13288        let is_selection_reversed = {
13289            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13290            new_selections.last_mut().expect("checked above").reversed =
13291                should_newest_selection_be_reversed;
13292            should_newest_selection_be_reversed
13293        };
13294
13295        if selected_larger_node {
13296            self.select_syntax_node_history.disable_clearing = true;
13297            self.change_selections(None, window, cx, |s| {
13298                s.select(new_selections.clone());
13299            });
13300            self.select_syntax_node_history.disable_clearing = false;
13301        }
13302
13303        let start_row = last_new.start.to_display_point(&display_map).row().0;
13304        let end_row = last_new.end.to_display_point(&display_map).row().0;
13305        let selection_height = end_row - start_row + 1;
13306        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13307
13308        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13309        let scroll_behavior = if fits_on_the_screen {
13310            self.request_autoscroll(Autoscroll::fit(), cx);
13311            SelectSyntaxNodeScrollBehavior::FitSelection
13312        } else if is_selection_reversed {
13313            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13314            SelectSyntaxNodeScrollBehavior::CursorTop
13315        } else {
13316            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13317            SelectSyntaxNodeScrollBehavior::CursorBottom
13318        };
13319
13320        self.select_syntax_node_history.push((
13321            old_selections,
13322            scroll_behavior,
13323            is_selection_reversed,
13324        ));
13325    }
13326
13327    pub fn select_smaller_syntax_node(
13328        &mut self,
13329        _: &SelectSmallerSyntaxNode,
13330        window: &mut Window,
13331        cx: &mut Context<Self>,
13332    ) {
13333        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13334
13335        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13336            self.select_syntax_node_history.pop()
13337        {
13338            if let Some(selection) = selections.last_mut() {
13339                selection.reversed = is_selection_reversed;
13340            }
13341
13342            self.select_syntax_node_history.disable_clearing = true;
13343            self.change_selections(None, window, cx, |s| {
13344                s.select(selections.to_vec());
13345            });
13346            self.select_syntax_node_history.disable_clearing = false;
13347
13348            match scroll_behavior {
13349                SelectSyntaxNodeScrollBehavior::CursorTop => {
13350                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13351                }
13352                SelectSyntaxNodeScrollBehavior::FitSelection => {
13353                    self.request_autoscroll(Autoscroll::fit(), cx);
13354                }
13355                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13356                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13357                }
13358            }
13359        }
13360    }
13361
13362    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13363        if !EditorSettings::get_global(cx).gutter.runnables {
13364            self.clear_tasks();
13365            return Task::ready(());
13366        }
13367        let project = self.project.as_ref().map(Entity::downgrade);
13368        let task_sources = self.lsp_task_sources(cx);
13369        cx.spawn_in(window, async move |editor, cx| {
13370            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13371            let Some(project) = project.and_then(|p| p.upgrade()) else {
13372                return;
13373            };
13374            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13375                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13376            }) else {
13377                return;
13378            };
13379
13380            let hide_runnables = project
13381                .update(cx, |project, cx| {
13382                    // Do not display any test indicators in non-dev server remote projects.
13383                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13384                })
13385                .unwrap_or(true);
13386            if hide_runnables {
13387                return;
13388            }
13389            let new_rows =
13390                cx.background_spawn({
13391                    let snapshot = display_snapshot.clone();
13392                    async move {
13393                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13394                    }
13395                })
13396                    .await;
13397            let Ok(lsp_tasks) =
13398                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13399            else {
13400                return;
13401            };
13402            let lsp_tasks = lsp_tasks.await;
13403
13404            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13405                lsp_tasks
13406                    .into_iter()
13407                    .flat_map(|(kind, tasks)| {
13408                        tasks.into_iter().filter_map(move |(location, task)| {
13409                            Some((kind.clone(), location?, task))
13410                        })
13411                    })
13412                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13413                        let buffer = location.target.buffer;
13414                        let buffer_snapshot = buffer.read(cx).snapshot();
13415                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13416                            |(excerpt_id, snapshot, _)| {
13417                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13418                                    display_snapshot
13419                                        .buffer_snapshot
13420                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13421                                } else {
13422                                    None
13423                                }
13424                            },
13425                        );
13426                        if let Some(offset) = offset {
13427                            let task_buffer_range =
13428                                location.target.range.to_point(&buffer_snapshot);
13429                            let context_buffer_range =
13430                                task_buffer_range.to_offset(&buffer_snapshot);
13431                            let context_range = BufferOffset(context_buffer_range.start)
13432                                ..BufferOffset(context_buffer_range.end);
13433
13434                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13435                                .or_insert_with(|| RunnableTasks {
13436                                    templates: Vec::new(),
13437                                    offset,
13438                                    column: task_buffer_range.start.column,
13439                                    extra_variables: HashMap::default(),
13440                                    context_range,
13441                                })
13442                                .templates
13443                                .push((kind, task.original_task().clone()));
13444                        }
13445
13446                        acc
13447                    })
13448            }) else {
13449                return;
13450            };
13451
13452            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13453            editor
13454                .update(cx, |editor, _| {
13455                    editor.clear_tasks();
13456                    for (key, mut value) in rows {
13457                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13458                            value.templates.extend(lsp_tasks.templates);
13459                        }
13460
13461                        editor.insert_tasks(key, value);
13462                    }
13463                    for (key, value) in lsp_tasks_by_rows {
13464                        editor.insert_tasks(key, value);
13465                    }
13466                })
13467                .ok();
13468        })
13469    }
13470    fn fetch_runnable_ranges(
13471        snapshot: &DisplaySnapshot,
13472        range: Range<Anchor>,
13473    ) -> Vec<language::RunnableRange> {
13474        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13475    }
13476
13477    fn runnable_rows(
13478        project: Entity<Project>,
13479        snapshot: DisplaySnapshot,
13480        runnable_ranges: Vec<RunnableRange>,
13481        mut cx: AsyncWindowContext,
13482    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13483        runnable_ranges
13484            .into_iter()
13485            .filter_map(|mut runnable| {
13486                let tasks = cx
13487                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13488                    .ok()?;
13489                if tasks.is_empty() {
13490                    return None;
13491                }
13492
13493                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13494
13495                let row = snapshot
13496                    .buffer_snapshot
13497                    .buffer_line_for_row(MultiBufferRow(point.row))?
13498                    .1
13499                    .start
13500                    .row;
13501
13502                let context_range =
13503                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13504                Some((
13505                    (runnable.buffer_id, row),
13506                    RunnableTasks {
13507                        templates: tasks,
13508                        offset: snapshot
13509                            .buffer_snapshot
13510                            .anchor_before(runnable.run_range.start),
13511                        context_range,
13512                        column: point.column,
13513                        extra_variables: runnable.extra_captures,
13514                    },
13515                ))
13516            })
13517            .collect()
13518    }
13519
13520    fn templates_with_tags(
13521        project: &Entity<Project>,
13522        runnable: &mut Runnable,
13523        cx: &mut App,
13524    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13525        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13526            let (worktree_id, file) = project
13527                .buffer_for_id(runnable.buffer, cx)
13528                .and_then(|buffer| buffer.read(cx).file())
13529                .map(|file| (file.worktree_id(cx), file.clone()))
13530                .unzip();
13531
13532            (
13533                project.task_store().read(cx).task_inventory().cloned(),
13534                worktree_id,
13535                file,
13536            )
13537        });
13538
13539        let mut templates_with_tags = mem::take(&mut runnable.tags)
13540            .into_iter()
13541            .flat_map(|RunnableTag(tag)| {
13542                inventory
13543                    .as_ref()
13544                    .into_iter()
13545                    .flat_map(|inventory| {
13546                        inventory.read(cx).list_tasks(
13547                            file.clone(),
13548                            Some(runnable.language.clone()),
13549                            worktree_id,
13550                            cx,
13551                        )
13552                    })
13553                    .filter(move |(_, template)| {
13554                        template.tags.iter().any(|source_tag| source_tag == &tag)
13555                    })
13556            })
13557            .sorted_by_key(|(kind, _)| kind.to_owned())
13558            .collect::<Vec<_>>();
13559        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13560            // Strongest source wins; if we have worktree tag binding, prefer that to
13561            // global and language bindings;
13562            // if we have a global binding, prefer that to language binding.
13563            let first_mismatch = templates_with_tags
13564                .iter()
13565                .position(|(tag_source, _)| tag_source != leading_tag_source);
13566            if let Some(index) = first_mismatch {
13567                templates_with_tags.truncate(index);
13568            }
13569        }
13570
13571        templates_with_tags
13572    }
13573
13574    pub fn move_to_enclosing_bracket(
13575        &mut self,
13576        _: &MoveToEnclosingBracket,
13577        window: &mut Window,
13578        cx: &mut Context<Self>,
13579    ) {
13580        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13581        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13582            s.move_offsets_with(|snapshot, selection| {
13583                let Some(enclosing_bracket_ranges) =
13584                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13585                else {
13586                    return;
13587                };
13588
13589                let mut best_length = usize::MAX;
13590                let mut best_inside = false;
13591                let mut best_in_bracket_range = false;
13592                let mut best_destination = None;
13593                for (open, close) in enclosing_bracket_ranges {
13594                    let close = close.to_inclusive();
13595                    let length = close.end() - open.start;
13596                    let inside = selection.start >= open.end && selection.end <= *close.start();
13597                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13598                        || close.contains(&selection.head());
13599
13600                    // If best is next to a bracket and current isn't, skip
13601                    if !in_bracket_range && best_in_bracket_range {
13602                        continue;
13603                    }
13604
13605                    // Prefer smaller lengths unless best is inside and current isn't
13606                    if length > best_length && (best_inside || !inside) {
13607                        continue;
13608                    }
13609
13610                    best_length = length;
13611                    best_inside = inside;
13612                    best_in_bracket_range = in_bracket_range;
13613                    best_destination = Some(
13614                        if close.contains(&selection.start) && close.contains(&selection.end) {
13615                            if inside { open.end } else { open.start }
13616                        } else if inside {
13617                            *close.start()
13618                        } else {
13619                            *close.end()
13620                        },
13621                    );
13622                }
13623
13624                if let Some(destination) = best_destination {
13625                    selection.collapse_to(destination, SelectionGoal::None);
13626                }
13627            })
13628        });
13629    }
13630
13631    pub fn undo_selection(
13632        &mut self,
13633        _: &UndoSelection,
13634        window: &mut Window,
13635        cx: &mut Context<Self>,
13636    ) {
13637        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13638        self.end_selection(window, cx);
13639        self.selection_history.mode = SelectionHistoryMode::Undoing;
13640        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13641            self.change_selections(None, window, cx, |s| {
13642                s.select_anchors(entry.selections.to_vec())
13643            });
13644            self.select_next_state = entry.select_next_state;
13645            self.select_prev_state = entry.select_prev_state;
13646            self.add_selections_state = entry.add_selections_state;
13647            self.request_autoscroll(Autoscroll::newest(), cx);
13648        }
13649        self.selection_history.mode = SelectionHistoryMode::Normal;
13650    }
13651
13652    pub fn redo_selection(
13653        &mut self,
13654        _: &RedoSelection,
13655        window: &mut Window,
13656        cx: &mut Context<Self>,
13657    ) {
13658        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13659        self.end_selection(window, cx);
13660        self.selection_history.mode = SelectionHistoryMode::Redoing;
13661        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13662            self.change_selections(None, window, cx, |s| {
13663                s.select_anchors(entry.selections.to_vec())
13664            });
13665            self.select_next_state = entry.select_next_state;
13666            self.select_prev_state = entry.select_prev_state;
13667            self.add_selections_state = entry.add_selections_state;
13668            self.request_autoscroll(Autoscroll::newest(), cx);
13669        }
13670        self.selection_history.mode = SelectionHistoryMode::Normal;
13671    }
13672
13673    pub fn expand_excerpts(
13674        &mut self,
13675        action: &ExpandExcerpts,
13676        _: &mut Window,
13677        cx: &mut Context<Self>,
13678    ) {
13679        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13680    }
13681
13682    pub fn expand_excerpts_down(
13683        &mut self,
13684        action: &ExpandExcerptsDown,
13685        _: &mut Window,
13686        cx: &mut Context<Self>,
13687    ) {
13688        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13689    }
13690
13691    pub fn expand_excerpts_up(
13692        &mut self,
13693        action: &ExpandExcerptsUp,
13694        _: &mut Window,
13695        cx: &mut Context<Self>,
13696    ) {
13697        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13698    }
13699
13700    pub fn expand_excerpts_for_direction(
13701        &mut self,
13702        lines: u32,
13703        direction: ExpandExcerptDirection,
13704
13705        cx: &mut Context<Self>,
13706    ) {
13707        let selections = self.selections.disjoint_anchors();
13708
13709        let lines = if lines == 0 {
13710            EditorSettings::get_global(cx).expand_excerpt_lines
13711        } else {
13712            lines
13713        };
13714
13715        self.buffer.update(cx, |buffer, cx| {
13716            let snapshot = buffer.snapshot(cx);
13717            let mut excerpt_ids = selections
13718                .iter()
13719                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13720                .collect::<Vec<_>>();
13721            excerpt_ids.sort();
13722            excerpt_ids.dedup();
13723            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13724        })
13725    }
13726
13727    pub fn expand_excerpt(
13728        &mut self,
13729        excerpt: ExcerptId,
13730        direction: ExpandExcerptDirection,
13731        window: &mut Window,
13732        cx: &mut Context<Self>,
13733    ) {
13734        let current_scroll_position = self.scroll_position(cx);
13735        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13736        let mut should_scroll_up = false;
13737
13738        if direction == ExpandExcerptDirection::Down {
13739            let multi_buffer = self.buffer.read(cx);
13740            let snapshot = multi_buffer.snapshot(cx);
13741            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13742                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13743                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13744                        let buffer_snapshot = buffer.read(cx).snapshot();
13745                        let excerpt_end_row =
13746                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13747                        let last_row = buffer_snapshot.max_point().row;
13748                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13749                        should_scroll_up = lines_below >= lines_to_expand;
13750                    }
13751                }
13752            }
13753        }
13754
13755        self.buffer.update(cx, |buffer, cx| {
13756            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13757        });
13758
13759        if should_scroll_up {
13760            let new_scroll_position =
13761                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13762            self.set_scroll_position(new_scroll_position, window, cx);
13763        }
13764    }
13765
13766    pub fn go_to_singleton_buffer_point(
13767        &mut self,
13768        point: Point,
13769        window: &mut Window,
13770        cx: &mut Context<Self>,
13771    ) {
13772        self.go_to_singleton_buffer_range(point..point, window, cx);
13773    }
13774
13775    pub fn go_to_singleton_buffer_range(
13776        &mut self,
13777        range: Range<Point>,
13778        window: &mut Window,
13779        cx: &mut Context<Self>,
13780    ) {
13781        let multibuffer = self.buffer().read(cx);
13782        let Some(buffer) = multibuffer.as_singleton() else {
13783            return;
13784        };
13785        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13786            return;
13787        };
13788        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13789            return;
13790        };
13791        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13792            s.select_anchor_ranges([start..end])
13793        });
13794    }
13795
13796    pub fn go_to_diagnostic(
13797        &mut self,
13798        _: &GoToDiagnostic,
13799        window: &mut Window,
13800        cx: &mut Context<Self>,
13801    ) {
13802        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13803        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13804    }
13805
13806    pub fn go_to_prev_diagnostic(
13807        &mut self,
13808        _: &GoToPreviousDiagnostic,
13809        window: &mut Window,
13810        cx: &mut Context<Self>,
13811    ) {
13812        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13813        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13814    }
13815
13816    pub fn go_to_diagnostic_impl(
13817        &mut self,
13818        direction: Direction,
13819        window: &mut Window,
13820        cx: &mut Context<Self>,
13821    ) {
13822        let buffer = self.buffer.read(cx).snapshot(cx);
13823        let selection = self.selections.newest::<usize>(cx);
13824
13825        let mut active_group_id = None;
13826        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13827            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13828                active_group_id = Some(active_group.group_id);
13829            }
13830        }
13831
13832        fn filtered(
13833            snapshot: EditorSnapshot,
13834            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13835        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13836            diagnostics
13837                .filter(|entry| entry.range.start != entry.range.end)
13838                .filter(|entry| !entry.diagnostic.is_unnecessary)
13839                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13840        }
13841
13842        let snapshot = self.snapshot(window, cx);
13843        let before = filtered(
13844            snapshot.clone(),
13845            buffer
13846                .diagnostics_in_range(0..selection.start)
13847                .filter(|entry| entry.range.start <= selection.start),
13848        );
13849        let after = filtered(
13850            snapshot,
13851            buffer
13852                .diagnostics_in_range(selection.start..buffer.len())
13853                .filter(|entry| entry.range.start >= selection.start),
13854        );
13855
13856        let mut found: Option<DiagnosticEntry<usize>> = None;
13857        if direction == Direction::Prev {
13858            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13859            {
13860                for diagnostic in prev_diagnostics.into_iter().rev() {
13861                    if diagnostic.range.start != selection.start
13862                        || active_group_id
13863                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13864                    {
13865                        found = Some(diagnostic);
13866                        break 'outer;
13867                    }
13868                }
13869            }
13870        } else {
13871            for diagnostic in after.chain(before) {
13872                if diagnostic.range.start != selection.start
13873                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13874                {
13875                    found = Some(diagnostic);
13876                    break;
13877                }
13878            }
13879        }
13880        let Some(next_diagnostic) = found else {
13881            return;
13882        };
13883
13884        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13885            return;
13886        };
13887        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13888            s.select_ranges(vec![
13889                next_diagnostic.range.start..next_diagnostic.range.start,
13890            ])
13891        });
13892        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13893        self.refresh_inline_completion(false, true, window, cx);
13894    }
13895
13896    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13897        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13898        let snapshot = self.snapshot(window, cx);
13899        let selection = self.selections.newest::<Point>(cx);
13900        self.go_to_hunk_before_or_after_position(
13901            &snapshot,
13902            selection.head(),
13903            Direction::Next,
13904            window,
13905            cx,
13906        );
13907    }
13908
13909    pub fn go_to_hunk_before_or_after_position(
13910        &mut self,
13911        snapshot: &EditorSnapshot,
13912        position: Point,
13913        direction: Direction,
13914        window: &mut Window,
13915        cx: &mut Context<Editor>,
13916    ) {
13917        let row = if direction == Direction::Next {
13918            self.hunk_after_position(snapshot, position)
13919                .map(|hunk| hunk.row_range.start)
13920        } else {
13921            self.hunk_before_position(snapshot, position)
13922        };
13923
13924        if let Some(row) = row {
13925            let destination = Point::new(row.0, 0);
13926            let autoscroll = Autoscroll::center();
13927
13928            self.unfold_ranges(&[destination..destination], false, false, cx);
13929            self.change_selections(Some(autoscroll), window, cx, |s| {
13930                s.select_ranges([destination..destination]);
13931            });
13932        }
13933    }
13934
13935    fn hunk_after_position(
13936        &mut self,
13937        snapshot: &EditorSnapshot,
13938        position: Point,
13939    ) -> Option<MultiBufferDiffHunk> {
13940        snapshot
13941            .buffer_snapshot
13942            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13943            .find(|hunk| hunk.row_range.start.0 > position.row)
13944            .or_else(|| {
13945                snapshot
13946                    .buffer_snapshot
13947                    .diff_hunks_in_range(Point::zero()..position)
13948                    .find(|hunk| hunk.row_range.end.0 < position.row)
13949            })
13950    }
13951
13952    fn go_to_prev_hunk(
13953        &mut self,
13954        _: &GoToPreviousHunk,
13955        window: &mut Window,
13956        cx: &mut Context<Self>,
13957    ) {
13958        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13959        let snapshot = self.snapshot(window, cx);
13960        let selection = self.selections.newest::<Point>(cx);
13961        self.go_to_hunk_before_or_after_position(
13962            &snapshot,
13963            selection.head(),
13964            Direction::Prev,
13965            window,
13966            cx,
13967        );
13968    }
13969
13970    fn hunk_before_position(
13971        &mut self,
13972        snapshot: &EditorSnapshot,
13973        position: Point,
13974    ) -> Option<MultiBufferRow> {
13975        snapshot
13976            .buffer_snapshot
13977            .diff_hunk_before(position)
13978            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13979    }
13980
13981    fn go_to_next_change(
13982        &mut self,
13983        _: &GoToNextChange,
13984        window: &mut Window,
13985        cx: &mut Context<Self>,
13986    ) {
13987        if let Some(selections) = self
13988            .change_list
13989            .next_change(1, Direction::Next)
13990            .map(|s| s.to_vec())
13991        {
13992            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13993                let map = s.display_map();
13994                s.select_display_ranges(selections.iter().map(|a| {
13995                    let point = a.to_display_point(&map);
13996                    point..point
13997                }))
13998            })
13999        }
14000    }
14001
14002    fn go_to_previous_change(
14003        &mut self,
14004        _: &GoToPreviousChange,
14005        window: &mut Window,
14006        cx: &mut Context<Self>,
14007    ) {
14008        if let Some(selections) = self
14009            .change_list
14010            .next_change(1, Direction::Prev)
14011            .map(|s| s.to_vec())
14012        {
14013            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14014                let map = s.display_map();
14015                s.select_display_ranges(selections.iter().map(|a| {
14016                    let point = a.to_display_point(&map);
14017                    point..point
14018                }))
14019            })
14020        }
14021    }
14022
14023    fn go_to_line<T: 'static>(
14024        &mut self,
14025        position: Anchor,
14026        highlight_color: Option<Hsla>,
14027        window: &mut Window,
14028        cx: &mut Context<Self>,
14029    ) {
14030        let snapshot = self.snapshot(window, cx).display_snapshot;
14031        let position = position.to_point(&snapshot.buffer_snapshot);
14032        let start = snapshot
14033            .buffer_snapshot
14034            .clip_point(Point::new(position.row, 0), Bias::Left);
14035        let end = start + Point::new(1, 0);
14036        let start = snapshot.buffer_snapshot.anchor_before(start);
14037        let end = snapshot.buffer_snapshot.anchor_before(end);
14038
14039        self.highlight_rows::<T>(
14040            start..end,
14041            highlight_color
14042                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14043            Default::default(),
14044            cx,
14045        );
14046
14047        if self.buffer.read(cx).is_singleton() {
14048            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14049        }
14050    }
14051
14052    pub fn go_to_definition(
14053        &mut self,
14054        _: &GoToDefinition,
14055        window: &mut Window,
14056        cx: &mut Context<Self>,
14057    ) -> Task<Result<Navigated>> {
14058        let definition =
14059            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14060        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14061        cx.spawn_in(window, async move |editor, cx| {
14062            if definition.await? == Navigated::Yes {
14063                return Ok(Navigated::Yes);
14064            }
14065            match fallback_strategy {
14066                GoToDefinitionFallback::None => Ok(Navigated::No),
14067                GoToDefinitionFallback::FindAllReferences => {
14068                    match editor.update_in(cx, |editor, window, cx| {
14069                        editor.find_all_references(&FindAllReferences, window, cx)
14070                    })? {
14071                        Some(references) => references.await,
14072                        None => Ok(Navigated::No),
14073                    }
14074                }
14075            }
14076        })
14077    }
14078
14079    pub fn go_to_declaration(
14080        &mut self,
14081        _: &GoToDeclaration,
14082        window: &mut Window,
14083        cx: &mut Context<Self>,
14084    ) -> Task<Result<Navigated>> {
14085        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14086    }
14087
14088    pub fn go_to_declaration_split(
14089        &mut self,
14090        _: &GoToDeclaration,
14091        window: &mut Window,
14092        cx: &mut Context<Self>,
14093    ) -> Task<Result<Navigated>> {
14094        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14095    }
14096
14097    pub fn go_to_implementation(
14098        &mut self,
14099        _: &GoToImplementation,
14100        window: &mut Window,
14101        cx: &mut Context<Self>,
14102    ) -> Task<Result<Navigated>> {
14103        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14104    }
14105
14106    pub fn go_to_implementation_split(
14107        &mut self,
14108        _: &GoToImplementationSplit,
14109        window: &mut Window,
14110        cx: &mut Context<Self>,
14111    ) -> Task<Result<Navigated>> {
14112        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14113    }
14114
14115    pub fn go_to_type_definition(
14116        &mut self,
14117        _: &GoToTypeDefinition,
14118        window: &mut Window,
14119        cx: &mut Context<Self>,
14120    ) -> Task<Result<Navigated>> {
14121        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14122    }
14123
14124    pub fn go_to_definition_split(
14125        &mut self,
14126        _: &GoToDefinitionSplit,
14127        window: &mut Window,
14128        cx: &mut Context<Self>,
14129    ) -> Task<Result<Navigated>> {
14130        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14131    }
14132
14133    pub fn go_to_type_definition_split(
14134        &mut self,
14135        _: &GoToTypeDefinitionSplit,
14136        window: &mut Window,
14137        cx: &mut Context<Self>,
14138    ) -> Task<Result<Navigated>> {
14139        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14140    }
14141
14142    fn go_to_definition_of_kind(
14143        &mut self,
14144        kind: GotoDefinitionKind,
14145        split: bool,
14146        window: &mut Window,
14147        cx: &mut Context<Self>,
14148    ) -> Task<Result<Navigated>> {
14149        let Some(provider) = self.semantics_provider.clone() else {
14150            return Task::ready(Ok(Navigated::No));
14151        };
14152        let head = self.selections.newest::<usize>(cx).head();
14153        let buffer = self.buffer.read(cx);
14154        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14155            text_anchor
14156        } else {
14157            return Task::ready(Ok(Navigated::No));
14158        };
14159
14160        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14161            return Task::ready(Ok(Navigated::No));
14162        };
14163
14164        cx.spawn_in(window, async move |editor, cx| {
14165            let definitions = definitions.await?;
14166            let navigated = editor
14167                .update_in(cx, |editor, window, cx| {
14168                    editor.navigate_to_hover_links(
14169                        Some(kind),
14170                        definitions
14171                            .into_iter()
14172                            .filter(|location| {
14173                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14174                            })
14175                            .map(HoverLink::Text)
14176                            .collect::<Vec<_>>(),
14177                        split,
14178                        window,
14179                        cx,
14180                    )
14181                })?
14182                .await?;
14183            anyhow::Ok(navigated)
14184        })
14185    }
14186
14187    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14188        let selection = self.selections.newest_anchor();
14189        let head = selection.head();
14190        let tail = selection.tail();
14191
14192        let Some((buffer, start_position)) =
14193            self.buffer.read(cx).text_anchor_for_position(head, cx)
14194        else {
14195            return;
14196        };
14197
14198        let end_position = if head != tail {
14199            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14200                return;
14201            };
14202            Some(pos)
14203        } else {
14204            None
14205        };
14206
14207        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14208            let url = if let Some(end_pos) = end_position {
14209                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14210            } else {
14211                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14212            };
14213
14214            if let Some(url) = url {
14215                editor.update(cx, |_, cx| {
14216                    cx.open_url(&url);
14217                })
14218            } else {
14219                Ok(())
14220            }
14221        });
14222
14223        url_finder.detach();
14224    }
14225
14226    pub fn open_selected_filename(
14227        &mut self,
14228        _: &OpenSelectedFilename,
14229        window: &mut Window,
14230        cx: &mut Context<Self>,
14231    ) {
14232        let Some(workspace) = self.workspace() else {
14233            return;
14234        };
14235
14236        let position = self.selections.newest_anchor().head();
14237
14238        let Some((buffer, buffer_position)) =
14239            self.buffer.read(cx).text_anchor_for_position(position, cx)
14240        else {
14241            return;
14242        };
14243
14244        let project = self.project.clone();
14245
14246        cx.spawn_in(window, async move |_, cx| {
14247            let result = find_file(&buffer, project, buffer_position, cx).await;
14248
14249            if let Some((_, path)) = result {
14250                workspace
14251                    .update_in(cx, |workspace, window, cx| {
14252                        workspace.open_resolved_path(path, window, cx)
14253                    })?
14254                    .await?;
14255            }
14256            anyhow::Ok(())
14257        })
14258        .detach();
14259    }
14260
14261    pub(crate) fn navigate_to_hover_links(
14262        &mut self,
14263        kind: Option<GotoDefinitionKind>,
14264        mut definitions: Vec<HoverLink>,
14265        split: bool,
14266        window: &mut Window,
14267        cx: &mut Context<Editor>,
14268    ) -> Task<Result<Navigated>> {
14269        // If there is one definition, just open it directly
14270        if definitions.len() == 1 {
14271            let definition = definitions.pop().unwrap();
14272
14273            enum TargetTaskResult {
14274                Location(Option<Location>),
14275                AlreadyNavigated,
14276            }
14277
14278            let target_task = match definition {
14279                HoverLink::Text(link) => {
14280                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14281                }
14282                HoverLink::InlayHint(lsp_location, server_id) => {
14283                    let computation =
14284                        self.compute_target_location(lsp_location, server_id, window, cx);
14285                    cx.background_spawn(async move {
14286                        let location = computation.await?;
14287                        Ok(TargetTaskResult::Location(location))
14288                    })
14289                }
14290                HoverLink::Url(url) => {
14291                    cx.open_url(&url);
14292                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14293                }
14294                HoverLink::File(path) => {
14295                    if let Some(workspace) = self.workspace() {
14296                        cx.spawn_in(window, async move |_, cx| {
14297                            workspace
14298                                .update_in(cx, |workspace, window, cx| {
14299                                    workspace.open_resolved_path(path, window, cx)
14300                                })?
14301                                .await
14302                                .map(|_| TargetTaskResult::AlreadyNavigated)
14303                        })
14304                    } else {
14305                        Task::ready(Ok(TargetTaskResult::Location(None)))
14306                    }
14307                }
14308            };
14309            cx.spawn_in(window, async move |editor, cx| {
14310                let target = match target_task.await.context("target resolution task")? {
14311                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14312                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14313                    TargetTaskResult::Location(Some(target)) => target,
14314                };
14315
14316                editor.update_in(cx, |editor, window, cx| {
14317                    let Some(workspace) = editor.workspace() else {
14318                        return Navigated::No;
14319                    };
14320                    let pane = workspace.read(cx).active_pane().clone();
14321
14322                    let range = target.range.to_point(target.buffer.read(cx));
14323                    let range = editor.range_for_match(&range);
14324                    let range = collapse_multiline_range(range);
14325
14326                    if !split
14327                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14328                    {
14329                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14330                    } else {
14331                        window.defer(cx, move |window, cx| {
14332                            let target_editor: Entity<Self> =
14333                                workspace.update(cx, |workspace, cx| {
14334                                    let pane = if split {
14335                                        workspace.adjacent_pane(window, cx)
14336                                    } else {
14337                                        workspace.active_pane().clone()
14338                                    };
14339
14340                                    workspace.open_project_item(
14341                                        pane,
14342                                        target.buffer.clone(),
14343                                        true,
14344                                        true,
14345                                        window,
14346                                        cx,
14347                                    )
14348                                });
14349                            target_editor.update(cx, |target_editor, cx| {
14350                                // When selecting a definition in a different buffer, disable the nav history
14351                                // to avoid creating a history entry at the previous cursor location.
14352                                pane.update(cx, |pane, _| pane.disable_history());
14353                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14354                                pane.update(cx, |pane, _| pane.enable_history());
14355                            });
14356                        });
14357                    }
14358                    Navigated::Yes
14359                })
14360            })
14361        } else if !definitions.is_empty() {
14362            cx.spawn_in(window, async move |editor, cx| {
14363                let (title, location_tasks, workspace) = editor
14364                    .update_in(cx, |editor, window, cx| {
14365                        let tab_kind = match kind {
14366                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14367                            _ => "Definitions",
14368                        };
14369                        let title = definitions
14370                            .iter()
14371                            .find_map(|definition| match definition {
14372                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14373                                    let buffer = origin.buffer.read(cx);
14374                                    format!(
14375                                        "{} for {}",
14376                                        tab_kind,
14377                                        buffer
14378                                            .text_for_range(origin.range.clone())
14379                                            .collect::<String>()
14380                                    )
14381                                }),
14382                                HoverLink::InlayHint(_, _) => None,
14383                                HoverLink::Url(_) => None,
14384                                HoverLink::File(_) => None,
14385                            })
14386                            .unwrap_or(tab_kind.to_string());
14387                        let location_tasks = definitions
14388                            .into_iter()
14389                            .map(|definition| match definition {
14390                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14391                                HoverLink::InlayHint(lsp_location, server_id) => editor
14392                                    .compute_target_location(lsp_location, server_id, window, cx),
14393                                HoverLink::Url(_) => Task::ready(Ok(None)),
14394                                HoverLink::File(_) => Task::ready(Ok(None)),
14395                            })
14396                            .collect::<Vec<_>>();
14397                        (title, location_tasks, editor.workspace().clone())
14398                    })
14399                    .context("location tasks preparation")?;
14400
14401                let locations = future::join_all(location_tasks)
14402                    .await
14403                    .into_iter()
14404                    .filter_map(|location| location.transpose())
14405                    .collect::<Result<_>>()
14406                    .context("location tasks")?;
14407
14408                let Some(workspace) = workspace else {
14409                    return Ok(Navigated::No);
14410                };
14411                let opened = workspace
14412                    .update_in(cx, |workspace, window, cx| {
14413                        Self::open_locations_in_multibuffer(
14414                            workspace,
14415                            locations,
14416                            title,
14417                            split,
14418                            MultibufferSelectionMode::First,
14419                            window,
14420                            cx,
14421                        )
14422                    })
14423                    .ok();
14424
14425                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14426            })
14427        } else {
14428            Task::ready(Ok(Navigated::No))
14429        }
14430    }
14431
14432    fn compute_target_location(
14433        &self,
14434        lsp_location: lsp::Location,
14435        server_id: LanguageServerId,
14436        window: &mut Window,
14437        cx: &mut Context<Self>,
14438    ) -> Task<anyhow::Result<Option<Location>>> {
14439        let Some(project) = self.project.clone() else {
14440            return Task::ready(Ok(None));
14441        };
14442
14443        cx.spawn_in(window, async move |editor, cx| {
14444            let location_task = editor.update(cx, |_, cx| {
14445                project.update(cx, |project, cx| {
14446                    let language_server_name = project
14447                        .language_server_statuses(cx)
14448                        .find(|(id, _)| server_id == *id)
14449                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14450                    language_server_name.map(|language_server_name| {
14451                        project.open_local_buffer_via_lsp(
14452                            lsp_location.uri.clone(),
14453                            server_id,
14454                            language_server_name,
14455                            cx,
14456                        )
14457                    })
14458                })
14459            })?;
14460            let location = match location_task {
14461                Some(task) => Some({
14462                    let target_buffer_handle = task.await.context("open local buffer")?;
14463                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14464                        let target_start = target_buffer
14465                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14466                        let target_end = target_buffer
14467                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14468                        target_buffer.anchor_after(target_start)
14469                            ..target_buffer.anchor_before(target_end)
14470                    })?;
14471                    Location {
14472                        buffer: target_buffer_handle,
14473                        range,
14474                    }
14475                }),
14476                None => None,
14477            };
14478            Ok(location)
14479        })
14480    }
14481
14482    pub fn find_all_references(
14483        &mut self,
14484        _: &FindAllReferences,
14485        window: &mut Window,
14486        cx: &mut Context<Self>,
14487    ) -> Option<Task<Result<Navigated>>> {
14488        let selection = self.selections.newest::<usize>(cx);
14489        let multi_buffer = self.buffer.read(cx);
14490        let head = selection.head();
14491
14492        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14493        let head_anchor = multi_buffer_snapshot.anchor_at(
14494            head,
14495            if head < selection.tail() {
14496                Bias::Right
14497            } else {
14498                Bias::Left
14499            },
14500        );
14501
14502        match self
14503            .find_all_references_task_sources
14504            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14505        {
14506            Ok(_) => {
14507                log::info!(
14508                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14509                );
14510                return None;
14511            }
14512            Err(i) => {
14513                self.find_all_references_task_sources.insert(i, head_anchor);
14514            }
14515        }
14516
14517        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14518        let workspace = self.workspace()?;
14519        let project = workspace.read(cx).project().clone();
14520        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14521        Some(cx.spawn_in(window, async move |editor, cx| {
14522            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14523                if let Ok(i) = editor
14524                    .find_all_references_task_sources
14525                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14526                {
14527                    editor.find_all_references_task_sources.remove(i);
14528                }
14529            });
14530
14531            let locations = references.await?;
14532            if locations.is_empty() {
14533                return anyhow::Ok(Navigated::No);
14534            }
14535
14536            workspace.update_in(cx, |workspace, window, cx| {
14537                let title = locations
14538                    .first()
14539                    .as_ref()
14540                    .map(|location| {
14541                        let buffer = location.buffer.read(cx);
14542                        format!(
14543                            "References to `{}`",
14544                            buffer
14545                                .text_for_range(location.range.clone())
14546                                .collect::<String>()
14547                        )
14548                    })
14549                    .unwrap();
14550                Self::open_locations_in_multibuffer(
14551                    workspace,
14552                    locations,
14553                    title,
14554                    false,
14555                    MultibufferSelectionMode::First,
14556                    window,
14557                    cx,
14558                );
14559                Navigated::Yes
14560            })
14561        }))
14562    }
14563
14564    /// Opens a multibuffer with the given project locations in it
14565    pub fn open_locations_in_multibuffer(
14566        workspace: &mut Workspace,
14567        mut locations: Vec<Location>,
14568        title: String,
14569        split: bool,
14570        multibuffer_selection_mode: MultibufferSelectionMode,
14571        window: &mut Window,
14572        cx: &mut Context<Workspace>,
14573    ) {
14574        // If there are multiple definitions, open them in a multibuffer
14575        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14576        let mut locations = locations.into_iter().peekable();
14577        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14578        let capability = workspace.project().read(cx).capability();
14579
14580        let excerpt_buffer = cx.new(|cx| {
14581            let mut multibuffer = MultiBuffer::new(capability);
14582            while let Some(location) = locations.next() {
14583                let buffer = location.buffer.read(cx);
14584                let mut ranges_for_buffer = Vec::new();
14585                let range = location.range.to_point(buffer);
14586                ranges_for_buffer.push(range.clone());
14587
14588                while let Some(next_location) = locations.peek() {
14589                    if next_location.buffer == location.buffer {
14590                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14591                        locations.next();
14592                    } else {
14593                        break;
14594                    }
14595                }
14596
14597                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14598                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14599                    PathKey::for_buffer(&location.buffer, cx),
14600                    location.buffer.clone(),
14601                    ranges_for_buffer,
14602                    DEFAULT_MULTIBUFFER_CONTEXT,
14603                    cx,
14604                );
14605                ranges.extend(new_ranges)
14606            }
14607
14608            multibuffer.with_title(title)
14609        });
14610
14611        let editor = cx.new(|cx| {
14612            Editor::for_multibuffer(
14613                excerpt_buffer,
14614                Some(workspace.project().clone()),
14615                window,
14616                cx,
14617            )
14618        });
14619        editor.update(cx, |editor, cx| {
14620            match multibuffer_selection_mode {
14621                MultibufferSelectionMode::First => {
14622                    if let Some(first_range) = ranges.first() {
14623                        editor.change_selections(None, window, cx, |selections| {
14624                            selections.clear_disjoint();
14625                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14626                        });
14627                    }
14628                    editor.highlight_background::<Self>(
14629                        &ranges,
14630                        |theme| theme.editor_highlighted_line_background,
14631                        cx,
14632                    );
14633                }
14634                MultibufferSelectionMode::All => {
14635                    editor.change_selections(None, window, cx, |selections| {
14636                        selections.clear_disjoint();
14637                        selections.select_anchor_ranges(ranges);
14638                    });
14639                }
14640            }
14641            editor.register_buffers_with_language_servers(cx);
14642        });
14643
14644        let item = Box::new(editor);
14645        let item_id = item.item_id();
14646
14647        if split {
14648            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14649        } else {
14650            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14651                let (preview_item_id, preview_item_idx) =
14652                    workspace.active_pane().update(cx, |pane, _| {
14653                        (pane.preview_item_id(), pane.preview_item_idx())
14654                    });
14655
14656                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14657
14658                if let Some(preview_item_id) = preview_item_id {
14659                    workspace.active_pane().update(cx, |pane, cx| {
14660                        pane.remove_item(preview_item_id, false, false, window, cx);
14661                    });
14662                }
14663            } else {
14664                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14665            }
14666        }
14667        workspace.active_pane().update(cx, |pane, cx| {
14668            pane.set_preview_item_id(Some(item_id), cx);
14669        });
14670    }
14671
14672    pub fn rename(
14673        &mut self,
14674        _: &Rename,
14675        window: &mut Window,
14676        cx: &mut Context<Self>,
14677    ) -> Option<Task<Result<()>>> {
14678        use language::ToOffset as _;
14679
14680        let provider = self.semantics_provider.clone()?;
14681        let selection = self.selections.newest_anchor().clone();
14682        let (cursor_buffer, cursor_buffer_position) = self
14683            .buffer
14684            .read(cx)
14685            .text_anchor_for_position(selection.head(), cx)?;
14686        let (tail_buffer, cursor_buffer_position_end) = self
14687            .buffer
14688            .read(cx)
14689            .text_anchor_for_position(selection.tail(), cx)?;
14690        if tail_buffer != cursor_buffer {
14691            return None;
14692        }
14693
14694        let snapshot = cursor_buffer.read(cx).snapshot();
14695        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14696        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14697        let prepare_rename = provider
14698            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14699            .unwrap_or_else(|| Task::ready(Ok(None)));
14700        drop(snapshot);
14701
14702        Some(cx.spawn_in(window, async move |this, cx| {
14703            let rename_range = if let Some(range) = prepare_rename.await? {
14704                Some(range)
14705            } else {
14706                this.update(cx, |this, cx| {
14707                    let buffer = this.buffer.read(cx).snapshot(cx);
14708                    let mut buffer_highlights = this
14709                        .document_highlights_for_position(selection.head(), &buffer)
14710                        .filter(|highlight| {
14711                            highlight.start.excerpt_id == selection.head().excerpt_id
14712                                && highlight.end.excerpt_id == selection.head().excerpt_id
14713                        });
14714                    buffer_highlights
14715                        .next()
14716                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14717                })?
14718            };
14719            if let Some(rename_range) = rename_range {
14720                this.update_in(cx, |this, window, cx| {
14721                    let snapshot = cursor_buffer.read(cx).snapshot();
14722                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14723                    let cursor_offset_in_rename_range =
14724                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14725                    let cursor_offset_in_rename_range_end =
14726                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14727
14728                    this.take_rename(false, window, cx);
14729                    let buffer = this.buffer.read(cx).read(cx);
14730                    let cursor_offset = selection.head().to_offset(&buffer);
14731                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14732                    let rename_end = rename_start + rename_buffer_range.len();
14733                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14734                    let mut old_highlight_id = None;
14735                    let old_name: Arc<str> = buffer
14736                        .chunks(rename_start..rename_end, true)
14737                        .map(|chunk| {
14738                            if old_highlight_id.is_none() {
14739                                old_highlight_id = chunk.syntax_highlight_id;
14740                            }
14741                            chunk.text
14742                        })
14743                        .collect::<String>()
14744                        .into();
14745
14746                    drop(buffer);
14747
14748                    // Position the selection in the rename editor so that it matches the current selection.
14749                    this.show_local_selections = false;
14750                    let rename_editor = cx.new(|cx| {
14751                        let mut editor = Editor::single_line(window, cx);
14752                        editor.buffer.update(cx, |buffer, cx| {
14753                            buffer.edit([(0..0, old_name.clone())], None, cx)
14754                        });
14755                        let rename_selection_range = match cursor_offset_in_rename_range
14756                            .cmp(&cursor_offset_in_rename_range_end)
14757                        {
14758                            Ordering::Equal => {
14759                                editor.select_all(&SelectAll, window, cx);
14760                                return editor;
14761                            }
14762                            Ordering::Less => {
14763                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14764                            }
14765                            Ordering::Greater => {
14766                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14767                            }
14768                        };
14769                        if rename_selection_range.end > old_name.len() {
14770                            editor.select_all(&SelectAll, window, cx);
14771                        } else {
14772                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14773                                s.select_ranges([rename_selection_range]);
14774                            });
14775                        }
14776                        editor
14777                    });
14778                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14779                        if e == &EditorEvent::Focused {
14780                            cx.emit(EditorEvent::FocusedIn)
14781                        }
14782                    })
14783                    .detach();
14784
14785                    let write_highlights =
14786                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14787                    let read_highlights =
14788                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14789                    let ranges = write_highlights
14790                        .iter()
14791                        .flat_map(|(_, ranges)| ranges.iter())
14792                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14793                        .cloned()
14794                        .collect();
14795
14796                    this.highlight_text::<Rename>(
14797                        ranges,
14798                        HighlightStyle {
14799                            fade_out: Some(0.6),
14800                            ..Default::default()
14801                        },
14802                        cx,
14803                    );
14804                    let rename_focus_handle = rename_editor.focus_handle(cx);
14805                    window.focus(&rename_focus_handle);
14806                    let block_id = this.insert_blocks(
14807                        [BlockProperties {
14808                            style: BlockStyle::Flex,
14809                            placement: BlockPlacement::Below(range.start),
14810                            height: Some(1),
14811                            render: Arc::new({
14812                                let rename_editor = rename_editor.clone();
14813                                move |cx: &mut BlockContext| {
14814                                    let mut text_style = cx.editor_style.text.clone();
14815                                    if let Some(highlight_style) = old_highlight_id
14816                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14817                                    {
14818                                        text_style = text_style.highlight(highlight_style);
14819                                    }
14820                                    div()
14821                                        .block_mouse_down()
14822                                        .pl(cx.anchor_x)
14823                                        .child(EditorElement::new(
14824                                            &rename_editor,
14825                                            EditorStyle {
14826                                                background: cx.theme().system().transparent,
14827                                                local_player: cx.editor_style.local_player,
14828                                                text: text_style,
14829                                                scrollbar_width: cx.editor_style.scrollbar_width,
14830                                                syntax: cx.editor_style.syntax.clone(),
14831                                                status: cx.editor_style.status.clone(),
14832                                                inlay_hints_style: HighlightStyle {
14833                                                    font_weight: Some(FontWeight::BOLD),
14834                                                    ..make_inlay_hints_style(cx.app)
14835                                                },
14836                                                inline_completion_styles: make_suggestion_styles(
14837                                                    cx.app,
14838                                                ),
14839                                                ..EditorStyle::default()
14840                                            },
14841                                        ))
14842                                        .into_any_element()
14843                                }
14844                            }),
14845                            priority: 0,
14846                            render_in_minimap: true,
14847                        }],
14848                        Some(Autoscroll::fit()),
14849                        cx,
14850                    )[0];
14851                    this.pending_rename = Some(RenameState {
14852                        range,
14853                        old_name,
14854                        editor: rename_editor,
14855                        block_id,
14856                    });
14857                })?;
14858            }
14859
14860            Ok(())
14861        }))
14862    }
14863
14864    pub fn confirm_rename(
14865        &mut self,
14866        _: &ConfirmRename,
14867        window: &mut Window,
14868        cx: &mut Context<Self>,
14869    ) -> Option<Task<Result<()>>> {
14870        let rename = self.take_rename(false, window, cx)?;
14871        let workspace = self.workspace()?.downgrade();
14872        let (buffer, start) = self
14873            .buffer
14874            .read(cx)
14875            .text_anchor_for_position(rename.range.start, cx)?;
14876        let (end_buffer, _) = self
14877            .buffer
14878            .read(cx)
14879            .text_anchor_for_position(rename.range.end, cx)?;
14880        if buffer != end_buffer {
14881            return None;
14882        }
14883
14884        let old_name = rename.old_name;
14885        let new_name = rename.editor.read(cx).text(cx);
14886
14887        let rename = self.semantics_provider.as_ref()?.perform_rename(
14888            &buffer,
14889            start,
14890            new_name.clone(),
14891            cx,
14892        )?;
14893
14894        Some(cx.spawn_in(window, async move |editor, cx| {
14895            let project_transaction = rename.await?;
14896            Self::open_project_transaction(
14897                &editor,
14898                workspace,
14899                project_transaction,
14900                format!("Rename: {}{}", old_name, new_name),
14901                cx,
14902            )
14903            .await?;
14904
14905            editor.update(cx, |editor, cx| {
14906                editor.refresh_document_highlights(cx);
14907            })?;
14908            Ok(())
14909        }))
14910    }
14911
14912    fn take_rename(
14913        &mut self,
14914        moving_cursor: bool,
14915        window: &mut Window,
14916        cx: &mut Context<Self>,
14917    ) -> Option<RenameState> {
14918        let rename = self.pending_rename.take()?;
14919        if rename.editor.focus_handle(cx).is_focused(window) {
14920            window.focus(&self.focus_handle);
14921        }
14922
14923        self.remove_blocks(
14924            [rename.block_id].into_iter().collect(),
14925            Some(Autoscroll::fit()),
14926            cx,
14927        );
14928        self.clear_highlights::<Rename>(cx);
14929        self.show_local_selections = true;
14930
14931        if moving_cursor {
14932            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14933                editor.selections.newest::<usize>(cx).head()
14934            });
14935
14936            // Update the selection to match the position of the selection inside
14937            // the rename editor.
14938            let snapshot = self.buffer.read(cx).read(cx);
14939            let rename_range = rename.range.to_offset(&snapshot);
14940            let cursor_in_editor = snapshot
14941                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14942                .min(rename_range.end);
14943            drop(snapshot);
14944
14945            self.change_selections(None, window, cx, |s| {
14946                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14947            });
14948        } else {
14949            self.refresh_document_highlights(cx);
14950        }
14951
14952        Some(rename)
14953    }
14954
14955    pub fn pending_rename(&self) -> Option<&RenameState> {
14956        self.pending_rename.as_ref()
14957    }
14958
14959    fn format(
14960        &mut self,
14961        _: &Format,
14962        window: &mut Window,
14963        cx: &mut Context<Self>,
14964    ) -> Option<Task<Result<()>>> {
14965        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14966
14967        let project = match &self.project {
14968            Some(project) => project.clone(),
14969            None => return None,
14970        };
14971
14972        Some(self.perform_format(
14973            project,
14974            FormatTrigger::Manual,
14975            FormatTarget::Buffers,
14976            window,
14977            cx,
14978        ))
14979    }
14980
14981    fn format_selections(
14982        &mut self,
14983        _: &FormatSelections,
14984        window: &mut Window,
14985        cx: &mut Context<Self>,
14986    ) -> Option<Task<Result<()>>> {
14987        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14988
14989        let project = match &self.project {
14990            Some(project) => project.clone(),
14991            None => return None,
14992        };
14993
14994        let ranges = self
14995            .selections
14996            .all_adjusted(cx)
14997            .into_iter()
14998            .map(|selection| selection.range())
14999            .collect_vec();
15000
15001        Some(self.perform_format(
15002            project,
15003            FormatTrigger::Manual,
15004            FormatTarget::Ranges(ranges),
15005            window,
15006            cx,
15007        ))
15008    }
15009
15010    fn perform_format(
15011        &mut self,
15012        project: Entity<Project>,
15013        trigger: FormatTrigger,
15014        target: FormatTarget,
15015        window: &mut Window,
15016        cx: &mut Context<Self>,
15017    ) -> Task<Result<()>> {
15018        let buffer = self.buffer.clone();
15019        let (buffers, target) = match target {
15020            FormatTarget::Buffers => {
15021                let mut buffers = buffer.read(cx).all_buffers();
15022                if trigger == FormatTrigger::Save {
15023                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15024                }
15025                (buffers, LspFormatTarget::Buffers)
15026            }
15027            FormatTarget::Ranges(selection_ranges) => {
15028                let multi_buffer = buffer.read(cx);
15029                let snapshot = multi_buffer.read(cx);
15030                let mut buffers = HashSet::default();
15031                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15032                    BTreeMap::new();
15033                for selection_range in selection_ranges {
15034                    for (buffer, buffer_range, _) in
15035                        snapshot.range_to_buffer_ranges(selection_range)
15036                    {
15037                        let buffer_id = buffer.remote_id();
15038                        let start = buffer.anchor_before(buffer_range.start);
15039                        let end = buffer.anchor_after(buffer_range.end);
15040                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15041                        buffer_id_to_ranges
15042                            .entry(buffer_id)
15043                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15044                            .or_insert_with(|| vec![start..end]);
15045                    }
15046                }
15047                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15048            }
15049        };
15050
15051        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15052        let selections_prev = transaction_id_prev
15053            .and_then(|transaction_id_prev| {
15054                // default to selections as they were after the last edit, if we have them,
15055                // instead of how they are now.
15056                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15057                // will take you back to where you made the last edit, instead of staying where you scrolled
15058                self.selection_history
15059                    .transaction(transaction_id_prev)
15060                    .map(|t| t.0.clone())
15061            })
15062            .unwrap_or_else(|| {
15063                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15064                self.selections.disjoint_anchors()
15065            });
15066
15067        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15068        let format = project.update(cx, |project, cx| {
15069            project.format(buffers, target, true, trigger, cx)
15070        });
15071
15072        cx.spawn_in(window, async move |editor, cx| {
15073            let transaction = futures::select_biased! {
15074                transaction = format.log_err().fuse() => transaction,
15075                () = timeout => {
15076                    log::warn!("timed out waiting for formatting");
15077                    None
15078                }
15079            };
15080
15081            buffer
15082                .update(cx, |buffer, cx| {
15083                    if let Some(transaction) = transaction {
15084                        if !buffer.is_singleton() {
15085                            buffer.push_transaction(&transaction.0, cx);
15086                        }
15087                    }
15088                    cx.notify();
15089                })
15090                .ok();
15091
15092            if let Some(transaction_id_now) =
15093                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15094            {
15095                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15096                if has_new_transaction {
15097                    _ = editor.update(cx, |editor, _| {
15098                        editor
15099                            .selection_history
15100                            .insert_transaction(transaction_id_now, selections_prev);
15101                    });
15102                }
15103            }
15104
15105            Ok(())
15106        })
15107    }
15108
15109    fn organize_imports(
15110        &mut self,
15111        _: &OrganizeImports,
15112        window: &mut Window,
15113        cx: &mut Context<Self>,
15114    ) -> Option<Task<Result<()>>> {
15115        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15116        let project = match &self.project {
15117            Some(project) => project.clone(),
15118            None => return None,
15119        };
15120        Some(self.perform_code_action_kind(
15121            project,
15122            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15123            window,
15124            cx,
15125        ))
15126    }
15127
15128    fn perform_code_action_kind(
15129        &mut self,
15130        project: Entity<Project>,
15131        kind: CodeActionKind,
15132        window: &mut Window,
15133        cx: &mut Context<Self>,
15134    ) -> Task<Result<()>> {
15135        let buffer = self.buffer.clone();
15136        let buffers = buffer.read(cx).all_buffers();
15137        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15138        let apply_action = project.update(cx, |project, cx| {
15139            project.apply_code_action_kind(buffers, kind, true, cx)
15140        });
15141        cx.spawn_in(window, async move |_, cx| {
15142            let transaction = futures::select_biased! {
15143                () = timeout => {
15144                    log::warn!("timed out waiting for executing code action");
15145                    None
15146                }
15147                transaction = apply_action.log_err().fuse() => transaction,
15148            };
15149            buffer
15150                .update(cx, |buffer, cx| {
15151                    // check if we need this
15152                    if let Some(transaction) = transaction {
15153                        if !buffer.is_singleton() {
15154                            buffer.push_transaction(&transaction.0, cx);
15155                        }
15156                    }
15157                    cx.notify();
15158                })
15159                .ok();
15160            Ok(())
15161        })
15162    }
15163
15164    fn restart_language_server(
15165        &mut self,
15166        _: &RestartLanguageServer,
15167        _: &mut Window,
15168        cx: &mut Context<Self>,
15169    ) {
15170        if let Some(project) = self.project.clone() {
15171            self.buffer.update(cx, |multi_buffer, cx| {
15172                project.update(cx, |project, cx| {
15173                    project.restart_language_servers_for_buffers(
15174                        multi_buffer.all_buffers().into_iter().collect(),
15175                        cx,
15176                    );
15177                });
15178            })
15179        }
15180    }
15181
15182    fn stop_language_server(
15183        &mut self,
15184        _: &StopLanguageServer,
15185        _: &mut Window,
15186        cx: &mut Context<Self>,
15187    ) {
15188        if let Some(project) = self.project.clone() {
15189            self.buffer.update(cx, |multi_buffer, cx| {
15190                project.update(cx, |project, cx| {
15191                    project.stop_language_servers_for_buffers(
15192                        multi_buffer.all_buffers().into_iter().collect(),
15193                        cx,
15194                    );
15195                    cx.emit(project::Event::RefreshInlayHints);
15196                });
15197            });
15198        }
15199    }
15200
15201    fn cancel_language_server_work(
15202        workspace: &mut Workspace,
15203        _: &actions::CancelLanguageServerWork,
15204        _: &mut Window,
15205        cx: &mut Context<Workspace>,
15206    ) {
15207        let project = workspace.project();
15208        let buffers = workspace
15209            .active_item(cx)
15210            .and_then(|item| item.act_as::<Editor>(cx))
15211            .map_or(HashSet::default(), |editor| {
15212                editor.read(cx).buffer.read(cx).all_buffers()
15213            });
15214        project.update(cx, |project, cx| {
15215            project.cancel_language_server_work_for_buffers(buffers, cx);
15216        });
15217    }
15218
15219    fn show_character_palette(
15220        &mut self,
15221        _: &ShowCharacterPalette,
15222        window: &mut Window,
15223        _: &mut Context<Self>,
15224    ) {
15225        window.show_character_palette();
15226    }
15227
15228    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15229        if self.mode.is_minimap() {
15230            return;
15231        }
15232
15233        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15234            let buffer = self.buffer.read(cx).snapshot(cx);
15235            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15236            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15237            let is_valid = buffer
15238                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15239                .any(|entry| {
15240                    entry.diagnostic.is_primary
15241                        && !entry.range.is_empty()
15242                        && entry.range.start == primary_range_start
15243                        && entry.diagnostic.message == active_diagnostics.active_message
15244                });
15245
15246            if !is_valid {
15247                self.dismiss_diagnostics(cx);
15248            }
15249        }
15250    }
15251
15252    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15253        match &self.active_diagnostics {
15254            ActiveDiagnostic::Group(group) => Some(group),
15255            _ => None,
15256        }
15257    }
15258
15259    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15260        self.dismiss_diagnostics(cx);
15261        self.active_diagnostics = ActiveDiagnostic::All;
15262    }
15263
15264    fn activate_diagnostics(
15265        &mut self,
15266        buffer_id: BufferId,
15267        diagnostic: DiagnosticEntry<usize>,
15268        window: &mut Window,
15269        cx: &mut Context<Self>,
15270    ) {
15271        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15272            return;
15273        }
15274        self.dismiss_diagnostics(cx);
15275        let snapshot = self.snapshot(window, cx);
15276        let buffer = self.buffer.read(cx).snapshot(cx);
15277        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15278            return;
15279        };
15280
15281        let diagnostic_group = buffer
15282            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15283            .collect::<Vec<_>>();
15284
15285        let blocks =
15286            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15287
15288        let blocks = self.display_map.update(cx, |display_map, cx| {
15289            display_map.insert_blocks(blocks, cx).into_iter().collect()
15290        });
15291        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15292            active_range: buffer.anchor_before(diagnostic.range.start)
15293                ..buffer.anchor_after(diagnostic.range.end),
15294            active_message: diagnostic.diagnostic.message.clone(),
15295            group_id: diagnostic.diagnostic.group_id,
15296            blocks,
15297        });
15298        cx.notify();
15299    }
15300
15301    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15302        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15303            return;
15304        };
15305
15306        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15307        if let ActiveDiagnostic::Group(group) = prev {
15308            self.display_map.update(cx, |display_map, cx| {
15309                display_map.remove_blocks(group.blocks, cx);
15310            });
15311            cx.notify();
15312        }
15313    }
15314
15315    /// Disable inline diagnostics rendering for this editor.
15316    pub fn disable_inline_diagnostics(&mut self) {
15317        self.inline_diagnostics_enabled = false;
15318        self.inline_diagnostics_update = Task::ready(());
15319        self.inline_diagnostics.clear();
15320    }
15321
15322    pub fn diagnostics_enabled(&self) -> bool {
15323        self.mode.is_full()
15324    }
15325
15326    pub fn inline_diagnostics_enabled(&self) -> bool {
15327        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15328    }
15329
15330    pub fn show_inline_diagnostics(&self) -> bool {
15331        self.show_inline_diagnostics
15332    }
15333
15334    pub fn toggle_inline_diagnostics(
15335        &mut self,
15336        _: &ToggleInlineDiagnostics,
15337        window: &mut Window,
15338        cx: &mut Context<Editor>,
15339    ) {
15340        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15341        self.refresh_inline_diagnostics(false, window, cx);
15342    }
15343
15344    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15345        self.diagnostics_max_severity = severity;
15346        self.display_map.update(cx, |display_map, _| {
15347            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15348        });
15349    }
15350
15351    pub fn toggle_diagnostics(
15352        &mut self,
15353        _: &ToggleDiagnostics,
15354        window: &mut Window,
15355        cx: &mut Context<Editor>,
15356    ) {
15357        if !self.diagnostics_enabled() {
15358            return;
15359        }
15360
15361        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15362            EditorSettings::get_global(cx)
15363                .diagnostics_max_severity
15364                .filter(|severity| severity != &DiagnosticSeverity::Off)
15365                .unwrap_or(DiagnosticSeverity::Hint)
15366        } else {
15367            DiagnosticSeverity::Off
15368        };
15369        self.set_max_diagnostics_severity(new_severity, cx);
15370        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15371            self.active_diagnostics = ActiveDiagnostic::None;
15372            self.inline_diagnostics_update = Task::ready(());
15373            self.inline_diagnostics.clear();
15374        } else {
15375            self.refresh_inline_diagnostics(false, window, cx);
15376        }
15377
15378        cx.notify();
15379    }
15380
15381    pub fn toggle_minimap(
15382        &mut self,
15383        _: &ToggleMinimap,
15384        window: &mut Window,
15385        cx: &mut Context<Editor>,
15386    ) {
15387        if self.supports_minimap(cx) {
15388            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15389        }
15390    }
15391
15392    fn refresh_inline_diagnostics(
15393        &mut self,
15394        debounce: bool,
15395        window: &mut Window,
15396        cx: &mut Context<Self>,
15397    ) {
15398        let max_severity = ProjectSettings::get_global(cx)
15399            .diagnostics
15400            .inline
15401            .max_severity
15402            .unwrap_or(self.diagnostics_max_severity);
15403
15404        if self.mode.is_minimap()
15405            || !self.inline_diagnostics_enabled()
15406            || !self.show_inline_diagnostics
15407            || max_severity == DiagnosticSeverity::Off
15408        {
15409            self.inline_diagnostics_update = Task::ready(());
15410            self.inline_diagnostics.clear();
15411            return;
15412        }
15413
15414        let debounce_ms = ProjectSettings::get_global(cx)
15415            .diagnostics
15416            .inline
15417            .update_debounce_ms;
15418        let debounce = if debounce && debounce_ms > 0 {
15419            Some(Duration::from_millis(debounce_ms))
15420        } else {
15421            None
15422        };
15423        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15424            let editor = editor.upgrade().unwrap();
15425
15426            if let Some(debounce) = debounce {
15427                cx.background_executor().timer(debounce).await;
15428            }
15429            let Some(snapshot) = editor
15430                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15431                .ok()
15432            else {
15433                return;
15434            };
15435
15436            let new_inline_diagnostics = cx
15437                .background_spawn(async move {
15438                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15439                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15440                        let message = diagnostic_entry
15441                            .diagnostic
15442                            .message
15443                            .split_once('\n')
15444                            .map(|(line, _)| line)
15445                            .map(SharedString::new)
15446                            .unwrap_or_else(|| {
15447                                SharedString::from(diagnostic_entry.diagnostic.message)
15448                            });
15449                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15450                        let (Ok(i) | Err(i)) = inline_diagnostics
15451                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15452                        inline_diagnostics.insert(
15453                            i,
15454                            (
15455                                start_anchor,
15456                                InlineDiagnostic {
15457                                    message,
15458                                    group_id: diagnostic_entry.diagnostic.group_id,
15459                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15460                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15461                                    severity: diagnostic_entry.diagnostic.severity,
15462                                },
15463                            ),
15464                        );
15465                    }
15466                    inline_diagnostics
15467                })
15468                .await;
15469
15470            editor
15471                .update(cx, |editor, cx| {
15472                    editor.inline_diagnostics = new_inline_diagnostics;
15473                    cx.notify();
15474                })
15475                .ok();
15476        });
15477    }
15478
15479    pub fn set_selections_from_remote(
15480        &mut self,
15481        selections: Vec<Selection<Anchor>>,
15482        pending_selection: Option<Selection<Anchor>>,
15483        window: &mut Window,
15484        cx: &mut Context<Self>,
15485    ) {
15486        let old_cursor_position = self.selections.newest_anchor().head();
15487        self.selections.change_with(cx, |s| {
15488            s.select_anchors(selections);
15489            if let Some(pending_selection) = pending_selection {
15490                s.set_pending(pending_selection, SelectMode::Character);
15491            } else {
15492                s.clear_pending();
15493            }
15494        });
15495        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15496    }
15497
15498    fn push_to_selection_history(&mut self) {
15499        self.selection_history.push(SelectionHistoryEntry {
15500            selections: self.selections.disjoint_anchors(),
15501            select_next_state: self.select_next_state.clone(),
15502            select_prev_state: self.select_prev_state.clone(),
15503            add_selections_state: self.add_selections_state.clone(),
15504        });
15505    }
15506
15507    pub fn transact(
15508        &mut self,
15509        window: &mut Window,
15510        cx: &mut Context<Self>,
15511        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15512    ) -> Option<TransactionId> {
15513        self.start_transaction_at(Instant::now(), window, cx);
15514        update(self, window, cx);
15515        self.end_transaction_at(Instant::now(), cx)
15516    }
15517
15518    pub fn start_transaction_at(
15519        &mut self,
15520        now: Instant,
15521        window: &mut Window,
15522        cx: &mut Context<Self>,
15523    ) {
15524        self.end_selection(window, cx);
15525        if let Some(tx_id) = self
15526            .buffer
15527            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15528        {
15529            self.selection_history
15530                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15531            cx.emit(EditorEvent::TransactionBegun {
15532                transaction_id: tx_id,
15533            })
15534        }
15535    }
15536
15537    pub fn end_transaction_at(
15538        &mut self,
15539        now: Instant,
15540        cx: &mut Context<Self>,
15541    ) -> Option<TransactionId> {
15542        if let Some(transaction_id) = self
15543            .buffer
15544            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15545        {
15546            if let Some((_, end_selections)) =
15547                self.selection_history.transaction_mut(transaction_id)
15548            {
15549                *end_selections = Some(self.selections.disjoint_anchors());
15550            } else {
15551                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15552            }
15553
15554            cx.emit(EditorEvent::Edited { transaction_id });
15555            Some(transaction_id)
15556        } else {
15557            None
15558        }
15559    }
15560
15561    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15562        if self.selection_mark_mode {
15563            self.change_selections(None, window, cx, |s| {
15564                s.move_with(|_, sel| {
15565                    sel.collapse_to(sel.head(), SelectionGoal::None);
15566                });
15567            })
15568        }
15569        self.selection_mark_mode = true;
15570        cx.notify();
15571    }
15572
15573    pub fn swap_selection_ends(
15574        &mut self,
15575        _: &actions::SwapSelectionEnds,
15576        window: &mut Window,
15577        cx: &mut Context<Self>,
15578    ) {
15579        self.change_selections(None, window, cx, |s| {
15580            s.move_with(|_, sel| {
15581                if sel.start != sel.end {
15582                    sel.reversed = !sel.reversed
15583                }
15584            });
15585        });
15586        self.request_autoscroll(Autoscroll::newest(), cx);
15587        cx.notify();
15588    }
15589
15590    pub fn toggle_fold(
15591        &mut self,
15592        _: &actions::ToggleFold,
15593        window: &mut Window,
15594        cx: &mut Context<Self>,
15595    ) {
15596        if self.is_singleton(cx) {
15597            let selection = self.selections.newest::<Point>(cx);
15598
15599            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15600            let range = if selection.is_empty() {
15601                let point = selection.head().to_display_point(&display_map);
15602                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15603                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15604                    .to_point(&display_map);
15605                start..end
15606            } else {
15607                selection.range()
15608            };
15609            if display_map.folds_in_range(range).next().is_some() {
15610                self.unfold_lines(&Default::default(), window, cx)
15611            } else {
15612                self.fold(&Default::default(), window, cx)
15613            }
15614        } else {
15615            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15616            let buffer_ids: HashSet<_> = self
15617                .selections
15618                .disjoint_anchor_ranges()
15619                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15620                .collect();
15621
15622            let should_unfold = buffer_ids
15623                .iter()
15624                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15625
15626            for buffer_id in buffer_ids {
15627                if should_unfold {
15628                    self.unfold_buffer(buffer_id, cx);
15629                } else {
15630                    self.fold_buffer(buffer_id, cx);
15631                }
15632            }
15633        }
15634    }
15635
15636    pub fn toggle_fold_recursive(
15637        &mut self,
15638        _: &actions::ToggleFoldRecursive,
15639        window: &mut Window,
15640        cx: &mut Context<Self>,
15641    ) {
15642        let selection = self.selections.newest::<Point>(cx);
15643
15644        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15645        let range = if selection.is_empty() {
15646            let point = selection.head().to_display_point(&display_map);
15647            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15648            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15649                .to_point(&display_map);
15650            start..end
15651        } else {
15652            selection.range()
15653        };
15654        if display_map.folds_in_range(range).next().is_some() {
15655            self.unfold_recursive(&Default::default(), window, cx)
15656        } else {
15657            self.fold_recursive(&Default::default(), window, cx)
15658        }
15659    }
15660
15661    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15662        if self.is_singleton(cx) {
15663            let mut to_fold = Vec::new();
15664            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15665            let selections = self.selections.all_adjusted(cx);
15666
15667            for selection in selections {
15668                let range = selection.range().sorted();
15669                let buffer_start_row = range.start.row;
15670
15671                if range.start.row != range.end.row {
15672                    let mut found = false;
15673                    let mut row = range.start.row;
15674                    while row <= range.end.row {
15675                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15676                        {
15677                            found = true;
15678                            row = crease.range().end.row + 1;
15679                            to_fold.push(crease);
15680                        } else {
15681                            row += 1
15682                        }
15683                    }
15684                    if found {
15685                        continue;
15686                    }
15687                }
15688
15689                for row in (0..=range.start.row).rev() {
15690                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15691                        if crease.range().end.row >= buffer_start_row {
15692                            to_fold.push(crease);
15693                            if row <= range.start.row {
15694                                break;
15695                            }
15696                        }
15697                    }
15698                }
15699            }
15700
15701            self.fold_creases(to_fold, true, window, cx);
15702        } else {
15703            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15704            let buffer_ids = self
15705                .selections
15706                .disjoint_anchor_ranges()
15707                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15708                .collect::<HashSet<_>>();
15709            for buffer_id in buffer_ids {
15710                self.fold_buffer(buffer_id, cx);
15711            }
15712        }
15713    }
15714
15715    fn fold_at_level(
15716        &mut self,
15717        fold_at: &FoldAtLevel,
15718        window: &mut Window,
15719        cx: &mut Context<Self>,
15720    ) {
15721        if !self.buffer.read(cx).is_singleton() {
15722            return;
15723        }
15724
15725        let fold_at_level = fold_at.0;
15726        let snapshot = self.buffer.read(cx).snapshot(cx);
15727        let mut to_fold = Vec::new();
15728        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15729
15730        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15731            while start_row < end_row {
15732                match self
15733                    .snapshot(window, cx)
15734                    .crease_for_buffer_row(MultiBufferRow(start_row))
15735                {
15736                    Some(crease) => {
15737                        let nested_start_row = crease.range().start.row + 1;
15738                        let nested_end_row = crease.range().end.row;
15739
15740                        if current_level < fold_at_level {
15741                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15742                        } else if current_level == fold_at_level {
15743                            to_fold.push(crease);
15744                        }
15745
15746                        start_row = nested_end_row + 1;
15747                    }
15748                    None => start_row += 1,
15749                }
15750            }
15751        }
15752
15753        self.fold_creases(to_fold, true, window, cx);
15754    }
15755
15756    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15757        if self.buffer.read(cx).is_singleton() {
15758            let mut fold_ranges = Vec::new();
15759            let snapshot = self.buffer.read(cx).snapshot(cx);
15760
15761            for row in 0..snapshot.max_row().0 {
15762                if let Some(foldable_range) = self
15763                    .snapshot(window, cx)
15764                    .crease_for_buffer_row(MultiBufferRow(row))
15765                {
15766                    fold_ranges.push(foldable_range);
15767                }
15768            }
15769
15770            self.fold_creases(fold_ranges, true, window, cx);
15771        } else {
15772            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15773                editor
15774                    .update_in(cx, |editor, _, cx| {
15775                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15776                            editor.fold_buffer(buffer_id, cx);
15777                        }
15778                    })
15779                    .ok();
15780            });
15781        }
15782    }
15783
15784    pub fn fold_function_bodies(
15785        &mut self,
15786        _: &actions::FoldFunctionBodies,
15787        window: &mut Window,
15788        cx: &mut Context<Self>,
15789    ) {
15790        let snapshot = self.buffer.read(cx).snapshot(cx);
15791
15792        let ranges = snapshot
15793            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15794            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15795            .collect::<Vec<_>>();
15796
15797        let creases = ranges
15798            .into_iter()
15799            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15800            .collect();
15801
15802        self.fold_creases(creases, true, window, cx);
15803    }
15804
15805    pub fn fold_recursive(
15806        &mut self,
15807        _: &actions::FoldRecursive,
15808        window: &mut Window,
15809        cx: &mut Context<Self>,
15810    ) {
15811        let mut to_fold = Vec::new();
15812        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15813        let selections = self.selections.all_adjusted(cx);
15814
15815        for selection in selections {
15816            let range = selection.range().sorted();
15817            let buffer_start_row = range.start.row;
15818
15819            if range.start.row != range.end.row {
15820                let mut found = false;
15821                for row in range.start.row..=range.end.row {
15822                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15823                        found = true;
15824                        to_fold.push(crease);
15825                    }
15826                }
15827                if found {
15828                    continue;
15829                }
15830            }
15831
15832            for row in (0..=range.start.row).rev() {
15833                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15834                    if crease.range().end.row >= buffer_start_row {
15835                        to_fold.push(crease);
15836                    } else {
15837                        break;
15838                    }
15839                }
15840            }
15841        }
15842
15843        self.fold_creases(to_fold, true, window, cx);
15844    }
15845
15846    pub fn fold_at(
15847        &mut self,
15848        buffer_row: MultiBufferRow,
15849        window: &mut Window,
15850        cx: &mut Context<Self>,
15851    ) {
15852        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15853
15854        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15855            let autoscroll = self
15856                .selections
15857                .all::<Point>(cx)
15858                .iter()
15859                .any(|selection| crease.range().overlaps(&selection.range()));
15860
15861            self.fold_creases(vec![crease], autoscroll, window, cx);
15862        }
15863    }
15864
15865    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15866        if self.is_singleton(cx) {
15867            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15868            let buffer = &display_map.buffer_snapshot;
15869            let selections = self.selections.all::<Point>(cx);
15870            let ranges = selections
15871                .iter()
15872                .map(|s| {
15873                    let range = s.display_range(&display_map).sorted();
15874                    let mut start = range.start.to_point(&display_map);
15875                    let mut end = range.end.to_point(&display_map);
15876                    start.column = 0;
15877                    end.column = buffer.line_len(MultiBufferRow(end.row));
15878                    start..end
15879                })
15880                .collect::<Vec<_>>();
15881
15882            self.unfold_ranges(&ranges, true, true, cx);
15883        } else {
15884            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15885            let buffer_ids = self
15886                .selections
15887                .disjoint_anchor_ranges()
15888                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15889                .collect::<HashSet<_>>();
15890            for buffer_id in buffer_ids {
15891                self.unfold_buffer(buffer_id, cx);
15892            }
15893        }
15894    }
15895
15896    pub fn unfold_recursive(
15897        &mut self,
15898        _: &UnfoldRecursive,
15899        _window: &mut Window,
15900        cx: &mut Context<Self>,
15901    ) {
15902        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15903        let selections = self.selections.all::<Point>(cx);
15904        let ranges = selections
15905            .iter()
15906            .map(|s| {
15907                let mut range = s.display_range(&display_map).sorted();
15908                *range.start.column_mut() = 0;
15909                *range.end.column_mut() = display_map.line_len(range.end.row());
15910                let start = range.start.to_point(&display_map);
15911                let end = range.end.to_point(&display_map);
15912                start..end
15913            })
15914            .collect::<Vec<_>>();
15915
15916        self.unfold_ranges(&ranges, true, true, cx);
15917    }
15918
15919    pub fn unfold_at(
15920        &mut self,
15921        buffer_row: MultiBufferRow,
15922        _window: &mut Window,
15923        cx: &mut Context<Self>,
15924    ) {
15925        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15926
15927        let intersection_range = Point::new(buffer_row.0, 0)
15928            ..Point::new(
15929                buffer_row.0,
15930                display_map.buffer_snapshot.line_len(buffer_row),
15931            );
15932
15933        let autoscroll = self
15934            .selections
15935            .all::<Point>(cx)
15936            .iter()
15937            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15938
15939        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15940    }
15941
15942    pub fn unfold_all(
15943        &mut self,
15944        _: &actions::UnfoldAll,
15945        _window: &mut Window,
15946        cx: &mut Context<Self>,
15947    ) {
15948        if self.buffer.read(cx).is_singleton() {
15949            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15950            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15951        } else {
15952            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15953                editor
15954                    .update(cx, |editor, cx| {
15955                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15956                            editor.unfold_buffer(buffer_id, cx);
15957                        }
15958                    })
15959                    .ok();
15960            });
15961        }
15962    }
15963
15964    pub fn fold_selected_ranges(
15965        &mut self,
15966        _: &FoldSelectedRanges,
15967        window: &mut Window,
15968        cx: &mut Context<Self>,
15969    ) {
15970        let selections = self.selections.all_adjusted(cx);
15971        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15972        let ranges = selections
15973            .into_iter()
15974            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15975            .collect::<Vec<_>>();
15976        self.fold_creases(ranges, true, window, cx);
15977    }
15978
15979    pub fn fold_ranges<T: ToOffset + Clone>(
15980        &mut self,
15981        ranges: Vec<Range<T>>,
15982        auto_scroll: bool,
15983        window: &mut Window,
15984        cx: &mut Context<Self>,
15985    ) {
15986        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15987        let ranges = ranges
15988            .into_iter()
15989            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
15990            .collect::<Vec<_>>();
15991        self.fold_creases(ranges, auto_scroll, window, cx);
15992    }
15993
15994    pub fn fold_creases<T: ToOffset + Clone>(
15995        &mut self,
15996        creases: Vec<Crease<T>>,
15997        auto_scroll: bool,
15998        _window: &mut Window,
15999        cx: &mut Context<Self>,
16000    ) {
16001        if creases.is_empty() {
16002            return;
16003        }
16004
16005        let mut buffers_affected = HashSet::default();
16006        let multi_buffer = self.buffer().read(cx);
16007        for crease in &creases {
16008            if let Some((_, buffer, _)) =
16009                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16010            {
16011                buffers_affected.insert(buffer.read(cx).remote_id());
16012            };
16013        }
16014
16015        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16016
16017        if auto_scroll {
16018            self.request_autoscroll(Autoscroll::fit(), cx);
16019        }
16020
16021        cx.notify();
16022
16023        self.scrollbar_marker_state.dirty = true;
16024        self.folds_did_change(cx);
16025    }
16026
16027    /// Removes any folds whose ranges intersect any of the given ranges.
16028    pub fn unfold_ranges<T: ToOffset + Clone>(
16029        &mut self,
16030        ranges: &[Range<T>],
16031        inclusive: bool,
16032        auto_scroll: bool,
16033        cx: &mut Context<Self>,
16034    ) {
16035        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16036            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16037        });
16038        self.folds_did_change(cx);
16039    }
16040
16041    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16042        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16043            return;
16044        }
16045        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16046        self.display_map.update(cx, |display_map, cx| {
16047            display_map.fold_buffers([buffer_id], cx)
16048        });
16049        cx.emit(EditorEvent::BufferFoldToggled {
16050            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16051            folded: true,
16052        });
16053        cx.notify();
16054    }
16055
16056    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16057        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16058            return;
16059        }
16060        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16061        self.display_map.update(cx, |display_map, cx| {
16062            display_map.unfold_buffers([buffer_id], cx);
16063        });
16064        cx.emit(EditorEvent::BufferFoldToggled {
16065            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16066            folded: false,
16067        });
16068        cx.notify();
16069    }
16070
16071    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16072        self.display_map.read(cx).is_buffer_folded(buffer)
16073    }
16074
16075    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16076        self.display_map.read(cx).folded_buffers()
16077    }
16078
16079    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16080        self.display_map.update(cx, |display_map, cx| {
16081            display_map.disable_header_for_buffer(buffer_id, cx);
16082        });
16083        cx.notify();
16084    }
16085
16086    /// Removes any folds with the given ranges.
16087    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16088        &mut self,
16089        ranges: &[Range<T>],
16090        type_id: TypeId,
16091        auto_scroll: bool,
16092        cx: &mut Context<Self>,
16093    ) {
16094        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16095            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16096        });
16097        self.folds_did_change(cx);
16098    }
16099
16100    fn remove_folds_with<T: ToOffset + Clone>(
16101        &mut self,
16102        ranges: &[Range<T>],
16103        auto_scroll: bool,
16104        cx: &mut Context<Self>,
16105        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16106    ) {
16107        if ranges.is_empty() {
16108            return;
16109        }
16110
16111        let mut buffers_affected = HashSet::default();
16112        let multi_buffer = self.buffer().read(cx);
16113        for range in ranges {
16114            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16115                buffers_affected.insert(buffer.read(cx).remote_id());
16116            };
16117        }
16118
16119        self.display_map.update(cx, update);
16120
16121        if auto_scroll {
16122            self.request_autoscroll(Autoscroll::fit(), cx);
16123        }
16124
16125        cx.notify();
16126        self.scrollbar_marker_state.dirty = true;
16127        self.active_indent_guides_state.dirty = true;
16128    }
16129
16130    pub fn update_fold_widths(
16131        &mut self,
16132        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16133        cx: &mut Context<Self>,
16134    ) -> bool {
16135        self.display_map
16136            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16137    }
16138
16139    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16140        self.display_map.read(cx).fold_placeholder.clone()
16141    }
16142
16143    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16144        self.buffer.update(cx, |buffer, cx| {
16145            buffer.set_all_diff_hunks_expanded(cx);
16146        });
16147    }
16148
16149    pub fn expand_all_diff_hunks(
16150        &mut self,
16151        _: &ExpandAllDiffHunks,
16152        _window: &mut Window,
16153        cx: &mut Context<Self>,
16154    ) {
16155        self.buffer.update(cx, |buffer, cx| {
16156            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16157        });
16158    }
16159
16160    pub fn toggle_selected_diff_hunks(
16161        &mut self,
16162        _: &ToggleSelectedDiffHunks,
16163        _window: &mut Window,
16164        cx: &mut Context<Self>,
16165    ) {
16166        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16167        self.toggle_diff_hunks_in_ranges(ranges, cx);
16168    }
16169
16170    pub fn diff_hunks_in_ranges<'a>(
16171        &'a self,
16172        ranges: &'a [Range<Anchor>],
16173        buffer: &'a MultiBufferSnapshot,
16174    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16175        ranges.iter().flat_map(move |range| {
16176            let end_excerpt_id = range.end.excerpt_id;
16177            let range = range.to_point(buffer);
16178            let mut peek_end = range.end;
16179            if range.end.row < buffer.max_row().0 {
16180                peek_end = Point::new(range.end.row + 1, 0);
16181            }
16182            buffer
16183                .diff_hunks_in_range(range.start..peek_end)
16184                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16185        })
16186    }
16187
16188    pub fn has_stageable_diff_hunks_in_ranges(
16189        &self,
16190        ranges: &[Range<Anchor>],
16191        snapshot: &MultiBufferSnapshot,
16192    ) -> bool {
16193        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16194        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16195    }
16196
16197    pub fn toggle_staged_selected_diff_hunks(
16198        &mut self,
16199        _: &::git::ToggleStaged,
16200        _: &mut Window,
16201        cx: &mut Context<Self>,
16202    ) {
16203        let snapshot = self.buffer.read(cx).snapshot(cx);
16204        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16205        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16206        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16207    }
16208
16209    pub fn set_render_diff_hunk_controls(
16210        &mut self,
16211        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16212        cx: &mut Context<Self>,
16213    ) {
16214        self.render_diff_hunk_controls = render_diff_hunk_controls;
16215        cx.notify();
16216    }
16217
16218    pub fn stage_and_next(
16219        &mut self,
16220        _: &::git::StageAndNext,
16221        window: &mut Window,
16222        cx: &mut Context<Self>,
16223    ) {
16224        self.do_stage_or_unstage_and_next(true, window, cx);
16225    }
16226
16227    pub fn unstage_and_next(
16228        &mut self,
16229        _: &::git::UnstageAndNext,
16230        window: &mut Window,
16231        cx: &mut Context<Self>,
16232    ) {
16233        self.do_stage_or_unstage_and_next(false, window, cx);
16234    }
16235
16236    pub fn stage_or_unstage_diff_hunks(
16237        &mut self,
16238        stage: bool,
16239        ranges: Vec<Range<Anchor>>,
16240        cx: &mut Context<Self>,
16241    ) {
16242        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16243        cx.spawn(async move |this, cx| {
16244            task.await?;
16245            this.update(cx, |this, cx| {
16246                let snapshot = this.buffer.read(cx).snapshot(cx);
16247                let chunk_by = this
16248                    .diff_hunks_in_ranges(&ranges, &snapshot)
16249                    .chunk_by(|hunk| hunk.buffer_id);
16250                for (buffer_id, hunks) in &chunk_by {
16251                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16252                }
16253            })
16254        })
16255        .detach_and_log_err(cx);
16256    }
16257
16258    fn save_buffers_for_ranges_if_needed(
16259        &mut self,
16260        ranges: &[Range<Anchor>],
16261        cx: &mut Context<Editor>,
16262    ) -> Task<Result<()>> {
16263        let multibuffer = self.buffer.read(cx);
16264        let snapshot = multibuffer.read(cx);
16265        let buffer_ids: HashSet<_> = ranges
16266            .iter()
16267            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16268            .collect();
16269        drop(snapshot);
16270
16271        let mut buffers = HashSet::default();
16272        for buffer_id in buffer_ids {
16273            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16274                let buffer = buffer_entity.read(cx);
16275                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16276                {
16277                    buffers.insert(buffer_entity);
16278                }
16279            }
16280        }
16281
16282        if let Some(project) = &self.project {
16283            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16284        } else {
16285            Task::ready(Ok(()))
16286        }
16287    }
16288
16289    fn do_stage_or_unstage_and_next(
16290        &mut self,
16291        stage: bool,
16292        window: &mut Window,
16293        cx: &mut Context<Self>,
16294    ) {
16295        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16296
16297        if ranges.iter().any(|range| range.start != range.end) {
16298            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16299            return;
16300        }
16301
16302        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16303        let snapshot = self.snapshot(window, cx);
16304        let position = self.selections.newest::<Point>(cx).head();
16305        let mut row = snapshot
16306            .buffer_snapshot
16307            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16308            .find(|hunk| hunk.row_range.start.0 > position.row)
16309            .map(|hunk| hunk.row_range.start);
16310
16311        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16312        // Outside of the project diff editor, wrap around to the beginning.
16313        if !all_diff_hunks_expanded {
16314            row = row.or_else(|| {
16315                snapshot
16316                    .buffer_snapshot
16317                    .diff_hunks_in_range(Point::zero()..position)
16318                    .find(|hunk| hunk.row_range.end.0 < position.row)
16319                    .map(|hunk| hunk.row_range.start)
16320            });
16321        }
16322
16323        if let Some(row) = row {
16324            let destination = Point::new(row.0, 0);
16325            let autoscroll = Autoscroll::center();
16326
16327            self.unfold_ranges(&[destination..destination], false, false, cx);
16328            self.change_selections(Some(autoscroll), window, cx, |s| {
16329                s.select_ranges([destination..destination]);
16330            });
16331        }
16332    }
16333
16334    fn do_stage_or_unstage(
16335        &self,
16336        stage: bool,
16337        buffer_id: BufferId,
16338        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16339        cx: &mut App,
16340    ) -> Option<()> {
16341        let project = self.project.as_ref()?;
16342        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16343        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16344        let buffer_snapshot = buffer.read(cx).snapshot();
16345        let file_exists = buffer_snapshot
16346            .file()
16347            .is_some_and(|file| file.disk_state().exists());
16348        diff.update(cx, |diff, cx| {
16349            diff.stage_or_unstage_hunks(
16350                stage,
16351                &hunks
16352                    .map(|hunk| buffer_diff::DiffHunk {
16353                        buffer_range: hunk.buffer_range,
16354                        diff_base_byte_range: hunk.diff_base_byte_range,
16355                        secondary_status: hunk.secondary_status,
16356                        range: Point::zero()..Point::zero(), // unused
16357                    })
16358                    .collect::<Vec<_>>(),
16359                &buffer_snapshot,
16360                file_exists,
16361                cx,
16362            )
16363        });
16364        None
16365    }
16366
16367    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16368        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16369        self.buffer
16370            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16371    }
16372
16373    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16374        self.buffer.update(cx, |buffer, cx| {
16375            let ranges = vec![Anchor::min()..Anchor::max()];
16376            if !buffer.all_diff_hunks_expanded()
16377                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16378            {
16379                buffer.collapse_diff_hunks(ranges, cx);
16380                true
16381            } else {
16382                false
16383            }
16384        })
16385    }
16386
16387    fn toggle_diff_hunks_in_ranges(
16388        &mut self,
16389        ranges: Vec<Range<Anchor>>,
16390        cx: &mut Context<Editor>,
16391    ) {
16392        self.buffer.update(cx, |buffer, cx| {
16393            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16394            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16395        })
16396    }
16397
16398    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16399        self.buffer.update(cx, |buffer, cx| {
16400            let snapshot = buffer.snapshot(cx);
16401            let excerpt_id = range.end.excerpt_id;
16402            let point_range = range.to_point(&snapshot);
16403            let expand = !buffer.single_hunk_is_expanded(range, cx);
16404            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16405        })
16406    }
16407
16408    pub(crate) fn apply_all_diff_hunks(
16409        &mut self,
16410        _: &ApplyAllDiffHunks,
16411        window: &mut Window,
16412        cx: &mut Context<Self>,
16413    ) {
16414        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16415
16416        let buffers = self.buffer.read(cx).all_buffers();
16417        for branch_buffer in buffers {
16418            branch_buffer.update(cx, |branch_buffer, cx| {
16419                branch_buffer.merge_into_base(Vec::new(), cx);
16420            });
16421        }
16422
16423        if let Some(project) = self.project.clone() {
16424            self.save(true, project, window, cx).detach_and_log_err(cx);
16425        }
16426    }
16427
16428    pub(crate) fn apply_selected_diff_hunks(
16429        &mut self,
16430        _: &ApplyDiffHunk,
16431        window: &mut Window,
16432        cx: &mut Context<Self>,
16433    ) {
16434        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16435        let snapshot = self.snapshot(window, cx);
16436        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16437        let mut ranges_by_buffer = HashMap::default();
16438        self.transact(window, cx, |editor, _window, cx| {
16439            for hunk in hunks {
16440                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16441                    ranges_by_buffer
16442                        .entry(buffer.clone())
16443                        .or_insert_with(Vec::new)
16444                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16445                }
16446            }
16447
16448            for (buffer, ranges) in ranges_by_buffer {
16449                buffer.update(cx, |buffer, cx| {
16450                    buffer.merge_into_base(ranges, cx);
16451                });
16452            }
16453        });
16454
16455        if let Some(project) = self.project.clone() {
16456            self.save(true, project, window, cx).detach_and_log_err(cx);
16457        }
16458    }
16459
16460    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16461        if hovered != self.gutter_hovered {
16462            self.gutter_hovered = hovered;
16463            cx.notify();
16464        }
16465    }
16466
16467    pub fn insert_blocks(
16468        &mut self,
16469        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16470        autoscroll: Option<Autoscroll>,
16471        cx: &mut Context<Self>,
16472    ) -> Vec<CustomBlockId> {
16473        let blocks = self
16474            .display_map
16475            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16476        if let Some(autoscroll) = autoscroll {
16477            self.request_autoscroll(autoscroll, cx);
16478        }
16479        cx.notify();
16480        blocks
16481    }
16482
16483    pub fn resize_blocks(
16484        &mut self,
16485        heights: HashMap<CustomBlockId, u32>,
16486        autoscroll: Option<Autoscroll>,
16487        cx: &mut Context<Self>,
16488    ) {
16489        self.display_map
16490            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16491        if let Some(autoscroll) = autoscroll {
16492            self.request_autoscroll(autoscroll, cx);
16493        }
16494        cx.notify();
16495    }
16496
16497    pub fn replace_blocks(
16498        &mut self,
16499        renderers: HashMap<CustomBlockId, RenderBlock>,
16500        autoscroll: Option<Autoscroll>,
16501        cx: &mut Context<Self>,
16502    ) {
16503        self.display_map
16504            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16505        if let Some(autoscroll) = autoscroll {
16506            self.request_autoscroll(autoscroll, cx);
16507        }
16508        cx.notify();
16509    }
16510
16511    pub fn remove_blocks(
16512        &mut self,
16513        block_ids: HashSet<CustomBlockId>,
16514        autoscroll: Option<Autoscroll>,
16515        cx: &mut Context<Self>,
16516    ) {
16517        self.display_map.update(cx, |display_map, cx| {
16518            display_map.remove_blocks(block_ids, cx)
16519        });
16520        if let Some(autoscroll) = autoscroll {
16521            self.request_autoscroll(autoscroll, cx);
16522        }
16523        cx.notify();
16524    }
16525
16526    pub fn row_for_block(
16527        &self,
16528        block_id: CustomBlockId,
16529        cx: &mut Context<Self>,
16530    ) -> Option<DisplayRow> {
16531        self.display_map
16532            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16533    }
16534
16535    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16536        self.focused_block = Some(focused_block);
16537    }
16538
16539    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16540        self.focused_block.take()
16541    }
16542
16543    pub fn insert_creases(
16544        &mut self,
16545        creases: impl IntoIterator<Item = Crease<Anchor>>,
16546        cx: &mut Context<Self>,
16547    ) -> Vec<CreaseId> {
16548        self.display_map
16549            .update(cx, |map, cx| map.insert_creases(creases, cx))
16550    }
16551
16552    pub fn remove_creases(
16553        &mut self,
16554        ids: impl IntoIterator<Item = CreaseId>,
16555        cx: &mut Context<Self>,
16556    ) -> Vec<(CreaseId, Range<Anchor>)> {
16557        self.display_map
16558            .update(cx, |map, cx| map.remove_creases(ids, cx))
16559    }
16560
16561    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16562        self.display_map
16563            .update(cx, |map, cx| map.snapshot(cx))
16564            .longest_row()
16565    }
16566
16567    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16568        self.display_map
16569            .update(cx, |map, cx| map.snapshot(cx))
16570            .max_point()
16571    }
16572
16573    pub fn text(&self, cx: &App) -> String {
16574        self.buffer.read(cx).read(cx).text()
16575    }
16576
16577    pub fn is_empty(&self, cx: &App) -> bool {
16578        self.buffer.read(cx).read(cx).is_empty()
16579    }
16580
16581    pub fn text_option(&self, cx: &App) -> Option<String> {
16582        let text = self.text(cx);
16583        let text = text.trim();
16584
16585        if text.is_empty() {
16586            return None;
16587        }
16588
16589        Some(text.to_string())
16590    }
16591
16592    pub fn set_text(
16593        &mut self,
16594        text: impl Into<Arc<str>>,
16595        window: &mut Window,
16596        cx: &mut Context<Self>,
16597    ) {
16598        self.transact(window, cx, |this, _, cx| {
16599            this.buffer
16600                .read(cx)
16601                .as_singleton()
16602                .expect("you can only call set_text on editors for singleton buffers")
16603                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16604        });
16605    }
16606
16607    pub fn display_text(&self, cx: &mut App) -> String {
16608        self.display_map
16609            .update(cx, |map, cx| map.snapshot(cx))
16610            .text()
16611    }
16612
16613    fn create_minimap(
16614        &self,
16615        minimap_settings: MinimapSettings,
16616        window: &mut Window,
16617        cx: &mut Context<Self>,
16618    ) -> Option<Entity<Self>> {
16619        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16620            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16621    }
16622
16623    fn initialize_new_minimap(
16624        &self,
16625        minimap_settings: MinimapSettings,
16626        window: &mut Window,
16627        cx: &mut Context<Self>,
16628    ) -> Entity<Self> {
16629        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16630
16631        let mut minimap = Editor::new_internal(
16632            EditorMode::Minimap {
16633                parent: cx.weak_entity(),
16634            },
16635            self.buffer.clone(),
16636            self.project.clone(),
16637            Some(self.display_map.clone()),
16638            window,
16639            cx,
16640        );
16641        minimap.scroll_manager.clone_state(&self.scroll_manager);
16642        minimap.set_text_style_refinement(TextStyleRefinement {
16643            font_size: Some(MINIMAP_FONT_SIZE),
16644            font_weight: Some(MINIMAP_FONT_WEIGHT),
16645            ..Default::default()
16646        });
16647        minimap.update_minimap_configuration(minimap_settings, cx);
16648        cx.new(|_| minimap)
16649    }
16650
16651    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16652        let current_line_highlight = minimap_settings
16653            .current_line_highlight
16654            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16655        self.set_current_line_highlight(Some(current_line_highlight));
16656    }
16657
16658    pub fn minimap(&self) -> Option<&Entity<Self>> {
16659        self.minimap
16660            .as_ref()
16661            .filter(|_| self.minimap_visibility.visible())
16662    }
16663
16664    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16665        let mut wrap_guides = smallvec::smallvec![];
16666
16667        if self.show_wrap_guides == Some(false) {
16668            return wrap_guides;
16669        }
16670
16671        let settings = self.buffer.read(cx).language_settings(cx);
16672        if settings.show_wrap_guides {
16673            match self.soft_wrap_mode(cx) {
16674                SoftWrap::Column(soft_wrap) => {
16675                    wrap_guides.push((soft_wrap as usize, true));
16676                }
16677                SoftWrap::Bounded(soft_wrap) => {
16678                    wrap_guides.push((soft_wrap as usize, true));
16679                }
16680                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16681            }
16682            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16683        }
16684
16685        wrap_guides
16686    }
16687
16688    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16689        let settings = self.buffer.read(cx).language_settings(cx);
16690        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16691        match mode {
16692            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16693                SoftWrap::None
16694            }
16695            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16696            language_settings::SoftWrap::PreferredLineLength => {
16697                SoftWrap::Column(settings.preferred_line_length)
16698            }
16699            language_settings::SoftWrap::Bounded => {
16700                SoftWrap::Bounded(settings.preferred_line_length)
16701            }
16702        }
16703    }
16704
16705    pub fn set_soft_wrap_mode(
16706        &mut self,
16707        mode: language_settings::SoftWrap,
16708
16709        cx: &mut Context<Self>,
16710    ) {
16711        self.soft_wrap_mode_override = Some(mode);
16712        cx.notify();
16713    }
16714
16715    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16716        self.hard_wrap = hard_wrap;
16717        cx.notify();
16718    }
16719
16720    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16721        self.text_style_refinement = Some(style);
16722    }
16723
16724    /// called by the Element so we know what style we were most recently rendered with.
16725    pub(crate) fn set_style(
16726        &mut self,
16727        style: EditorStyle,
16728        window: &mut Window,
16729        cx: &mut Context<Self>,
16730    ) {
16731        // We intentionally do not inform the display map about the minimap style
16732        // so that wrapping is not recalculated and stays consistent for the editor
16733        // and its linked minimap.
16734        if !self.mode.is_minimap() {
16735            let rem_size = window.rem_size();
16736            self.display_map.update(cx, |map, cx| {
16737                map.set_font(
16738                    style.text.font(),
16739                    style.text.font_size.to_pixels(rem_size),
16740                    cx,
16741                )
16742            });
16743        }
16744        self.style = Some(style);
16745    }
16746
16747    pub fn style(&self) -> Option<&EditorStyle> {
16748        self.style.as_ref()
16749    }
16750
16751    // Called by the element. This method is not designed to be called outside of the editor
16752    // element's layout code because it does not notify when rewrapping is computed synchronously.
16753    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16754        self.display_map
16755            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16756    }
16757
16758    pub fn set_soft_wrap(&mut self) {
16759        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16760    }
16761
16762    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16763        if self.soft_wrap_mode_override.is_some() {
16764            self.soft_wrap_mode_override.take();
16765        } else {
16766            let soft_wrap = match self.soft_wrap_mode(cx) {
16767                SoftWrap::GitDiff => return,
16768                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16769                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16770                    language_settings::SoftWrap::None
16771                }
16772            };
16773            self.soft_wrap_mode_override = Some(soft_wrap);
16774        }
16775        cx.notify();
16776    }
16777
16778    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16779        let Some(workspace) = self.workspace() else {
16780            return;
16781        };
16782        let fs = workspace.read(cx).app_state().fs.clone();
16783        let current_show = TabBarSettings::get_global(cx).show;
16784        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16785            setting.show = Some(!current_show);
16786        });
16787    }
16788
16789    pub fn toggle_indent_guides(
16790        &mut self,
16791        _: &ToggleIndentGuides,
16792        _: &mut Window,
16793        cx: &mut Context<Self>,
16794    ) {
16795        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16796            self.buffer
16797                .read(cx)
16798                .language_settings(cx)
16799                .indent_guides
16800                .enabled
16801        });
16802        self.show_indent_guides = Some(!currently_enabled);
16803        cx.notify();
16804    }
16805
16806    fn should_show_indent_guides(&self) -> Option<bool> {
16807        self.show_indent_guides
16808    }
16809
16810    pub fn toggle_line_numbers(
16811        &mut self,
16812        _: &ToggleLineNumbers,
16813        _: &mut Window,
16814        cx: &mut Context<Self>,
16815    ) {
16816        let mut editor_settings = EditorSettings::get_global(cx).clone();
16817        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16818        EditorSettings::override_global(editor_settings, cx);
16819    }
16820
16821    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16822        if let Some(show_line_numbers) = self.show_line_numbers {
16823            return show_line_numbers;
16824        }
16825        EditorSettings::get_global(cx).gutter.line_numbers
16826    }
16827
16828    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16829        self.use_relative_line_numbers
16830            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16831    }
16832
16833    pub fn toggle_relative_line_numbers(
16834        &mut self,
16835        _: &ToggleRelativeLineNumbers,
16836        _: &mut Window,
16837        cx: &mut Context<Self>,
16838    ) {
16839        let is_relative = self.should_use_relative_line_numbers(cx);
16840        self.set_relative_line_number(Some(!is_relative), cx)
16841    }
16842
16843    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16844        self.use_relative_line_numbers = is_relative;
16845        cx.notify();
16846    }
16847
16848    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16849        self.show_gutter = show_gutter;
16850        cx.notify();
16851    }
16852
16853    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16854        self.show_scrollbars = show_scrollbars;
16855        cx.notify();
16856    }
16857
16858    pub fn set_minimap_visibility(
16859        &mut self,
16860        minimap_visibility: MinimapVisibility,
16861        window: &mut Window,
16862        cx: &mut Context<Self>,
16863    ) {
16864        if self.minimap_visibility != minimap_visibility {
16865            if minimap_visibility.visible() && self.minimap.is_none() {
16866                let minimap_settings = EditorSettings::get_global(cx).minimap;
16867                self.minimap =
16868                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16869            }
16870            self.minimap_visibility = minimap_visibility;
16871            cx.notify();
16872        }
16873    }
16874
16875    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16876        self.set_show_scrollbars(false, cx);
16877        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16878    }
16879
16880    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16881        self.show_line_numbers = Some(show_line_numbers);
16882        cx.notify();
16883    }
16884
16885    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16886        self.disable_expand_excerpt_buttons = true;
16887        cx.notify();
16888    }
16889
16890    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16891        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16892        cx.notify();
16893    }
16894
16895    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16896        self.show_code_actions = Some(show_code_actions);
16897        cx.notify();
16898    }
16899
16900    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16901        self.show_runnables = Some(show_runnables);
16902        cx.notify();
16903    }
16904
16905    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16906        self.show_breakpoints = Some(show_breakpoints);
16907        cx.notify();
16908    }
16909
16910    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16911        if self.display_map.read(cx).masked != masked {
16912            self.display_map.update(cx, |map, _| map.masked = masked);
16913        }
16914        cx.notify()
16915    }
16916
16917    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16918        self.show_wrap_guides = Some(show_wrap_guides);
16919        cx.notify();
16920    }
16921
16922    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16923        self.show_indent_guides = Some(show_indent_guides);
16924        cx.notify();
16925    }
16926
16927    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16928        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16929            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16930                if let Some(dir) = file.abs_path(cx).parent() {
16931                    return Some(dir.to_owned());
16932                }
16933            }
16934
16935            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16936                return Some(project_path.path.to_path_buf());
16937            }
16938        }
16939
16940        None
16941    }
16942
16943    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16944        self.active_excerpt(cx)?
16945            .1
16946            .read(cx)
16947            .file()
16948            .and_then(|f| f.as_local())
16949    }
16950
16951    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16952        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16953            let buffer = buffer.read(cx);
16954            if let Some(project_path) = buffer.project_path(cx) {
16955                let project = self.project.as_ref()?.read(cx);
16956                project.absolute_path(&project_path, cx)
16957            } else {
16958                buffer
16959                    .file()
16960                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16961            }
16962        })
16963    }
16964
16965    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16966        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16967            let project_path = buffer.read(cx).project_path(cx)?;
16968            let project = self.project.as_ref()?.read(cx);
16969            let entry = project.entry_for_path(&project_path, cx)?;
16970            let path = entry.path.to_path_buf();
16971            Some(path)
16972        })
16973    }
16974
16975    pub fn reveal_in_finder(
16976        &mut self,
16977        _: &RevealInFileManager,
16978        _window: &mut Window,
16979        cx: &mut Context<Self>,
16980    ) {
16981        if let Some(target) = self.target_file(cx) {
16982            cx.reveal_path(&target.abs_path(cx));
16983        }
16984    }
16985
16986    pub fn copy_path(
16987        &mut self,
16988        _: &zed_actions::workspace::CopyPath,
16989        _window: &mut Window,
16990        cx: &mut Context<Self>,
16991    ) {
16992        if let Some(path) = self.target_file_abs_path(cx) {
16993            if let Some(path) = path.to_str() {
16994                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16995            }
16996        }
16997    }
16998
16999    pub fn copy_relative_path(
17000        &mut self,
17001        _: &zed_actions::workspace::CopyRelativePath,
17002        _window: &mut Window,
17003        cx: &mut Context<Self>,
17004    ) {
17005        if let Some(path) = self.target_file_path(cx) {
17006            if let Some(path) = path.to_str() {
17007                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17008            }
17009        }
17010    }
17011
17012    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17013        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17014            buffer.read(cx).project_path(cx)
17015        } else {
17016            None
17017        }
17018    }
17019
17020    // Returns true if the editor handled a go-to-line request
17021    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17022        maybe!({
17023            let breakpoint_store = self.breakpoint_store.as_ref()?;
17024
17025            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17026            else {
17027                self.clear_row_highlights::<ActiveDebugLine>();
17028                return None;
17029            };
17030
17031            let position = active_stack_frame.position;
17032            let buffer_id = position.buffer_id?;
17033            let snapshot = self
17034                .project
17035                .as_ref()?
17036                .read(cx)
17037                .buffer_for_id(buffer_id, cx)?
17038                .read(cx)
17039                .snapshot();
17040
17041            let mut handled = false;
17042            for (id, ExcerptRange { context, .. }) in
17043                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17044            {
17045                if context.start.cmp(&position, &snapshot).is_ge()
17046                    || context.end.cmp(&position, &snapshot).is_lt()
17047                {
17048                    continue;
17049                }
17050                let snapshot = self.buffer.read(cx).snapshot(cx);
17051                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17052
17053                handled = true;
17054                self.clear_row_highlights::<ActiveDebugLine>();
17055
17056                self.go_to_line::<ActiveDebugLine>(
17057                    multibuffer_anchor,
17058                    Some(cx.theme().colors().editor_debugger_active_line_background),
17059                    window,
17060                    cx,
17061                );
17062
17063                cx.notify();
17064            }
17065
17066            handled.then_some(())
17067        })
17068        .is_some()
17069    }
17070
17071    pub fn copy_file_name_without_extension(
17072        &mut self,
17073        _: &CopyFileNameWithoutExtension,
17074        _: &mut Window,
17075        cx: &mut Context<Self>,
17076    ) {
17077        if let Some(file) = self.target_file(cx) {
17078            if let Some(file_stem) = file.path().file_stem() {
17079                if let Some(name) = file_stem.to_str() {
17080                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17081                }
17082            }
17083        }
17084    }
17085
17086    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17087        if let Some(file) = self.target_file(cx) {
17088            if let Some(file_name) = file.path().file_name() {
17089                if let Some(name) = file_name.to_str() {
17090                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17091                }
17092            }
17093        }
17094    }
17095
17096    pub fn toggle_git_blame(
17097        &mut self,
17098        _: &::git::Blame,
17099        window: &mut Window,
17100        cx: &mut Context<Self>,
17101    ) {
17102        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17103
17104        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17105            self.start_git_blame(true, window, cx);
17106        }
17107
17108        cx.notify();
17109    }
17110
17111    pub fn toggle_git_blame_inline(
17112        &mut self,
17113        _: &ToggleGitBlameInline,
17114        window: &mut Window,
17115        cx: &mut Context<Self>,
17116    ) {
17117        self.toggle_git_blame_inline_internal(true, window, cx);
17118        cx.notify();
17119    }
17120
17121    pub fn open_git_blame_commit(
17122        &mut self,
17123        _: &OpenGitBlameCommit,
17124        window: &mut Window,
17125        cx: &mut Context<Self>,
17126    ) {
17127        self.open_git_blame_commit_internal(window, cx);
17128    }
17129
17130    fn open_git_blame_commit_internal(
17131        &mut self,
17132        window: &mut Window,
17133        cx: &mut Context<Self>,
17134    ) -> Option<()> {
17135        let blame = self.blame.as_ref()?;
17136        let snapshot = self.snapshot(window, cx);
17137        let cursor = self.selections.newest::<Point>(cx).head();
17138        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17139        let blame_entry = blame
17140            .update(cx, |blame, cx| {
17141                blame
17142                    .blame_for_rows(
17143                        &[RowInfo {
17144                            buffer_id: Some(buffer.remote_id()),
17145                            buffer_row: Some(point.row),
17146                            ..Default::default()
17147                        }],
17148                        cx,
17149                    )
17150                    .next()
17151            })
17152            .flatten()?;
17153        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17154        let repo = blame.read(cx).repository(cx)?;
17155        let workspace = self.workspace()?.downgrade();
17156        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17157        None
17158    }
17159
17160    pub fn git_blame_inline_enabled(&self) -> bool {
17161        self.git_blame_inline_enabled
17162    }
17163
17164    pub fn toggle_selection_menu(
17165        &mut self,
17166        _: &ToggleSelectionMenu,
17167        _: &mut Window,
17168        cx: &mut Context<Self>,
17169    ) {
17170        self.show_selection_menu = self
17171            .show_selection_menu
17172            .map(|show_selections_menu| !show_selections_menu)
17173            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17174
17175        cx.notify();
17176    }
17177
17178    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17179        self.show_selection_menu
17180            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17181    }
17182
17183    fn start_git_blame(
17184        &mut self,
17185        user_triggered: bool,
17186        window: &mut Window,
17187        cx: &mut Context<Self>,
17188    ) {
17189        if let Some(project) = self.project.as_ref() {
17190            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17191                return;
17192            };
17193
17194            if buffer.read(cx).file().is_none() {
17195                return;
17196            }
17197
17198            let focused = self.focus_handle(cx).contains_focused(window, cx);
17199
17200            let project = project.clone();
17201            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17202            self.blame_subscription =
17203                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17204            self.blame = Some(blame);
17205        }
17206    }
17207
17208    fn toggle_git_blame_inline_internal(
17209        &mut self,
17210        user_triggered: bool,
17211        window: &mut Window,
17212        cx: &mut Context<Self>,
17213    ) {
17214        if self.git_blame_inline_enabled {
17215            self.git_blame_inline_enabled = false;
17216            self.show_git_blame_inline = false;
17217            self.show_git_blame_inline_delay_task.take();
17218        } else {
17219            self.git_blame_inline_enabled = true;
17220            self.start_git_blame_inline(user_triggered, window, cx);
17221        }
17222
17223        cx.notify();
17224    }
17225
17226    fn start_git_blame_inline(
17227        &mut self,
17228        user_triggered: bool,
17229        window: &mut Window,
17230        cx: &mut Context<Self>,
17231    ) {
17232        self.start_git_blame(user_triggered, window, cx);
17233
17234        if ProjectSettings::get_global(cx)
17235            .git
17236            .inline_blame_delay()
17237            .is_some()
17238        {
17239            self.start_inline_blame_timer(window, cx);
17240        } else {
17241            self.show_git_blame_inline = true
17242        }
17243    }
17244
17245    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17246        self.blame.as_ref()
17247    }
17248
17249    pub fn show_git_blame_gutter(&self) -> bool {
17250        self.show_git_blame_gutter
17251    }
17252
17253    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17254        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17255    }
17256
17257    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17258        self.show_git_blame_inline
17259            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17260            && !self.newest_selection_head_on_empty_line(cx)
17261            && self.has_blame_entries(cx)
17262    }
17263
17264    fn has_blame_entries(&self, cx: &App) -> bool {
17265        self.blame()
17266            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17267    }
17268
17269    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17270        let cursor_anchor = self.selections.newest_anchor().head();
17271
17272        let snapshot = self.buffer.read(cx).snapshot(cx);
17273        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17274
17275        snapshot.line_len(buffer_row) == 0
17276    }
17277
17278    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17279        let buffer_and_selection = maybe!({
17280            let selection = self.selections.newest::<Point>(cx);
17281            let selection_range = selection.range();
17282
17283            let multi_buffer = self.buffer().read(cx);
17284            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17285            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17286
17287            let (buffer, range, _) = if selection.reversed {
17288                buffer_ranges.first()
17289            } else {
17290                buffer_ranges.last()
17291            }?;
17292
17293            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17294                ..text::ToPoint::to_point(&range.end, &buffer).row;
17295            Some((
17296                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17297                selection,
17298            ))
17299        });
17300
17301        let Some((buffer, selection)) = buffer_and_selection else {
17302            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17303        };
17304
17305        let Some(project) = self.project.as_ref() else {
17306            return Task::ready(Err(anyhow!("editor does not have project")));
17307        };
17308
17309        project.update(cx, |project, cx| {
17310            project.get_permalink_to_line(&buffer, selection, cx)
17311        })
17312    }
17313
17314    pub fn copy_permalink_to_line(
17315        &mut self,
17316        _: &CopyPermalinkToLine,
17317        window: &mut Window,
17318        cx: &mut Context<Self>,
17319    ) {
17320        let permalink_task = self.get_permalink_to_line(cx);
17321        let workspace = self.workspace();
17322
17323        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17324            Ok(permalink) => {
17325                cx.update(|_, cx| {
17326                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17327                })
17328                .ok();
17329            }
17330            Err(err) => {
17331                let message = format!("Failed to copy permalink: {err}");
17332
17333                anyhow::Result::<()>::Err(err).log_err();
17334
17335                if let Some(workspace) = workspace {
17336                    workspace
17337                        .update_in(cx, |workspace, _, cx| {
17338                            struct CopyPermalinkToLine;
17339
17340                            workspace.show_toast(
17341                                Toast::new(
17342                                    NotificationId::unique::<CopyPermalinkToLine>(),
17343                                    message,
17344                                ),
17345                                cx,
17346                            )
17347                        })
17348                        .ok();
17349                }
17350            }
17351        })
17352        .detach();
17353    }
17354
17355    pub fn copy_file_location(
17356        &mut self,
17357        _: &CopyFileLocation,
17358        _: &mut Window,
17359        cx: &mut Context<Self>,
17360    ) {
17361        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17362        if let Some(file) = self.target_file(cx) {
17363            if let Some(path) = file.path().to_str() {
17364                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17365            }
17366        }
17367    }
17368
17369    pub fn open_permalink_to_line(
17370        &mut self,
17371        _: &OpenPermalinkToLine,
17372        window: &mut Window,
17373        cx: &mut Context<Self>,
17374    ) {
17375        let permalink_task = self.get_permalink_to_line(cx);
17376        let workspace = self.workspace();
17377
17378        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17379            Ok(permalink) => {
17380                cx.update(|_, cx| {
17381                    cx.open_url(permalink.as_ref());
17382                })
17383                .ok();
17384            }
17385            Err(err) => {
17386                let message = format!("Failed to open permalink: {err}");
17387
17388                anyhow::Result::<()>::Err(err).log_err();
17389
17390                if let Some(workspace) = workspace {
17391                    workspace
17392                        .update(cx, |workspace, cx| {
17393                            struct OpenPermalinkToLine;
17394
17395                            workspace.show_toast(
17396                                Toast::new(
17397                                    NotificationId::unique::<OpenPermalinkToLine>(),
17398                                    message,
17399                                ),
17400                                cx,
17401                            )
17402                        })
17403                        .ok();
17404                }
17405            }
17406        })
17407        .detach();
17408    }
17409
17410    pub fn insert_uuid_v4(
17411        &mut self,
17412        _: &InsertUuidV4,
17413        window: &mut Window,
17414        cx: &mut Context<Self>,
17415    ) {
17416        self.insert_uuid(UuidVersion::V4, window, cx);
17417    }
17418
17419    pub fn insert_uuid_v7(
17420        &mut self,
17421        _: &InsertUuidV7,
17422        window: &mut Window,
17423        cx: &mut Context<Self>,
17424    ) {
17425        self.insert_uuid(UuidVersion::V7, window, cx);
17426    }
17427
17428    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17429        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17430        self.transact(window, cx, |this, window, cx| {
17431            let edits = this
17432                .selections
17433                .all::<Point>(cx)
17434                .into_iter()
17435                .map(|selection| {
17436                    let uuid = match version {
17437                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17438                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17439                    };
17440
17441                    (selection.range(), uuid.to_string())
17442                });
17443            this.edit(edits, cx);
17444            this.refresh_inline_completion(true, false, window, cx);
17445        });
17446    }
17447
17448    pub fn open_selections_in_multibuffer(
17449        &mut self,
17450        _: &OpenSelectionsInMultibuffer,
17451        window: &mut Window,
17452        cx: &mut Context<Self>,
17453    ) {
17454        let multibuffer = self.buffer.read(cx);
17455
17456        let Some(buffer) = multibuffer.as_singleton() else {
17457            return;
17458        };
17459
17460        let Some(workspace) = self.workspace() else {
17461            return;
17462        };
17463
17464        let locations = self
17465            .selections
17466            .disjoint_anchors()
17467            .iter()
17468            .map(|range| Location {
17469                buffer: buffer.clone(),
17470                range: range.start.text_anchor..range.end.text_anchor,
17471            })
17472            .collect::<Vec<_>>();
17473
17474        let title = multibuffer.title(cx).to_string();
17475
17476        cx.spawn_in(window, async move |_, cx| {
17477            workspace.update_in(cx, |workspace, window, cx| {
17478                Self::open_locations_in_multibuffer(
17479                    workspace,
17480                    locations,
17481                    format!("Selections for '{title}'"),
17482                    false,
17483                    MultibufferSelectionMode::All,
17484                    window,
17485                    cx,
17486                );
17487            })
17488        })
17489        .detach();
17490    }
17491
17492    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17493    /// last highlight added will be used.
17494    ///
17495    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17496    pub fn highlight_rows<T: 'static>(
17497        &mut self,
17498        range: Range<Anchor>,
17499        color: Hsla,
17500        options: RowHighlightOptions,
17501        cx: &mut Context<Self>,
17502    ) {
17503        let snapshot = self.buffer().read(cx).snapshot(cx);
17504        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17505        let ix = row_highlights.binary_search_by(|highlight| {
17506            Ordering::Equal
17507                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17508                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17509        });
17510
17511        if let Err(mut ix) = ix {
17512            let index = post_inc(&mut self.highlight_order);
17513
17514            // If this range intersects with the preceding highlight, then merge it with
17515            // the preceding highlight. Otherwise insert a new highlight.
17516            let mut merged = false;
17517            if ix > 0 {
17518                let prev_highlight = &mut row_highlights[ix - 1];
17519                if prev_highlight
17520                    .range
17521                    .end
17522                    .cmp(&range.start, &snapshot)
17523                    .is_ge()
17524                {
17525                    ix -= 1;
17526                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17527                        prev_highlight.range.end = range.end;
17528                    }
17529                    merged = true;
17530                    prev_highlight.index = index;
17531                    prev_highlight.color = color;
17532                    prev_highlight.options = options;
17533                }
17534            }
17535
17536            if !merged {
17537                row_highlights.insert(
17538                    ix,
17539                    RowHighlight {
17540                        range: range.clone(),
17541                        index,
17542                        color,
17543                        options,
17544                        type_id: TypeId::of::<T>(),
17545                    },
17546                );
17547            }
17548
17549            // If any of the following highlights intersect with this one, merge them.
17550            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17551                let highlight = &row_highlights[ix];
17552                if next_highlight
17553                    .range
17554                    .start
17555                    .cmp(&highlight.range.end, &snapshot)
17556                    .is_le()
17557                {
17558                    if next_highlight
17559                        .range
17560                        .end
17561                        .cmp(&highlight.range.end, &snapshot)
17562                        .is_gt()
17563                    {
17564                        row_highlights[ix].range.end = next_highlight.range.end;
17565                    }
17566                    row_highlights.remove(ix + 1);
17567                } else {
17568                    break;
17569                }
17570            }
17571        }
17572    }
17573
17574    /// Remove any highlighted row ranges of the given type that intersect the
17575    /// given ranges.
17576    pub fn remove_highlighted_rows<T: 'static>(
17577        &mut self,
17578        ranges_to_remove: Vec<Range<Anchor>>,
17579        cx: &mut Context<Self>,
17580    ) {
17581        let snapshot = self.buffer().read(cx).snapshot(cx);
17582        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17583        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17584        row_highlights.retain(|highlight| {
17585            while let Some(range_to_remove) = ranges_to_remove.peek() {
17586                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17587                    Ordering::Less | Ordering::Equal => {
17588                        ranges_to_remove.next();
17589                    }
17590                    Ordering::Greater => {
17591                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17592                            Ordering::Less | Ordering::Equal => {
17593                                return false;
17594                            }
17595                            Ordering::Greater => break,
17596                        }
17597                    }
17598                }
17599            }
17600
17601            true
17602        })
17603    }
17604
17605    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17606    pub fn clear_row_highlights<T: 'static>(&mut self) {
17607        self.highlighted_rows.remove(&TypeId::of::<T>());
17608    }
17609
17610    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17611    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17612        self.highlighted_rows
17613            .get(&TypeId::of::<T>())
17614            .map_or(&[] as &[_], |vec| vec.as_slice())
17615            .iter()
17616            .map(|highlight| (highlight.range.clone(), highlight.color))
17617    }
17618
17619    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17620    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17621    /// Allows to ignore certain kinds of highlights.
17622    pub fn highlighted_display_rows(
17623        &self,
17624        window: &mut Window,
17625        cx: &mut App,
17626    ) -> BTreeMap<DisplayRow, LineHighlight> {
17627        let snapshot = self.snapshot(window, cx);
17628        let mut used_highlight_orders = HashMap::default();
17629        self.highlighted_rows
17630            .iter()
17631            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17632            .fold(
17633                BTreeMap::<DisplayRow, LineHighlight>::new(),
17634                |mut unique_rows, highlight| {
17635                    let start = highlight.range.start.to_display_point(&snapshot);
17636                    let end = highlight.range.end.to_display_point(&snapshot);
17637                    let start_row = start.row().0;
17638                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17639                        && end.column() == 0
17640                    {
17641                        end.row().0.saturating_sub(1)
17642                    } else {
17643                        end.row().0
17644                    };
17645                    for row in start_row..=end_row {
17646                        let used_index =
17647                            used_highlight_orders.entry(row).or_insert(highlight.index);
17648                        if highlight.index >= *used_index {
17649                            *used_index = highlight.index;
17650                            unique_rows.insert(
17651                                DisplayRow(row),
17652                                LineHighlight {
17653                                    include_gutter: highlight.options.include_gutter,
17654                                    border: None,
17655                                    background: highlight.color.into(),
17656                                    type_id: Some(highlight.type_id),
17657                                },
17658                            );
17659                        }
17660                    }
17661                    unique_rows
17662                },
17663            )
17664    }
17665
17666    pub fn highlighted_display_row_for_autoscroll(
17667        &self,
17668        snapshot: &DisplaySnapshot,
17669    ) -> Option<DisplayRow> {
17670        self.highlighted_rows
17671            .values()
17672            .flat_map(|highlighted_rows| highlighted_rows.iter())
17673            .filter_map(|highlight| {
17674                if highlight.options.autoscroll {
17675                    Some(highlight.range.start.to_display_point(snapshot).row())
17676                } else {
17677                    None
17678                }
17679            })
17680            .min()
17681    }
17682
17683    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17684        self.highlight_background::<SearchWithinRange>(
17685            ranges,
17686            |colors| colors.editor_document_highlight_read_background,
17687            cx,
17688        )
17689    }
17690
17691    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17692        self.breadcrumb_header = Some(new_header);
17693    }
17694
17695    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17696        self.clear_background_highlights::<SearchWithinRange>(cx);
17697    }
17698
17699    pub fn highlight_background<T: 'static>(
17700        &mut self,
17701        ranges: &[Range<Anchor>],
17702        color_fetcher: fn(&ThemeColors) -> Hsla,
17703        cx: &mut Context<Self>,
17704    ) {
17705        self.background_highlights
17706            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17707        self.scrollbar_marker_state.dirty = true;
17708        cx.notify();
17709    }
17710
17711    pub fn clear_background_highlights<T: 'static>(
17712        &mut self,
17713        cx: &mut Context<Self>,
17714    ) -> Option<BackgroundHighlight> {
17715        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17716        if !text_highlights.1.is_empty() {
17717            self.scrollbar_marker_state.dirty = true;
17718            cx.notify();
17719        }
17720        Some(text_highlights)
17721    }
17722
17723    pub fn highlight_gutter<T: 'static>(
17724        &mut self,
17725        ranges: &[Range<Anchor>],
17726        color_fetcher: fn(&App) -> Hsla,
17727        cx: &mut Context<Self>,
17728    ) {
17729        self.gutter_highlights
17730            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17731        cx.notify();
17732    }
17733
17734    pub fn clear_gutter_highlights<T: 'static>(
17735        &mut self,
17736        cx: &mut Context<Self>,
17737    ) -> Option<GutterHighlight> {
17738        cx.notify();
17739        self.gutter_highlights.remove(&TypeId::of::<T>())
17740    }
17741
17742    #[cfg(feature = "test-support")]
17743    pub fn all_text_background_highlights(
17744        &self,
17745        window: &mut Window,
17746        cx: &mut Context<Self>,
17747    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17748        let snapshot = self.snapshot(window, cx);
17749        let buffer = &snapshot.buffer_snapshot;
17750        let start = buffer.anchor_before(0);
17751        let end = buffer.anchor_after(buffer.len());
17752        let theme = cx.theme().colors();
17753        self.background_highlights_in_range(start..end, &snapshot, theme)
17754    }
17755
17756    #[cfg(feature = "test-support")]
17757    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17758        let snapshot = self.buffer().read(cx).snapshot(cx);
17759
17760        let highlights = self
17761            .background_highlights
17762            .get(&TypeId::of::<items::BufferSearchHighlights>());
17763
17764        if let Some((_color, ranges)) = highlights {
17765            ranges
17766                .iter()
17767                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17768                .collect_vec()
17769        } else {
17770            vec![]
17771        }
17772    }
17773
17774    fn document_highlights_for_position<'a>(
17775        &'a self,
17776        position: Anchor,
17777        buffer: &'a MultiBufferSnapshot,
17778    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17779        let read_highlights = self
17780            .background_highlights
17781            .get(&TypeId::of::<DocumentHighlightRead>())
17782            .map(|h| &h.1);
17783        let write_highlights = self
17784            .background_highlights
17785            .get(&TypeId::of::<DocumentHighlightWrite>())
17786            .map(|h| &h.1);
17787        let left_position = position.bias_left(buffer);
17788        let right_position = position.bias_right(buffer);
17789        read_highlights
17790            .into_iter()
17791            .chain(write_highlights)
17792            .flat_map(move |ranges| {
17793                let start_ix = match ranges.binary_search_by(|probe| {
17794                    let cmp = probe.end.cmp(&left_position, buffer);
17795                    if cmp.is_ge() {
17796                        Ordering::Greater
17797                    } else {
17798                        Ordering::Less
17799                    }
17800                }) {
17801                    Ok(i) | Err(i) => i,
17802                };
17803
17804                ranges[start_ix..]
17805                    .iter()
17806                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17807            })
17808    }
17809
17810    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17811        self.background_highlights
17812            .get(&TypeId::of::<T>())
17813            .map_or(false, |(_, highlights)| !highlights.is_empty())
17814    }
17815
17816    pub fn background_highlights_in_range(
17817        &self,
17818        search_range: Range<Anchor>,
17819        display_snapshot: &DisplaySnapshot,
17820        theme: &ThemeColors,
17821    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17822        let mut results = Vec::new();
17823        for (color_fetcher, ranges) in self.background_highlights.values() {
17824            let color = color_fetcher(theme);
17825            let start_ix = match ranges.binary_search_by(|probe| {
17826                let cmp = probe
17827                    .end
17828                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17829                if cmp.is_gt() {
17830                    Ordering::Greater
17831                } else {
17832                    Ordering::Less
17833                }
17834            }) {
17835                Ok(i) | Err(i) => i,
17836            };
17837            for range in &ranges[start_ix..] {
17838                if range
17839                    .start
17840                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17841                    .is_ge()
17842                {
17843                    break;
17844                }
17845
17846                let start = range.start.to_display_point(display_snapshot);
17847                let end = range.end.to_display_point(display_snapshot);
17848                results.push((start..end, color))
17849            }
17850        }
17851        results
17852    }
17853
17854    pub fn background_highlight_row_ranges<T: 'static>(
17855        &self,
17856        search_range: Range<Anchor>,
17857        display_snapshot: &DisplaySnapshot,
17858        count: usize,
17859    ) -> Vec<RangeInclusive<DisplayPoint>> {
17860        let mut results = Vec::new();
17861        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17862            return vec![];
17863        };
17864
17865        let start_ix = match ranges.binary_search_by(|probe| {
17866            let cmp = probe
17867                .end
17868                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17869            if cmp.is_gt() {
17870                Ordering::Greater
17871            } else {
17872                Ordering::Less
17873            }
17874        }) {
17875            Ok(i) | Err(i) => i,
17876        };
17877        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17878            if let (Some(start_display), Some(end_display)) = (start, end) {
17879                results.push(
17880                    start_display.to_display_point(display_snapshot)
17881                        ..=end_display.to_display_point(display_snapshot),
17882                );
17883            }
17884        };
17885        let mut start_row: Option<Point> = None;
17886        let mut end_row: Option<Point> = None;
17887        if ranges.len() > count {
17888            return Vec::new();
17889        }
17890        for range in &ranges[start_ix..] {
17891            if range
17892                .start
17893                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17894                .is_ge()
17895            {
17896                break;
17897            }
17898            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17899            if let Some(current_row) = &end_row {
17900                if end.row == current_row.row {
17901                    continue;
17902                }
17903            }
17904            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17905            if start_row.is_none() {
17906                assert_eq!(end_row, None);
17907                start_row = Some(start);
17908                end_row = Some(end);
17909                continue;
17910            }
17911            if let Some(current_end) = end_row.as_mut() {
17912                if start.row > current_end.row + 1 {
17913                    push_region(start_row, end_row);
17914                    start_row = Some(start);
17915                    end_row = Some(end);
17916                } else {
17917                    // Merge two hunks.
17918                    *current_end = end;
17919                }
17920            } else {
17921                unreachable!();
17922            }
17923        }
17924        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17925        push_region(start_row, end_row);
17926        results
17927    }
17928
17929    pub fn gutter_highlights_in_range(
17930        &self,
17931        search_range: Range<Anchor>,
17932        display_snapshot: &DisplaySnapshot,
17933        cx: &App,
17934    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17935        let mut results = Vec::new();
17936        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17937            let color = color_fetcher(cx);
17938            let start_ix = match ranges.binary_search_by(|probe| {
17939                let cmp = probe
17940                    .end
17941                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17942                if cmp.is_gt() {
17943                    Ordering::Greater
17944                } else {
17945                    Ordering::Less
17946                }
17947            }) {
17948                Ok(i) | Err(i) => i,
17949            };
17950            for range in &ranges[start_ix..] {
17951                if range
17952                    .start
17953                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17954                    .is_ge()
17955                {
17956                    break;
17957                }
17958
17959                let start = range.start.to_display_point(display_snapshot);
17960                let end = range.end.to_display_point(display_snapshot);
17961                results.push((start..end, color))
17962            }
17963        }
17964        results
17965    }
17966
17967    /// Get the text ranges corresponding to the redaction query
17968    pub fn redacted_ranges(
17969        &self,
17970        search_range: Range<Anchor>,
17971        display_snapshot: &DisplaySnapshot,
17972        cx: &App,
17973    ) -> Vec<Range<DisplayPoint>> {
17974        display_snapshot
17975            .buffer_snapshot
17976            .redacted_ranges(search_range, |file| {
17977                if let Some(file) = file {
17978                    file.is_private()
17979                        && EditorSettings::get(
17980                            Some(SettingsLocation {
17981                                worktree_id: file.worktree_id(cx),
17982                                path: file.path().as_ref(),
17983                            }),
17984                            cx,
17985                        )
17986                        .redact_private_values
17987                } else {
17988                    false
17989                }
17990            })
17991            .map(|range| {
17992                range.start.to_display_point(display_snapshot)
17993                    ..range.end.to_display_point(display_snapshot)
17994            })
17995            .collect()
17996    }
17997
17998    pub fn highlight_text<T: 'static>(
17999        &mut self,
18000        ranges: Vec<Range<Anchor>>,
18001        style: HighlightStyle,
18002        cx: &mut Context<Self>,
18003    ) {
18004        self.display_map.update(cx, |map, _| {
18005            map.highlight_text(TypeId::of::<T>(), ranges, style)
18006        });
18007        cx.notify();
18008    }
18009
18010    pub(crate) fn highlight_inlays<T: 'static>(
18011        &mut self,
18012        highlights: Vec<InlayHighlight>,
18013        style: HighlightStyle,
18014        cx: &mut Context<Self>,
18015    ) {
18016        self.display_map.update(cx, |map, _| {
18017            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18018        });
18019        cx.notify();
18020    }
18021
18022    pub fn text_highlights<'a, T: 'static>(
18023        &'a self,
18024        cx: &'a App,
18025    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18026        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18027    }
18028
18029    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18030        let cleared = self
18031            .display_map
18032            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18033        if cleared {
18034            cx.notify();
18035        }
18036    }
18037
18038    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18039        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18040            && self.focus_handle.is_focused(window)
18041    }
18042
18043    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18044        self.show_cursor_when_unfocused = is_enabled;
18045        cx.notify();
18046    }
18047
18048    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18049        cx.notify();
18050    }
18051
18052    fn on_debug_session_event(
18053        &mut self,
18054        _session: Entity<Session>,
18055        event: &SessionEvent,
18056        cx: &mut Context<Self>,
18057    ) {
18058        match event {
18059            SessionEvent::InvalidateInlineValue => {
18060                self.refresh_inline_values(cx);
18061            }
18062            _ => {}
18063        }
18064    }
18065
18066    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18067        let Some(project) = self.project.clone() else {
18068            return;
18069        };
18070
18071        if !self.inline_value_cache.enabled {
18072            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18073            self.splice_inlays(&inlays, Vec::new(), cx);
18074            return;
18075        }
18076
18077        let current_execution_position = self
18078            .highlighted_rows
18079            .get(&TypeId::of::<ActiveDebugLine>())
18080            .and_then(|lines| lines.last().map(|line| line.range.start));
18081
18082        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18083            let inline_values = editor
18084                .update(cx, |editor, cx| {
18085                    let Some(current_execution_position) = current_execution_position else {
18086                        return Some(Task::ready(Ok(Vec::new())));
18087                    };
18088
18089                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18090                        let snapshot = buffer.snapshot(cx);
18091
18092                        let excerpt = snapshot.excerpt_containing(
18093                            current_execution_position..current_execution_position,
18094                        )?;
18095
18096                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18097                    })?;
18098
18099                    let range =
18100                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18101
18102                    project.inline_values(buffer, range, cx)
18103                })
18104                .ok()
18105                .flatten()?
18106                .await
18107                .context("refreshing debugger inlays")
18108                .log_err()?;
18109
18110            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18111
18112            for (buffer_id, inline_value) in inline_values
18113                .into_iter()
18114                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18115            {
18116                buffer_inline_values
18117                    .entry(buffer_id)
18118                    .or_default()
18119                    .push(inline_value);
18120            }
18121
18122            editor
18123                .update(cx, |editor, cx| {
18124                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18125                    let mut new_inlays = Vec::default();
18126
18127                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18128                        let buffer_id = buffer_snapshot.remote_id();
18129                        buffer_inline_values
18130                            .get(&buffer_id)
18131                            .into_iter()
18132                            .flatten()
18133                            .for_each(|hint| {
18134                                let inlay = Inlay::debugger_hint(
18135                                    post_inc(&mut editor.next_inlay_id),
18136                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18137                                    hint.text(),
18138                                );
18139
18140                                new_inlays.push(inlay);
18141                            });
18142                    }
18143
18144                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18145                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18146
18147                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18148                })
18149                .ok()?;
18150            Some(())
18151        });
18152    }
18153
18154    fn on_buffer_event(
18155        &mut self,
18156        multibuffer: &Entity<MultiBuffer>,
18157        event: &multi_buffer::Event,
18158        window: &mut Window,
18159        cx: &mut Context<Self>,
18160    ) {
18161        match event {
18162            multi_buffer::Event::Edited {
18163                singleton_buffer_edited,
18164                edited_buffer: buffer_edited,
18165            } => {
18166                self.scrollbar_marker_state.dirty = true;
18167                self.active_indent_guides_state.dirty = true;
18168                self.refresh_active_diagnostics(cx);
18169                self.refresh_code_actions(window, cx);
18170                self.refresh_selected_text_highlights(true, window, cx);
18171                refresh_matching_bracket_highlights(self, window, cx);
18172                if self.has_active_inline_completion() {
18173                    self.update_visible_inline_completion(window, cx);
18174                }
18175                if let Some(buffer) = buffer_edited {
18176                    let buffer_id = buffer.read(cx).remote_id();
18177                    if !self.registered_buffers.contains_key(&buffer_id) {
18178                        if let Some(project) = self.project.as_ref() {
18179                            project.update(cx, |project, cx| {
18180                                self.registered_buffers.insert(
18181                                    buffer_id,
18182                                    project.register_buffer_with_language_servers(&buffer, cx),
18183                                );
18184                            })
18185                        }
18186                    }
18187                }
18188                cx.emit(EditorEvent::BufferEdited);
18189                cx.emit(SearchEvent::MatchesInvalidated);
18190                if *singleton_buffer_edited {
18191                    if let Some(project) = &self.project {
18192                        #[allow(clippy::mutable_key_type)]
18193                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18194                            multibuffer
18195                                .all_buffers()
18196                                .into_iter()
18197                                .filter_map(|buffer| {
18198                                    buffer.update(cx, |buffer, cx| {
18199                                        let language = buffer.language()?;
18200                                        let should_discard = project.update(cx, |project, cx| {
18201                                            project.is_local()
18202                                                && !project.has_language_servers_for(buffer, cx)
18203                                        });
18204                                        should_discard.not().then_some(language.clone())
18205                                    })
18206                                })
18207                                .collect::<HashSet<_>>()
18208                        });
18209                        if !languages_affected.is_empty() {
18210                            self.refresh_inlay_hints(
18211                                InlayHintRefreshReason::BufferEdited(languages_affected),
18212                                cx,
18213                            );
18214                        }
18215                    }
18216                }
18217
18218                let Some(project) = &self.project else { return };
18219                let (telemetry, is_via_ssh) = {
18220                    let project = project.read(cx);
18221                    let telemetry = project.client().telemetry().clone();
18222                    let is_via_ssh = project.is_via_ssh();
18223                    (telemetry, is_via_ssh)
18224                };
18225                refresh_linked_ranges(self, window, cx);
18226                telemetry.log_edit_event("editor", is_via_ssh);
18227            }
18228            multi_buffer::Event::ExcerptsAdded {
18229                buffer,
18230                predecessor,
18231                excerpts,
18232            } => {
18233                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18234                let buffer_id = buffer.read(cx).remote_id();
18235                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18236                    if let Some(project) = &self.project {
18237                        update_uncommitted_diff_for_buffer(
18238                            cx.entity(),
18239                            project,
18240                            [buffer.clone()],
18241                            self.buffer.clone(),
18242                            cx,
18243                        )
18244                        .detach();
18245                    }
18246                }
18247                cx.emit(EditorEvent::ExcerptsAdded {
18248                    buffer: buffer.clone(),
18249                    predecessor: *predecessor,
18250                    excerpts: excerpts.clone(),
18251                });
18252                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18253            }
18254            multi_buffer::Event::ExcerptsRemoved {
18255                ids,
18256                removed_buffer_ids,
18257            } => {
18258                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18259                let buffer = self.buffer.read(cx);
18260                self.registered_buffers
18261                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18262                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18263                cx.emit(EditorEvent::ExcerptsRemoved {
18264                    ids: ids.clone(),
18265                    removed_buffer_ids: removed_buffer_ids.clone(),
18266                })
18267            }
18268            multi_buffer::Event::ExcerptsEdited {
18269                excerpt_ids,
18270                buffer_ids,
18271            } => {
18272                self.display_map.update(cx, |map, cx| {
18273                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18274                });
18275                cx.emit(EditorEvent::ExcerptsEdited {
18276                    ids: excerpt_ids.clone(),
18277                })
18278            }
18279            multi_buffer::Event::ExcerptsExpanded { ids } => {
18280                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18281                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18282            }
18283            multi_buffer::Event::Reparsed(buffer_id) => {
18284                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18285                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18286
18287                cx.emit(EditorEvent::Reparsed(*buffer_id));
18288            }
18289            multi_buffer::Event::DiffHunksToggled => {
18290                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18291            }
18292            multi_buffer::Event::LanguageChanged(buffer_id) => {
18293                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18294                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18295                cx.emit(EditorEvent::Reparsed(*buffer_id));
18296                cx.notify();
18297            }
18298            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18299            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18300            multi_buffer::Event::FileHandleChanged
18301            | multi_buffer::Event::Reloaded
18302            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18303            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18304            multi_buffer::Event::DiagnosticsUpdated => {
18305                self.refresh_active_diagnostics(cx);
18306                self.refresh_inline_diagnostics(true, window, cx);
18307                self.scrollbar_marker_state.dirty = true;
18308                cx.notify();
18309            }
18310            _ => {}
18311        };
18312    }
18313
18314    pub fn start_temporary_diff_override(&mut self) {
18315        self.load_diff_task.take();
18316        self.temporary_diff_override = true;
18317    }
18318
18319    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18320        self.temporary_diff_override = false;
18321        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18322        self.buffer.update(cx, |buffer, cx| {
18323            buffer.set_all_diff_hunks_collapsed(cx);
18324        });
18325
18326        if let Some(project) = self.project.clone() {
18327            self.load_diff_task = Some(
18328                update_uncommitted_diff_for_buffer(
18329                    cx.entity(),
18330                    &project,
18331                    self.buffer.read(cx).all_buffers(),
18332                    self.buffer.clone(),
18333                    cx,
18334                )
18335                .shared(),
18336            );
18337        }
18338    }
18339
18340    fn on_display_map_changed(
18341        &mut self,
18342        _: Entity<DisplayMap>,
18343        _: &mut Window,
18344        cx: &mut Context<Self>,
18345    ) {
18346        cx.notify();
18347    }
18348
18349    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18350        let new_severity = if self.diagnostics_enabled() {
18351            EditorSettings::get_global(cx)
18352                .diagnostics_max_severity
18353                .unwrap_or(DiagnosticSeverity::Hint)
18354        } else {
18355            DiagnosticSeverity::Off
18356        };
18357        self.set_max_diagnostics_severity(new_severity, cx);
18358        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18359        self.update_edit_prediction_settings(cx);
18360        self.refresh_inline_completion(true, false, window, cx);
18361        self.refresh_inlay_hints(
18362            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18363                self.selections.newest_anchor().head(),
18364                &self.buffer.read(cx).snapshot(cx),
18365                cx,
18366            )),
18367            cx,
18368        );
18369
18370        let old_cursor_shape = self.cursor_shape;
18371
18372        {
18373            let editor_settings = EditorSettings::get_global(cx);
18374            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18375            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18376            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18377            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18378        }
18379
18380        if old_cursor_shape != self.cursor_shape {
18381            cx.emit(EditorEvent::CursorShapeChanged);
18382        }
18383
18384        let project_settings = ProjectSettings::get_global(cx);
18385        self.serialize_dirty_buffers =
18386            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18387
18388        if self.mode.is_full() {
18389            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18390            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18391            if self.show_inline_diagnostics != show_inline_diagnostics {
18392                self.show_inline_diagnostics = show_inline_diagnostics;
18393                self.refresh_inline_diagnostics(false, window, cx);
18394            }
18395
18396            if self.git_blame_inline_enabled != inline_blame_enabled {
18397                self.toggle_git_blame_inline_internal(false, window, cx);
18398            }
18399
18400            let minimap_settings = EditorSettings::get_global(cx).minimap;
18401            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18402                self.set_minimap_visibility(
18403                    self.minimap_visibility.toggle_visibility(),
18404                    window,
18405                    cx,
18406                );
18407            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18408                minimap_entity.update(cx, |minimap_editor, cx| {
18409                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18410                })
18411            }
18412        }
18413
18414        cx.notify();
18415    }
18416
18417    pub fn set_searchable(&mut self, searchable: bool) {
18418        self.searchable = searchable;
18419    }
18420
18421    pub fn searchable(&self) -> bool {
18422        self.searchable
18423    }
18424
18425    fn open_proposed_changes_editor(
18426        &mut self,
18427        _: &OpenProposedChangesEditor,
18428        window: &mut Window,
18429        cx: &mut Context<Self>,
18430    ) {
18431        let Some(workspace) = self.workspace() else {
18432            cx.propagate();
18433            return;
18434        };
18435
18436        let selections = self.selections.all::<usize>(cx);
18437        let multi_buffer = self.buffer.read(cx);
18438        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18439        let mut new_selections_by_buffer = HashMap::default();
18440        for selection in selections {
18441            for (buffer, range, _) in
18442                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18443            {
18444                let mut range = range.to_point(buffer);
18445                range.start.column = 0;
18446                range.end.column = buffer.line_len(range.end.row);
18447                new_selections_by_buffer
18448                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18449                    .or_insert(Vec::new())
18450                    .push(range)
18451            }
18452        }
18453
18454        let proposed_changes_buffers = new_selections_by_buffer
18455            .into_iter()
18456            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18457            .collect::<Vec<_>>();
18458        let proposed_changes_editor = cx.new(|cx| {
18459            ProposedChangesEditor::new(
18460                "Proposed changes",
18461                proposed_changes_buffers,
18462                self.project.clone(),
18463                window,
18464                cx,
18465            )
18466        });
18467
18468        window.defer(cx, move |window, cx| {
18469            workspace.update(cx, |workspace, cx| {
18470                workspace.active_pane().update(cx, |pane, cx| {
18471                    pane.add_item(
18472                        Box::new(proposed_changes_editor),
18473                        true,
18474                        true,
18475                        None,
18476                        window,
18477                        cx,
18478                    );
18479                });
18480            });
18481        });
18482    }
18483
18484    pub fn open_excerpts_in_split(
18485        &mut self,
18486        _: &OpenExcerptsSplit,
18487        window: &mut Window,
18488        cx: &mut Context<Self>,
18489    ) {
18490        self.open_excerpts_common(None, true, window, cx)
18491    }
18492
18493    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18494        self.open_excerpts_common(None, false, window, cx)
18495    }
18496
18497    fn open_excerpts_common(
18498        &mut self,
18499        jump_data: Option<JumpData>,
18500        split: bool,
18501        window: &mut Window,
18502        cx: &mut Context<Self>,
18503    ) {
18504        let Some(workspace) = self.workspace() else {
18505            cx.propagate();
18506            return;
18507        };
18508
18509        if self.buffer.read(cx).is_singleton() {
18510            cx.propagate();
18511            return;
18512        }
18513
18514        let mut new_selections_by_buffer = HashMap::default();
18515        match &jump_data {
18516            Some(JumpData::MultiBufferPoint {
18517                excerpt_id,
18518                position,
18519                anchor,
18520                line_offset_from_top,
18521            }) => {
18522                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18523                if let Some(buffer) = multi_buffer_snapshot
18524                    .buffer_id_for_excerpt(*excerpt_id)
18525                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18526                {
18527                    let buffer_snapshot = buffer.read(cx).snapshot();
18528                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18529                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18530                    } else {
18531                        buffer_snapshot.clip_point(*position, Bias::Left)
18532                    };
18533                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18534                    new_selections_by_buffer.insert(
18535                        buffer,
18536                        (
18537                            vec![jump_to_offset..jump_to_offset],
18538                            Some(*line_offset_from_top),
18539                        ),
18540                    );
18541                }
18542            }
18543            Some(JumpData::MultiBufferRow {
18544                row,
18545                line_offset_from_top,
18546            }) => {
18547                let point = MultiBufferPoint::new(row.0, 0);
18548                if let Some((buffer, buffer_point, _)) =
18549                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18550                {
18551                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18552                    new_selections_by_buffer
18553                        .entry(buffer)
18554                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18555                        .0
18556                        .push(buffer_offset..buffer_offset)
18557                }
18558            }
18559            None => {
18560                let selections = self.selections.all::<usize>(cx);
18561                let multi_buffer = self.buffer.read(cx);
18562                for selection in selections {
18563                    for (snapshot, range, _, anchor) in multi_buffer
18564                        .snapshot(cx)
18565                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18566                    {
18567                        if let Some(anchor) = anchor {
18568                            // selection is in a deleted hunk
18569                            let Some(buffer_id) = anchor.buffer_id else {
18570                                continue;
18571                            };
18572                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18573                                continue;
18574                            };
18575                            let offset = text::ToOffset::to_offset(
18576                                &anchor.text_anchor,
18577                                &buffer_handle.read(cx).snapshot(),
18578                            );
18579                            let range = offset..offset;
18580                            new_selections_by_buffer
18581                                .entry(buffer_handle)
18582                                .or_insert((Vec::new(), None))
18583                                .0
18584                                .push(range)
18585                        } else {
18586                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18587                            else {
18588                                continue;
18589                            };
18590                            new_selections_by_buffer
18591                                .entry(buffer_handle)
18592                                .or_insert((Vec::new(), None))
18593                                .0
18594                                .push(range)
18595                        }
18596                    }
18597                }
18598            }
18599        }
18600
18601        new_selections_by_buffer
18602            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18603
18604        if new_selections_by_buffer.is_empty() {
18605            return;
18606        }
18607
18608        // We defer the pane interaction because we ourselves are a workspace item
18609        // and activating a new item causes the pane to call a method on us reentrantly,
18610        // which panics if we're on the stack.
18611        window.defer(cx, move |window, cx| {
18612            workspace.update(cx, |workspace, cx| {
18613                let pane = if split {
18614                    workspace.adjacent_pane(window, cx)
18615                } else {
18616                    workspace.active_pane().clone()
18617                };
18618
18619                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18620                    let editor = buffer
18621                        .read(cx)
18622                        .file()
18623                        .is_none()
18624                        .then(|| {
18625                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18626                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18627                            // Instead, we try to activate the existing editor in the pane first.
18628                            let (editor, pane_item_index) =
18629                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18630                                    let editor = item.downcast::<Editor>()?;
18631                                    let singleton_buffer =
18632                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18633                                    if singleton_buffer == buffer {
18634                                        Some((editor, i))
18635                                    } else {
18636                                        None
18637                                    }
18638                                })?;
18639                            pane.update(cx, |pane, cx| {
18640                                pane.activate_item(pane_item_index, true, true, window, cx)
18641                            });
18642                            Some(editor)
18643                        })
18644                        .flatten()
18645                        .unwrap_or_else(|| {
18646                            workspace.open_project_item::<Self>(
18647                                pane.clone(),
18648                                buffer,
18649                                true,
18650                                true,
18651                                window,
18652                                cx,
18653                            )
18654                        });
18655
18656                    editor.update(cx, |editor, cx| {
18657                        let autoscroll = match scroll_offset {
18658                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18659                            None => Autoscroll::newest(),
18660                        };
18661                        let nav_history = editor.nav_history.take();
18662                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18663                            s.select_ranges(ranges);
18664                        });
18665                        editor.nav_history = nav_history;
18666                    });
18667                }
18668            })
18669        });
18670    }
18671
18672    // For now, don't allow opening excerpts in buffers that aren't backed by
18673    // regular project files.
18674    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18675        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18676    }
18677
18678    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18679        let snapshot = self.buffer.read(cx).read(cx);
18680        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18681        Some(
18682            ranges
18683                .iter()
18684                .map(move |range| {
18685                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18686                })
18687                .collect(),
18688        )
18689    }
18690
18691    fn selection_replacement_ranges(
18692        &self,
18693        range: Range<OffsetUtf16>,
18694        cx: &mut App,
18695    ) -> Vec<Range<OffsetUtf16>> {
18696        let selections = self.selections.all::<OffsetUtf16>(cx);
18697        let newest_selection = selections
18698            .iter()
18699            .max_by_key(|selection| selection.id)
18700            .unwrap();
18701        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18702        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18703        let snapshot = self.buffer.read(cx).read(cx);
18704        selections
18705            .into_iter()
18706            .map(|mut selection| {
18707                selection.start.0 =
18708                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18709                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18710                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18711                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18712            })
18713            .collect()
18714    }
18715
18716    fn report_editor_event(
18717        &self,
18718        event_type: &'static str,
18719        file_extension: Option<String>,
18720        cx: &App,
18721    ) {
18722        if cfg!(any(test, feature = "test-support")) {
18723            return;
18724        }
18725
18726        let Some(project) = &self.project else { return };
18727
18728        // If None, we are in a file without an extension
18729        let file = self
18730            .buffer
18731            .read(cx)
18732            .as_singleton()
18733            .and_then(|b| b.read(cx).file());
18734        let file_extension = file_extension.or(file
18735            .as_ref()
18736            .and_then(|file| Path::new(file.file_name(cx)).extension())
18737            .and_then(|e| e.to_str())
18738            .map(|a| a.to_string()));
18739
18740        let vim_mode = vim_enabled(cx);
18741
18742        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18743        let copilot_enabled = edit_predictions_provider
18744            == language::language_settings::EditPredictionProvider::Copilot;
18745        let copilot_enabled_for_language = self
18746            .buffer
18747            .read(cx)
18748            .language_settings(cx)
18749            .show_edit_predictions;
18750
18751        let project = project.read(cx);
18752        telemetry::event!(
18753            event_type,
18754            file_extension,
18755            vim_mode,
18756            copilot_enabled,
18757            copilot_enabled_for_language,
18758            edit_predictions_provider,
18759            is_via_ssh = project.is_via_ssh(),
18760        );
18761    }
18762
18763    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18764    /// with each line being an array of {text, highlight} objects.
18765    fn copy_highlight_json(
18766        &mut self,
18767        _: &CopyHighlightJson,
18768        window: &mut Window,
18769        cx: &mut Context<Self>,
18770    ) {
18771        #[derive(Serialize)]
18772        struct Chunk<'a> {
18773            text: String,
18774            highlight: Option<&'a str>,
18775        }
18776
18777        let snapshot = self.buffer.read(cx).snapshot(cx);
18778        let range = self
18779            .selected_text_range(false, window, cx)
18780            .and_then(|selection| {
18781                if selection.range.is_empty() {
18782                    None
18783                } else {
18784                    Some(selection.range)
18785                }
18786            })
18787            .unwrap_or_else(|| 0..snapshot.len());
18788
18789        let chunks = snapshot.chunks(range, true);
18790        let mut lines = Vec::new();
18791        let mut line: VecDeque<Chunk> = VecDeque::new();
18792
18793        let Some(style) = self.style.as_ref() else {
18794            return;
18795        };
18796
18797        for chunk in chunks {
18798            let highlight = chunk
18799                .syntax_highlight_id
18800                .and_then(|id| id.name(&style.syntax));
18801            let mut chunk_lines = chunk.text.split('\n').peekable();
18802            while let Some(text) = chunk_lines.next() {
18803                let mut merged_with_last_token = false;
18804                if let Some(last_token) = line.back_mut() {
18805                    if last_token.highlight == highlight {
18806                        last_token.text.push_str(text);
18807                        merged_with_last_token = true;
18808                    }
18809                }
18810
18811                if !merged_with_last_token {
18812                    line.push_back(Chunk {
18813                        text: text.into(),
18814                        highlight,
18815                    });
18816                }
18817
18818                if chunk_lines.peek().is_some() {
18819                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18820                        line.pop_front();
18821                    }
18822                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18823                        line.pop_back();
18824                    }
18825
18826                    lines.push(mem::take(&mut line));
18827                }
18828            }
18829        }
18830
18831        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18832            return;
18833        };
18834        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18835    }
18836
18837    pub fn open_context_menu(
18838        &mut self,
18839        _: &OpenContextMenu,
18840        window: &mut Window,
18841        cx: &mut Context<Self>,
18842    ) {
18843        self.request_autoscroll(Autoscroll::newest(), cx);
18844        let position = self.selections.newest_display(cx).start;
18845        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18846    }
18847
18848    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18849        &self.inlay_hint_cache
18850    }
18851
18852    pub fn replay_insert_event(
18853        &mut self,
18854        text: &str,
18855        relative_utf16_range: Option<Range<isize>>,
18856        window: &mut Window,
18857        cx: &mut Context<Self>,
18858    ) {
18859        if !self.input_enabled {
18860            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18861            return;
18862        }
18863        if let Some(relative_utf16_range) = relative_utf16_range {
18864            let selections = self.selections.all::<OffsetUtf16>(cx);
18865            self.change_selections(None, window, cx, |s| {
18866                let new_ranges = selections.into_iter().map(|range| {
18867                    let start = OffsetUtf16(
18868                        range
18869                            .head()
18870                            .0
18871                            .saturating_add_signed(relative_utf16_range.start),
18872                    );
18873                    let end = OffsetUtf16(
18874                        range
18875                            .head()
18876                            .0
18877                            .saturating_add_signed(relative_utf16_range.end),
18878                    );
18879                    start..end
18880                });
18881                s.select_ranges(new_ranges);
18882            });
18883        }
18884
18885        self.handle_input(text, window, cx);
18886    }
18887
18888    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18889        let Some(provider) = self.semantics_provider.as_ref() else {
18890            return false;
18891        };
18892
18893        let mut supports = false;
18894        self.buffer().update(cx, |this, cx| {
18895            this.for_each_buffer(|buffer| {
18896                supports |= provider.supports_inlay_hints(buffer, cx);
18897            });
18898        });
18899
18900        supports
18901    }
18902
18903    pub fn is_focused(&self, window: &Window) -> bool {
18904        self.focus_handle.is_focused(window)
18905    }
18906
18907    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18908        cx.emit(EditorEvent::Focused);
18909
18910        if let Some(descendant) = self
18911            .last_focused_descendant
18912            .take()
18913            .and_then(|descendant| descendant.upgrade())
18914        {
18915            window.focus(&descendant);
18916        } else {
18917            if let Some(blame) = self.blame.as_ref() {
18918                blame.update(cx, GitBlame::focus)
18919            }
18920
18921            self.blink_manager.update(cx, BlinkManager::enable);
18922            self.show_cursor_names(window, cx);
18923            self.buffer.update(cx, |buffer, cx| {
18924                buffer.finalize_last_transaction(cx);
18925                if self.leader_id.is_none() {
18926                    buffer.set_active_selections(
18927                        &self.selections.disjoint_anchors(),
18928                        self.selections.line_mode,
18929                        self.cursor_shape,
18930                        cx,
18931                    );
18932                }
18933            });
18934        }
18935    }
18936
18937    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18938        cx.emit(EditorEvent::FocusedIn)
18939    }
18940
18941    fn handle_focus_out(
18942        &mut self,
18943        event: FocusOutEvent,
18944        _window: &mut Window,
18945        cx: &mut Context<Self>,
18946    ) {
18947        if event.blurred != self.focus_handle {
18948            self.last_focused_descendant = Some(event.blurred);
18949        }
18950        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18951    }
18952
18953    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18954        self.blink_manager.update(cx, BlinkManager::disable);
18955        self.buffer
18956            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18957
18958        if let Some(blame) = self.blame.as_ref() {
18959            blame.update(cx, GitBlame::blur)
18960        }
18961        if !self.hover_state.focused(window, cx) {
18962            hide_hover(self, cx);
18963        }
18964        if !self
18965            .context_menu
18966            .borrow()
18967            .as_ref()
18968            .is_some_and(|context_menu| context_menu.focused(window, cx))
18969        {
18970            self.hide_context_menu(window, cx);
18971        }
18972        self.discard_inline_completion(false, cx);
18973        cx.emit(EditorEvent::Blurred);
18974        cx.notify();
18975    }
18976
18977    pub fn register_action<A: Action>(
18978        &mut self,
18979        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
18980    ) -> Subscription {
18981        let id = self.next_editor_action_id.post_inc();
18982        let listener = Arc::new(listener);
18983        self.editor_actions.borrow_mut().insert(
18984            id,
18985            Box::new(move |window, _| {
18986                let listener = listener.clone();
18987                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
18988                    let action = action.downcast_ref().unwrap();
18989                    if phase == DispatchPhase::Bubble {
18990                        listener(action, window, cx)
18991                    }
18992                })
18993            }),
18994        );
18995
18996        let editor_actions = self.editor_actions.clone();
18997        Subscription::new(move || {
18998            editor_actions.borrow_mut().remove(&id);
18999        })
19000    }
19001
19002    pub fn file_header_size(&self) -> u32 {
19003        FILE_HEADER_HEIGHT
19004    }
19005
19006    pub fn restore(
19007        &mut self,
19008        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19009        window: &mut Window,
19010        cx: &mut Context<Self>,
19011    ) {
19012        let workspace = self.workspace();
19013        let project = self.project.as_ref();
19014        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19015            let mut tasks = Vec::new();
19016            for (buffer_id, changes) in revert_changes {
19017                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19018                    buffer.update(cx, |buffer, cx| {
19019                        buffer.edit(
19020                            changes
19021                                .into_iter()
19022                                .map(|(range, text)| (range, text.to_string())),
19023                            None,
19024                            cx,
19025                        );
19026                    });
19027
19028                    if let Some(project) =
19029                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19030                    {
19031                        project.update(cx, |project, cx| {
19032                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19033                        })
19034                    }
19035                }
19036            }
19037            tasks
19038        });
19039        cx.spawn_in(window, async move |_, cx| {
19040            for (buffer, task) in save_tasks {
19041                let result = task.await;
19042                if result.is_err() {
19043                    let Some(path) = buffer
19044                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19045                        .ok()
19046                    else {
19047                        continue;
19048                    };
19049                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19050                        let Some(task) = cx
19051                            .update_window_entity(&workspace, |workspace, window, cx| {
19052                                workspace
19053                                    .open_path_preview(path, None, false, false, false, window, cx)
19054                            })
19055                            .ok()
19056                        else {
19057                            continue;
19058                        };
19059                        task.await.log_err();
19060                    }
19061                }
19062            }
19063        })
19064        .detach();
19065        self.change_selections(None, window, cx, |selections| selections.refresh());
19066    }
19067
19068    pub fn to_pixel_point(
19069        &self,
19070        source: multi_buffer::Anchor,
19071        editor_snapshot: &EditorSnapshot,
19072        window: &mut Window,
19073    ) -> Option<gpui::Point<Pixels>> {
19074        let source_point = source.to_display_point(editor_snapshot);
19075        self.display_to_pixel_point(source_point, editor_snapshot, window)
19076    }
19077
19078    pub fn display_to_pixel_point(
19079        &self,
19080        source: DisplayPoint,
19081        editor_snapshot: &EditorSnapshot,
19082        window: &mut Window,
19083    ) -> Option<gpui::Point<Pixels>> {
19084        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19085        let text_layout_details = self.text_layout_details(window);
19086        let scroll_top = text_layout_details
19087            .scroll_anchor
19088            .scroll_position(editor_snapshot)
19089            .y;
19090
19091        if source.row().as_f32() < scroll_top.floor() {
19092            return None;
19093        }
19094        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19095        let source_y = line_height * (source.row().as_f32() - scroll_top);
19096        Some(gpui::Point::new(source_x, source_y))
19097    }
19098
19099    pub fn has_visible_completions_menu(&self) -> bool {
19100        !self.edit_prediction_preview_is_active()
19101            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19102                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19103            })
19104    }
19105
19106    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19107        if self.mode.is_minimap() {
19108            return;
19109        }
19110        self.addons
19111            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19112    }
19113
19114    pub fn unregister_addon<T: Addon>(&mut self) {
19115        self.addons.remove(&std::any::TypeId::of::<T>());
19116    }
19117
19118    pub fn addon<T: Addon>(&self) -> Option<&T> {
19119        let type_id = std::any::TypeId::of::<T>();
19120        self.addons
19121            .get(&type_id)
19122            .and_then(|item| item.to_any().downcast_ref::<T>())
19123    }
19124
19125    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19126        let type_id = std::any::TypeId::of::<T>();
19127        self.addons
19128            .get_mut(&type_id)
19129            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19130    }
19131
19132    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19133        let text_layout_details = self.text_layout_details(window);
19134        let style = &text_layout_details.editor_style;
19135        let font_id = window.text_system().resolve_font(&style.text.font());
19136        let font_size = style.text.font_size.to_pixels(window.rem_size());
19137        let line_height = style.text.line_height_in_pixels(window.rem_size());
19138        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19139
19140        gpui::Size::new(em_width, line_height)
19141    }
19142
19143    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19144        self.load_diff_task.clone()
19145    }
19146
19147    fn read_metadata_from_db(
19148        &mut self,
19149        item_id: u64,
19150        workspace_id: WorkspaceId,
19151        window: &mut Window,
19152        cx: &mut Context<Editor>,
19153    ) {
19154        if self.is_singleton(cx)
19155            && !self.mode.is_minimap()
19156            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19157        {
19158            let buffer_snapshot = OnceCell::new();
19159
19160            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19161                if !folds.is_empty() {
19162                    let snapshot =
19163                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19164                    self.fold_ranges(
19165                        folds
19166                            .into_iter()
19167                            .map(|(start, end)| {
19168                                snapshot.clip_offset(start, Bias::Left)
19169                                    ..snapshot.clip_offset(end, Bias::Right)
19170                            })
19171                            .collect(),
19172                        false,
19173                        window,
19174                        cx,
19175                    );
19176                }
19177            }
19178
19179            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19180                if !selections.is_empty() {
19181                    let snapshot =
19182                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19183                    self.change_selections(None, window, cx, |s| {
19184                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19185                            snapshot.clip_offset(start, Bias::Left)
19186                                ..snapshot.clip_offset(end, Bias::Right)
19187                        }));
19188                    });
19189                }
19190            };
19191        }
19192
19193        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19194    }
19195}
19196
19197fn vim_enabled(cx: &App) -> bool {
19198    cx.global::<SettingsStore>()
19199        .raw_user_settings()
19200        .get("vim_mode")
19201        == Some(&serde_json::Value::Bool(true))
19202}
19203
19204// Consider user intent and default settings
19205fn choose_completion_range(
19206    completion: &Completion,
19207    intent: CompletionIntent,
19208    buffer: &Entity<Buffer>,
19209    cx: &mut Context<Editor>,
19210) -> Range<usize> {
19211    fn should_replace(
19212        completion: &Completion,
19213        insert_range: &Range<text::Anchor>,
19214        intent: CompletionIntent,
19215        completion_mode_setting: LspInsertMode,
19216        buffer: &Buffer,
19217    ) -> bool {
19218        // specific actions take precedence over settings
19219        match intent {
19220            CompletionIntent::CompleteWithInsert => return false,
19221            CompletionIntent::CompleteWithReplace => return true,
19222            CompletionIntent::Complete | CompletionIntent::Compose => {}
19223        }
19224
19225        match completion_mode_setting {
19226            LspInsertMode::Insert => false,
19227            LspInsertMode::Replace => true,
19228            LspInsertMode::ReplaceSubsequence => {
19229                let mut text_to_replace = buffer.chars_for_range(
19230                    buffer.anchor_before(completion.replace_range.start)
19231                        ..buffer.anchor_after(completion.replace_range.end),
19232                );
19233                let mut completion_text = completion.new_text.chars();
19234
19235                // is `text_to_replace` a subsequence of `completion_text`
19236                text_to_replace
19237                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19238            }
19239            LspInsertMode::ReplaceSuffix => {
19240                let range_after_cursor = insert_range.end..completion.replace_range.end;
19241
19242                let text_after_cursor = buffer
19243                    .text_for_range(
19244                        buffer.anchor_before(range_after_cursor.start)
19245                            ..buffer.anchor_after(range_after_cursor.end),
19246                    )
19247                    .collect::<String>();
19248                completion.new_text.ends_with(&text_after_cursor)
19249            }
19250        }
19251    }
19252
19253    let buffer = buffer.read(cx);
19254
19255    if let CompletionSource::Lsp {
19256        insert_range: Some(insert_range),
19257        ..
19258    } = &completion.source
19259    {
19260        let completion_mode_setting =
19261            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19262                .completions
19263                .lsp_insert_mode;
19264
19265        if !should_replace(
19266            completion,
19267            &insert_range,
19268            intent,
19269            completion_mode_setting,
19270            buffer,
19271        ) {
19272            return insert_range.to_offset(buffer);
19273        }
19274    }
19275
19276    completion.replace_range.to_offset(buffer)
19277}
19278
19279fn insert_extra_newline_brackets(
19280    buffer: &MultiBufferSnapshot,
19281    range: Range<usize>,
19282    language: &language::LanguageScope,
19283) -> bool {
19284    let leading_whitespace_len = buffer
19285        .reversed_chars_at(range.start)
19286        .take_while(|c| c.is_whitespace() && *c != '\n')
19287        .map(|c| c.len_utf8())
19288        .sum::<usize>();
19289    let trailing_whitespace_len = buffer
19290        .chars_at(range.end)
19291        .take_while(|c| c.is_whitespace() && *c != '\n')
19292        .map(|c| c.len_utf8())
19293        .sum::<usize>();
19294    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19295
19296    language.brackets().any(|(pair, enabled)| {
19297        let pair_start = pair.start.trim_end();
19298        let pair_end = pair.end.trim_start();
19299
19300        enabled
19301            && pair.newline
19302            && buffer.contains_str_at(range.end, pair_end)
19303            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19304    })
19305}
19306
19307fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19308    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19309        [(buffer, range, _)] => (*buffer, range.clone()),
19310        _ => return false,
19311    };
19312    let pair = {
19313        let mut result: Option<BracketMatch> = None;
19314
19315        for pair in buffer
19316            .all_bracket_ranges(range.clone())
19317            .filter(move |pair| {
19318                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19319            })
19320        {
19321            let len = pair.close_range.end - pair.open_range.start;
19322
19323            if let Some(existing) = &result {
19324                let existing_len = existing.close_range.end - existing.open_range.start;
19325                if len > existing_len {
19326                    continue;
19327                }
19328            }
19329
19330            result = Some(pair);
19331        }
19332
19333        result
19334    };
19335    let Some(pair) = pair else {
19336        return false;
19337    };
19338    pair.newline_only
19339        && buffer
19340            .chars_for_range(pair.open_range.end..range.start)
19341            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19342            .all(|c| c.is_whitespace() && c != '\n')
19343}
19344
19345fn update_uncommitted_diff_for_buffer(
19346    editor: Entity<Editor>,
19347    project: &Entity<Project>,
19348    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19349    buffer: Entity<MultiBuffer>,
19350    cx: &mut App,
19351) -> Task<()> {
19352    let mut tasks = Vec::new();
19353    project.update(cx, |project, cx| {
19354        for buffer in buffers {
19355            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19356                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19357            }
19358        }
19359    });
19360    cx.spawn(async move |cx| {
19361        let diffs = future::join_all(tasks).await;
19362        if editor
19363            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19364            .unwrap_or(false)
19365        {
19366            return;
19367        }
19368
19369        buffer
19370            .update(cx, |buffer, cx| {
19371                for diff in diffs.into_iter().flatten() {
19372                    buffer.add_diff(diff, cx);
19373                }
19374            })
19375            .ok();
19376    })
19377}
19378
19379fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19380    let tab_size = tab_size.get() as usize;
19381    let mut width = offset;
19382
19383    for ch in text.chars() {
19384        width += if ch == '\t' {
19385            tab_size - (width % tab_size)
19386        } else {
19387            1
19388        };
19389    }
19390
19391    width - offset
19392}
19393
19394#[cfg(test)]
19395mod tests {
19396    use super::*;
19397
19398    #[test]
19399    fn test_string_size_with_expanded_tabs() {
19400        let nz = |val| NonZeroU32::new(val).unwrap();
19401        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19402        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19403        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19404        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19405        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19406        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19407        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19408        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19409    }
19410}
19411
19412/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19413struct WordBreakingTokenizer<'a> {
19414    input: &'a str,
19415}
19416
19417impl<'a> WordBreakingTokenizer<'a> {
19418    fn new(input: &'a str) -> Self {
19419        Self { input }
19420    }
19421}
19422
19423fn is_char_ideographic(ch: char) -> bool {
19424    use unicode_script::Script::*;
19425    use unicode_script::UnicodeScript;
19426    matches!(ch.script(), Han | Tangut | Yi)
19427}
19428
19429fn is_grapheme_ideographic(text: &str) -> bool {
19430    text.chars().any(is_char_ideographic)
19431}
19432
19433fn is_grapheme_whitespace(text: &str) -> bool {
19434    text.chars().any(|x| x.is_whitespace())
19435}
19436
19437fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19438    text.chars().next().map_or(false, |ch| {
19439        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19440    })
19441}
19442
19443#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19444enum WordBreakToken<'a> {
19445    Word { token: &'a str, grapheme_len: usize },
19446    InlineWhitespace { token: &'a str, grapheme_len: usize },
19447    Newline,
19448}
19449
19450impl<'a> Iterator for WordBreakingTokenizer<'a> {
19451    /// Yields a span, the count of graphemes in the token, and whether it was
19452    /// whitespace. Note that it also breaks at word boundaries.
19453    type Item = WordBreakToken<'a>;
19454
19455    fn next(&mut self) -> Option<Self::Item> {
19456        use unicode_segmentation::UnicodeSegmentation;
19457        if self.input.is_empty() {
19458            return None;
19459        }
19460
19461        let mut iter = self.input.graphemes(true).peekable();
19462        let mut offset = 0;
19463        let mut grapheme_len = 0;
19464        if let Some(first_grapheme) = iter.next() {
19465            let is_newline = first_grapheme == "\n";
19466            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19467            offset += first_grapheme.len();
19468            grapheme_len += 1;
19469            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19470                if let Some(grapheme) = iter.peek().copied() {
19471                    if should_stay_with_preceding_ideograph(grapheme) {
19472                        offset += grapheme.len();
19473                        grapheme_len += 1;
19474                    }
19475                }
19476            } else {
19477                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19478                let mut next_word_bound = words.peek().copied();
19479                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19480                    next_word_bound = words.next();
19481                }
19482                while let Some(grapheme) = iter.peek().copied() {
19483                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19484                        break;
19485                    };
19486                    if is_grapheme_whitespace(grapheme) != is_whitespace
19487                        || (grapheme == "\n") != is_newline
19488                    {
19489                        break;
19490                    };
19491                    offset += grapheme.len();
19492                    grapheme_len += 1;
19493                    iter.next();
19494                }
19495            }
19496            let token = &self.input[..offset];
19497            self.input = &self.input[offset..];
19498            if token == "\n" {
19499                Some(WordBreakToken::Newline)
19500            } else if is_whitespace {
19501                Some(WordBreakToken::InlineWhitespace {
19502                    token,
19503                    grapheme_len,
19504                })
19505            } else {
19506                Some(WordBreakToken::Word {
19507                    token,
19508                    grapheme_len,
19509                })
19510            }
19511        } else {
19512            None
19513        }
19514    }
19515}
19516
19517#[test]
19518fn test_word_breaking_tokenizer() {
19519    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19520        ("", &[]),
19521        ("  ", &[whitespace("  ", 2)]),
19522        ("Ʒ", &[word("Ʒ", 1)]),
19523        ("Ǽ", &[word("Ǽ", 1)]),
19524        ("", &[word("", 1)]),
19525        ("⋑⋑", &[word("⋑⋑", 2)]),
19526        (
19527            "原理,进而",
19528            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19529        ),
19530        (
19531            "hello world",
19532            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19533        ),
19534        (
19535            "hello, world",
19536            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19537        ),
19538        (
19539            "  hello world",
19540            &[
19541                whitespace("  ", 2),
19542                word("hello", 5),
19543                whitespace(" ", 1),
19544                word("world", 5),
19545            ],
19546        ),
19547        (
19548            "这是什么 \n 钢笔",
19549            &[
19550                word("", 1),
19551                word("", 1),
19552                word("", 1),
19553                word("", 1),
19554                whitespace(" ", 1),
19555                newline(),
19556                whitespace(" ", 1),
19557                word("", 1),
19558                word("", 1),
19559            ],
19560        ),
19561        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19562    ];
19563
19564    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19565        WordBreakToken::Word {
19566            token,
19567            grapheme_len,
19568        }
19569    }
19570
19571    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19572        WordBreakToken::InlineWhitespace {
19573            token,
19574            grapheme_len,
19575        }
19576    }
19577
19578    fn newline() -> WordBreakToken<'static> {
19579        WordBreakToken::Newline
19580    }
19581
19582    for (input, result) in tests {
19583        assert_eq!(
19584            WordBreakingTokenizer::new(input)
19585                .collect::<Vec<_>>()
19586                .as_slice(),
19587            *result,
19588        );
19589    }
19590}
19591
19592fn wrap_with_prefix(
19593    line_prefix: String,
19594    unwrapped_text: String,
19595    wrap_column: usize,
19596    tab_size: NonZeroU32,
19597    preserve_existing_whitespace: bool,
19598) -> String {
19599    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19600    let mut wrapped_text = String::new();
19601    let mut current_line = line_prefix.clone();
19602
19603    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19604    let mut current_line_len = line_prefix_len;
19605    let mut in_whitespace = false;
19606    for token in tokenizer {
19607        let have_preceding_whitespace = in_whitespace;
19608        match token {
19609            WordBreakToken::Word {
19610                token,
19611                grapheme_len,
19612            } => {
19613                in_whitespace = false;
19614                if current_line_len + grapheme_len > wrap_column
19615                    && current_line_len != line_prefix_len
19616                {
19617                    wrapped_text.push_str(current_line.trim_end());
19618                    wrapped_text.push('\n');
19619                    current_line.truncate(line_prefix.len());
19620                    current_line_len = line_prefix_len;
19621                }
19622                current_line.push_str(token);
19623                current_line_len += grapheme_len;
19624            }
19625            WordBreakToken::InlineWhitespace {
19626                mut token,
19627                mut grapheme_len,
19628            } => {
19629                in_whitespace = true;
19630                if have_preceding_whitespace && !preserve_existing_whitespace {
19631                    continue;
19632                }
19633                if !preserve_existing_whitespace {
19634                    token = " ";
19635                    grapheme_len = 1;
19636                }
19637                if current_line_len + grapheme_len > wrap_column {
19638                    wrapped_text.push_str(current_line.trim_end());
19639                    wrapped_text.push('\n');
19640                    current_line.truncate(line_prefix.len());
19641                    current_line_len = line_prefix_len;
19642                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19643                    current_line.push_str(token);
19644                    current_line_len += grapheme_len;
19645                }
19646            }
19647            WordBreakToken::Newline => {
19648                in_whitespace = true;
19649                if preserve_existing_whitespace {
19650                    wrapped_text.push_str(current_line.trim_end());
19651                    wrapped_text.push('\n');
19652                    current_line.truncate(line_prefix.len());
19653                    current_line_len = line_prefix_len;
19654                } else if have_preceding_whitespace {
19655                    continue;
19656                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19657                {
19658                    wrapped_text.push_str(current_line.trim_end());
19659                    wrapped_text.push('\n');
19660                    current_line.truncate(line_prefix.len());
19661                    current_line_len = line_prefix_len;
19662                } else if current_line_len != line_prefix_len {
19663                    current_line.push(' ');
19664                    current_line_len += 1;
19665                }
19666            }
19667        }
19668    }
19669
19670    if !current_line.is_empty() {
19671        wrapped_text.push_str(&current_line);
19672    }
19673    wrapped_text
19674}
19675
19676#[test]
19677fn test_wrap_with_prefix() {
19678    assert_eq!(
19679        wrap_with_prefix(
19680            "# ".to_string(),
19681            "abcdefg".to_string(),
19682            4,
19683            NonZeroU32::new(4).unwrap(),
19684            false,
19685        ),
19686        "# abcdefg"
19687    );
19688    assert_eq!(
19689        wrap_with_prefix(
19690            "".to_string(),
19691            "\thello world".to_string(),
19692            8,
19693            NonZeroU32::new(4).unwrap(),
19694            false,
19695        ),
19696        "hello\nworld"
19697    );
19698    assert_eq!(
19699        wrap_with_prefix(
19700            "// ".to_string(),
19701            "xx \nyy zz aa bb cc".to_string(),
19702            12,
19703            NonZeroU32::new(4).unwrap(),
19704            false,
19705        ),
19706        "// xx yy zz\n// aa bb cc"
19707    );
19708    assert_eq!(
19709        wrap_with_prefix(
19710            String::new(),
19711            "这是什么 \n 钢笔".to_string(),
19712            3,
19713            NonZeroU32::new(4).unwrap(),
19714            false,
19715        ),
19716        "这是什\n么 钢\n"
19717    );
19718}
19719
19720pub trait CollaborationHub {
19721    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19722    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19723    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19724}
19725
19726impl CollaborationHub for Entity<Project> {
19727    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19728        self.read(cx).collaborators()
19729    }
19730
19731    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19732        self.read(cx).user_store().read(cx).participant_indices()
19733    }
19734
19735    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19736        let this = self.read(cx);
19737        let user_ids = this.collaborators().values().map(|c| c.user_id);
19738        this.user_store().read_with(cx, |user_store, cx| {
19739            user_store.participant_names(user_ids, cx)
19740        })
19741    }
19742}
19743
19744pub trait SemanticsProvider {
19745    fn hover(
19746        &self,
19747        buffer: &Entity<Buffer>,
19748        position: text::Anchor,
19749        cx: &mut App,
19750    ) -> Option<Task<Vec<project::Hover>>>;
19751
19752    fn inline_values(
19753        &self,
19754        buffer_handle: Entity<Buffer>,
19755        range: Range<text::Anchor>,
19756        cx: &mut App,
19757    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19758
19759    fn inlay_hints(
19760        &self,
19761        buffer_handle: Entity<Buffer>,
19762        range: Range<text::Anchor>,
19763        cx: &mut App,
19764    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19765
19766    fn resolve_inlay_hint(
19767        &self,
19768        hint: InlayHint,
19769        buffer_handle: Entity<Buffer>,
19770        server_id: LanguageServerId,
19771        cx: &mut App,
19772    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19773
19774    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19775
19776    fn document_highlights(
19777        &self,
19778        buffer: &Entity<Buffer>,
19779        position: text::Anchor,
19780        cx: &mut App,
19781    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19782
19783    fn definitions(
19784        &self,
19785        buffer: &Entity<Buffer>,
19786        position: text::Anchor,
19787        kind: GotoDefinitionKind,
19788        cx: &mut App,
19789    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19790
19791    fn range_for_rename(
19792        &self,
19793        buffer: &Entity<Buffer>,
19794        position: text::Anchor,
19795        cx: &mut App,
19796    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19797
19798    fn perform_rename(
19799        &self,
19800        buffer: &Entity<Buffer>,
19801        position: text::Anchor,
19802        new_name: String,
19803        cx: &mut App,
19804    ) -> Option<Task<Result<ProjectTransaction>>>;
19805}
19806
19807pub trait CompletionProvider {
19808    fn completions(
19809        &self,
19810        excerpt_id: ExcerptId,
19811        buffer: &Entity<Buffer>,
19812        buffer_position: text::Anchor,
19813        trigger: CompletionContext,
19814        window: &mut Window,
19815        cx: &mut Context<Editor>,
19816    ) -> Task<Result<Option<Vec<Completion>>>>;
19817
19818    fn resolve_completions(
19819        &self,
19820        buffer: Entity<Buffer>,
19821        completion_indices: Vec<usize>,
19822        completions: Rc<RefCell<Box<[Completion]>>>,
19823        cx: &mut Context<Editor>,
19824    ) -> Task<Result<bool>>;
19825
19826    fn apply_additional_edits_for_completion(
19827        &self,
19828        _buffer: Entity<Buffer>,
19829        _completions: Rc<RefCell<Box<[Completion]>>>,
19830        _completion_index: usize,
19831        _push_to_history: bool,
19832        _cx: &mut Context<Editor>,
19833    ) -> Task<Result<Option<language::Transaction>>> {
19834        Task::ready(Ok(None))
19835    }
19836
19837    fn is_completion_trigger(
19838        &self,
19839        buffer: &Entity<Buffer>,
19840        position: language::Anchor,
19841        text: &str,
19842        trigger_in_words: bool,
19843        cx: &mut Context<Editor>,
19844    ) -> bool;
19845
19846    fn sort_completions(&self) -> bool {
19847        true
19848    }
19849
19850    fn filter_completions(&self) -> bool {
19851        true
19852    }
19853}
19854
19855pub trait CodeActionProvider {
19856    fn id(&self) -> Arc<str>;
19857
19858    fn code_actions(
19859        &self,
19860        buffer: &Entity<Buffer>,
19861        range: Range<text::Anchor>,
19862        window: &mut Window,
19863        cx: &mut App,
19864    ) -> Task<Result<Vec<CodeAction>>>;
19865
19866    fn apply_code_action(
19867        &self,
19868        buffer_handle: Entity<Buffer>,
19869        action: CodeAction,
19870        excerpt_id: ExcerptId,
19871        push_to_history: bool,
19872        window: &mut Window,
19873        cx: &mut App,
19874    ) -> Task<Result<ProjectTransaction>>;
19875}
19876
19877impl CodeActionProvider for Entity<Project> {
19878    fn id(&self) -> Arc<str> {
19879        "project".into()
19880    }
19881
19882    fn code_actions(
19883        &self,
19884        buffer: &Entity<Buffer>,
19885        range: Range<text::Anchor>,
19886        _window: &mut Window,
19887        cx: &mut App,
19888    ) -> Task<Result<Vec<CodeAction>>> {
19889        self.update(cx, |project, cx| {
19890            let code_lens = project.code_lens(buffer, range.clone(), cx);
19891            let code_actions = project.code_actions(buffer, range, None, cx);
19892            cx.background_spawn(async move {
19893                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19894                Ok(code_lens
19895                    .context("code lens fetch")?
19896                    .into_iter()
19897                    .chain(code_actions.context("code action fetch")?)
19898                    .collect())
19899            })
19900        })
19901    }
19902
19903    fn apply_code_action(
19904        &self,
19905        buffer_handle: Entity<Buffer>,
19906        action: CodeAction,
19907        _excerpt_id: ExcerptId,
19908        push_to_history: bool,
19909        _window: &mut Window,
19910        cx: &mut App,
19911    ) -> Task<Result<ProjectTransaction>> {
19912        self.update(cx, |project, cx| {
19913            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19914        })
19915    }
19916}
19917
19918fn snippet_completions(
19919    project: &Project,
19920    buffer: &Entity<Buffer>,
19921    buffer_position: text::Anchor,
19922    cx: &mut App,
19923) -> Task<Result<Vec<Completion>>> {
19924    let languages = buffer.read(cx).languages_at(buffer_position);
19925    let snippet_store = project.snippets().read(cx);
19926
19927    let scopes: Vec<_> = languages
19928        .iter()
19929        .filter_map(|language| {
19930            let language_name = language.lsp_id();
19931            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19932
19933            if snippets.is_empty() {
19934                None
19935            } else {
19936                Some((language.default_scope(), snippets))
19937            }
19938        })
19939        .collect();
19940
19941    if scopes.is_empty() {
19942        return Task::ready(Ok(vec![]));
19943    }
19944
19945    let snapshot = buffer.read(cx).text_snapshot();
19946    let chars: String = snapshot
19947        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19948        .collect();
19949    let executor = cx.background_executor().clone();
19950
19951    cx.background_spawn(async move {
19952        let mut all_results: Vec<Completion> = Vec::new();
19953        for (scope, snippets) in scopes.into_iter() {
19954            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19955            let mut last_word = chars
19956                .chars()
19957                .take_while(|c| classifier.is_word(*c))
19958                .collect::<String>();
19959            last_word = last_word.chars().rev().collect();
19960
19961            if last_word.is_empty() {
19962                return Ok(vec![]);
19963            }
19964
19965            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19966            let to_lsp = |point: &text::Anchor| {
19967                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19968                point_to_lsp(end)
19969            };
19970            let lsp_end = to_lsp(&buffer_position);
19971
19972            let candidates = snippets
19973                .iter()
19974                .enumerate()
19975                .flat_map(|(ix, snippet)| {
19976                    snippet
19977                        .prefix
19978                        .iter()
19979                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19980                })
19981                .collect::<Vec<StringMatchCandidate>>();
19982
19983            let mut matches = fuzzy::match_strings(
19984                &candidates,
19985                &last_word,
19986                last_word.chars().any(|c| c.is_uppercase()),
19987                100,
19988                &Default::default(),
19989                executor.clone(),
19990            )
19991            .await;
19992
19993            // Remove all candidates where the query's start does not match the start of any word in the candidate
19994            if let Some(query_start) = last_word.chars().next() {
19995                matches.retain(|string_match| {
19996                    split_words(&string_match.string).any(|word| {
19997                        // Check that the first codepoint of the word as lowercase matches the first
19998                        // codepoint of the query as lowercase
19999                        word.chars()
20000                            .flat_map(|codepoint| codepoint.to_lowercase())
20001                            .zip(query_start.to_lowercase())
20002                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20003                    })
20004                });
20005            }
20006
20007            let matched_strings = matches
20008                .into_iter()
20009                .map(|m| m.string)
20010                .collect::<HashSet<_>>();
20011
20012            let mut result: Vec<Completion> = snippets
20013                .iter()
20014                .filter_map(|snippet| {
20015                    let matching_prefix = snippet
20016                        .prefix
20017                        .iter()
20018                        .find(|prefix| matched_strings.contains(*prefix))?;
20019                    let start = as_offset - last_word.len();
20020                    let start = snapshot.anchor_before(start);
20021                    let range = start..buffer_position;
20022                    let lsp_start = to_lsp(&start);
20023                    let lsp_range = lsp::Range {
20024                        start: lsp_start,
20025                        end: lsp_end,
20026                    };
20027                    Some(Completion {
20028                        replace_range: range,
20029                        new_text: snippet.body.clone(),
20030                        source: CompletionSource::Lsp {
20031                            insert_range: None,
20032                            server_id: LanguageServerId(usize::MAX),
20033                            resolved: true,
20034                            lsp_completion: Box::new(lsp::CompletionItem {
20035                                label: snippet.prefix.first().unwrap().clone(),
20036                                kind: Some(CompletionItemKind::SNIPPET),
20037                                label_details: snippet.description.as_ref().map(|description| {
20038                                    lsp::CompletionItemLabelDetails {
20039                                        detail: Some(description.clone()),
20040                                        description: None,
20041                                    }
20042                                }),
20043                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20044                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20045                                    lsp::InsertReplaceEdit {
20046                                        new_text: snippet.body.clone(),
20047                                        insert: lsp_range,
20048                                        replace: lsp_range,
20049                                    },
20050                                )),
20051                                filter_text: Some(snippet.body.clone()),
20052                                sort_text: Some(char::MAX.to_string()),
20053                                ..lsp::CompletionItem::default()
20054                            }),
20055                            lsp_defaults: None,
20056                        },
20057                        label: CodeLabel {
20058                            text: matching_prefix.clone(),
20059                            runs: Vec::new(),
20060                            filter_range: 0..matching_prefix.len(),
20061                        },
20062                        icon_path: None,
20063                        documentation: Some(
20064                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20065                                single_line: snippet.name.clone().into(),
20066                                plain_text: snippet
20067                                    .description
20068                                    .clone()
20069                                    .map(|description| description.into()),
20070                            },
20071                        ),
20072                        insert_text_mode: None,
20073                        confirm: None,
20074                    })
20075                })
20076                .collect();
20077
20078            all_results.append(&mut result);
20079        }
20080
20081        Ok(all_results)
20082    })
20083}
20084
20085impl CompletionProvider for Entity<Project> {
20086    fn completions(
20087        &self,
20088        _excerpt_id: ExcerptId,
20089        buffer: &Entity<Buffer>,
20090        buffer_position: text::Anchor,
20091        options: CompletionContext,
20092        _window: &mut Window,
20093        cx: &mut Context<Editor>,
20094    ) -> Task<Result<Option<Vec<Completion>>>> {
20095        self.update(cx, |project, cx| {
20096            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20097            let project_completions = project.completions(buffer, buffer_position, options, cx);
20098            cx.background_spawn(async move {
20099                let snippets_completions = snippets.await?;
20100                match project_completions.await? {
20101                    Some(mut completions) => {
20102                        completions.extend(snippets_completions);
20103                        Ok(Some(completions))
20104                    }
20105                    None => {
20106                        if snippets_completions.is_empty() {
20107                            Ok(None)
20108                        } else {
20109                            Ok(Some(snippets_completions))
20110                        }
20111                    }
20112                }
20113            })
20114        })
20115    }
20116
20117    fn resolve_completions(
20118        &self,
20119        buffer: Entity<Buffer>,
20120        completion_indices: Vec<usize>,
20121        completions: Rc<RefCell<Box<[Completion]>>>,
20122        cx: &mut Context<Editor>,
20123    ) -> Task<Result<bool>> {
20124        self.update(cx, |project, cx| {
20125            project.lsp_store().update(cx, |lsp_store, cx| {
20126                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20127            })
20128        })
20129    }
20130
20131    fn apply_additional_edits_for_completion(
20132        &self,
20133        buffer: Entity<Buffer>,
20134        completions: Rc<RefCell<Box<[Completion]>>>,
20135        completion_index: usize,
20136        push_to_history: bool,
20137        cx: &mut Context<Editor>,
20138    ) -> Task<Result<Option<language::Transaction>>> {
20139        self.update(cx, |project, cx| {
20140            project.lsp_store().update(cx, |lsp_store, cx| {
20141                lsp_store.apply_additional_edits_for_completion(
20142                    buffer,
20143                    completions,
20144                    completion_index,
20145                    push_to_history,
20146                    cx,
20147                )
20148            })
20149        })
20150    }
20151
20152    fn is_completion_trigger(
20153        &self,
20154        buffer: &Entity<Buffer>,
20155        position: language::Anchor,
20156        text: &str,
20157        trigger_in_words: bool,
20158        cx: &mut Context<Editor>,
20159    ) -> bool {
20160        let mut chars = text.chars();
20161        let char = if let Some(char) = chars.next() {
20162            char
20163        } else {
20164            return false;
20165        };
20166        if chars.next().is_some() {
20167            return false;
20168        }
20169
20170        let buffer = buffer.read(cx);
20171        let snapshot = buffer.snapshot();
20172        if !snapshot.settings_at(position, cx).show_completions_on_input {
20173            return false;
20174        }
20175        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20176        if trigger_in_words && classifier.is_word(char) {
20177            return true;
20178        }
20179
20180        buffer.completion_triggers().contains(text)
20181    }
20182}
20183
20184impl SemanticsProvider for Entity<Project> {
20185    fn hover(
20186        &self,
20187        buffer: &Entity<Buffer>,
20188        position: text::Anchor,
20189        cx: &mut App,
20190    ) -> Option<Task<Vec<project::Hover>>> {
20191        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20192    }
20193
20194    fn document_highlights(
20195        &self,
20196        buffer: &Entity<Buffer>,
20197        position: text::Anchor,
20198        cx: &mut App,
20199    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20200        Some(self.update(cx, |project, cx| {
20201            project.document_highlights(buffer, position, cx)
20202        }))
20203    }
20204
20205    fn definitions(
20206        &self,
20207        buffer: &Entity<Buffer>,
20208        position: text::Anchor,
20209        kind: GotoDefinitionKind,
20210        cx: &mut App,
20211    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20212        Some(self.update(cx, |project, cx| match kind {
20213            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20214            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20215            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20216            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20217        }))
20218    }
20219
20220    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20221        // TODO: make this work for remote projects
20222        self.update(cx, |project, cx| {
20223            if project
20224                .active_debug_session(cx)
20225                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20226            {
20227                return true;
20228            }
20229
20230            buffer.update(cx, |buffer, cx| {
20231                project.any_language_server_supports_inlay_hints(buffer, cx)
20232            })
20233        })
20234    }
20235
20236    fn inline_values(
20237        &self,
20238        buffer_handle: Entity<Buffer>,
20239        range: Range<text::Anchor>,
20240        cx: &mut App,
20241    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20242        self.update(cx, |project, cx| {
20243            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20244
20245            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20246        })
20247    }
20248
20249    fn inlay_hints(
20250        &self,
20251        buffer_handle: Entity<Buffer>,
20252        range: Range<text::Anchor>,
20253        cx: &mut App,
20254    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20255        Some(self.update(cx, |project, cx| {
20256            project.inlay_hints(buffer_handle, range, cx)
20257        }))
20258    }
20259
20260    fn resolve_inlay_hint(
20261        &self,
20262        hint: InlayHint,
20263        buffer_handle: Entity<Buffer>,
20264        server_id: LanguageServerId,
20265        cx: &mut App,
20266    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20267        Some(self.update(cx, |project, cx| {
20268            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20269        }))
20270    }
20271
20272    fn range_for_rename(
20273        &self,
20274        buffer: &Entity<Buffer>,
20275        position: text::Anchor,
20276        cx: &mut App,
20277    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20278        Some(self.update(cx, |project, cx| {
20279            let buffer = buffer.clone();
20280            let task = project.prepare_rename(buffer.clone(), position, cx);
20281            cx.spawn(async move |_, cx| {
20282                Ok(match task.await? {
20283                    PrepareRenameResponse::Success(range) => Some(range),
20284                    PrepareRenameResponse::InvalidPosition => None,
20285                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20286                        // Fallback on using TreeSitter info to determine identifier range
20287                        buffer.update(cx, |buffer, _| {
20288                            let snapshot = buffer.snapshot();
20289                            let (range, kind) = snapshot.surrounding_word(position);
20290                            if kind != Some(CharKind::Word) {
20291                                return None;
20292                            }
20293                            Some(
20294                                snapshot.anchor_before(range.start)
20295                                    ..snapshot.anchor_after(range.end),
20296                            )
20297                        })?
20298                    }
20299                })
20300            })
20301        }))
20302    }
20303
20304    fn perform_rename(
20305        &self,
20306        buffer: &Entity<Buffer>,
20307        position: text::Anchor,
20308        new_name: String,
20309        cx: &mut App,
20310    ) -> Option<Task<Result<ProjectTransaction>>> {
20311        Some(self.update(cx, |project, cx| {
20312            project.perform_rename(buffer.clone(), position, new_name, cx)
20313        }))
20314    }
20315}
20316
20317fn inlay_hint_settings(
20318    location: Anchor,
20319    snapshot: &MultiBufferSnapshot,
20320    cx: &mut Context<Editor>,
20321) -> InlayHintSettings {
20322    let file = snapshot.file_at(location);
20323    let language = snapshot.language_at(location).map(|l| l.name());
20324    language_settings(language, file, cx).inlay_hints
20325}
20326
20327fn consume_contiguous_rows(
20328    contiguous_row_selections: &mut Vec<Selection<Point>>,
20329    selection: &Selection<Point>,
20330    display_map: &DisplaySnapshot,
20331    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20332) -> (MultiBufferRow, MultiBufferRow) {
20333    contiguous_row_selections.push(selection.clone());
20334    let start_row = MultiBufferRow(selection.start.row);
20335    let mut end_row = ending_row(selection, display_map);
20336
20337    while let Some(next_selection) = selections.peek() {
20338        if next_selection.start.row <= end_row.0 {
20339            end_row = ending_row(next_selection, display_map);
20340            contiguous_row_selections.push(selections.next().unwrap().clone());
20341        } else {
20342            break;
20343        }
20344    }
20345    (start_row, end_row)
20346}
20347
20348fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20349    if next_selection.end.column > 0 || next_selection.is_empty() {
20350        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20351    } else {
20352        MultiBufferRow(next_selection.end.row)
20353    }
20354}
20355
20356impl EditorSnapshot {
20357    pub fn remote_selections_in_range<'a>(
20358        &'a self,
20359        range: &'a Range<Anchor>,
20360        collaboration_hub: &dyn CollaborationHub,
20361        cx: &'a App,
20362    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20363        let participant_names = collaboration_hub.user_names(cx);
20364        let participant_indices = collaboration_hub.user_participant_indices(cx);
20365        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20366        let collaborators_by_replica_id = collaborators_by_peer_id
20367            .values()
20368            .map(|collaborator| (collaborator.replica_id, collaborator))
20369            .collect::<HashMap<_, _>>();
20370        self.buffer_snapshot
20371            .selections_in_range(range, false)
20372            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20373                if replica_id == AGENT_REPLICA_ID {
20374                    Some(RemoteSelection {
20375                        replica_id,
20376                        selection,
20377                        cursor_shape,
20378                        line_mode,
20379                        collaborator_id: CollaboratorId::Agent,
20380                        user_name: Some("Agent".into()),
20381                        color: cx.theme().players().agent(),
20382                    })
20383                } else {
20384                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20385                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20386                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20387                    Some(RemoteSelection {
20388                        replica_id,
20389                        selection,
20390                        cursor_shape,
20391                        line_mode,
20392                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20393                        user_name,
20394                        color: if let Some(index) = participant_index {
20395                            cx.theme().players().color_for_participant(index.0)
20396                        } else {
20397                            cx.theme().players().absent()
20398                        },
20399                    })
20400                }
20401            })
20402    }
20403
20404    pub fn hunks_for_ranges(
20405        &self,
20406        ranges: impl IntoIterator<Item = Range<Point>>,
20407    ) -> Vec<MultiBufferDiffHunk> {
20408        let mut hunks = Vec::new();
20409        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20410            HashMap::default();
20411        for query_range in ranges {
20412            let query_rows =
20413                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20414            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20415                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20416            ) {
20417                // Include deleted hunks that are adjacent to the query range, because
20418                // otherwise they would be missed.
20419                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20420                if hunk.status().is_deleted() {
20421                    intersects_range |= hunk.row_range.start == query_rows.end;
20422                    intersects_range |= hunk.row_range.end == query_rows.start;
20423                }
20424                if intersects_range {
20425                    if !processed_buffer_rows
20426                        .entry(hunk.buffer_id)
20427                        .or_default()
20428                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20429                    {
20430                        continue;
20431                    }
20432                    hunks.push(hunk);
20433                }
20434            }
20435        }
20436
20437        hunks
20438    }
20439
20440    fn display_diff_hunks_for_rows<'a>(
20441        &'a self,
20442        display_rows: Range<DisplayRow>,
20443        folded_buffers: &'a HashSet<BufferId>,
20444    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20445        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20446        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20447
20448        self.buffer_snapshot
20449            .diff_hunks_in_range(buffer_start..buffer_end)
20450            .filter_map(|hunk| {
20451                if folded_buffers.contains(&hunk.buffer_id) {
20452                    return None;
20453                }
20454
20455                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20456                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20457
20458                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20459                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20460
20461                let display_hunk = if hunk_display_start.column() != 0 {
20462                    DisplayDiffHunk::Folded {
20463                        display_row: hunk_display_start.row(),
20464                    }
20465                } else {
20466                    let mut end_row = hunk_display_end.row();
20467                    if hunk_display_end.column() > 0 {
20468                        end_row.0 += 1;
20469                    }
20470                    let is_created_file = hunk.is_created_file();
20471                    DisplayDiffHunk::Unfolded {
20472                        status: hunk.status(),
20473                        diff_base_byte_range: hunk.diff_base_byte_range,
20474                        display_row_range: hunk_display_start.row()..end_row,
20475                        multi_buffer_range: Anchor::range_in_buffer(
20476                            hunk.excerpt_id,
20477                            hunk.buffer_id,
20478                            hunk.buffer_range,
20479                        ),
20480                        is_created_file,
20481                    }
20482                };
20483
20484                Some(display_hunk)
20485            })
20486    }
20487
20488    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20489        self.display_snapshot.buffer_snapshot.language_at(position)
20490    }
20491
20492    pub fn is_focused(&self) -> bool {
20493        self.is_focused
20494    }
20495
20496    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20497        self.placeholder_text.as_ref()
20498    }
20499
20500    pub fn scroll_position(&self) -> gpui::Point<f32> {
20501        self.scroll_anchor.scroll_position(&self.display_snapshot)
20502    }
20503
20504    fn gutter_dimensions(
20505        &self,
20506        font_id: FontId,
20507        font_size: Pixels,
20508        max_line_number_width: Pixels,
20509        cx: &App,
20510    ) -> Option<GutterDimensions> {
20511        if !self.show_gutter {
20512            return None;
20513        }
20514
20515        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20516        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20517
20518        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20519            matches!(
20520                ProjectSettings::get_global(cx).git.git_gutter,
20521                Some(GitGutterSetting::TrackedFiles)
20522            )
20523        });
20524        let gutter_settings = EditorSettings::get_global(cx).gutter;
20525        let show_line_numbers = self
20526            .show_line_numbers
20527            .unwrap_or(gutter_settings.line_numbers);
20528        let line_gutter_width = if show_line_numbers {
20529            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20530            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20531            max_line_number_width.max(min_width_for_number_on_gutter)
20532        } else {
20533            0.0.into()
20534        };
20535
20536        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20537        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20538
20539        let git_blame_entries_width =
20540            self.git_blame_gutter_max_author_length
20541                .map(|max_author_length| {
20542                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20543                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20544
20545                    /// The number of characters to dedicate to gaps and margins.
20546                    const SPACING_WIDTH: usize = 4;
20547
20548                    let max_char_count = max_author_length.min(renderer.max_author_length())
20549                        + ::git::SHORT_SHA_LENGTH
20550                        + MAX_RELATIVE_TIMESTAMP.len()
20551                        + SPACING_WIDTH;
20552
20553                    em_advance * max_char_count
20554                });
20555
20556        let is_singleton = self.buffer_snapshot.is_singleton();
20557
20558        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20559        left_padding += if !is_singleton {
20560            em_width * 4.0
20561        } else if show_runnables || show_breakpoints {
20562            em_width * 3.0
20563        } else if show_git_gutter && show_line_numbers {
20564            em_width * 2.0
20565        } else if show_git_gutter || show_line_numbers {
20566            em_width
20567        } else {
20568            px(0.)
20569        };
20570
20571        let shows_folds = is_singleton && gutter_settings.folds;
20572
20573        let right_padding = if shows_folds && show_line_numbers {
20574            em_width * 4.0
20575        } else if shows_folds || (!is_singleton && show_line_numbers) {
20576            em_width * 3.0
20577        } else if show_line_numbers {
20578            em_width
20579        } else {
20580            px(0.)
20581        };
20582
20583        Some(GutterDimensions {
20584            left_padding,
20585            right_padding,
20586            width: line_gutter_width + left_padding + right_padding,
20587            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20588            git_blame_entries_width,
20589        })
20590    }
20591
20592    pub fn render_crease_toggle(
20593        &self,
20594        buffer_row: MultiBufferRow,
20595        row_contains_cursor: bool,
20596        editor: Entity<Editor>,
20597        window: &mut Window,
20598        cx: &mut App,
20599    ) -> Option<AnyElement> {
20600        let folded = self.is_line_folded(buffer_row);
20601        let mut is_foldable = false;
20602
20603        if let Some(crease) = self
20604            .crease_snapshot
20605            .query_row(buffer_row, &self.buffer_snapshot)
20606        {
20607            is_foldable = true;
20608            match crease {
20609                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20610                    if let Some(render_toggle) = render_toggle {
20611                        let toggle_callback =
20612                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20613                                if folded {
20614                                    editor.update(cx, |editor, cx| {
20615                                        editor.fold_at(buffer_row, window, cx)
20616                                    });
20617                                } else {
20618                                    editor.update(cx, |editor, cx| {
20619                                        editor.unfold_at(buffer_row, window, cx)
20620                                    });
20621                                }
20622                            });
20623                        return Some((render_toggle)(
20624                            buffer_row,
20625                            folded,
20626                            toggle_callback,
20627                            window,
20628                            cx,
20629                        ));
20630                    }
20631                }
20632            }
20633        }
20634
20635        is_foldable |= self.starts_indent(buffer_row);
20636
20637        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20638            Some(
20639                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20640                    .toggle_state(folded)
20641                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20642                        if folded {
20643                            this.unfold_at(buffer_row, window, cx);
20644                        } else {
20645                            this.fold_at(buffer_row, window, cx);
20646                        }
20647                    }))
20648                    .into_any_element(),
20649            )
20650        } else {
20651            None
20652        }
20653    }
20654
20655    pub fn render_crease_trailer(
20656        &self,
20657        buffer_row: MultiBufferRow,
20658        window: &mut Window,
20659        cx: &mut App,
20660    ) -> Option<AnyElement> {
20661        let folded = self.is_line_folded(buffer_row);
20662        if let Crease::Inline { render_trailer, .. } = self
20663            .crease_snapshot
20664            .query_row(buffer_row, &self.buffer_snapshot)?
20665        {
20666            let render_trailer = render_trailer.as_ref()?;
20667            Some(render_trailer(buffer_row, folded, window, cx))
20668        } else {
20669            None
20670        }
20671    }
20672}
20673
20674impl Deref for EditorSnapshot {
20675    type Target = DisplaySnapshot;
20676
20677    fn deref(&self) -> &Self::Target {
20678        &self.display_snapshot
20679    }
20680}
20681
20682#[derive(Clone, Debug, PartialEq, Eq)]
20683pub enum EditorEvent {
20684    InputIgnored {
20685        text: Arc<str>,
20686    },
20687    InputHandled {
20688        utf16_range_to_replace: Option<Range<isize>>,
20689        text: Arc<str>,
20690    },
20691    ExcerptsAdded {
20692        buffer: Entity<Buffer>,
20693        predecessor: ExcerptId,
20694        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20695    },
20696    ExcerptsRemoved {
20697        ids: Vec<ExcerptId>,
20698        removed_buffer_ids: Vec<BufferId>,
20699    },
20700    BufferFoldToggled {
20701        ids: Vec<ExcerptId>,
20702        folded: bool,
20703    },
20704    ExcerptsEdited {
20705        ids: Vec<ExcerptId>,
20706    },
20707    ExcerptsExpanded {
20708        ids: Vec<ExcerptId>,
20709    },
20710    BufferEdited,
20711    Edited {
20712        transaction_id: clock::Lamport,
20713    },
20714    Reparsed(BufferId),
20715    Focused,
20716    FocusedIn,
20717    Blurred,
20718    DirtyChanged,
20719    Saved,
20720    TitleChanged,
20721    DiffBaseChanged,
20722    SelectionsChanged {
20723        local: bool,
20724    },
20725    ScrollPositionChanged {
20726        local: bool,
20727        autoscroll: bool,
20728    },
20729    Closed,
20730    TransactionUndone {
20731        transaction_id: clock::Lamport,
20732    },
20733    TransactionBegun {
20734        transaction_id: clock::Lamport,
20735    },
20736    Reloaded,
20737    CursorShapeChanged,
20738    PushedToNavHistory {
20739        anchor: Anchor,
20740        is_deactivate: bool,
20741    },
20742}
20743
20744impl EventEmitter<EditorEvent> for Editor {}
20745
20746impl Focusable for Editor {
20747    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20748        self.focus_handle.clone()
20749    }
20750}
20751
20752impl Render for Editor {
20753    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20754        let settings = ThemeSettings::get_global(cx);
20755
20756        let mut text_style = match self.mode {
20757            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20758                color: cx.theme().colors().editor_foreground,
20759                font_family: settings.ui_font.family.clone(),
20760                font_features: settings.ui_font.features.clone(),
20761                font_fallbacks: settings.ui_font.fallbacks.clone(),
20762                font_size: rems(0.875).into(),
20763                font_weight: settings.ui_font.weight,
20764                line_height: relative(settings.buffer_line_height.value()),
20765                ..Default::default()
20766            },
20767            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20768                color: cx.theme().colors().editor_foreground,
20769                font_family: settings.buffer_font.family.clone(),
20770                font_features: settings.buffer_font.features.clone(),
20771                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20772                font_size: settings.buffer_font_size(cx).into(),
20773                font_weight: settings.buffer_font.weight,
20774                line_height: relative(settings.buffer_line_height.value()),
20775                ..Default::default()
20776            },
20777        };
20778        if let Some(text_style_refinement) = &self.text_style_refinement {
20779            text_style.refine(text_style_refinement)
20780        }
20781
20782        let background = match self.mode {
20783            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20784            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20785            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20786            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20787        };
20788
20789        EditorElement::new(
20790            &cx.entity(),
20791            EditorStyle {
20792                background,
20793                local_player: cx.theme().players().local(),
20794                text: text_style,
20795                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20796                syntax: cx.theme().syntax().clone(),
20797                status: cx.theme().status().clone(),
20798                inlay_hints_style: make_inlay_hints_style(cx),
20799                inline_completion_styles: make_suggestion_styles(cx),
20800                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20801                show_underlines: !self.mode.is_minimap(),
20802            },
20803        )
20804    }
20805}
20806
20807impl EntityInputHandler for Editor {
20808    fn text_for_range(
20809        &mut self,
20810        range_utf16: Range<usize>,
20811        adjusted_range: &mut Option<Range<usize>>,
20812        _: &mut Window,
20813        cx: &mut Context<Self>,
20814    ) -> Option<String> {
20815        let snapshot = self.buffer.read(cx).read(cx);
20816        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20817        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20818        if (start.0..end.0) != range_utf16 {
20819            adjusted_range.replace(start.0..end.0);
20820        }
20821        Some(snapshot.text_for_range(start..end).collect())
20822    }
20823
20824    fn selected_text_range(
20825        &mut self,
20826        ignore_disabled_input: bool,
20827        _: &mut Window,
20828        cx: &mut Context<Self>,
20829    ) -> Option<UTF16Selection> {
20830        // Prevent the IME menu from appearing when holding down an alphabetic key
20831        // while input is disabled.
20832        if !ignore_disabled_input && !self.input_enabled {
20833            return None;
20834        }
20835
20836        let selection = self.selections.newest::<OffsetUtf16>(cx);
20837        let range = selection.range();
20838
20839        Some(UTF16Selection {
20840            range: range.start.0..range.end.0,
20841            reversed: selection.reversed,
20842        })
20843    }
20844
20845    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20846        let snapshot = self.buffer.read(cx).read(cx);
20847        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20848        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20849    }
20850
20851    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20852        self.clear_highlights::<InputComposition>(cx);
20853        self.ime_transaction.take();
20854    }
20855
20856    fn replace_text_in_range(
20857        &mut self,
20858        range_utf16: Option<Range<usize>>,
20859        text: &str,
20860        window: &mut Window,
20861        cx: &mut Context<Self>,
20862    ) {
20863        if !self.input_enabled {
20864            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20865            return;
20866        }
20867
20868        self.transact(window, cx, |this, window, cx| {
20869            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20870                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20871                Some(this.selection_replacement_ranges(range_utf16, cx))
20872            } else {
20873                this.marked_text_ranges(cx)
20874            };
20875
20876            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20877                let newest_selection_id = this.selections.newest_anchor().id;
20878                this.selections
20879                    .all::<OffsetUtf16>(cx)
20880                    .iter()
20881                    .zip(ranges_to_replace.iter())
20882                    .find_map(|(selection, range)| {
20883                        if selection.id == newest_selection_id {
20884                            Some(
20885                                (range.start.0 as isize - selection.head().0 as isize)
20886                                    ..(range.end.0 as isize - selection.head().0 as isize),
20887                            )
20888                        } else {
20889                            None
20890                        }
20891                    })
20892            });
20893
20894            cx.emit(EditorEvent::InputHandled {
20895                utf16_range_to_replace: range_to_replace,
20896                text: text.into(),
20897            });
20898
20899            if let Some(new_selected_ranges) = new_selected_ranges {
20900                this.change_selections(None, window, cx, |selections| {
20901                    selections.select_ranges(new_selected_ranges)
20902                });
20903                this.backspace(&Default::default(), window, cx);
20904            }
20905
20906            this.handle_input(text, window, cx);
20907        });
20908
20909        if let Some(transaction) = self.ime_transaction {
20910            self.buffer.update(cx, |buffer, cx| {
20911                buffer.group_until_transaction(transaction, cx);
20912            });
20913        }
20914
20915        self.unmark_text(window, cx);
20916    }
20917
20918    fn replace_and_mark_text_in_range(
20919        &mut self,
20920        range_utf16: Option<Range<usize>>,
20921        text: &str,
20922        new_selected_range_utf16: Option<Range<usize>>,
20923        window: &mut Window,
20924        cx: &mut Context<Self>,
20925    ) {
20926        if !self.input_enabled {
20927            return;
20928        }
20929
20930        let transaction = self.transact(window, cx, |this, window, cx| {
20931            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20932                let snapshot = this.buffer.read(cx).read(cx);
20933                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20934                    for marked_range in &mut marked_ranges {
20935                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20936                        marked_range.start.0 += relative_range_utf16.start;
20937                        marked_range.start =
20938                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20939                        marked_range.end =
20940                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20941                    }
20942                }
20943                Some(marked_ranges)
20944            } else if let Some(range_utf16) = range_utf16 {
20945                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20946                Some(this.selection_replacement_ranges(range_utf16, cx))
20947            } else {
20948                None
20949            };
20950
20951            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20952                let newest_selection_id = this.selections.newest_anchor().id;
20953                this.selections
20954                    .all::<OffsetUtf16>(cx)
20955                    .iter()
20956                    .zip(ranges_to_replace.iter())
20957                    .find_map(|(selection, range)| {
20958                        if selection.id == newest_selection_id {
20959                            Some(
20960                                (range.start.0 as isize - selection.head().0 as isize)
20961                                    ..(range.end.0 as isize - selection.head().0 as isize),
20962                            )
20963                        } else {
20964                            None
20965                        }
20966                    })
20967            });
20968
20969            cx.emit(EditorEvent::InputHandled {
20970                utf16_range_to_replace: range_to_replace,
20971                text: text.into(),
20972            });
20973
20974            if let Some(ranges) = ranges_to_replace {
20975                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20976            }
20977
20978            let marked_ranges = {
20979                let snapshot = this.buffer.read(cx).read(cx);
20980                this.selections
20981                    .disjoint_anchors()
20982                    .iter()
20983                    .map(|selection| {
20984                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20985                    })
20986                    .collect::<Vec<_>>()
20987            };
20988
20989            if text.is_empty() {
20990                this.unmark_text(window, cx);
20991            } else {
20992                this.highlight_text::<InputComposition>(
20993                    marked_ranges.clone(),
20994                    HighlightStyle {
20995                        underline: Some(UnderlineStyle {
20996                            thickness: px(1.),
20997                            color: None,
20998                            wavy: false,
20999                        }),
21000                        ..Default::default()
21001                    },
21002                    cx,
21003                );
21004            }
21005
21006            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21007            let use_autoclose = this.use_autoclose;
21008            let use_auto_surround = this.use_auto_surround;
21009            this.set_use_autoclose(false);
21010            this.set_use_auto_surround(false);
21011            this.handle_input(text, window, cx);
21012            this.set_use_autoclose(use_autoclose);
21013            this.set_use_auto_surround(use_auto_surround);
21014
21015            if let Some(new_selected_range) = new_selected_range_utf16 {
21016                let snapshot = this.buffer.read(cx).read(cx);
21017                let new_selected_ranges = marked_ranges
21018                    .into_iter()
21019                    .map(|marked_range| {
21020                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21021                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21022                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21023                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21024                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21025                    })
21026                    .collect::<Vec<_>>();
21027
21028                drop(snapshot);
21029                this.change_selections(None, window, cx, |selections| {
21030                    selections.select_ranges(new_selected_ranges)
21031                });
21032            }
21033        });
21034
21035        self.ime_transaction = self.ime_transaction.or(transaction);
21036        if let Some(transaction) = self.ime_transaction {
21037            self.buffer.update(cx, |buffer, cx| {
21038                buffer.group_until_transaction(transaction, cx);
21039            });
21040        }
21041
21042        if self.text_highlights::<InputComposition>(cx).is_none() {
21043            self.ime_transaction.take();
21044        }
21045    }
21046
21047    fn bounds_for_range(
21048        &mut self,
21049        range_utf16: Range<usize>,
21050        element_bounds: gpui::Bounds<Pixels>,
21051        window: &mut Window,
21052        cx: &mut Context<Self>,
21053    ) -> Option<gpui::Bounds<Pixels>> {
21054        let text_layout_details = self.text_layout_details(window);
21055        let gpui::Size {
21056            width: em_width,
21057            height: line_height,
21058        } = self.character_size(window);
21059
21060        let snapshot = self.snapshot(window, cx);
21061        let scroll_position = snapshot.scroll_position();
21062        let scroll_left = scroll_position.x * em_width;
21063
21064        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21065        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21066            + self.gutter_dimensions.width
21067            + self.gutter_dimensions.margin;
21068        let y = line_height * (start.row().as_f32() - scroll_position.y);
21069
21070        Some(Bounds {
21071            origin: element_bounds.origin + point(x, y),
21072            size: size(em_width, line_height),
21073        })
21074    }
21075
21076    fn character_index_for_point(
21077        &mut self,
21078        point: gpui::Point<Pixels>,
21079        _window: &mut Window,
21080        _cx: &mut Context<Self>,
21081    ) -> Option<usize> {
21082        let position_map = self.last_position_map.as_ref()?;
21083        if !position_map.text_hitbox.contains(&point) {
21084            return None;
21085        }
21086        let display_point = position_map.point_for_position(point).previous_valid;
21087        let anchor = position_map
21088            .snapshot
21089            .display_point_to_anchor(display_point, Bias::Left);
21090        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21091        Some(utf16_offset.0)
21092    }
21093}
21094
21095trait SelectionExt {
21096    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21097    fn spanned_rows(
21098        &self,
21099        include_end_if_at_line_start: bool,
21100        map: &DisplaySnapshot,
21101    ) -> Range<MultiBufferRow>;
21102}
21103
21104impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21105    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21106        let start = self
21107            .start
21108            .to_point(&map.buffer_snapshot)
21109            .to_display_point(map);
21110        let end = self
21111            .end
21112            .to_point(&map.buffer_snapshot)
21113            .to_display_point(map);
21114        if self.reversed {
21115            end..start
21116        } else {
21117            start..end
21118        }
21119    }
21120
21121    fn spanned_rows(
21122        &self,
21123        include_end_if_at_line_start: bool,
21124        map: &DisplaySnapshot,
21125    ) -> Range<MultiBufferRow> {
21126        let start = self.start.to_point(&map.buffer_snapshot);
21127        let mut end = self.end.to_point(&map.buffer_snapshot);
21128        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21129            end.row -= 1;
21130        }
21131
21132        let buffer_start = map.prev_line_boundary(start).0;
21133        let buffer_end = map.next_line_boundary(end).0;
21134        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21135    }
21136}
21137
21138impl<T: InvalidationRegion> InvalidationStack<T> {
21139    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21140    where
21141        S: Clone + ToOffset,
21142    {
21143        while let Some(region) = self.last() {
21144            let all_selections_inside_invalidation_ranges =
21145                if selections.len() == region.ranges().len() {
21146                    selections
21147                        .iter()
21148                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21149                        .all(|(selection, invalidation_range)| {
21150                            let head = selection.head().to_offset(buffer);
21151                            invalidation_range.start <= head && invalidation_range.end >= head
21152                        })
21153                } else {
21154                    false
21155                };
21156
21157            if all_selections_inside_invalidation_ranges {
21158                break;
21159            } else {
21160                self.pop();
21161            }
21162        }
21163    }
21164}
21165
21166impl<T> Default for InvalidationStack<T> {
21167    fn default() -> Self {
21168        Self(Default::default())
21169    }
21170}
21171
21172impl<T> Deref for InvalidationStack<T> {
21173    type Target = Vec<T>;
21174
21175    fn deref(&self) -> &Self::Target {
21176        &self.0
21177    }
21178}
21179
21180impl<T> DerefMut for InvalidationStack<T> {
21181    fn deref_mut(&mut self) -> &mut Self::Target {
21182        &mut self.0
21183    }
21184}
21185
21186impl InvalidationRegion for SnippetState {
21187    fn ranges(&self) -> &[Range<Anchor>] {
21188        &self.ranges[self.active_index]
21189    }
21190}
21191
21192fn inline_completion_edit_text(
21193    current_snapshot: &BufferSnapshot,
21194    edits: &[(Range<Anchor>, String)],
21195    edit_preview: &EditPreview,
21196    include_deletions: bool,
21197    cx: &App,
21198) -> HighlightedText {
21199    let edits = edits
21200        .iter()
21201        .map(|(anchor, text)| {
21202            (
21203                anchor.start.text_anchor..anchor.end.text_anchor,
21204                text.clone(),
21205            )
21206        })
21207        .collect::<Vec<_>>();
21208
21209    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21210}
21211
21212pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21213    match severity {
21214        lsp::DiagnosticSeverity::ERROR => colors.error,
21215        lsp::DiagnosticSeverity::WARNING => colors.warning,
21216        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21217        lsp::DiagnosticSeverity::HINT => colors.info,
21218        _ => colors.ignored,
21219    }
21220}
21221
21222pub fn styled_runs_for_code_label<'a>(
21223    label: &'a CodeLabel,
21224    syntax_theme: &'a theme::SyntaxTheme,
21225) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21226    let fade_out = HighlightStyle {
21227        fade_out: Some(0.35),
21228        ..Default::default()
21229    };
21230
21231    let mut prev_end = label.filter_range.end;
21232    label
21233        .runs
21234        .iter()
21235        .enumerate()
21236        .flat_map(move |(ix, (range, highlight_id))| {
21237            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21238                style
21239            } else {
21240                return Default::default();
21241            };
21242            let mut muted_style = style;
21243            muted_style.highlight(fade_out);
21244
21245            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21246            if range.start >= label.filter_range.end {
21247                if range.start > prev_end {
21248                    runs.push((prev_end..range.start, fade_out));
21249                }
21250                runs.push((range.clone(), muted_style));
21251            } else if range.end <= label.filter_range.end {
21252                runs.push((range.clone(), style));
21253            } else {
21254                runs.push((range.start..label.filter_range.end, style));
21255                runs.push((label.filter_range.end..range.end, muted_style));
21256            }
21257            prev_end = cmp::max(prev_end, range.end);
21258
21259            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21260                runs.push((prev_end..label.text.len(), fade_out));
21261            }
21262
21263            runs
21264        })
21265}
21266
21267pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21268    let mut prev_index = 0;
21269    let mut prev_codepoint: Option<char> = None;
21270    text.char_indices()
21271        .chain([(text.len(), '\0')])
21272        .filter_map(move |(index, codepoint)| {
21273            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21274            let is_boundary = index == text.len()
21275                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21276                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21277            if is_boundary {
21278                let chunk = &text[prev_index..index];
21279                prev_index = index;
21280                Some(chunk)
21281            } else {
21282                None
21283            }
21284        })
21285}
21286
21287pub trait RangeToAnchorExt: Sized {
21288    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21289
21290    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21291        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21292        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21293    }
21294}
21295
21296impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21297    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21298        let start_offset = self.start.to_offset(snapshot);
21299        let end_offset = self.end.to_offset(snapshot);
21300        if start_offset == end_offset {
21301            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21302        } else {
21303            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21304        }
21305    }
21306}
21307
21308pub trait RowExt {
21309    fn as_f32(&self) -> f32;
21310
21311    fn next_row(&self) -> Self;
21312
21313    fn previous_row(&self) -> Self;
21314
21315    fn minus(&self, other: Self) -> u32;
21316}
21317
21318impl RowExt for DisplayRow {
21319    fn as_f32(&self) -> f32 {
21320        self.0 as f32
21321    }
21322
21323    fn next_row(&self) -> Self {
21324        Self(self.0 + 1)
21325    }
21326
21327    fn previous_row(&self) -> Self {
21328        Self(self.0.saturating_sub(1))
21329    }
21330
21331    fn minus(&self, other: Self) -> u32 {
21332        self.0 - other.0
21333    }
21334}
21335
21336impl RowExt for MultiBufferRow {
21337    fn as_f32(&self) -> f32 {
21338        self.0 as f32
21339    }
21340
21341    fn next_row(&self) -> Self {
21342        Self(self.0 + 1)
21343    }
21344
21345    fn previous_row(&self) -> Self {
21346        Self(self.0.saturating_sub(1))
21347    }
21348
21349    fn minus(&self, other: Self) -> u32 {
21350        self.0 - other.0
21351    }
21352}
21353
21354trait RowRangeExt {
21355    type Row;
21356
21357    fn len(&self) -> usize;
21358
21359    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21360}
21361
21362impl RowRangeExt for Range<MultiBufferRow> {
21363    type Row = MultiBufferRow;
21364
21365    fn len(&self) -> usize {
21366        (self.end.0 - self.start.0) as usize
21367    }
21368
21369    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21370        (self.start.0..self.end.0).map(MultiBufferRow)
21371    }
21372}
21373
21374impl RowRangeExt for Range<DisplayRow> {
21375    type Row = DisplayRow;
21376
21377    fn len(&self) -> usize {
21378        (self.end.0 - self.start.0) as usize
21379    }
21380
21381    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21382        (self.start.0..self.end.0).map(DisplayRow)
21383    }
21384}
21385
21386/// If select range has more than one line, we
21387/// just point the cursor to range.start.
21388fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21389    if range.start.row == range.end.row {
21390        range
21391    } else {
21392        range.start..range.start
21393    }
21394}
21395pub struct KillRing(ClipboardItem);
21396impl Global for KillRing {}
21397
21398const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21399
21400enum BreakpointPromptEditAction {
21401    Log,
21402    Condition,
21403    HitCondition,
21404}
21405
21406struct BreakpointPromptEditor {
21407    pub(crate) prompt: Entity<Editor>,
21408    editor: WeakEntity<Editor>,
21409    breakpoint_anchor: Anchor,
21410    breakpoint: Breakpoint,
21411    edit_action: BreakpointPromptEditAction,
21412    block_ids: HashSet<CustomBlockId>,
21413    editor_margins: Arc<Mutex<EditorMargins>>,
21414    _subscriptions: Vec<Subscription>,
21415}
21416
21417impl BreakpointPromptEditor {
21418    const MAX_LINES: u8 = 4;
21419
21420    fn new(
21421        editor: WeakEntity<Editor>,
21422        breakpoint_anchor: Anchor,
21423        breakpoint: Breakpoint,
21424        edit_action: BreakpointPromptEditAction,
21425        window: &mut Window,
21426        cx: &mut Context<Self>,
21427    ) -> Self {
21428        let base_text = match edit_action {
21429            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21430            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21431            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21432        }
21433        .map(|msg| msg.to_string())
21434        .unwrap_or_default();
21435
21436        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21437        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21438
21439        let prompt = cx.new(|cx| {
21440            let mut prompt = Editor::new(
21441                EditorMode::AutoHeight {
21442                    max_lines: Self::MAX_LINES as usize,
21443                },
21444                buffer,
21445                None,
21446                window,
21447                cx,
21448            );
21449            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21450            prompt.set_show_cursor_when_unfocused(false, cx);
21451            prompt.set_placeholder_text(
21452                match edit_action {
21453                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21454                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21455                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21456                },
21457                cx,
21458            );
21459
21460            prompt
21461        });
21462
21463        Self {
21464            prompt,
21465            editor,
21466            breakpoint_anchor,
21467            breakpoint,
21468            edit_action,
21469            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21470            block_ids: Default::default(),
21471            _subscriptions: vec![],
21472        }
21473    }
21474
21475    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21476        self.block_ids.extend(block_ids)
21477    }
21478
21479    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21480        if let Some(editor) = self.editor.upgrade() {
21481            let message = self
21482                .prompt
21483                .read(cx)
21484                .buffer
21485                .read(cx)
21486                .as_singleton()
21487                .expect("A multi buffer in breakpoint prompt isn't possible")
21488                .read(cx)
21489                .as_rope()
21490                .to_string();
21491
21492            editor.update(cx, |editor, cx| {
21493                editor.edit_breakpoint_at_anchor(
21494                    self.breakpoint_anchor,
21495                    self.breakpoint.clone(),
21496                    match self.edit_action {
21497                        BreakpointPromptEditAction::Log => {
21498                            BreakpointEditAction::EditLogMessage(message.into())
21499                        }
21500                        BreakpointPromptEditAction::Condition => {
21501                            BreakpointEditAction::EditCondition(message.into())
21502                        }
21503                        BreakpointPromptEditAction::HitCondition => {
21504                            BreakpointEditAction::EditHitCondition(message.into())
21505                        }
21506                    },
21507                    cx,
21508                );
21509
21510                editor.remove_blocks(self.block_ids.clone(), None, cx);
21511                cx.focus_self(window);
21512            });
21513        }
21514    }
21515
21516    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21517        self.editor
21518            .update(cx, |editor, cx| {
21519                editor.remove_blocks(self.block_ids.clone(), None, cx);
21520                window.focus(&editor.focus_handle);
21521            })
21522            .log_err();
21523    }
21524
21525    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21526        let settings = ThemeSettings::get_global(cx);
21527        let text_style = TextStyle {
21528            color: if self.prompt.read(cx).read_only(cx) {
21529                cx.theme().colors().text_disabled
21530            } else {
21531                cx.theme().colors().text
21532            },
21533            font_family: settings.buffer_font.family.clone(),
21534            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21535            font_size: settings.buffer_font_size(cx).into(),
21536            font_weight: settings.buffer_font.weight,
21537            line_height: relative(settings.buffer_line_height.value()),
21538            ..Default::default()
21539        };
21540        EditorElement::new(
21541            &self.prompt,
21542            EditorStyle {
21543                background: cx.theme().colors().editor_background,
21544                local_player: cx.theme().players().local(),
21545                text: text_style,
21546                ..Default::default()
21547            },
21548        )
21549    }
21550}
21551
21552impl Render for BreakpointPromptEditor {
21553    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21554        let editor_margins = *self.editor_margins.lock();
21555        let gutter_dimensions = editor_margins.gutter;
21556        h_flex()
21557            .key_context("Editor")
21558            .bg(cx.theme().colors().editor_background)
21559            .border_y_1()
21560            .border_color(cx.theme().status().info_border)
21561            .size_full()
21562            .py(window.line_height() / 2.5)
21563            .on_action(cx.listener(Self::confirm))
21564            .on_action(cx.listener(Self::cancel))
21565            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21566            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21567    }
21568}
21569
21570impl Focusable for BreakpointPromptEditor {
21571    fn focus_handle(&self, cx: &App) -> FocusHandle {
21572        self.prompt.focus_handle(cx)
21573    }
21574}
21575
21576fn all_edits_insertions_or_deletions(
21577    edits: &Vec<(Range<Anchor>, String)>,
21578    snapshot: &MultiBufferSnapshot,
21579) -> bool {
21580    let mut all_insertions = true;
21581    let mut all_deletions = true;
21582
21583    for (range, new_text) in edits.iter() {
21584        let range_is_empty = range.to_offset(&snapshot).is_empty();
21585        let text_is_empty = new_text.is_empty();
21586
21587        if range_is_empty != text_is_empty {
21588            if range_is_empty {
21589                all_deletions = false;
21590            } else {
21591                all_insertions = false;
21592            }
21593        } else {
21594            return false;
21595        }
21596
21597        if !all_insertions && !all_deletions {
21598            return false;
21599        }
21600    }
21601    all_insertions || all_deletions
21602}
21603
21604struct MissingEditPredictionKeybindingTooltip;
21605
21606impl Render for MissingEditPredictionKeybindingTooltip {
21607    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21608        ui::tooltip_container(window, cx, |container, _, cx| {
21609            container
21610                .flex_shrink_0()
21611                .max_w_80()
21612                .min_h(rems_from_px(124.))
21613                .justify_between()
21614                .child(
21615                    v_flex()
21616                        .flex_1()
21617                        .text_ui_sm(cx)
21618                        .child(Label::new("Conflict with Accept Keybinding"))
21619                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21620                )
21621                .child(
21622                    h_flex()
21623                        .pb_1()
21624                        .gap_1()
21625                        .items_end()
21626                        .w_full()
21627                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21628                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21629                        }))
21630                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21631                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21632                        })),
21633                )
21634        })
21635    }
21636}
21637
21638#[derive(Debug, Clone, Copy, PartialEq)]
21639pub struct LineHighlight {
21640    pub background: Background,
21641    pub border: Option<gpui::Hsla>,
21642    pub include_gutter: bool,
21643    pub type_id: Option<TypeId>,
21644}
21645
21646fn render_diff_hunk_controls(
21647    row: u32,
21648    status: &DiffHunkStatus,
21649    hunk_range: Range<Anchor>,
21650    is_created_file: bool,
21651    line_height: Pixels,
21652    editor: &Entity<Editor>,
21653    _window: &mut Window,
21654    cx: &mut App,
21655) -> AnyElement {
21656    h_flex()
21657        .h(line_height)
21658        .mr_1()
21659        .gap_1()
21660        .px_0p5()
21661        .pb_1()
21662        .border_x_1()
21663        .border_b_1()
21664        .border_color(cx.theme().colors().border_variant)
21665        .rounded_b_lg()
21666        .bg(cx.theme().colors().editor_background)
21667        .gap_1()
21668        .occlude()
21669        .shadow_md()
21670        .child(if status.has_secondary_hunk() {
21671            Button::new(("stage", row as u64), "Stage")
21672                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21673                .tooltip({
21674                    let focus_handle = editor.focus_handle(cx);
21675                    move |window, cx| {
21676                        Tooltip::for_action_in(
21677                            "Stage Hunk",
21678                            &::git::ToggleStaged,
21679                            &focus_handle,
21680                            window,
21681                            cx,
21682                        )
21683                    }
21684                })
21685                .on_click({
21686                    let editor = editor.clone();
21687                    move |_event, _window, cx| {
21688                        editor.update(cx, |editor, cx| {
21689                            editor.stage_or_unstage_diff_hunks(
21690                                true,
21691                                vec![hunk_range.start..hunk_range.start],
21692                                cx,
21693                            );
21694                        });
21695                    }
21696                })
21697        } else {
21698            Button::new(("unstage", row as u64), "Unstage")
21699                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21700                .tooltip({
21701                    let focus_handle = editor.focus_handle(cx);
21702                    move |window, cx| {
21703                        Tooltip::for_action_in(
21704                            "Unstage Hunk",
21705                            &::git::ToggleStaged,
21706                            &focus_handle,
21707                            window,
21708                            cx,
21709                        )
21710                    }
21711                })
21712                .on_click({
21713                    let editor = editor.clone();
21714                    move |_event, _window, cx| {
21715                        editor.update(cx, |editor, cx| {
21716                            editor.stage_or_unstage_diff_hunks(
21717                                false,
21718                                vec![hunk_range.start..hunk_range.start],
21719                                cx,
21720                            );
21721                        });
21722                    }
21723                })
21724        })
21725        .child(
21726            Button::new(("restore", row as u64), "Restore")
21727                .tooltip({
21728                    let focus_handle = editor.focus_handle(cx);
21729                    move |window, cx| {
21730                        Tooltip::for_action_in(
21731                            "Restore Hunk",
21732                            &::git::Restore,
21733                            &focus_handle,
21734                            window,
21735                            cx,
21736                        )
21737                    }
21738                })
21739                .on_click({
21740                    let editor = editor.clone();
21741                    move |_event, window, cx| {
21742                        editor.update(cx, |editor, cx| {
21743                            let snapshot = editor.snapshot(window, cx);
21744                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21745                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21746                        });
21747                    }
21748                })
21749                .disabled(is_created_file),
21750        )
21751        .when(
21752            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21753            |el| {
21754                el.child(
21755                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21756                        .shape(IconButtonShape::Square)
21757                        .icon_size(IconSize::Small)
21758                        // .disabled(!has_multiple_hunks)
21759                        .tooltip({
21760                            let focus_handle = editor.focus_handle(cx);
21761                            move |window, cx| {
21762                                Tooltip::for_action_in(
21763                                    "Next Hunk",
21764                                    &GoToHunk,
21765                                    &focus_handle,
21766                                    window,
21767                                    cx,
21768                                )
21769                            }
21770                        })
21771                        .on_click({
21772                            let editor = editor.clone();
21773                            move |_event, window, cx| {
21774                                editor.update(cx, |editor, cx| {
21775                                    let snapshot = editor.snapshot(window, cx);
21776                                    let position =
21777                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21778                                    editor.go_to_hunk_before_or_after_position(
21779                                        &snapshot,
21780                                        position,
21781                                        Direction::Next,
21782                                        window,
21783                                        cx,
21784                                    );
21785                                    editor.expand_selected_diff_hunks(cx);
21786                                });
21787                            }
21788                        }),
21789                )
21790                .child(
21791                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21792                        .shape(IconButtonShape::Square)
21793                        .icon_size(IconSize::Small)
21794                        // .disabled(!has_multiple_hunks)
21795                        .tooltip({
21796                            let focus_handle = editor.focus_handle(cx);
21797                            move |window, cx| {
21798                                Tooltip::for_action_in(
21799                                    "Previous Hunk",
21800                                    &GoToPreviousHunk,
21801                                    &focus_handle,
21802                                    window,
21803                                    cx,
21804                                )
21805                            }
21806                        })
21807                        .on_click({
21808                            let editor = editor.clone();
21809                            move |_event, window, cx| {
21810                                editor.update(cx, |editor, cx| {
21811                                    let snapshot = editor.snapshot(window, cx);
21812                                    let point =
21813                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21814                                    editor.go_to_hunk_before_or_after_position(
21815                                        &snapshot,
21816                                        point,
21817                                        Direction::Prev,
21818                                        window,
21819                                        cx,
21820                                    );
21821                                    editor.expand_selected_diff_hunks(cx);
21822                                });
21823                            }
21824                        }),
21825                )
21826            },
21827        )
21828        .into_any_element()
21829}