editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82
   83use ::git::blame::BlameEntry;
   84use ::git::{Restore, blame::ParsedCommitMessage};
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use git::blame::{GitBlame, GlobalBlameRenderer};
   90use gpui::{
   91    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   92    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   93    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   94    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   95    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   96    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   97    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   98    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   99};
  100use highlight_matching_bracket::refresh_matching_bracket_highlights;
  101use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  102pub use hover_popover::hover_markdown_style;
  103use hover_popover::{HoverState, hide_hover};
  104use indent_guides::ActiveIndentGuidesState;
  105use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  106pub use inline_completion::Direction;
  107use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  108pub use items::MAX_TAB_TITLE_LEN;
  109use itertools::Itertools;
  110use language::{
  111    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  112    CursorShape, DiagnosticEntry, DiagnosticSourceKind, DiffOptions, DocumentationConfig,
  113    EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language,
  114    OffsetRangeExt, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  115    WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, LspPullDiagnostics, ProjectPath, PulledDiagnostics,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    project_settings::DiagnosticSeverity,
  137};
  138
  139pub use git::blame::BlameRenderer;
  140pub use proposed_changes_editor::{
  141    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  142};
  143use std::{cell::OnceCell, iter::Peekable, ops::Not};
  144use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  145
  146pub use lsp::CompletionContext;
  147use lsp::{
  148    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  149    LanguageServerId, LanguageServerName,
  150};
  151
  152use language::BufferSnapshot;
  153pub use lsp_ext::lsp_tasks;
  154use movement::TextLayoutDetails;
  155pub use multi_buffer::{
  156    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  157    RowInfo, ToOffset, ToPoint,
  158};
  159use multi_buffer::{
  160    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  161    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  162};
  163use parking_lot::Mutex;
  164use project::{
  165    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  166    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  167    TaskSourceKind,
  168    debugger::breakpoint_store::Breakpoint,
  169    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  170    project_settings::{GitGutterSetting, ProjectSettings},
  171};
  172use rand::prelude::*;
  173use rpc::{ErrorExt, proto::*};
  174use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  175use selections_collection::{
  176    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  177};
  178use serde::{Deserialize, Serialize};
  179use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  180use smallvec::{SmallVec, smallvec};
  181use snippet::Snippet;
  182use std::sync::Arc;
  183use std::{
  184    any::TypeId,
  185    borrow::Cow,
  186    cell::RefCell,
  187    cmp::{self, Ordering, Reverse},
  188    mem,
  189    num::NonZeroU32,
  190    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  191    path::{Path, PathBuf},
  192    rc::Rc,
  193    time::{Duration, Instant},
  194};
  195pub use sum_tree::Bias;
  196use sum_tree::TreeMap;
  197use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  198use theme::{
  199    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  200    observe_buffer_font_size_adjustment,
  201};
  202use ui::{
  203    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  204    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  205};
  206use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  207use workspace::{
  208    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  209    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  210    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  211    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  212    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  213    searchable::SearchEvent,
  214};
  215
  216use crate::{
  217    code_context_menus::CompletionsMenuSource,
  218    hover_links::{find_url, find_url_from_range},
  219};
  220use crate::{
  221    editor_settings::MultiCursorModifier,
  222    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  223};
  224
  225pub const FILE_HEADER_HEIGHT: u32 = 2;
  226pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  227pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  228const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  229const MAX_LINE_LEN: usize = 1024;
  230const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  231const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  232pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  233#[doc(hidden)]
  234pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  235const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  236
  237pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  240
  241pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  242pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  243pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  244
  245pub type RenderDiffHunkControlsFn = Arc<
  246    dyn Fn(
  247        u32,
  248        &DiffHunkStatus,
  249        Range<Anchor>,
  250        bool,
  251        Pixels,
  252        &Entity<Editor>,
  253        &mut Window,
  254        &mut App,
  255    ) -> AnyElement,
  256>;
  257
  258struct InlineValueCache {
  259    enabled: bool,
  260    inlays: Vec<InlayId>,
  261    refresh_task: Task<Option<()>>,
  262}
  263
  264impl InlineValueCache {
  265    fn new(enabled: bool) -> Self {
  266        Self {
  267            enabled,
  268            inlays: Vec::new(),
  269            refresh_task: Task::ready(None),
  270        }
  271    }
  272}
  273
  274#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  275pub enum InlayId {
  276    InlineCompletion(usize),
  277    Hint(usize),
  278    DebuggerValue(usize),
  279}
  280
  281impl InlayId {
  282    fn id(&self) -> usize {
  283        match self {
  284            Self::InlineCompletion(id) => *id,
  285            Self::Hint(id) => *id,
  286            Self::DebuggerValue(id) => *id,
  287        }
  288    }
  289}
  290
  291pub enum ActiveDebugLine {}
  292pub enum DebugStackFrameLine {}
  293enum DocumentHighlightRead {}
  294enum DocumentHighlightWrite {}
  295enum InputComposition {}
  296pub enum PendingInput {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        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, Vec<Range<Anchor>>);
  701
  702#[derive(Default)]
  703struct ScrollbarMarkerState {
  704    scrollbar_size: Size<Pixels>,
  705    dirty: bool,
  706    markers: Arc<[PaintQuad]>,
  707    pending_refresh: Option<Task<Result<()>>>,
  708}
  709
  710impl ScrollbarMarkerState {
  711    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  712        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  713    }
  714}
  715
  716#[derive(Clone, Copy, PartialEq, Eq)]
  717pub enum MinimapVisibility {
  718    Disabled,
  719    Enabled {
  720        /// The configuration currently present in the users settings.
  721        setting_configuration: bool,
  722        /// Whether to override the currently set visibility from the users setting.
  723        toggle_override: bool,
  724    },
  725}
  726
  727impl MinimapVisibility {
  728    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  729        if mode.is_full() {
  730            Self::Enabled {
  731                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  732                toggle_override: false,
  733            }
  734        } else {
  735            Self::Disabled
  736        }
  737    }
  738
  739    fn hidden(&self) -> Self {
  740        match *self {
  741            Self::Enabled {
  742                setting_configuration,
  743                ..
  744            } => Self::Enabled {
  745                setting_configuration,
  746                toggle_override: setting_configuration,
  747            },
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751
  752    fn disabled(&self) -> bool {
  753        match *self {
  754            Self::Disabled => true,
  755            _ => false,
  756        }
  757    }
  758
  759    fn settings_visibility(&self) -> bool {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => setting_configuration,
  765            _ => false,
  766        }
  767    }
  768
  769    fn visible(&self) -> bool {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                toggle_override,
  774            } => setting_configuration ^ toggle_override,
  775            _ => false,
  776        }
  777    }
  778
  779    fn toggle_visibility(&self) -> Self {
  780        match *self {
  781            Self::Enabled {
  782                toggle_override,
  783                setting_configuration,
  784            } => Self::Enabled {
  785                setting_configuration,
  786                toggle_override: !toggle_override,
  787            },
  788            Self::Disabled => Self::Disabled,
  789        }
  790    }
  791}
  792
  793#[derive(Clone, Debug)]
  794struct RunnableTasks {
  795    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  796    offset: multi_buffer::Anchor,
  797    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  798    column: u32,
  799    // Values of all named captures, including those starting with '_'
  800    extra_variables: HashMap<String, String>,
  801    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  802    context_range: Range<BufferOffset>,
  803}
  804
  805impl RunnableTasks {
  806    fn resolve<'a>(
  807        &'a self,
  808        cx: &'a task::TaskContext,
  809    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  810        self.templates.iter().filter_map(|(kind, template)| {
  811            template
  812                .resolve_task(&kind.to_id_base(), cx)
  813                .map(|task| (kind.clone(), task))
  814        })
  815    }
  816}
  817
  818#[derive(Clone)]
  819pub struct ResolvedTasks {
  820    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  821    position: Anchor,
  822}
  823
  824#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  825struct BufferOffset(usize);
  826
  827// Addons allow storing per-editor state in other crates (e.g. Vim)
  828pub trait Addon: 'static {
  829    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  830
  831    fn render_buffer_header_controls(
  832        &self,
  833        _: &ExcerptInfo,
  834        _: &Window,
  835        _: &App,
  836    ) -> Option<AnyElement> {
  837        None
  838    }
  839
  840    fn to_any(&self) -> &dyn std::any::Any;
  841
  842    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  843        None
  844    }
  845}
  846
  847/// A set of caret positions, registered when the editor was edited.
  848pub struct ChangeList {
  849    changes: Vec<Vec<Anchor>>,
  850    /// Currently "selected" change.
  851    position: Option<usize>,
  852}
  853
  854impl ChangeList {
  855    pub fn new() -> Self {
  856        Self {
  857            changes: Vec::new(),
  858            position: None,
  859        }
  860    }
  861
  862    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  863    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  864    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  865        if self.changes.is_empty() {
  866            return None;
  867        }
  868
  869        let prev = self.position.unwrap_or(self.changes.len());
  870        let next = if direction == Direction::Prev {
  871            prev.saturating_sub(count)
  872        } else {
  873            (prev + count).min(self.changes.len() - 1)
  874        };
  875        self.position = Some(next);
  876        self.changes.get(next).map(|anchors| anchors.as_slice())
  877    }
  878
  879    /// Adds a new change to the list, resetting the change list position.
  880    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  881        self.position.take();
  882        if pop_state {
  883            self.changes.pop();
  884        }
  885        self.changes.push(new_positions.clone());
  886    }
  887
  888    pub fn last(&self) -> Option<&[Anchor]> {
  889        self.changes.last().map(|anchors| anchors.as_slice())
  890    }
  891}
  892
  893#[derive(Clone)]
  894struct InlineBlamePopoverState {
  895    scroll_handle: ScrollHandle,
  896    commit_message: Option<ParsedCommitMessage>,
  897    markdown: Entity<Markdown>,
  898}
  899
  900struct InlineBlamePopover {
  901    position: gpui::Point<Pixels>,
  902    hide_task: Option<Task<()>>,
  903    popover_bounds: Option<Bounds<Pixels>>,
  904    popover_state: InlineBlamePopoverState,
  905}
  906
  907enum SelectionDragState {
  908    /// State when no drag related activity is detected.
  909    None,
  910    /// State when the mouse is down on a selection that is about to be dragged.
  911    ReadyToDrag {
  912        selection: Selection<Anchor>,
  913        click_position: gpui::Point<Pixels>,
  914        mouse_down_time: Instant,
  915    },
  916    /// State when the mouse is dragging the selection in the editor.
  917    Dragging {
  918        selection: Selection<Anchor>,
  919        drop_cursor: Selection<Anchor>,
  920        hide_drop_cursor: bool,
  921    },
  922}
  923
  924/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  925/// a breakpoint on them.
  926#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  927struct PhantomBreakpointIndicator {
  928    display_row: DisplayRow,
  929    /// There's a small debounce between hovering over the line and showing the indicator.
  930    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  931    is_active: bool,
  932    collides_with_existing_breakpoint: bool,
  933}
  934
  935/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  936///
  937/// See the [module level documentation](self) for more information.
  938pub struct Editor {
  939    focus_handle: FocusHandle,
  940    last_focused_descendant: Option<WeakFocusHandle>,
  941    /// The text buffer being edited
  942    buffer: Entity<MultiBuffer>,
  943    /// Map of how text in the buffer should be displayed.
  944    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  945    pub display_map: Entity<DisplayMap>,
  946    pub selections: SelectionsCollection,
  947    pub scroll_manager: ScrollManager,
  948    /// When inline assist editors are linked, they all render cursors because
  949    /// typing enters text into each of them, even the ones that aren't focused.
  950    pub(crate) show_cursor_when_unfocused: bool,
  951    columnar_selection_tail: Option<Anchor>,
  952    columnar_display_point: Option<DisplayPoint>,
  953    add_selections_state: Option<AddSelectionsState>,
  954    select_next_state: Option<SelectNextState>,
  955    select_prev_state: Option<SelectNextState>,
  956    selection_history: SelectionHistory,
  957    defer_selection_effects: bool,
  958    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  959    autoclose_regions: Vec<AutocloseRegion>,
  960    snippet_stack: InvalidationStack<SnippetState>,
  961    select_syntax_node_history: SelectSyntaxNodeHistory,
  962    ime_transaction: Option<TransactionId>,
  963    pub diagnostics_max_severity: DiagnosticSeverity,
  964    active_diagnostics: ActiveDiagnostic,
  965    show_inline_diagnostics: bool,
  966    inline_diagnostics_update: Task<()>,
  967    inline_diagnostics_enabled: bool,
  968    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  969    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  970    hard_wrap: Option<usize>,
  971
  972    // TODO: make this a access method
  973    pub project: Option<Entity<Project>>,
  974    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  975    completion_provider: Option<Rc<dyn CompletionProvider>>,
  976    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  977    blink_manager: Entity<BlinkManager>,
  978    show_cursor_names: bool,
  979    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  980    pub show_local_selections: bool,
  981    mode: EditorMode,
  982    show_breadcrumbs: bool,
  983    show_gutter: bool,
  984    show_scrollbars: ScrollbarAxes,
  985    minimap_visibility: MinimapVisibility,
  986    offset_content: bool,
  987    disable_expand_excerpt_buttons: bool,
  988    show_line_numbers: Option<bool>,
  989    use_relative_line_numbers: Option<bool>,
  990    show_git_diff_gutter: Option<bool>,
  991    show_code_actions: Option<bool>,
  992    show_runnables: Option<bool>,
  993    show_breakpoints: Option<bool>,
  994    show_wrap_guides: Option<bool>,
  995    show_indent_guides: Option<bool>,
  996    placeholder_text: Option<Arc<str>>,
  997    highlight_order: usize,
  998    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  999    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1000    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1001    scrollbar_marker_state: ScrollbarMarkerState,
 1002    active_indent_guides_state: ActiveIndentGuidesState,
 1003    nav_history: Option<ItemNavHistory>,
 1004    context_menu: RefCell<Option<CodeContextMenu>>,
 1005    context_menu_options: Option<ContextMenuOptions>,
 1006    mouse_context_menu: Option<MouseContextMenu>,
 1007    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1008    inline_blame_popover: Option<InlineBlamePopover>,
 1009    inline_blame_popover_show_task: Option<Task<()>>,
 1010    signature_help_state: SignatureHelpState,
 1011    auto_signature_help: Option<bool>,
 1012    find_all_references_task_sources: Vec<Anchor>,
 1013    next_completion_id: CompletionId,
 1014    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1015    code_actions_task: Option<Task<Result<()>>>,
 1016    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1017    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1018    document_highlights_task: Option<Task<()>>,
 1019    linked_editing_range_task: Option<Task<Option<()>>>,
 1020    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1021    pending_rename: Option<RenameState>,
 1022    searchable: bool,
 1023    cursor_shape: CursorShape,
 1024    current_line_highlight: Option<CurrentLineHighlight>,
 1025    collapse_matches: bool,
 1026    autoindent_mode: Option<AutoindentMode>,
 1027    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1028    input_enabled: bool,
 1029    use_modal_editing: bool,
 1030    read_only: bool,
 1031    leader_id: Option<CollaboratorId>,
 1032    remote_id: Option<ViewId>,
 1033    pub hover_state: HoverState,
 1034    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1035    gutter_hovered: bool,
 1036    hovered_link_state: Option<HoveredLinkState>,
 1037    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1038    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1039    active_inline_completion: Option<InlineCompletionState>,
 1040    /// Used to prevent flickering as the user types while the menu is open
 1041    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1042    edit_prediction_settings: EditPredictionSettings,
 1043    inline_completions_hidden_for_vim_mode: bool,
 1044    show_inline_completions_override: Option<bool>,
 1045    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1046    edit_prediction_preview: EditPredictionPreview,
 1047    edit_prediction_indent_conflict: bool,
 1048    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1049    inlay_hint_cache: InlayHintCache,
 1050    next_inlay_id: usize,
 1051    _subscriptions: Vec<Subscription>,
 1052    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1053    gutter_dimensions: GutterDimensions,
 1054    style: Option<EditorStyle>,
 1055    text_style_refinement: Option<TextStyleRefinement>,
 1056    next_editor_action_id: EditorActionId,
 1057    editor_actions: Rc<
 1058        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1059    >,
 1060    use_autoclose: bool,
 1061    use_auto_surround: bool,
 1062    auto_replace_emoji_shortcode: bool,
 1063    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1064    show_git_blame_gutter: bool,
 1065    show_git_blame_inline: bool,
 1066    show_git_blame_inline_delay_task: Option<Task<()>>,
 1067    git_blame_inline_enabled: bool,
 1068    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1069    serialize_dirty_buffers: bool,
 1070    show_selection_menu: Option<bool>,
 1071    blame: Option<Entity<GitBlame>>,
 1072    blame_subscription: Option<Subscription>,
 1073    custom_context_menu: Option<
 1074        Box<
 1075            dyn 'static
 1076                + Fn(
 1077                    &mut Self,
 1078                    DisplayPoint,
 1079                    &mut Window,
 1080                    &mut Context<Self>,
 1081                ) -> Option<Entity<ui::ContextMenu>>,
 1082        >,
 1083    >,
 1084    last_bounds: Option<Bounds<Pixels>>,
 1085    last_position_map: Option<Rc<PositionMap>>,
 1086    expect_bounds_change: Option<Bounds<Pixels>>,
 1087    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1088    tasks_update_task: Option<Task<()>>,
 1089    breakpoint_store: Option<Entity<BreakpointStore>>,
 1090    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1091    hovered_diff_hunk_row: Option<DisplayRow>,
 1092    pull_diagnostics_task: Task<()>,
 1093    in_project_search: bool,
 1094    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1095    breadcrumb_header: Option<String>,
 1096    focused_block: Option<FocusedBlock>,
 1097    next_scroll_position: NextScrollCursorCenterTopBottom,
 1098    addons: HashMap<TypeId, Box<dyn Addon>>,
 1099    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1100    load_diff_task: Option<Shared<Task<()>>>,
 1101    /// Whether we are temporarily displaying a diff other than git's
 1102    temporary_diff_override: bool,
 1103    selection_mark_mode: bool,
 1104    toggle_fold_multiple_buffers: Task<()>,
 1105    _scroll_cursor_center_top_bottom_task: Task<()>,
 1106    serialize_selections: Task<()>,
 1107    serialize_folds: Task<()>,
 1108    mouse_cursor_hidden: bool,
 1109    minimap: Option<Entity<Self>>,
 1110    hide_mouse_mode: HideMouseMode,
 1111    pub change_list: ChangeList,
 1112    inline_value_cache: InlineValueCache,
 1113    selection_drag_state: SelectionDragState,
 1114    drag_and_drop_selection_enabled: bool,
 1115}
 1116
 1117#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1118enum NextScrollCursorCenterTopBottom {
 1119    #[default]
 1120    Center,
 1121    Top,
 1122    Bottom,
 1123}
 1124
 1125impl NextScrollCursorCenterTopBottom {
 1126    fn next(&self) -> Self {
 1127        match self {
 1128            Self::Center => Self::Top,
 1129            Self::Top => Self::Bottom,
 1130            Self::Bottom => Self::Center,
 1131        }
 1132    }
 1133}
 1134
 1135#[derive(Clone)]
 1136pub struct EditorSnapshot {
 1137    pub mode: EditorMode,
 1138    show_gutter: bool,
 1139    show_line_numbers: Option<bool>,
 1140    show_git_diff_gutter: Option<bool>,
 1141    show_code_actions: Option<bool>,
 1142    show_runnables: Option<bool>,
 1143    show_breakpoints: Option<bool>,
 1144    git_blame_gutter_max_author_length: Option<usize>,
 1145    pub display_snapshot: DisplaySnapshot,
 1146    pub placeholder_text: Option<Arc<str>>,
 1147    is_focused: bool,
 1148    scroll_anchor: ScrollAnchor,
 1149    ongoing_scroll: OngoingScroll,
 1150    current_line_highlight: CurrentLineHighlight,
 1151    gutter_hovered: bool,
 1152}
 1153
 1154#[derive(Default, Debug, Clone, Copy)]
 1155pub struct GutterDimensions {
 1156    pub left_padding: Pixels,
 1157    pub right_padding: Pixels,
 1158    pub width: Pixels,
 1159    pub margin: Pixels,
 1160    pub git_blame_entries_width: Option<Pixels>,
 1161}
 1162
 1163impl GutterDimensions {
 1164    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1165        Self {
 1166            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1167            ..Default::default()
 1168        }
 1169    }
 1170
 1171    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1172        -cx.text_system().descent(font_id, font_size)
 1173    }
 1174    /// The full width of the space taken up by the gutter.
 1175    pub fn full_width(&self) -> Pixels {
 1176        self.margin + self.width
 1177    }
 1178
 1179    /// The width of the space reserved for the fold indicators,
 1180    /// use alongside 'justify_end' and `gutter_width` to
 1181    /// right align content with the line numbers
 1182    pub fn fold_area_width(&self) -> Pixels {
 1183        self.margin + self.right_padding
 1184    }
 1185}
 1186
 1187#[derive(Debug)]
 1188pub struct RemoteSelection {
 1189    pub replica_id: ReplicaId,
 1190    pub selection: Selection<Anchor>,
 1191    pub cursor_shape: CursorShape,
 1192    pub collaborator_id: CollaboratorId,
 1193    pub line_mode: bool,
 1194    pub user_name: Option<SharedString>,
 1195    pub color: PlayerColor,
 1196}
 1197
 1198#[derive(Clone, Debug)]
 1199struct SelectionHistoryEntry {
 1200    selections: Arc<[Selection<Anchor>]>,
 1201    select_next_state: Option<SelectNextState>,
 1202    select_prev_state: Option<SelectNextState>,
 1203    add_selections_state: Option<AddSelectionsState>,
 1204}
 1205
 1206#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1207enum SelectionHistoryMode {
 1208    Normal,
 1209    Undoing,
 1210    Redoing,
 1211    Skipping,
 1212}
 1213
 1214#[derive(Clone, PartialEq, Eq, Hash)]
 1215struct HoveredCursor {
 1216    replica_id: u16,
 1217    selection_id: usize,
 1218}
 1219
 1220impl Default for SelectionHistoryMode {
 1221    fn default() -> Self {
 1222        Self::Normal
 1223    }
 1224}
 1225
 1226#[derive(Debug)]
 1227pub struct SelectionEffects {
 1228    nav_history: bool,
 1229    completions: bool,
 1230    scroll: Option<Autoscroll>,
 1231}
 1232
 1233impl Default for SelectionEffects {
 1234    fn default() -> Self {
 1235        Self {
 1236            nav_history: true,
 1237            completions: true,
 1238            scroll: Some(Autoscroll::fit()),
 1239        }
 1240    }
 1241}
 1242impl SelectionEffects {
 1243    pub fn scroll(scroll: Autoscroll) -> Self {
 1244        Self {
 1245            scroll: Some(scroll),
 1246            ..Default::default()
 1247        }
 1248    }
 1249
 1250    pub fn no_scroll() -> Self {
 1251        Self {
 1252            scroll: None,
 1253            ..Default::default()
 1254        }
 1255    }
 1256
 1257    pub fn completions(self, completions: bool) -> Self {
 1258        Self {
 1259            completions,
 1260            ..self
 1261        }
 1262    }
 1263
 1264    pub fn nav_history(self, nav_history: bool) -> Self {
 1265        Self {
 1266            nav_history,
 1267            ..self
 1268        }
 1269    }
 1270}
 1271
 1272struct DeferredSelectionEffectsState {
 1273    changed: bool,
 1274    effects: SelectionEffects,
 1275    old_cursor_position: Anchor,
 1276    history_entry: SelectionHistoryEntry,
 1277}
 1278
 1279#[derive(Default)]
 1280struct SelectionHistory {
 1281    #[allow(clippy::type_complexity)]
 1282    selections_by_transaction:
 1283        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1284    mode: SelectionHistoryMode,
 1285    undo_stack: VecDeque<SelectionHistoryEntry>,
 1286    redo_stack: VecDeque<SelectionHistoryEntry>,
 1287}
 1288
 1289impl SelectionHistory {
 1290    #[track_caller]
 1291    fn insert_transaction(
 1292        &mut self,
 1293        transaction_id: TransactionId,
 1294        selections: Arc<[Selection<Anchor>]>,
 1295    ) {
 1296        if selections.is_empty() {
 1297            log::error!(
 1298                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1299                std::panic::Location::caller()
 1300            );
 1301            return;
 1302        }
 1303        self.selections_by_transaction
 1304            .insert(transaction_id, (selections, None));
 1305    }
 1306
 1307    #[allow(clippy::type_complexity)]
 1308    fn transaction(
 1309        &self,
 1310        transaction_id: TransactionId,
 1311    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1312        self.selections_by_transaction.get(&transaction_id)
 1313    }
 1314
 1315    #[allow(clippy::type_complexity)]
 1316    fn transaction_mut(
 1317        &mut self,
 1318        transaction_id: TransactionId,
 1319    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1320        self.selections_by_transaction.get_mut(&transaction_id)
 1321    }
 1322
 1323    fn push(&mut self, entry: SelectionHistoryEntry) {
 1324        if !entry.selections.is_empty() {
 1325            match self.mode {
 1326                SelectionHistoryMode::Normal => {
 1327                    self.push_undo(entry);
 1328                    self.redo_stack.clear();
 1329                }
 1330                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1331                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1332                SelectionHistoryMode::Skipping => {}
 1333            }
 1334        }
 1335    }
 1336
 1337    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1338        if self
 1339            .undo_stack
 1340            .back()
 1341            .map_or(true, |e| e.selections != entry.selections)
 1342        {
 1343            self.undo_stack.push_back(entry);
 1344            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1345                self.undo_stack.pop_front();
 1346            }
 1347        }
 1348    }
 1349
 1350    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1351        if self
 1352            .redo_stack
 1353            .back()
 1354            .map_or(true, |e| e.selections != entry.selections)
 1355        {
 1356            self.redo_stack.push_back(entry);
 1357            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1358                self.redo_stack.pop_front();
 1359            }
 1360        }
 1361    }
 1362}
 1363
 1364#[derive(Clone, Copy)]
 1365pub struct RowHighlightOptions {
 1366    pub autoscroll: bool,
 1367    pub include_gutter: bool,
 1368}
 1369
 1370impl Default for RowHighlightOptions {
 1371    fn default() -> Self {
 1372        Self {
 1373            autoscroll: Default::default(),
 1374            include_gutter: true,
 1375        }
 1376    }
 1377}
 1378
 1379struct RowHighlight {
 1380    index: usize,
 1381    range: Range<Anchor>,
 1382    color: Hsla,
 1383    options: RowHighlightOptions,
 1384    type_id: TypeId,
 1385}
 1386
 1387#[derive(Clone, Debug)]
 1388struct AddSelectionsState {
 1389    groups: Vec<AddSelectionsGroup>,
 1390}
 1391
 1392#[derive(Clone, Debug)]
 1393struct AddSelectionsGroup {
 1394    above: bool,
 1395    stack: Vec<usize>,
 1396}
 1397
 1398#[derive(Clone)]
 1399struct SelectNextState {
 1400    query: AhoCorasick,
 1401    wordwise: bool,
 1402    done: bool,
 1403}
 1404
 1405impl std::fmt::Debug for SelectNextState {
 1406    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1407        f.debug_struct(std::any::type_name::<Self>())
 1408            .field("wordwise", &self.wordwise)
 1409            .field("done", &self.done)
 1410            .finish()
 1411    }
 1412}
 1413
 1414#[derive(Debug)]
 1415struct AutocloseRegion {
 1416    selection_id: usize,
 1417    range: Range<Anchor>,
 1418    pair: BracketPair,
 1419}
 1420
 1421#[derive(Debug)]
 1422struct SnippetState {
 1423    ranges: Vec<Vec<Range<Anchor>>>,
 1424    active_index: usize,
 1425    choices: Vec<Option<Vec<String>>>,
 1426}
 1427
 1428#[doc(hidden)]
 1429pub struct RenameState {
 1430    pub range: Range<Anchor>,
 1431    pub old_name: Arc<str>,
 1432    pub editor: Entity<Editor>,
 1433    block_id: CustomBlockId,
 1434}
 1435
 1436struct InvalidationStack<T>(Vec<T>);
 1437
 1438struct RegisteredInlineCompletionProvider {
 1439    provider: Arc<dyn InlineCompletionProviderHandle>,
 1440    _subscription: Subscription,
 1441}
 1442
 1443#[derive(Debug, PartialEq, Eq)]
 1444pub struct ActiveDiagnosticGroup {
 1445    pub active_range: Range<Anchor>,
 1446    pub active_message: String,
 1447    pub group_id: usize,
 1448    pub blocks: HashSet<CustomBlockId>,
 1449}
 1450
 1451#[derive(Debug, PartialEq, Eq)]
 1452
 1453pub(crate) enum ActiveDiagnostic {
 1454    None,
 1455    All,
 1456    Group(ActiveDiagnosticGroup),
 1457}
 1458
 1459#[derive(Serialize, Deserialize, Clone, Debug)]
 1460pub struct ClipboardSelection {
 1461    /// The number of bytes in this selection.
 1462    pub len: usize,
 1463    /// Whether this was a full-line selection.
 1464    pub is_entire_line: bool,
 1465    /// The indentation of the first line when this content was originally copied.
 1466    pub first_line_indent: u32,
 1467}
 1468
 1469// selections, scroll behavior, was newest selection reversed
 1470type SelectSyntaxNodeHistoryState = (
 1471    Box<[Selection<usize>]>,
 1472    SelectSyntaxNodeScrollBehavior,
 1473    bool,
 1474);
 1475
 1476#[derive(Default)]
 1477struct SelectSyntaxNodeHistory {
 1478    stack: Vec<SelectSyntaxNodeHistoryState>,
 1479    // disable temporarily to allow changing selections without losing the stack
 1480    pub disable_clearing: bool,
 1481}
 1482
 1483impl SelectSyntaxNodeHistory {
 1484    pub fn try_clear(&mut self) {
 1485        if !self.disable_clearing {
 1486            self.stack.clear();
 1487        }
 1488    }
 1489
 1490    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1491        self.stack.push(selection);
 1492    }
 1493
 1494    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1495        self.stack.pop()
 1496    }
 1497}
 1498
 1499enum SelectSyntaxNodeScrollBehavior {
 1500    CursorTop,
 1501    FitSelection,
 1502    CursorBottom,
 1503}
 1504
 1505#[derive(Debug)]
 1506pub(crate) struct NavigationData {
 1507    cursor_anchor: Anchor,
 1508    cursor_position: Point,
 1509    scroll_anchor: ScrollAnchor,
 1510    scroll_top_row: u32,
 1511}
 1512
 1513#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1514pub enum GotoDefinitionKind {
 1515    Symbol,
 1516    Declaration,
 1517    Type,
 1518    Implementation,
 1519}
 1520
 1521#[derive(Debug, Clone)]
 1522enum InlayHintRefreshReason {
 1523    ModifiersChanged(bool),
 1524    Toggle(bool),
 1525    SettingsChange(InlayHintSettings),
 1526    NewLinesShown,
 1527    BufferEdited(HashSet<Arc<Language>>),
 1528    RefreshRequested,
 1529    ExcerptsRemoved(Vec<ExcerptId>),
 1530}
 1531
 1532impl InlayHintRefreshReason {
 1533    fn description(&self) -> &'static str {
 1534        match self {
 1535            Self::ModifiersChanged(_) => "modifiers changed",
 1536            Self::Toggle(_) => "toggle",
 1537            Self::SettingsChange(_) => "settings change",
 1538            Self::NewLinesShown => "new lines shown",
 1539            Self::BufferEdited(_) => "buffer edited",
 1540            Self::RefreshRequested => "refresh requested",
 1541            Self::ExcerptsRemoved(_) => "excerpts removed",
 1542        }
 1543    }
 1544}
 1545
 1546pub enum FormatTarget {
 1547    Buffers(HashSet<Entity<Buffer>>),
 1548    Ranges(Vec<Range<MultiBufferPoint>>),
 1549}
 1550
 1551pub(crate) struct FocusedBlock {
 1552    id: BlockId,
 1553    focus_handle: WeakFocusHandle,
 1554}
 1555
 1556#[derive(Clone)]
 1557enum JumpData {
 1558    MultiBufferRow {
 1559        row: MultiBufferRow,
 1560        line_offset_from_top: u32,
 1561    },
 1562    MultiBufferPoint {
 1563        excerpt_id: ExcerptId,
 1564        position: Point,
 1565        anchor: text::Anchor,
 1566        line_offset_from_top: u32,
 1567    },
 1568}
 1569
 1570pub enum MultibufferSelectionMode {
 1571    First,
 1572    All,
 1573}
 1574
 1575#[derive(Clone, Copy, Debug, Default)]
 1576pub struct RewrapOptions {
 1577    pub override_language_settings: bool,
 1578    pub preserve_existing_whitespace: bool,
 1579}
 1580
 1581impl Editor {
 1582    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1583        let buffer = cx.new(|cx| Buffer::local("", cx));
 1584        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1585        Self::new(
 1586            EditorMode::SingleLine { auto_width: false },
 1587            buffer,
 1588            None,
 1589            window,
 1590            cx,
 1591        )
 1592    }
 1593
 1594    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1595        let buffer = cx.new(|cx| Buffer::local("", cx));
 1596        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1597        Self::new(EditorMode::full(), buffer, None, window, cx)
 1598    }
 1599
 1600    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1601        let buffer = cx.new(|cx| Buffer::local("", cx));
 1602        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1603        Self::new(
 1604            EditorMode::SingleLine { auto_width: true },
 1605            buffer,
 1606            None,
 1607            window,
 1608            cx,
 1609        )
 1610    }
 1611
 1612    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1613        let buffer = cx.new(|cx| Buffer::local("", cx));
 1614        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1615        Self::new(
 1616            EditorMode::AutoHeight { max_lines },
 1617            buffer,
 1618            None,
 1619            window,
 1620            cx,
 1621        )
 1622    }
 1623
 1624    pub fn for_buffer(
 1625        buffer: Entity<Buffer>,
 1626        project: Option<Entity<Project>>,
 1627        window: &mut Window,
 1628        cx: &mut Context<Self>,
 1629    ) -> Self {
 1630        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1631        Self::new(EditorMode::full(), buffer, project, window, cx)
 1632    }
 1633
 1634    pub fn for_multibuffer(
 1635        buffer: Entity<MultiBuffer>,
 1636        project: Option<Entity<Project>>,
 1637        window: &mut Window,
 1638        cx: &mut Context<Self>,
 1639    ) -> Self {
 1640        Self::new(EditorMode::full(), buffer, project, window, cx)
 1641    }
 1642
 1643    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1644        let mut clone = Self::new(
 1645            self.mode.clone(),
 1646            self.buffer.clone(),
 1647            self.project.clone(),
 1648            window,
 1649            cx,
 1650        );
 1651        self.display_map.update(cx, |display_map, cx| {
 1652            let snapshot = display_map.snapshot(cx);
 1653            clone.display_map.update(cx, |display_map, cx| {
 1654                display_map.set_state(&snapshot, cx);
 1655            });
 1656        });
 1657        clone.folds_did_change(cx);
 1658        clone.selections.clone_state(&self.selections);
 1659        clone.scroll_manager.clone_state(&self.scroll_manager);
 1660        clone.searchable = self.searchable;
 1661        clone.read_only = self.read_only;
 1662        clone
 1663    }
 1664
 1665    pub fn new(
 1666        mode: EditorMode,
 1667        buffer: Entity<MultiBuffer>,
 1668        project: Option<Entity<Project>>,
 1669        window: &mut Window,
 1670        cx: &mut Context<Self>,
 1671    ) -> Self {
 1672        Editor::new_internal(mode, buffer, project, None, window, cx)
 1673    }
 1674
 1675    fn new_internal(
 1676        mode: EditorMode,
 1677        buffer: Entity<MultiBuffer>,
 1678        project: Option<Entity<Project>>,
 1679        display_map: Option<Entity<DisplayMap>>,
 1680        window: &mut Window,
 1681        cx: &mut Context<Self>,
 1682    ) -> Self {
 1683        debug_assert!(
 1684            display_map.is_none() || mode.is_minimap(),
 1685            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1686        );
 1687
 1688        let full_mode = mode.is_full();
 1689        let diagnostics_max_severity = if full_mode {
 1690            EditorSettings::get_global(cx)
 1691                .diagnostics_max_severity
 1692                .unwrap_or(DiagnosticSeverity::Hint)
 1693        } else {
 1694            DiagnosticSeverity::Off
 1695        };
 1696        let style = window.text_style();
 1697        let font_size = style.font_size.to_pixels(window.rem_size());
 1698        let editor = cx.entity().downgrade();
 1699        let fold_placeholder = FoldPlaceholder {
 1700            constrain_width: true,
 1701            render: Arc::new(move |fold_id, fold_range, cx| {
 1702                let editor = editor.clone();
 1703                div()
 1704                    .id(fold_id)
 1705                    .bg(cx.theme().colors().ghost_element_background)
 1706                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1707                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1708                    .rounded_xs()
 1709                    .size_full()
 1710                    .cursor_pointer()
 1711                    .child("")
 1712                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1713                    .on_click(move |_, _window, cx| {
 1714                        editor
 1715                            .update(cx, |editor, cx| {
 1716                                editor.unfold_ranges(
 1717                                    &[fold_range.start..fold_range.end],
 1718                                    true,
 1719                                    false,
 1720                                    cx,
 1721                                );
 1722                                cx.stop_propagation();
 1723                            })
 1724                            .ok();
 1725                    })
 1726                    .into_any()
 1727            }),
 1728            merge_adjacent: true,
 1729            ..FoldPlaceholder::default()
 1730        };
 1731        let display_map = display_map.unwrap_or_else(|| {
 1732            cx.new(|cx| {
 1733                DisplayMap::new(
 1734                    buffer.clone(),
 1735                    style.font(),
 1736                    font_size,
 1737                    None,
 1738                    FILE_HEADER_HEIGHT,
 1739                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1740                    fold_placeholder,
 1741                    diagnostics_max_severity,
 1742                    cx,
 1743                )
 1744            })
 1745        });
 1746
 1747        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1748
 1749        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1750
 1751        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1752            .then(|| language_settings::SoftWrap::None);
 1753
 1754        let mut project_subscriptions = Vec::new();
 1755        if mode.is_full() {
 1756            if let Some(project) = project.as_ref() {
 1757                project_subscriptions.push(cx.subscribe_in(
 1758                    project,
 1759                    window,
 1760                    |editor, _, event, window, cx| match event {
 1761                        project::Event::RefreshCodeLens => {
 1762                            // we always query lens with actions, without storing them, always refreshing them
 1763                        }
 1764                        project::Event::RefreshInlayHints => {
 1765                            editor
 1766                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1767                        }
 1768                        project::Event::LanguageServerAdded(..)
 1769                        | project::Event::LanguageServerRemoved(..) => {
 1770                            if editor.tasks_update_task.is_none() {
 1771                                editor.tasks_update_task =
 1772                                    Some(editor.refresh_runnables(window, cx));
 1773                            }
 1774                            editor.pull_diagnostics(None, window, cx);
 1775                        }
 1776                        project::Event::SnippetEdit(id, snippet_edits) => {
 1777                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1778                                let focus_handle = editor.focus_handle(cx);
 1779                                if focus_handle.is_focused(window) {
 1780                                    let snapshot = buffer.read(cx).snapshot();
 1781                                    for (range, snippet) in snippet_edits {
 1782                                        let editor_range =
 1783                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1784                                        editor
 1785                                            .insert_snippet(
 1786                                                &[editor_range],
 1787                                                snippet.clone(),
 1788                                                window,
 1789                                                cx,
 1790                                            )
 1791                                            .ok();
 1792                                    }
 1793                                }
 1794                            }
 1795                        }
 1796                        _ => {}
 1797                    },
 1798                ));
 1799                if let Some(task_inventory) = project
 1800                    .read(cx)
 1801                    .task_store()
 1802                    .read(cx)
 1803                    .task_inventory()
 1804                    .cloned()
 1805                {
 1806                    project_subscriptions.push(cx.observe_in(
 1807                        &task_inventory,
 1808                        window,
 1809                        |editor, _, window, cx| {
 1810                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1811                        },
 1812                    ));
 1813                };
 1814
 1815                project_subscriptions.push(cx.subscribe_in(
 1816                    &project.read(cx).breakpoint_store(),
 1817                    window,
 1818                    |editor, _, event, window, cx| match event {
 1819                        BreakpointStoreEvent::ClearDebugLines => {
 1820                            editor.clear_row_highlights::<ActiveDebugLine>();
 1821                            editor.refresh_inline_values(cx);
 1822                        }
 1823                        BreakpointStoreEvent::SetDebugLine => {
 1824                            if editor.go_to_active_debug_line(window, cx) {
 1825                                cx.stop_propagation();
 1826                            }
 1827
 1828                            editor.refresh_inline_values(cx);
 1829                        }
 1830                        _ => {}
 1831                    },
 1832                ));
 1833            }
 1834        }
 1835
 1836        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1837
 1838        let inlay_hint_settings =
 1839            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1840        let focus_handle = cx.focus_handle();
 1841        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1842            .detach();
 1843        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1844            .detach();
 1845        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1846            .detach();
 1847        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1848            .detach();
 1849        cx.observe_pending_input(window, Self::observe_pending_input)
 1850            .detach();
 1851
 1852        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1853            Some(false)
 1854        } else {
 1855            None
 1856        };
 1857
 1858        let breakpoint_store = match (&mode, project.as_ref()) {
 1859            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1860            _ => None,
 1861        };
 1862
 1863        let mut code_action_providers = Vec::new();
 1864        let mut load_uncommitted_diff = None;
 1865        if let Some(project) = project.clone() {
 1866            load_uncommitted_diff = Some(
 1867                update_uncommitted_diff_for_buffer(
 1868                    cx.entity(),
 1869                    &project,
 1870                    buffer.read(cx).all_buffers(),
 1871                    buffer.clone(),
 1872                    cx,
 1873                )
 1874                .shared(),
 1875            );
 1876            code_action_providers.push(Rc::new(project) as Rc<_>);
 1877        }
 1878
 1879        let mut editor = Self {
 1880            focus_handle,
 1881            show_cursor_when_unfocused: false,
 1882            last_focused_descendant: None,
 1883            buffer: buffer.clone(),
 1884            display_map: display_map.clone(),
 1885            selections,
 1886            scroll_manager: ScrollManager::new(cx),
 1887            columnar_selection_tail: None,
 1888            columnar_display_point: None,
 1889            add_selections_state: None,
 1890            select_next_state: None,
 1891            select_prev_state: None,
 1892            selection_history: SelectionHistory::default(),
 1893            defer_selection_effects: false,
 1894            deferred_selection_effects_state: None,
 1895            autoclose_regions: Vec::new(),
 1896            snippet_stack: InvalidationStack::default(),
 1897            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1898            ime_transaction: None,
 1899            active_diagnostics: ActiveDiagnostic::None,
 1900            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1901            inline_diagnostics_update: Task::ready(()),
 1902            inline_diagnostics: Vec::new(),
 1903            soft_wrap_mode_override,
 1904            diagnostics_max_severity,
 1905            hard_wrap: None,
 1906            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1907            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1908            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1909            project,
 1910            blink_manager: blink_manager.clone(),
 1911            show_local_selections: true,
 1912            show_scrollbars: ScrollbarAxes {
 1913                horizontal: full_mode,
 1914                vertical: full_mode,
 1915            },
 1916            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1917            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1918            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1919            show_gutter: mode.is_full(),
 1920            show_line_numbers: None,
 1921            use_relative_line_numbers: None,
 1922            disable_expand_excerpt_buttons: false,
 1923            show_git_diff_gutter: None,
 1924            show_code_actions: None,
 1925            show_runnables: None,
 1926            show_breakpoints: None,
 1927            show_wrap_guides: None,
 1928            show_indent_guides,
 1929            placeholder_text: None,
 1930            highlight_order: 0,
 1931            highlighted_rows: HashMap::default(),
 1932            background_highlights: TreeMap::default(),
 1933            gutter_highlights: TreeMap::default(),
 1934            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1935            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1936            nav_history: None,
 1937            context_menu: RefCell::new(None),
 1938            context_menu_options: None,
 1939            mouse_context_menu: None,
 1940            completion_tasks: Vec::new(),
 1941            inline_blame_popover: None,
 1942            inline_blame_popover_show_task: None,
 1943            signature_help_state: SignatureHelpState::default(),
 1944            auto_signature_help: None,
 1945            find_all_references_task_sources: Vec::new(),
 1946            next_completion_id: 0,
 1947            next_inlay_id: 0,
 1948            code_action_providers,
 1949            available_code_actions: None,
 1950            code_actions_task: None,
 1951            quick_selection_highlight_task: None,
 1952            debounced_selection_highlight_task: None,
 1953            document_highlights_task: None,
 1954            linked_editing_range_task: None,
 1955            pending_rename: None,
 1956            searchable: true,
 1957            cursor_shape: EditorSettings::get_global(cx)
 1958                .cursor_shape
 1959                .unwrap_or_default(),
 1960            current_line_highlight: None,
 1961            autoindent_mode: Some(AutoindentMode::EachLine),
 1962            collapse_matches: false,
 1963            workspace: None,
 1964            input_enabled: true,
 1965            use_modal_editing: mode.is_full(),
 1966            read_only: mode.is_minimap(),
 1967            use_autoclose: true,
 1968            use_auto_surround: true,
 1969            auto_replace_emoji_shortcode: false,
 1970            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1971            leader_id: None,
 1972            remote_id: None,
 1973            hover_state: HoverState::default(),
 1974            pending_mouse_down: None,
 1975            hovered_link_state: None,
 1976            edit_prediction_provider: None,
 1977            active_inline_completion: None,
 1978            stale_inline_completion_in_menu: None,
 1979            edit_prediction_preview: EditPredictionPreview::Inactive {
 1980                released_too_fast: false,
 1981            },
 1982            inline_diagnostics_enabled: mode.is_full(),
 1983            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1984            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1985
 1986            gutter_hovered: false,
 1987            pixel_position_of_newest_cursor: None,
 1988            last_bounds: None,
 1989            last_position_map: None,
 1990            expect_bounds_change: None,
 1991            gutter_dimensions: GutterDimensions::default(),
 1992            style: None,
 1993            show_cursor_names: false,
 1994            hovered_cursors: HashMap::default(),
 1995            next_editor_action_id: EditorActionId::default(),
 1996            editor_actions: Rc::default(),
 1997            inline_completions_hidden_for_vim_mode: false,
 1998            show_inline_completions_override: None,
 1999            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2000            edit_prediction_settings: EditPredictionSettings::Disabled,
 2001            edit_prediction_indent_conflict: false,
 2002            edit_prediction_requires_modifier_in_indent_conflict: true,
 2003            custom_context_menu: None,
 2004            show_git_blame_gutter: false,
 2005            show_git_blame_inline: false,
 2006            show_selection_menu: None,
 2007            show_git_blame_inline_delay_task: None,
 2008            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2009            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2010            serialize_dirty_buffers: !mode.is_minimap()
 2011                && ProjectSettings::get_global(cx)
 2012                    .session
 2013                    .restore_unsaved_buffers,
 2014            blame: None,
 2015            blame_subscription: None,
 2016            tasks: BTreeMap::default(),
 2017
 2018            breakpoint_store,
 2019            gutter_breakpoint_indicator: (None, None),
 2020            hovered_diff_hunk_row: None,
 2021            _subscriptions: vec![
 2022                cx.observe(&buffer, Self::on_buffer_changed),
 2023                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2024                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2025                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2026                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2027                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2028                cx.observe_window_activation(window, |editor, window, cx| {
 2029                    let active = window.is_window_active();
 2030                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2031                        if active {
 2032                            blink_manager.enable(cx);
 2033                        } else {
 2034                            blink_manager.disable(cx);
 2035                        }
 2036                    });
 2037                    if active {
 2038                        editor.show_mouse_cursor();
 2039                    }
 2040                }),
 2041            ],
 2042            tasks_update_task: None,
 2043            pull_diagnostics_task: Task::ready(()),
 2044            linked_edit_ranges: Default::default(),
 2045            in_project_search: false,
 2046            previous_search_ranges: None,
 2047            breadcrumb_header: None,
 2048            focused_block: None,
 2049            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2050            addons: HashMap::default(),
 2051            registered_buffers: HashMap::default(),
 2052            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2053            selection_mark_mode: false,
 2054            toggle_fold_multiple_buffers: Task::ready(()),
 2055            serialize_selections: Task::ready(()),
 2056            serialize_folds: Task::ready(()),
 2057            text_style_refinement: None,
 2058            load_diff_task: load_uncommitted_diff,
 2059            temporary_diff_override: false,
 2060            mouse_cursor_hidden: false,
 2061            minimap: None,
 2062            hide_mouse_mode: EditorSettings::get_global(cx)
 2063                .hide_mouse
 2064                .unwrap_or_default(),
 2065            change_list: ChangeList::new(),
 2066            mode,
 2067            selection_drag_state: SelectionDragState::None,
 2068            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2069        };
 2070        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2071            editor
 2072                ._subscriptions
 2073                .push(cx.observe(breakpoints, |_, _, cx| {
 2074                    cx.notify();
 2075                }));
 2076        }
 2077        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2078        editor._subscriptions.extend(project_subscriptions);
 2079
 2080        editor._subscriptions.push(cx.subscribe_in(
 2081            &cx.entity(),
 2082            window,
 2083            |editor, _, e: &EditorEvent, window, cx| match e {
 2084                EditorEvent::ScrollPositionChanged { local, .. } => {
 2085                    if *local {
 2086                        let new_anchor = editor.scroll_manager.anchor();
 2087                        let snapshot = editor.snapshot(window, cx);
 2088                        editor.update_restoration_data(cx, move |data| {
 2089                            data.scroll_position = (
 2090                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2091                                new_anchor.offset,
 2092                            );
 2093                        });
 2094                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2095                        editor.inline_blame_popover.take();
 2096                    }
 2097                }
 2098                EditorEvent::Edited { .. } => {
 2099                    if !vim_enabled(cx) {
 2100                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2101                        let pop_state = editor
 2102                            .change_list
 2103                            .last()
 2104                            .map(|previous| {
 2105                                previous.len() == selections.len()
 2106                                    && previous.iter().enumerate().all(|(ix, p)| {
 2107                                        p.to_display_point(&map).row()
 2108                                            == selections[ix].head().row()
 2109                                    })
 2110                            })
 2111                            .unwrap_or(false);
 2112                        let new_positions = selections
 2113                            .into_iter()
 2114                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2115                            .collect();
 2116                        editor
 2117                            .change_list
 2118                            .push_to_change_list(pop_state, new_positions);
 2119                    }
 2120                }
 2121                _ => (),
 2122            },
 2123        ));
 2124
 2125        if let Some(dap_store) = editor
 2126            .project
 2127            .as_ref()
 2128            .map(|project| project.read(cx).dap_store())
 2129        {
 2130            let weak_editor = cx.weak_entity();
 2131
 2132            editor
 2133                ._subscriptions
 2134                .push(
 2135                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2136                        let session_entity = cx.entity();
 2137                        weak_editor
 2138                            .update(cx, |editor, cx| {
 2139                                editor._subscriptions.push(
 2140                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2141                                );
 2142                            })
 2143                            .ok();
 2144                    }),
 2145                );
 2146
 2147            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2148                editor
 2149                    ._subscriptions
 2150                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2151            }
 2152        }
 2153
 2154        // skip adding the initial selection to selection history
 2155        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2156        editor.end_selection(window, cx);
 2157        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2158
 2159        editor.scroll_manager.show_scrollbars(window, cx);
 2160        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2161
 2162        if full_mode {
 2163            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2164            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2165
 2166            if editor.git_blame_inline_enabled {
 2167                editor.start_git_blame_inline(false, window, cx);
 2168            }
 2169
 2170            editor.go_to_active_debug_line(window, cx);
 2171
 2172            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2173                if let Some(project) = editor.project.as_ref() {
 2174                    let handle = project.update(cx, |project, cx| {
 2175                        project.register_buffer_with_language_servers(&buffer, cx)
 2176                    });
 2177                    editor
 2178                        .registered_buffers
 2179                        .insert(buffer.read(cx).remote_id(), handle);
 2180                }
 2181            }
 2182
 2183            editor.minimap =
 2184                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2185            editor.pull_diagnostics(None, window, cx);
 2186        }
 2187
 2188        editor.report_editor_event("Editor Opened", None, cx);
 2189        editor
 2190    }
 2191
 2192    pub fn deploy_mouse_context_menu(
 2193        &mut self,
 2194        position: gpui::Point<Pixels>,
 2195        context_menu: Entity<ContextMenu>,
 2196        window: &mut Window,
 2197        cx: &mut Context<Self>,
 2198    ) {
 2199        self.mouse_context_menu = Some(MouseContextMenu::new(
 2200            self,
 2201            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2202            context_menu,
 2203            window,
 2204            cx,
 2205        ));
 2206    }
 2207
 2208    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2209        self.mouse_context_menu
 2210            .as_ref()
 2211            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2212    }
 2213
 2214    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2215        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2216    }
 2217
 2218    fn key_context_internal(
 2219        &self,
 2220        has_active_edit_prediction: bool,
 2221        window: &Window,
 2222        cx: &App,
 2223    ) -> KeyContext {
 2224        let mut key_context = KeyContext::new_with_defaults();
 2225        key_context.add("Editor");
 2226        let mode = match self.mode {
 2227            EditorMode::SingleLine { .. } => "single_line",
 2228            EditorMode::AutoHeight { .. } => "auto_height",
 2229            EditorMode::Minimap { .. } => "minimap",
 2230            EditorMode::Full { .. } => "full",
 2231        };
 2232
 2233        if EditorSettings::jupyter_enabled(cx) {
 2234            key_context.add("jupyter");
 2235        }
 2236
 2237        key_context.set("mode", mode);
 2238        if self.pending_rename.is_some() {
 2239            key_context.add("renaming");
 2240        }
 2241
 2242        match self.context_menu.borrow().as_ref() {
 2243            Some(CodeContextMenu::Completions(_)) => {
 2244                key_context.add("menu");
 2245                key_context.add("showing_completions");
 2246            }
 2247            Some(CodeContextMenu::CodeActions(_)) => {
 2248                key_context.add("menu");
 2249                key_context.add("showing_code_actions")
 2250            }
 2251            None => {}
 2252        }
 2253
 2254        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2255        if !self.focus_handle(cx).contains_focused(window, cx)
 2256            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2257        {
 2258            for addon in self.addons.values() {
 2259                addon.extend_key_context(&mut key_context, cx)
 2260            }
 2261        }
 2262
 2263        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2264            if let Some(extension) = singleton_buffer
 2265                .read(cx)
 2266                .file()
 2267                .and_then(|file| file.path().extension()?.to_str())
 2268            {
 2269                key_context.set("extension", extension.to_string());
 2270            }
 2271        } else {
 2272            key_context.add("multibuffer");
 2273        }
 2274
 2275        if has_active_edit_prediction {
 2276            if self.edit_prediction_in_conflict() {
 2277                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2278            } else {
 2279                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2280                key_context.add("copilot_suggestion");
 2281            }
 2282        }
 2283
 2284        if self.selection_mark_mode {
 2285            key_context.add("selection_mode");
 2286        }
 2287
 2288        key_context
 2289    }
 2290
 2291    fn show_mouse_cursor(&mut self) {
 2292        self.mouse_cursor_hidden = false;
 2293    }
 2294
 2295    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2296        self.mouse_cursor_hidden = match origin {
 2297            HideMouseCursorOrigin::TypingAction => {
 2298                matches!(
 2299                    self.hide_mouse_mode,
 2300                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2301                )
 2302            }
 2303            HideMouseCursorOrigin::MovementAction => {
 2304                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2305            }
 2306        };
 2307    }
 2308
 2309    pub fn edit_prediction_in_conflict(&self) -> bool {
 2310        if !self.show_edit_predictions_in_menu() {
 2311            return false;
 2312        }
 2313
 2314        let showing_completions = self
 2315            .context_menu
 2316            .borrow()
 2317            .as_ref()
 2318            .map_or(false, |context| {
 2319                matches!(context, CodeContextMenu::Completions(_))
 2320            });
 2321
 2322        showing_completions
 2323            || self.edit_prediction_requires_modifier()
 2324            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2325            // bindings to insert tab characters.
 2326            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2327    }
 2328
 2329    pub fn accept_edit_prediction_keybind(
 2330        &self,
 2331        accept_partial: bool,
 2332        window: &Window,
 2333        cx: &App,
 2334    ) -> AcceptEditPredictionBinding {
 2335        let key_context = self.key_context_internal(true, window, cx);
 2336        let in_conflict = self.edit_prediction_in_conflict();
 2337
 2338        let bindings = if accept_partial {
 2339            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2340        } else {
 2341            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2342        };
 2343
 2344        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2345        // just the first one.
 2346        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2347            !in_conflict
 2348                || binding
 2349                    .keystrokes()
 2350                    .first()
 2351                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2352        }))
 2353    }
 2354
 2355    pub fn new_file(
 2356        workspace: &mut Workspace,
 2357        _: &workspace::NewFile,
 2358        window: &mut Window,
 2359        cx: &mut Context<Workspace>,
 2360    ) {
 2361        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2362            "Failed to create buffer",
 2363            window,
 2364            cx,
 2365            |e, _, _| match e.error_code() {
 2366                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2367                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2368                e.error_tag("required").unwrap_or("the latest version")
 2369            )),
 2370                _ => None,
 2371            },
 2372        );
 2373    }
 2374
 2375    pub fn new_in_workspace(
 2376        workspace: &mut Workspace,
 2377        window: &mut Window,
 2378        cx: &mut Context<Workspace>,
 2379    ) -> Task<Result<Entity<Editor>>> {
 2380        let project = workspace.project().clone();
 2381        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2382
 2383        cx.spawn_in(window, async move |workspace, cx| {
 2384            let buffer = create.await?;
 2385            workspace.update_in(cx, |workspace, window, cx| {
 2386                let editor =
 2387                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2388                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2389                editor
 2390            })
 2391        })
 2392    }
 2393
 2394    fn new_file_vertical(
 2395        workspace: &mut Workspace,
 2396        _: &workspace::NewFileSplitVertical,
 2397        window: &mut Window,
 2398        cx: &mut Context<Workspace>,
 2399    ) {
 2400        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2401    }
 2402
 2403    fn new_file_horizontal(
 2404        workspace: &mut Workspace,
 2405        _: &workspace::NewFileSplitHorizontal,
 2406        window: &mut Window,
 2407        cx: &mut Context<Workspace>,
 2408    ) {
 2409        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2410    }
 2411
 2412    fn new_file_in_direction(
 2413        workspace: &mut Workspace,
 2414        direction: SplitDirection,
 2415        window: &mut Window,
 2416        cx: &mut Context<Workspace>,
 2417    ) {
 2418        let project = workspace.project().clone();
 2419        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2420
 2421        cx.spawn_in(window, async move |workspace, cx| {
 2422            let buffer = create.await?;
 2423            workspace.update_in(cx, move |workspace, window, cx| {
 2424                workspace.split_item(
 2425                    direction,
 2426                    Box::new(
 2427                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2428                    ),
 2429                    window,
 2430                    cx,
 2431                )
 2432            })?;
 2433            anyhow::Ok(())
 2434        })
 2435        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2436            match e.error_code() {
 2437                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2438                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2439                e.error_tag("required").unwrap_or("the latest version")
 2440            )),
 2441                _ => None,
 2442            }
 2443        });
 2444    }
 2445
 2446    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2447        self.leader_id
 2448    }
 2449
 2450    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2451        &self.buffer
 2452    }
 2453
 2454    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2455        self.workspace.as_ref()?.0.upgrade()
 2456    }
 2457
 2458    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2459        self.buffer().read(cx).title(cx)
 2460    }
 2461
 2462    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2463        let git_blame_gutter_max_author_length = self
 2464            .render_git_blame_gutter(cx)
 2465            .then(|| {
 2466                if let Some(blame) = self.blame.as_ref() {
 2467                    let max_author_length =
 2468                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2469                    Some(max_author_length)
 2470                } else {
 2471                    None
 2472                }
 2473            })
 2474            .flatten();
 2475
 2476        EditorSnapshot {
 2477            mode: self.mode.clone(),
 2478            show_gutter: self.show_gutter,
 2479            show_line_numbers: self.show_line_numbers,
 2480            show_git_diff_gutter: self.show_git_diff_gutter,
 2481            show_code_actions: self.show_code_actions,
 2482            show_runnables: self.show_runnables,
 2483            show_breakpoints: self.show_breakpoints,
 2484            git_blame_gutter_max_author_length,
 2485            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2486            scroll_anchor: self.scroll_manager.anchor(),
 2487            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2488            placeholder_text: self.placeholder_text.clone(),
 2489            is_focused: self.focus_handle.is_focused(window),
 2490            current_line_highlight: self
 2491                .current_line_highlight
 2492                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2493            gutter_hovered: self.gutter_hovered,
 2494        }
 2495    }
 2496
 2497    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2498        self.buffer.read(cx).language_at(point, cx)
 2499    }
 2500
 2501    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2502        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2503    }
 2504
 2505    pub fn active_excerpt(
 2506        &self,
 2507        cx: &App,
 2508    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2509        self.buffer
 2510            .read(cx)
 2511            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2512    }
 2513
 2514    pub fn mode(&self) -> &EditorMode {
 2515        &self.mode
 2516    }
 2517
 2518    pub fn set_mode(&mut self, mode: EditorMode) {
 2519        self.mode = mode;
 2520    }
 2521
 2522    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2523        self.collaboration_hub.as_deref()
 2524    }
 2525
 2526    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2527        self.collaboration_hub = Some(hub);
 2528    }
 2529
 2530    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2531        self.in_project_search = in_project_search;
 2532    }
 2533
 2534    pub fn set_custom_context_menu(
 2535        &mut self,
 2536        f: impl 'static
 2537        + Fn(
 2538            &mut Self,
 2539            DisplayPoint,
 2540            &mut Window,
 2541            &mut Context<Self>,
 2542        ) -> Option<Entity<ui::ContextMenu>>,
 2543    ) {
 2544        self.custom_context_menu = Some(Box::new(f))
 2545    }
 2546
 2547    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2548        self.completion_provider = provider;
 2549    }
 2550
 2551    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2552        self.semantics_provider.clone()
 2553    }
 2554
 2555    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2556        self.semantics_provider = provider;
 2557    }
 2558
 2559    pub fn set_edit_prediction_provider<T>(
 2560        &mut self,
 2561        provider: Option<Entity<T>>,
 2562        window: &mut Window,
 2563        cx: &mut Context<Self>,
 2564    ) where
 2565        T: EditPredictionProvider,
 2566    {
 2567        self.edit_prediction_provider =
 2568            provider.map(|provider| RegisteredInlineCompletionProvider {
 2569                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2570                    if this.focus_handle.is_focused(window) {
 2571                        this.update_visible_inline_completion(window, cx);
 2572                    }
 2573                }),
 2574                provider: Arc::new(provider),
 2575            });
 2576        self.update_edit_prediction_settings(cx);
 2577        self.refresh_inline_completion(false, false, window, cx);
 2578    }
 2579
 2580    pub fn placeholder_text(&self) -> Option<&str> {
 2581        self.placeholder_text.as_deref()
 2582    }
 2583
 2584    pub fn set_placeholder_text(
 2585        &mut self,
 2586        placeholder_text: impl Into<Arc<str>>,
 2587        cx: &mut Context<Self>,
 2588    ) {
 2589        let placeholder_text = Some(placeholder_text.into());
 2590        if self.placeholder_text != placeholder_text {
 2591            self.placeholder_text = placeholder_text;
 2592            cx.notify();
 2593        }
 2594    }
 2595
 2596    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2597        self.cursor_shape = cursor_shape;
 2598
 2599        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2600        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2601
 2602        cx.notify();
 2603    }
 2604
 2605    pub fn set_current_line_highlight(
 2606        &mut self,
 2607        current_line_highlight: Option<CurrentLineHighlight>,
 2608    ) {
 2609        self.current_line_highlight = current_line_highlight;
 2610    }
 2611
 2612    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2613        self.collapse_matches = collapse_matches;
 2614    }
 2615
 2616    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2617        let buffers = self.buffer.read(cx).all_buffers();
 2618        let Some(project) = self.project.as_ref() else {
 2619            return;
 2620        };
 2621        project.update(cx, |project, cx| {
 2622            for buffer in buffers {
 2623                self.registered_buffers
 2624                    .entry(buffer.read(cx).remote_id())
 2625                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2626            }
 2627        })
 2628    }
 2629
 2630    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2631        if self.collapse_matches {
 2632            return range.start..range.start;
 2633        }
 2634        range.clone()
 2635    }
 2636
 2637    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2638        if self.display_map.read(cx).clip_at_line_ends != clip {
 2639            self.display_map
 2640                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2641        }
 2642    }
 2643
 2644    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2645        self.input_enabled = input_enabled;
 2646    }
 2647
 2648    pub fn set_inline_completions_hidden_for_vim_mode(
 2649        &mut self,
 2650        hidden: bool,
 2651        window: &mut Window,
 2652        cx: &mut Context<Self>,
 2653    ) {
 2654        if hidden != self.inline_completions_hidden_for_vim_mode {
 2655            self.inline_completions_hidden_for_vim_mode = hidden;
 2656            if hidden {
 2657                self.update_visible_inline_completion(window, cx);
 2658            } else {
 2659                self.refresh_inline_completion(true, false, window, cx);
 2660            }
 2661        }
 2662    }
 2663
 2664    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2665        self.menu_inline_completions_policy = value;
 2666    }
 2667
 2668    pub fn set_autoindent(&mut self, autoindent: bool) {
 2669        if autoindent {
 2670            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2671        } else {
 2672            self.autoindent_mode = None;
 2673        }
 2674    }
 2675
 2676    pub fn read_only(&self, cx: &App) -> bool {
 2677        self.read_only || self.buffer.read(cx).read_only()
 2678    }
 2679
 2680    pub fn set_read_only(&mut self, read_only: bool) {
 2681        self.read_only = read_only;
 2682    }
 2683
 2684    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2685        self.use_autoclose = autoclose;
 2686    }
 2687
 2688    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2689        self.use_auto_surround = auto_surround;
 2690    }
 2691
 2692    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2693        self.auto_replace_emoji_shortcode = auto_replace;
 2694    }
 2695
 2696    pub fn toggle_edit_predictions(
 2697        &mut self,
 2698        _: &ToggleEditPrediction,
 2699        window: &mut Window,
 2700        cx: &mut Context<Self>,
 2701    ) {
 2702        if self.show_inline_completions_override.is_some() {
 2703            self.set_show_edit_predictions(None, window, cx);
 2704        } else {
 2705            let show_edit_predictions = !self.edit_predictions_enabled();
 2706            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2707        }
 2708    }
 2709
 2710    pub fn set_show_edit_predictions(
 2711        &mut self,
 2712        show_edit_predictions: Option<bool>,
 2713        window: &mut Window,
 2714        cx: &mut Context<Self>,
 2715    ) {
 2716        self.show_inline_completions_override = show_edit_predictions;
 2717        self.update_edit_prediction_settings(cx);
 2718
 2719        if let Some(false) = show_edit_predictions {
 2720            self.discard_inline_completion(false, cx);
 2721        } else {
 2722            self.refresh_inline_completion(false, true, window, cx);
 2723        }
 2724    }
 2725
 2726    fn inline_completions_disabled_in_scope(
 2727        &self,
 2728        buffer: &Entity<Buffer>,
 2729        buffer_position: language::Anchor,
 2730        cx: &App,
 2731    ) -> bool {
 2732        let snapshot = buffer.read(cx).snapshot();
 2733        let settings = snapshot.settings_at(buffer_position, cx);
 2734
 2735        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2736            return false;
 2737        };
 2738
 2739        scope.override_name().map_or(false, |scope_name| {
 2740            settings
 2741                .edit_predictions_disabled_in
 2742                .iter()
 2743                .any(|s| s == scope_name)
 2744        })
 2745    }
 2746
 2747    pub fn set_use_modal_editing(&mut self, to: bool) {
 2748        self.use_modal_editing = to;
 2749    }
 2750
 2751    pub fn use_modal_editing(&self) -> bool {
 2752        self.use_modal_editing
 2753    }
 2754
 2755    fn selections_did_change(
 2756        &mut self,
 2757        local: bool,
 2758        old_cursor_position: &Anchor,
 2759        effects: SelectionEffects,
 2760        window: &mut Window,
 2761        cx: &mut Context<Self>,
 2762    ) {
 2763        window.invalidate_character_coordinates();
 2764
 2765        // Copy selections to primary selection buffer
 2766        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2767        if local {
 2768            let selections = self.selections.all::<usize>(cx);
 2769            let buffer_handle = self.buffer.read(cx).read(cx);
 2770
 2771            let mut text = String::new();
 2772            for (index, selection) in selections.iter().enumerate() {
 2773                let text_for_selection = buffer_handle
 2774                    .text_for_range(selection.start..selection.end)
 2775                    .collect::<String>();
 2776
 2777                text.push_str(&text_for_selection);
 2778                if index != selections.len() - 1 {
 2779                    text.push('\n');
 2780                }
 2781            }
 2782
 2783            if !text.is_empty() {
 2784                cx.write_to_primary(ClipboardItem::new_string(text));
 2785            }
 2786        }
 2787
 2788        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2789            self.buffer.update(cx, |buffer, cx| {
 2790                buffer.set_active_selections(
 2791                    &self.selections.disjoint_anchors(),
 2792                    self.selections.line_mode,
 2793                    self.cursor_shape,
 2794                    cx,
 2795                )
 2796            });
 2797        }
 2798        let display_map = self
 2799            .display_map
 2800            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2801        let buffer = &display_map.buffer_snapshot;
 2802        if self.selections.count() == 1 {
 2803            self.add_selections_state = None;
 2804        }
 2805        self.select_next_state = None;
 2806        self.select_prev_state = None;
 2807        self.select_syntax_node_history.try_clear();
 2808        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2809        self.snippet_stack
 2810            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2811        self.take_rename(false, window, cx);
 2812
 2813        let newest_selection = self.selections.newest_anchor();
 2814        let new_cursor_position = newest_selection.head();
 2815        let selection_start = newest_selection.start;
 2816
 2817        if effects.nav_history {
 2818            self.push_to_nav_history(
 2819                *old_cursor_position,
 2820                Some(new_cursor_position.to_point(buffer)),
 2821                false,
 2822                cx,
 2823            );
 2824        }
 2825
 2826        if local {
 2827            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2828                if !self.registered_buffers.contains_key(&buffer_id) {
 2829                    if let Some(project) = self.project.as_ref() {
 2830                        project.update(cx, |project, cx| {
 2831                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2832                                return;
 2833                            };
 2834                            self.registered_buffers.insert(
 2835                                buffer_id,
 2836                                project.register_buffer_with_language_servers(&buffer, cx),
 2837                            );
 2838                        })
 2839                    }
 2840                }
 2841            }
 2842
 2843            let mut context_menu = self.context_menu.borrow_mut();
 2844            let completion_menu = match context_menu.as_ref() {
 2845                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2846                Some(CodeContextMenu::CodeActions(_)) => {
 2847                    *context_menu = None;
 2848                    None
 2849                }
 2850                None => None,
 2851            };
 2852            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2853            drop(context_menu);
 2854
 2855            if effects.completions {
 2856                if let Some(completion_position) = completion_position {
 2857                    let start_offset = selection_start.to_offset(buffer);
 2858                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2859                    let continue_showing = if position_matches {
 2860                        if self.snippet_stack.is_empty() {
 2861                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2862                        } else {
 2863                            // Snippet choices can be shown even when the cursor is in whitespace.
 2864                            // Dismissing the menu when actions like backspace
 2865                            true
 2866                        }
 2867                    } else {
 2868                        false
 2869                    };
 2870
 2871                    if continue_showing {
 2872                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2873                    } else {
 2874                        self.hide_context_menu(window, cx);
 2875                    }
 2876                }
 2877            }
 2878
 2879            hide_hover(self, cx);
 2880
 2881            if old_cursor_position.to_display_point(&display_map).row()
 2882                != new_cursor_position.to_display_point(&display_map).row()
 2883            {
 2884                self.available_code_actions.take();
 2885            }
 2886            self.refresh_code_actions(window, cx);
 2887            self.refresh_document_highlights(cx);
 2888            self.refresh_selected_text_highlights(false, window, cx);
 2889            refresh_matching_bracket_highlights(self, window, cx);
 2890            self.update_visible_inline_completion(window, cx);
 2891            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2892            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2893            self.inline_blame_popover.take();
 2894            if self.git_blame_inline_enabled {
 2895                self.start_inline_blame_timer(window, cx);
 2896            }
 2897        }
 2898
 2899        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2900        cx.emit(EditorEvent::SelectionsChanged { local });
 2901
 2902        let selections = &self.selections.disjoint;
 2903        if selections.len() == 1 {
 2904            cx.emit(SearchEvent::ActiveMatchChanged)
 2905        }
 2906        if local {
 2907            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2908                let inmemory_selections = selections
 2909                    .iter()
 2910                    .map(|s| {
 2911                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2912                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2913                    })
 2914                    .collect();
 2915                self.update_restoration_data(cx, |data| {
 2916                    data.selections = inmemory_selections;
 2917                });
 2918
 2919                if WorkspaceSettings::get(None, cx).restore_on_startup
 2920                    != RestoreOnStartupBehavior::None
 2921                {
 2922                    if let Some(workspace_id) =
 2923                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2924                    {
 2925                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2926                        let selections = selections.clone();
 2927                        let background_executor = cx.background_executor().clone();
 2928                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2929                        self.serialize_selections = cx.background_spawn(async move {
 2930                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2931                    let db_selections = selections
 2932                        .iter()
 2933                        .map(|selection| {
 2934                            (
 2935                                selection.start.to_offset(&snapshot),
 2936                                selection.end.to_offset(&snapshot),
 2937                            )
 2938                        })
 2939                        .collect();
 2940
 2941                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2942                        .await
 2943                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2944                        .log_err();
 2945                });
 2946                    }
 2947                }
 2948            }
 2949        }
 2950
 2951        cx.notify();
 2952    }
 2953
 2954    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2955        use text::ToOffset as _;
 2956        use text::ToPoint as _;
 2957
 2958        if self.mode.is_minimap()
 2959            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2960        {
 2961            return;
 2962        }
 2963
 2964        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2965            return;
 2966        };
 2967
 2968        let snapshot = singleton.read(cx).snapshot();
 2969        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2970            let display_snapshot = display_map.snapshot(cx);
 2971
 2972            display_snapshot
 2973                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2974                .map(|fold| {
 2975                    fold.range.start.text_anchor.to_point(&snapshot)
 2976                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2977                })
 2978                .collect()
 2979        });
 2980        self.update_restoration_data(cx, |data| {
 2981            data.folds = inmemory_folds;
 2982        });
 2983
 2984        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2985            return;
 2986        };
 2987        let background_executor = cx.background_executor().clone();
 2988        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2989        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2990            display_map
 2991                .snapshot(cx)
 2992                .folds_in_range(0..snapshot.len())
 2993                .map(|fold| {
 2994                    (
 2995                        fold.range.start.text_anchor.to_offset(&snapshot),
 2996                        fold.range.end.text_anchor.to_offset(&snapshot),
 2997                    )
 2998                })
 2999                .collect()
 3000        });
 3001        self.serialize_folds = cx.background_spawn(async move {
 3002            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3003            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3004                .await
 3005                .with_context(|| {
 3006                    format!(
 3007                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3008                    )
 3009                })
 3010                .log_err();
 3011        });
 3012    }
 3013
 3014    pub fn sync_selections(
 3015        &mut self,
 3016        other: Entity<Editor>,
 3017        cx: &mut Context<Self>,
 3018    ) -> gpui::Subscription {
 3019        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3020        self.selections.change_with(cx, |selections| {
 3021            selections.select_anchors(other_selections);
 3022        });
 3023
 3024        let other_subscription =
 3025            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3026                EditorEvent::SelectionsChanged { local: true } => {
 3027                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3028                    if other_selections.is_empty() {
 3029                        return;
 3030                    }
 3031                    this.selections.change_with(cx, |selections| {
 3032                        selections.select_anchors(other_selections);
 3033                    });
 3034                }
 3035                _ => {}
 3036            });
 3037
 3038        let this_subscription =
 3039            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3040                EditorEvent::SelectionsChanged { local: true } => {
 3041                    let these_selections = this.selections.disjoint.to_vec();
 3042                    if these_selections.is_empty() {
 3043                        return;
 3044                    }
 3045                    other.update(cx, |other_editor, cx| {
 3046                        other_editor.selections.change_with(cx, |selections| {
 3047                            selections.select_anchors(these_selections);
 3048                        })
 3049                    });
 3050                }
 3051                _ => {}
 3052            });
 3053
 3054        Subscription::join(other_subscription, this_subscription)
 3055    }
 3056
 3057    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3058    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3059    /// effects of selection change occur at the end of the transaction.
 3060    pub fn change_selections<R>(
 3061        &mut self,
 3062        effects: impl Into<SelectionEffects>,
 3063        window: &mut Window,
 3064        cx: &mut Context<Self>,
 3065        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3066    ) -> R {
 3067        let effects = effects.into();
 3068        if let Some(state) = &mut self.deferred_selection_effects_state {
 3069            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3070            state.effects.completions = effects.completions;
 3071            state.effects.nav_history |= effects.nav_history;
 3072            let (changed, result) = self.selections.change_with(cx, change);
 3073            state.changed |= changed;
 3074            return result;
 3075        }
 3076        let mut state = DeferredSelectionEffectsState {
 3077            changed: false,
 3078            effects,
 3079            old_cursor_position: self.selections.newest_anchor().head(),
 3080            history_entry: SelectionHistoryEntry {
 3081                selections: self.selections.disjoint_anchors(),
 3082                select_next_state: self.select_next_state.clone(),
 3083                select_prev_state: self.select_prev_state.clone(),
 3084                add_selections_state: self.add_selections_state.clone(),
 3085            },
 3086        };
 3087        let (changed, result) = self.selections.change_with(cx, change);
 3088        state.changed = state.changed || changed;
 3089        if self.defer_selection_effects {
 3090            self.deferred_selection_effects_state = Some(state);
 3091        } else {
 3092            self.apply_selection_effects(state, window, cx);
 3093        }
 3094        result
 3095    }
 3096
 3097    /// Defers the effects of selection change, so that the effects of multiple calls to
 3098    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3099    /// to selection history and the state of popovers based on selection position aren't
 3100    /// erroneously updated.
 3101    pub fn with_selection_effects_deferred<R>(
 3102        &mut self,
 3103        window: &mut Window,
 3104        cx: &mut Context<Self>,
 3105        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3106    ) -> R {
 3107        let already_deferred = self.defer_selection_effects;
 3108        self.defer_selection_effects = true;
 3109        let result = update(self, window, cx);
 3110        if !already_deferred {
 3111            self.defer_selection_effects = false;
 3112            if let Some(state) = self.deferred_selection_effects_state.take() {
 3113                self.apply_selection_effects(state, window, cx);
 3114            }
 3115        }
 3116        result
 3117    }
 3118
 3119    fn apply_selection_effects(
 3120        &mut self,
 3121        state: DeferredSelectionEffectsState,
 3122        window: &mut Window,
 3123        cx: &mut Context<Self>,
 3124    ) {
 3125        if state.changed {
 3126            self.selection_history.push(state.history_entry);
 3127
 3128            if let Some(autoscroll) = state.effects.scroll {
 3129                self.request_autoscroll(autoscroll, cx);
 3130            }
 3131
 3132            let old_cursor_position = &state.old_cursor_position;
 3133
 3134            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3135
 3136            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3137                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3138            }
 3139        }
 3140    }
 3141
 3142    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3143    where
 3144        I: IntoIterator<Item = (Range<S>, T)>,
 3145        S: ToOffset,
 3146        T: Into<Arc<str>>,
 3147    {
 3148        if self.read_only(cx) {
 3149            return;
 3150        }
 3151
 3152        self.buffer
 3153            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3154    }
 3155
 3156    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3157    where
 3158        I: IntoIterator<Item = (Range<S>, T)>,
 3159        S: ToOffset,
 3160        T: Into<Arc<str>>,
 3161    {
 3162        if self.read_only(cx) {
 3163            return;
 3164        }
 3165
 3166        self.buffer.update(cx, |buffer, cx| {
 3167            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3168        });
 3169    }
 3170
 3171    pub fn edit_with_block_indent<I, S, T>(
 3172        &mut self,
 3173        edits: I,
 3174        original_indent_columns: Vec<Option<u32>>,
 3175        cx: &mut Context<Self>,
 3176    ) where
 3177        I: IntoIterator<Item = (Range<S>, T)>,
 3178        S: ToOffset,
 3179        T: Into<Arc<str>>,
 3180    {
 3181        if self.read_only(cx) {
 3182            return;
 3183        }
 3184
 3185        self.buffer.update(cx, |buffer, cx| {
 3186            buffer.edit(
 3187                edits,
 3188                Some(AutoindentMode::Block {
 3189                    original_indent_columns,
 3190                }),
 3191                cx,
 3192            )
 3193        });
 3194    }
 3195
 3196    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3197        self.hide_context_menu(window, cx);
 3198
 3199        match phase {
 3200            SelectPhase::Begin {
 3201                position,
 3202                add,
 3203                click_count,
 3204            } => self.begin_selection(position, add, click_count, window, cx),
 3205            SelectPhase::BeginColumnar {
 3206                position,
 3207                goal_column,
 3208                reset,
 3209            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3210            SelectPhase::Extend {
 3211                position,
 3212                click_count,
 3213            } => self.extend_selection(position, click_count, window, cx),
 3214            SelectPhase::Update {
 3215                position,
 3216                goal_column,
 3217                scroll_delta,
 3218            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3219            SelectPhase::End => self.end_selection(window, cx),
 3220        }
 3221    }
 3222
 3223    fn extend_selection(
 3224        &mut self,
 3225        position: DisplayPoint,
 3226        click_count: usize,
 3227        window: &mut Window,
 3228        cx: &mut Context<Self>,
 3229    ) {
 3230        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3231        let tail = self.selections.newest::<usize>(cx).tail();
 3232        self.begin_selection(position, false, click_count, window, cx);
 3233
 3234        let position = position.to_offset(&display_map, Bias::Left);
 3235        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3236
 3237        let mut pending_selection = self
 3238            .selections
 3239            .pending_anchor()
 3240            .expect("extend_selection not called with pending selection");
 3241        if position >= tail {
 3242            pending_selection.start = tail_anchor;
 3243        } else {
 3244            pending_selection.end = tail_anchor;
 3245            pending_selection.reversed = true;
 3246        }
 3247
 3248        let mut pending_mode = self.selections.pending_mode().unwrap();
 3249        match &mut pending_mode {
 3250            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3251            _ => {}
 3252        }
 3253
 3254        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3255            SelectionEffects::scroll(Autoscroll::fit())
 3256        } else {
 3257            SelectionEffects::no_scroll()
 3258        };
 3259
 3260        self.change_selections(effects, window, cx, |s| {
 3261            s.set_pending(pending_selection, pending_mode)
 3262        });
 3263    }
 3264
 3265    fn begin_selection(
 3266        &mut self,
 3267        position: DisplayPoint,
 3268        add: bool,
 3269        click_count: usize,
 3270        window: &mut Window,
 3271        cx: &mut Context<Self>,
 3272    ) {
 3273        if !self.focus_handle.is_focused(window) {
 3274            self.last_focused_descendant = None;
 3275            window.focus(&self.focus_handle);
 3276        }
 3277
 3278        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3279        let buffer = &display_map.buffer_snapshot;
 3280        let position = display_map.clip_point(position, Bias::Left);
 3281
 3282        let start;
 3283        let end;
 3284        let mode;
 3285        let mut auto_scroll;
 3286        match click_count {
 3287            1 => {
 3288                start = buffer.anchor_before(position.to_point(&display_map));
 3289                end = start;
 3290                mode = SelectMode::Character;
 3291                auto_scroll = true;
 3292            }
 3293            2 => {
 3294                let range = movement::surrounding_word(&display_map, position);
 3295                start = buffer.anchor_before(range.start.to_point(&display_map));
 3296                end = buffer.anchor_before(range.end.to_point(&display_map));
 3297                mode = SelectMode::Word(start..end);
 3298                auto_scroll = true;
 3299            }
 3300            3 => {
 3301                let position = display_map
 3302                    .clip_point(position, Bias::Left)
 3303                    .to_point(&display_map);
 3304                let line_start = display_map.prev_line_boundary(position).0;
 3305                let next_line_start = buffer.clip_point(
 3306                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3307                    Bias::Left,
 3308                );
 3309                start = buffer.anchor_before(line_start);
 3310                end = buffer.anchor_before(next_line_start);
 3311                mode = SelectMode::Line(start..end);
 3312                auto_scroll = true;
 3313            }
 3314            _ => {
 3315                start = buffer.anchor_before(0);
 3316                end = buffer.anchor_before(buffer.len());
 3317                mode = SelectMode::All;
 3318                auto_scroll = false;
 3319            }
 3320        }
 3321        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3322
 3323        let point_to_delete: Option<usize> = {
 3324            let selected_points: Vec<Selection<Point>> =
 3325                self.selections.disjoint_in_range(start..end, cx);
 3326
 3327            if !add || click_count > 1 {
 3328                None
 3329            } else if !selected_points.is_empty() {
 3330                Some(selected_points[0].id)
 3331            } else {
 3332                let clicked_point_already_selected =
 3333                    self.selections.disjoint.iter().find(|selection| {
 3334                        selection.start.to_point(buffer) == start.to_point(buffer)
 3335                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3336                    });
 3337
 3338                clicked_point_already_selected.map(|selection| selection.id)
 3339            }
 3340        };
 3341
 3342        let selections_count = self.selections.count();
 3343
 3344        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3345            if let Some(point_to_delete) = point_to_delete {
 3346                s.delete(point_to_delete);
 3347
 3348                if selections_count == 1 {
 3349                    s.set_pending_anchor_range(start..end, mode);
 3350                }
 3351            } else {
 3352                if !add {
 3353                    s.clear_disjoint();
 3354                }
 3355
 3356                s.set_pending_anchor_range(start..end, mode);
 3357            }
 3358        });
 3359    }
 3360
 3361    fn begin_columnar_selection(
 3362        &mut self,
 3363        position: DisplayPoint,
 3364        goal_column: u32,
 3365        reset: bool,
 3366        window: &mut Window,
 3367        cx: &mut Context<Self>,
 3368    ) {
 3369        if !self.focus_handle.is_focused(window) {
 3370            self.last_focused_descendant = None;
 3371            window.focus(&self.focus_handle);
 3372        }
 3373
 3374        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3375
 3376        if reset {
 3377            let pointer_position = display_map
 3378                .buffer_snapshot
 3379                .anchor_before(position.to_point(&display_map));
 3380
 3381            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3382                s.clear_disjoint();
 3383                s.set_pending_anchor_range(
 3384                    pointer_position..pointer_position,
 3385                    SelectMode::Character,
 3386                );
 3387            });
 3388            if position.column() != goal_column {
 3389                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3390            } else {
 3391                self.columnar_display_point = None;
 3392            }
 3393        }
 3394
 3395        let tail = self.selections.newest::<Point>(cx).tail();
 3396        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3397
 3398        if !reset {
 3399            self.columnar_display_point = None;
 3400            self.select_columns(
 3401                tail.to_display_point(&display_map),
 3402                position,
 3403                goal_column,
 3404                &display_map,
 3405                window,
 3406                cx,
 3407            );
 3408        }
 3409    }
 3410
 3411    fn update_selection(
 3412        &mut self,
 3413        position: DisplayPoint,
 3414        goal_column: u32,
 3415        scroll_delta: gpui::Point<f32>,
 3416        window: &mut Window,
 3417        cx: &mut Context<Self>,
 3418    ) {
 3419        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3420
 3421        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3422            let tail = self
 3423                .columnar_display_point
 3424                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3425            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3426        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3427            let buffer = self.buffer.read(cx).snapshot(cx);
 3428            let head;
 3429            let tail;
 3430            let mode = self.selections.pending_mode().unwrap();
 3431            match &mode {
 3432                SelectMode::Character => {
 3433                    head = position.to_point(&display_map);
 3434                    tail = pending.tail().to_point(&buffer);
 3435                }
 3436                SelectMode::Word(original_range) => {
 3437                    let original_display_range = original_range.start.to_display_point(&display_map)
 3438                        ..original_range.end.to_display_point(&display_map);
 3439                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3440                        ..original_display_range.end.to_point(&display_map);
 3441                    if movement::is_inside_word(&display_map, position)
 3442                        || original_display_range.contains(&position)
 3443                    {
 3444                        let word_range = movement::surrounding_word(&display_map, position);
 3445                        if word_range.start < original_display_range.start {
 3446                            head = word_range.start.to_point(&display_map);
 3447                        } else {
 3448                            head = word_range.end.to_point(&display_map);
 3449                        }
 3450                    } else {
 3451                        head = position.to_point(&display_map);
 3452                    }
 3453
 3454                    if head <= original_buffer_range.start {
 3455                        tail = original_buffer_range.end;
 3456                    } else {
 3457                        tail = original_buffer_range.start;
 3458                    }
 3459                }
 3460                SelectMode::Line(original_range) => {
 3461                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3462
 3463                    let position = display_map
 3464                        .clip_point(position, Bias::Left)
 3465                        .to_point(&display_map);
 3466                    let line_start = display_map.prev_line_boundary(position).0;
 3467                    let next_line_start = buffer.clip_point(
 3468                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3469                        Bias::Left,
 3470                    );
 3471
 3472                    if line_start < original_range.start {
 3473                        head = line_start
 3474                    } else {
 3475                        head = next_line_start
 3476                    }
 3477
 3478                    if head <= original_range.start {
 3479                        tail = original_range.end;
 3480                    } else {
 3481                        tail = original_range.start;
 3482                    }
 3483                }
 3484                SelectMode::All => {
 3485                    return;
 3486                }
 3487            };
 3488
 3489            if head < tail {
 3490                pending.start = buffer.anchor_before(head);
 3491                pending.end = buffer.anchor_before(tail);
 3492                pending.reversed = true;
 3493            } else {
 3494                pending.start = buffer.anchor_before(tail);
 3495                pending.end = buffer.anchor_before(head);
 3496                pending.reversed = false;
 3497            }
 3498
 3499            self.change_selections(None, window, cx, |s| {
 3500                s.set_pending(pending, mode);
 3501            });
 3502        } else {
 3503            log::error!("update_selection dispatched with no pending selection");
 3504            return;
 3505        }
 3506
 3507        self.apply_scroll_delta(scroll_delta, window, cx);
 3508        cx.notify();
 3509    }
 3510
 3511    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3512        self.columnar_selection_tail.take();
 3513        if self.selections.pending_anchor().is_some() {
 3514            let selections = self.selections.all::<usize>(cx);
 3515            self.change_selections(None, window, cx, |s| {
 3516                s.select(selections);
 3517                s.clear_pending();
 3518            });
 3519        }
 3520    }
 3521
 3522    fn select_columns(
 3523        &mut self,
 3524        tail: DisplayPoint,
 3525        head: DisplayPoint,
 3526        goal_column: u32,
 3527        display_map: &DisplaySnapshot,
 3528        window: &mut Window,
 3529        cx: &mut Context<Self>,
 3530    ) {
 3531        let start_row = cmp::min(tail.row(), head.row());
 3532        let end_row = cmp::max(tail.row(), head.row());
 3533        let start_column = cmp::min(tail.column(), goal_column);
 3534        let end_column = cmp::max(tail.column(), goal_column);
 3535        let reversed = start_column < tail.column();
 3536
 3537        let selection_ranges = (start_row.0..=end_row.0)
 3538            .map(DisplayRow)
 3539            .filter_map(|row| {
 3540                if !display_map.is_block_line(row) {
 3541                    let start = display_map
 3542                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3543                        .to_point(display_map);
 3544                    let end = display_map
 3545                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3546                        .to_point(display_map);
 3547                    if reversed {
 3548                        Some(end..start)
 3549                    } else {
 3550                        Some(start..end)
 3551                    }
 3552                } else {
 3553                    None
 3554                }
 3555            })
 3556            .collect::<Vec<_>>();
 3557
 3558        let mut non_empty_ranges = selection_ranges
 3559            .iter()
 3560            .filter(|selection_range| selection_range.start != selection_range.end)
 3561            .peekable();
 3562
 3563        let ranges = if non_empty_ranges.peek().is_some() {
 3564            non_empty_ranges.cloned().collect()
 3565        } else {
 3566            selection_ranges
 3567        };
 3568
 3569        self.change_selections(None, window, cx, |s| {
 3570            s.select_ranges(ranges);
 3571        });
 3572        cx.notify();
 3573    }
 3574
 3575    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3576        self.selections
 3577            .all_adjusted(cx)
 3578            .iter()
 3579            .any(|selection| !selection.is_empty())
 3580    }
 3581
 3582    pub fn has_pending_nonempty_selection(&self) -> bool {
 3583        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3584            Some(Selection { start, end, .. }) => start != end,
 3585            None => false,
 3586        };
 3587
 3588        pending_nonempty_selection
 3589            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3590    }
 3591
 3592    pub fn has_pending_selection(&self) -> bool {
 3593        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3594    }
 3595
 3596    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3597        self.selection_mark_mode = false;
 3598        self.selection_drag_state = SelectionDragState::None;
 3599
 3600        if self.clear_expanded_diff_hunks(cx) {
 3601            cx.notify();
 3602            return;
 3603        }
 3604        if self.dismiss_menus_and_popups(true, window, cx) {
 3605            return;
 3606        }
 3607
 3608        if self.mode.is_full()
 3609            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3610        {
 3611            return;
 3612        }
 3613
 3614        cx.propagate();
 3615    }
 3616
 3617    pub fn dismiss_menus_and_popups(
 3618        &mut self,
 3619        is_user_requested: bool,
 3620        window: &mut Window,
 3621        cx: &mut Context<Self>,
 3622    ) -> bool {
 3623        if self.take_rename(false, window, cx).is_some() {
 3624            return true;
 3625        }
 3626
 3627        if hide_hover(self, cx) {
 3628            return true;
 3629        }
 3630
 3631        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3632            return true;
 3633        }
 3634
 3635        if self.hide_context_menu(window, cx).is_some() {
 3636            return true;
 3637        }
 3638
 3639        if self.mouse_context_menu.take().is_some() {
 3640            return true;
 3641        }
 3642
 3643        if is_user_requested && self.discard_inline_completion(true, cx) {
 3644            return true;
 3645        }
 3646
 3647        if self.snippet_stack.pop().is_some() {
 3648            return true;
 3649        }
 3650
 3651        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3652            self.dismiss_diagnostics(cx);
 3653            return true;
 3654        }
 3655
 3656        false
 3657    }
 3658
 3659    fn linked_editing_ranges_for(
 3660        &self,
 3661        selection: Range<text::Anchor>,
 3662        cx: &App,
 3663    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3664        if self.linked_edit_ranges.is_empty() {
 3665            return None;
 3666        }
 3667        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3668            selection.end.buffer_id.and_then(|end_buffer_id| {
 3669                if selection.start.buffer_id != Some(end_buffer_id) {
 3670                    return None;
 3671                }
 3672                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3673                let snapshot = buffer.read(cx).snapshot();
 3674                self.linked_edit_ranges
 3675                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3676                    .map(|ranges| (ranges, snapshot, buffer))
 3677            })?;
 3678        use text::ToOffset as TO;
 3679        // find offset from the start of current range to current cursor position
 3680        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3681
 3682        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3683        let start_difference = start_offset - start_byte_offset;
 3684        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3685        let end_difference = end_offset - start_byte_offset;
 3686        // Current range has associated linked ranges.
 3687        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3688        for range in linked_ranges.iter() {
 3689            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3690            let end_offset = start_offset + end_difference;
 3691            let start_offset = start_offset + start_difference;
 3692            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3693                continue;
 3694            }
 3695            if self.selections.disjoint_anchor_ranges().any(|s| {
 3696                if s.start.buffer_id != selection.start.buffer_id
 3697                    || s.end.buffer_id != selection.end.buffer_id
 3698                {
 3699                    return false;
 3700                }
 3701                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3702                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3703            }) {
 3704                continue;
 3705            }
 3706            let start = buffer_snapshot.anchor_after(start_offset);
 3707            let end = buffer_snapshot.anchor_after(end_offset);
 3708            linked_edits
 3709                .entry(buffer.clone())
 3710                .or_default()
 3711                .push(start..end);
 3712        }
 3713        Some(linked_edits)
 3714    }
 3715
 3716    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3717        let text: Arc<str> = text.into();
 3718
 3719        if self.read_only(cx) {
 3720            return;
 3721        }
 3722
 3723        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3724
 3725        let selections = self.selections.all_adjusted(cx);
 3726        let mut bracket_inserted = false;
 3727        let mut edits = Vec::new();
 3728        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3729        let mut new_selections = Vec::with_capacity(selections.len());
 3730        let mut new_autoclose_regions = Vec::new();
 3731        let snapshot = self.buffer.read(cx).read(cx);
 3732        let mut clear_linked_edit_ranges = false;
 3733
 3734        for (selection, autoclose_region) in
 3735            self.selections_with_autoclose_regions(selections, &snapshot)
 3736        {
 3737            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3738                // Determine if the inserted text matches the opening or closing
 3739                // bracket of any of this language's bracket pairs.
 3740                let mut bracket_pair = None;
 3741                let mut is_bracket_pair_start = false;
 3742                let mut is_bracket_pair_end = false;
 3743                if !text.is_empty() {
 3744                    let mut bracket_pair_matching_end = None;
 3745                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3746                    //  and they are removing the character that triggered IME popup.
 3747                    for (pair, enabled) in scope.brackets() {
 3748                        if !pair.close && !pair.surround {
 3749                            continue;
 3750                        }
 3751
 3752                        if enabled && pair.start.ends_with(text.as_ref()) {
 3753                            let prefix_len = pair.start.len() - text.len();
 3754                            let preceding_text_matches_prefix = prefix_len == 0
 3755                                || (selection.start.column >= (prefix_len as u32)
 3756                                    && snapshot.contains_str_at(
 3757                                        Point::new(
 3758                                            selection.start.row,
 3759                                            selection.start.column - (prefix_len as u32),
 3760                                        ),
 3761                                        &pair.start[..prefix_len],
 3762                                    ));
 3763                            if preceding_text_matches_prefix {
 3764                                bracket_pair = Some(pair.clone());
 3765                                is_bracket_pair_start = true;
 3766                                break;
 3767                            }
 3768                        }
 3769                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3770                        {
 3771                            // take first bracket pair matching end, but don't break in case a later bracket
 3772                            // pair matches start
 3773                            bracket_pair_matching_end = Some(pair.clone());
 3774                        }
 3775                    }
 3776                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3777                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3778                        is_bracket_pair_end = true;
 3779                    }
 3780                }
 3781
 3782                if let Some(bracket_pair) = bracket_pair {
 3783                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3784                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3785                    let auto_surround =
 3786                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3787                    if selection.is_empty() {
 3788                        if is_bracket_pair_start {
 3789                            // If the inserted text is a suffix of an opening bracket and the
 3790                            // selection is preceded by the rest of the opening bracket, then
 3791                            // insert the closing bracket.
 3792                            let following_text_allows_autoclose = snapshot
 3793                                .chars_at(selection.start)
 3794                                .next()
 3795                                .map_or(true, |c| scope.should_autoclose_before(c));
 3796
 3797                            let preceding_text_allows_autoclose = selection.start.column == 0
 3798                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3799                                    true,
 3800                                    |c| {
 3801                                        bracket_pair.start != bracket_pair.end
 3802                                            || !snapshot
 3803                                                .char_classifier_at(selection.start)
 3804                                                .is_word(c)
 3805                                    },
 3806                                );
 3807
 3808                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3809                                && bracket_pair.start.len() == 1
 3810                            {
 3811                                let target = bracket_pair.start.chars().next().unwrap();
 3812                                let current_line_count = snapshot
 3813                                    .reversed_chars_at(selection.start)
 3814                                    .take_while(|&c| c != '\n')
 3815                                    .filter(|&c| c == target)
 3816                                    .count();
 3817                                current_line_count % 2 == 1
 3818                            } else {
 3819                                false
 3820                            };
 3821
 3822                            if autoclose
 3823                                && bracket_pair.close
 3824                                && following_text_allows_autoclose
 3825                                && preceding_text_allows_autoclose
 3826                                && !is_closing_quote
 3827                            {
 3828                                let anchor = snapshot.anchor_before(selection.end);
 3829                                new_selections.push((selection.map(|_| anchor), text.len()));
 3830                                new_autoclose_regions.push((
 3831                                    anchor,
 3832                                    text.len(),
 3833                                    selection.id,
 3834                                    bracket_pair.clone(),
 3835                                ));
 3836                                edits.push((
 3837                                    selection.range(),
 3838                                    format!("{}{}", text, bracket_pair.end).into(),
 3839                                ));
 3840                                bracket_inserted = true;
 3841                                continue;
 3842                            }
 3843                        }
 3844
 3845                        if let Some(region) = autoclose_region {
 3846                            // If the selection is followed by an auto-inserted closing bracket,
 3847                            // then don't insert that closing bracket again; just move the selection
 3848                            // past the closing bracket.
 3849                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3850                                && text.as_ref() == region.pair.end.as_str();
 3851                            if should_skip {
 3852                                let anchor = snapshot.anchor_after(selection.end);
 3853                                new_selections
 3854                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3855                                continue;
 3856                            }
 3857                        }
 3858
 3859                        let always_treat_brackets_as_autoclosed = snapshot
 3860                            .language_settings_at(selection.start, cx)
 3861                            .always_treat_brackets_as_autoclosed;
 3862                        if always_treat_brackets_as_autoclosed
 3863                            && is_bracket_pair_end
 3864                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3865                        {
 3866                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3867                            // and the inserted text is a closing bracket and the selection is followed
 3868                            // by the closing bracket then move the selection past the closing bracket.
 3869                            let anchor = snapshot.anchor_after(selection.end);
 3870                            new_selections.push((selection.map(|_| anchor), text.len()));
 3871                            continue;
 3872                        }
 3873                    }
 3874                    // If an opening bracket is 1 character long and is typed while
 3875                    // text is selected, then surround that text with the bracket pair.
 3876                    else if auto_surround
 3877                        && bracket_pair.surround
 3878                        && is_bracket_pair_start
 3879                        && bracket_pair.start.chars().count() == 1
 3880                    {
 3881                        edits.push((selection.start..selection.start, text.clone()));
 3882                        edits.push((
 3883                            selection.end..selection.end,
 3884                            bracket_pair.end.as_str().into(),
 3885                        ));
 3886                        bracket_inserted = true;
 3887                        new_selections.push((
 3888                            Selection {
 3889                                id: selection.id,
 3890                                start: snapshot.anchor_after(selection.start),
 3891                                end: snapshot.anchor_before(selection.end),
 3892                                reversed: selection.reversed,
 3893                                goal: selection.goal,
 3894                            },
 3895                            0,
 3896                        ));
 3897                        continue;
 3898                    }
 3899                }
 3900            }
 3901
 3902            if self.auto_replace_emoji_shortcode
 3903                && selection.is_empty()
 3904                && text.as_ref().ends_with(':')
 3905            {
 3906                if let Some(possible_emoji_short_code) =
 3907                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3908                {
 3909                    if !possible_emoji_short_code.is_empty() {
 3910                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3911                            let emoji_shortcode_start = Point::new(
 3912                                selection.start.row,
 3913                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3914                            );
 3915
 3916                            // Remove shortcode from buffer
 3917                            edits.push((
 3918                                emoji_shortcode_start..selection.start,
 3919                                "".to_string().into(),
 3920                            ));
 3921                            new_selections.push((
 3922                                Selection {
 3923                                    id: selection.id,
 3924                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3925                                    end: snapshot.anchor_before(selection.start),
 3926                                    reversed: selection.reversed,
 3927                                    goal: selection.goal,
 3928                                },
 3929                                0,
 3930                            ));
 3931
 3932                            // Insert emoji
 3933                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3934                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3935                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3936
 3937                            continue;
 3938                        }
 3939                    }
 3940                }
 3941            }
 3942
 3943            // If not handling any auto-close operation, then just replace the selected
 3944            // text with the given input and move the selection to the end of the
 3945            // newly inserted text.
 3946            let anchor = snapshot.anchor_after(selection.end);
 3947            if !self.linked_edit_ranges.is_empty() {
 3948                let start_anchor = snapshot.anchor_before(selection.start);
 3949
 3950                let is_word_char = text.chars().next().map_or(true, |char| {
 3951                    let classifier = snapshot
 3952                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3953                        .ignore_punctuation(true);
 3954                    classifier.is_word(char)
 3955                });
 3956
 3957                if is_word_char {
 3958                    if let Some(ranges) = self
 3959                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3960                    {
 3961                        for (buffer, edits) in ranges {
 3962                            linked_edits
 3963                                .entry(buffer.clone())
 3964                                .or_default()
 3965                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3966                        }
 3967                    }
 3968                } else {
 3969                    clear_linked_edit_ranges = true;
 3970                }
 3971            }
 3972
 3973            new_selections.push((selection.map(|_| anchor), 0));
 3974            edits.push((selection.start..selection.end, text.clone()));
 3975        }
 3976
 3977        drop(snapshot);
 3978
 3979        self.transact(window, cx, |this, window, cx| {
 3980            if clear_linked_edit_ranges {
 3981                this.linked_edit_ranges.clear();
 3982            }
 3983            let initial_buffer_versions =
 3984                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3985
 3986            this.buffer.update(cx, |buffer, cx| {
 3987                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3988            });
 3989            for (buffer, edits) in linked_edits {
 3990                buffer.update(cx, |buffer, cx| {
 3991                    let snapshot = buffer.snapshot();
 3992                    let edits = edits
 3993                        .into_iter()
 3994                        .map(|(range, text)| {
 3995                            use text::ToPoint as TP;
 3996                            let end_point = TP::to_point(&range.end, &snapshot);
 3997                            let start_point = TP::to_point(&range.start, &snapshot);
 3998                            (start_point..end_point, text)
 3999                        })
 4000                        .sorted_by_key(|(range, _)| range.start);
 4001                    buffer.edit(edits, None, cx);
 4002                })
 4003            }
 4004            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4005            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4006            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4007            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4008                .zip(new_selection_deltas)
 4009                .map(|(selection, delta)| Selection {
 4010                    id: selection.id,
 4011                    start: selection.start + delta,
 4012                    end: selection.end + delta,
 4013                    reversed: selection.reversed,
 4014                    goal: SelectionGoal::None,
 4015                })
 4016                .collect::<Vec<_>>();
 4017
 4018            let mut i = 0;
 4019            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4020                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4021                let start = map.buffer_snapshot.anchor_before(position);
 4022                let end = map.buffer_snapshot.anchor_after(position);
 4023                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4024                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4025                        Ordering::Less => i += 1,
 4026                        Ordering::Greater => break,
 4027                        Ordering::Equal => {
 4028                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4029                                Ordering::Less => i += 1,
 4030                                Ordering::Equal => break,
 4031                                Ordering::Greater => break,
 4032                            }
 4033                        }
 4034                    }
 4035                }
 4036                this.autoclose_regions.insert(
 4037                    i,
 4038                    AutocloseRegion {
 4039                        selection_id,
 4040                        range: start..end,
 4041                        pair,
 4042                    },
 4043                );
 4044            }
 4045
 4046            let had_active_inline_completion = this.has_active_inline_completion();
 4047            this.change_selections(
 4048                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4049                window,
 4050                cx,
 4051                |s| s.select(new_selections),
 4052            );
 4053
 4054            if !bracket_inserted {
 4055                if let Some(on_type_format_task) =
 4056                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4057                {
 4058                    on_type_format_task.detach_and_log_err(cx);
 4059                }
 4060            }
 4061
 4062            let editor_settings = EditorSettings::get_global(cx);
 4063            if bracket_inserted
 4064                && (editor_settings.auto_signature_help
 4065                    || editor_settings.show_signature_help_after_edits)
 4066            {
 4067                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4068            }
 4069
 4070            let trigger_in_words =
 4071                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4072            if this.hard_wrap.is_some() {
 4073                let latest: Range<Point> = this.selections.newest(cx).range();
 4074                if latest.is_empty()
 4075                    && this
 4076                        .buffer()
 4077                        .read(cx)
 4078                        .snapshot(cx)
 4079                        .line_len(MultiBufferRow(latest.start.row))
 4080                        == latest.start.column
 4081                {
 4082                    this.rewrap_impl(
 4083                        RewrapOptions {
 4084                            override_language_settings: true,
 4085                            preserve_existing_whitespace: true,
 4086                        },
 4087                        cx,
 4088                    )
 4089                }
 4090            }
 4091            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4092            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4093            this.refresh_inline_completion(true, false, window, cx);
 4094            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4095        });
 4096    }
 4097
 4098    fn find_possible_emoji_shortcode_at_position(
 4099        snapshot: &MultiBufferSnapshot,
 4100        position: Point,
 4101    ) -> Option<String> {
 4102        let mut chars = Vec::new();
 4103        let mut found_colon = false;
 4104        for char in snapshot.reversed_chars_at(position).take(100) {
 4105            // Found a possible emoji shortcode in the middle of the buffer
 4106            if found_colon {
 4107                if char.is_whitespace() {
 4108                    chars.reverse();
 4109                    return Some(chars.iter().collect());
 4110                }
 4111                // If the previous character is not a whitespace, we are in the middle of a word
 4112                // and we only want to complete the shortcode if the word is made up of other emojis
 4113                let mut containing_word = String::new();
 4114                for ch in snapshot
 4115                    .reversed_chars_at(position)
 4116                    .skip(chars.len() + 1)
 4117                    .take(100)
 4118                {
 4119                    if ch.is_whitespace() {
 4120                        break;
 4121                    }
 4122                    containing_word.push(ch);
 4123                }
 4124                let containing_word = containing_word.chars().rev().collect::<String>();
 4125                if util::word_consists_of_emojis(containing_word.as_str()) {
 4126                    chars.reverse();
 4127                    return Some(chars.iter().collect());
 4128                }
 4129            }
 4130
 4131            if char.is_whitespace() || !char.is_ascii() {
 4132                return None;
 4133            }
 4134            if char == ':' {
 4135                found_colon = true;
 4136            } else {
 4137                chars.push(char);
 4138            }
 4139        }
 4140        // Found a possible emoji shortcode at the beginning of the buffer
 4141        chars.reverse();
 4142        Some(chars.iter().collect())
 4143    }
 4144
 4145    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4146        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4147        self.transact(window, cx, |this, window, cx| {
 4148            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4149                let selections = this.selections.all::<usize>(cx);
 4150                let multi_buffer = this.buffer.read(cx);
 4151                let buffer = multi_buffer.snapshot(cx);
 4152                selections
 4153                    .iter()
 4154                    .map(|selection| {
 4155                        let start_point = selection.start.to_point(&buffer);
 4156                        let mut existing_indent =
 4157                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4158                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4159                        let start = selection.start;
 4160                        let end = selection.end;
 4161                        let selection_is_empty = start == end;
 4162                        let language_scope = buffer.language_scope_at(start);
 4163                        let (
 4164                            comment_delimiter,
 4165                            doc_delimiter,
 4166                            insert_extra_newline,
 4167                            indent_on_newline,
 4168                            indent_on_extra_newline,
 4169                        ) = if let Some(language) = &language_scope {
 4170                            let mut insert_extra_newline =
 4171                                insert_extra_newline_brackets(&buffer, start..end, language)
 4172                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4173
 4174                            // Comment extension on newline is allowed only for cursor selections
 4175                            let comment_delimiter = maybe!({
 4176                                if !selection_is_empty {
 4177                                    return None;
 4178                                }
 4179
 4180                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4181                                    return None;
 4182                                }
 4183
 4184                                let delimiters = language.line_comment_prefixes();
 4185                                let max_len_of_delimiter =
 4186                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4187                                let (snapshot, range) =
 4188                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4189
 4190                                let num_of_whitespaces = snapshot
 4191                                    .chars_for_range(range.clone())
 4192                                    .take_while(|c| c.is_whitespace())
 4193                                    .count();
 4194                                let comment_candidate = snapshot
 4195                                    .chars_for_range(range)
 4196                                    .skip(num_of_whitespaces)
 4197                                    .take(max_len_of_delimiter)
 4198                                    .collect::<String>();
 4199                                let (delimiter, trimmed_len) = delimiters
 4200                                    .iter()
 4201                                    .filter_map(|delimiter| {
 4202                                        let prefix = delimiter.trim_end();
 4203                                        if comment_candidate.starts_with(prefix) {
 4204                                            Some((delimiter, prefix.len()))
 4205                                        } else {
 4206                                            None
 4207                                        }
 4208                                    })
 4209                                    .max_by_key(|(_, len)| *len)?;
 4210
 4211                                let cursor_is_placed_after_comment_marker =
 4212                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4213                                if cursor_is_placed_after_comment_marker {
 4214                                    Some(delimiter.clone())
 4215                                } else {
 4216                                    None
 4217                                }
 4218                            });
 4219
 4220                            let mut indent_on_newline = IndentSize::spaces(0);
 4221                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4222
 4223                            let doc_delimiter = maybe!({
 4224                                if !selection_is_empty {
 4225                                    return None;
 4226                                }
 4227
 4228                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4229                                    return None;
 4230                                }
 4231
 4232                                let DocumentationConfig {
 4233                                    start: start_tag,
 4234                                    end: end_tag,
 4235                                    prefix: delimiter,
 4236                                    tab_size: len,
 4237                                } = language.documentation()?;
 4238
 4239                                let is_within_block_comment = buffer
 4240                                    .language_scope_at(start_point)
 4241                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4242                                if !is_within_block_comment {
 4243                                    return None;
 4244                                }
 4245
 4246                                let (snapshot, range) =
 4247                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4248
 4249                                let num_of_whitespaces = snapshot
 4250                                    .chars_for_range(range.clone())
 4251                                    .take_while(|c| c.is_whitespace())
 4252                                    .count();
 4253
 4254                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4255                                let column = start_point.column;
 4256                                let cursor_is_after_start_tag = {
 4257                                    let start_tag_len = start_tag.len();
 4258                                    let start_tag_line = snapshot
 4259                                        .chars_for_range(range.clone())
 4260                                        .skip(num_of_whitespaces)
 4261                                        .take(start_tag_len)
 4262                                        .collect::<String>();
 4263                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4264                                        num_of_whitespaces + start_tag_len <= column as usize
 4265                                    } else {
 4266                                        false
 4267                                    }
 4268                                };
 4269
 4270                                let cursor_is_after_delimiter = {
 4271                                    let delimiter_trim = delimiter.trim_end();
 4272                                    let delimiter_line = snapshot
 4273                                        .chars_for_range(range.clone())
 4274                                        .skip(num_of_whitespaces)
 4275                                        .take(delimiter_trim.len())
 4276                                        .collect::<String>();
 4277                                    if delimiter_line.starts_with(delimiter_trim) {
 4278                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4279                                    } else {
 4280                                        false
 4281                                    }
 4282                                };
 4283
 4284                                let cursor_is_before_end_tag_if_exists = {
 4285                                    let mut char_position = 0u32;
 4286                                    let mut end_tag_offset = None;
 4287
 4288                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4289                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4290                                            let chars_before_match =
 4291                                                chunk[..byte_pos].chars().count() as u32;
 4292                                            end_tag_offset =
 4293                                                Some(char_position + chars_before_match);
 4294                                            break 'outer;
 4295                                        }
 4296                                        char_position += chunk.chars().count() as u32;
 4297                                    }
 4298
 4299                                    if let Some(end_tag_offset) = end_tag_offset {
 4300                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4301                                        if cursor_is_after_start_tag {
 4302                                            if cursor_is_before_end_tag {
 4303                                                insert_extra_newline = true;
 4304                                            }
 4305                                            let cursor_is_at_start_of_end_tag =
 4306                                                column == end_tag_offset;
 4307                                            if cursor_is_at_start_of_end_tag {
 4308                                                indent_on_extra_newline.len = (*len).into();
 4309                                            }
 4310                                        }
 4311                                        cursor_is_before_end_tag
 4312                                    } else {
 4313                                        true
 4314                                    }
 4315                                };
 4316
 4317                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4318                                    && cursor_is_before_end_tag_if_exists
 4319                                {
 4320                                    if cursor_is_after_start_tag {
 4321                                        indent_on_newline.len = (*len).into();
 4322                                    }
 4323                                    Some(delimiter.clone())
 4324                                } else {
 4325                                    None
 4326                                }
 4327                            });
 4328
 4329                            (
 4330                                comment_delimiter,
 4331                                doc_delimiter,
 4332                                insert_extra_newline,
 4333                                indent_on_newline,
 4334                                indent_on_extra_newline,
 4335                            )
 4336                        } else {
 4337                            (
 4338                                None,
 4339                                None,
 4340                                false,
 4341                                IndentSize::default(),
 4342                                IndentSize::default(),
 4343                            )
 4344                        };
 4345
 4346                        let prevent_auto_indent = doc_delimiter.is_some();
 4347                        let delimiter = comment_delimiter.or(doc_delimiter);
 4348
 4349                        let capacity_for_delimiter =
 4350                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4351                        let mut new_text = String::with_capacity(
 4352                            1 + capacity_for_delimiter
 4353                                + existing_indent.len as usize
 4354                                + indent_on_newline.len as usize
 4355                                + indent_on_extra_newline.len as usize,
 4356                        );
 4357                        new_text.push('\n');
 4358                        new_text.extend(existing_indent.chars());
 4359                        new_text.extend(indent_on_newline.chars());
 4360
 4361                        if let Some(delimiter) = &delimiter {
 4362                            new_text.push_str(delimiter);
 4363                        }
 4364
 4365                        if insert_extra_newline {
 4366                            new_text.push('\n');
 4367                            new_text.extend(existing_indent.chars());
 4368                            new_text.extend(indent_on_extra_newline.chars());
 4369                        }
 4370
 4371                        let anchor = buffer.anchor_after(end);
 4372                        let new_selection = selection.map(|_| anchor);
 4373                        (
 4374                            ((start..end, new_text), prevent_auto_indent),
 4375                            (insert_extra_newline, new_selection),
 4376                        )
 4377                    })
 4378                    .unzip()
 4379            };
 4380
 4381            let mut auto_indent_edits = Vec::new();
 4382            let mut edits = Vec::new();
 4383            for (edit, prevent_auto_indent) in edits_with_flags {
 4384                if prevent_auto_indent {
 4385                    edits.push(edit);
 4386                } else {
 4387                    auto_indent_edits.push(edit);
 4388                }
 4389            }
 4390            if !edits.is_empty() {
 4391                this.edit(edits, cx);
 4392            }
 4393            if !auto_indent_edits.is_empty() {
 4394                this.edit_with_autoindent(auto_indent_edits, cx);
 4395            }
 4396
 4397            let buffer = this.buffer.read(cx).snapshot(cx);
 4398            let new_selections = selection_info
 4399                .into_iter()
 4400                .map(|(extra_newline_inserted, new_selection)| {
 4401                    let mut cursor = new_selection.end.to_point(&buffer);
 4402                    if extra_newline_inserted {
 4403                        cursor.row -= 1;
 4404                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4405                    }
 4406                    new_selection.map(|_| cursor)
 4407                })
 4408                .collect();
 4409
 4410            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4411                s.select(new_selections)
 4412            });
 4413            this.refresh_inline_completion(true, false, window, cx);
 4414        });
 4415    }
 4416
 4417    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4418        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4419
 4420        let buffer = self.buffer.read(cx);
 4421        let snapshot = buffer.snapshot(cx);
 4422
 4423        let mut edits = Vec::new();
 4424        let mut rows = Vec::new();
 4425
 4426        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4427            let cursor = selection.head();
 4428            let row = cursor.row;
 4429
 4430            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4431
 4432            let newline = "\n".to_string();
 4433            edits.push((start_of_line..start_of_line, newline));
 4434
 4435            rows.push(row + rows_inserted as u32);
 4436        }
 4437
 4438        self.transact(window, cx, |editor, window, cx| {
 4439            editor.edit(edits, cx);
 4440
 4441            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4442                let mut index = 0;
 4443                s.move_cursors_with(|map, _, _| {
 4444                    let row = rows[index];
 4445                    index += 1;
 4446
 4447                    let point = Point::new(row, 0);
 4448                    let boundary = map.next_line_boundary(point).1;
 4449                    let clipped = map.clip_point(boundary, Bias::Left);
 4450
 4451                    (clipped, SelectionGoal::None)
 4452                });
 4453            });
 4454
 4455            let mut indent_edits = Vec::new();
 4456            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4457            for row in rows {
 4458                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4459                for (row, indent) in indents {
 4460                    if indent.len == 0 {
 4461                        continue;
 4462                    }
 4463
 4464                    let text = match indent.kind {
 4465                        IndentKind::Space => " ".repeat(indent.len as usize),
 4466                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4467                    };
 4468                    let point = Point::new(row.0, 0);
 4469                    indent_edits.push((point..point, text));
 4470                }
 4471            }
 4472            editor.edit(indent_edits, cx);
 4473        });
 4474    }
 4475
 4476    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4477        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4478
 4479        let buffer = self.buffer.read(cx);
 4480        let snapshot = buffer.snapshot(cx);
 4481
 4482        let mut edits = Vec::new();
 4483        let mut rows = Vec::new();
 4484        let mut rows_inserted = 0;
 4485
 4486        for selection in self.selections.all_adjusted(cx) {
 4487            let cursor = selection.head();
 4488            let row = cursor.row;
 4489
 4490            let point = Point::new(row + 1, 0);
 4491            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4492
 4493            let newline = "\n".to_string();
 4494            edits.push((start_of_line..start_of_line, newline));
 4495
 4496            rows_inserted += 1;
 4497            rows.push(row + rows_inserted);
 4498        }
 4499
 4500        self.transact(window, cx, |editor, window, cx| {
 4501            editor.edit(edits, cx);
 4502
 4503            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4504                let mut index = 0;
 4505                s.move_cursors_with(|map, _, _| {
 4506                    let row = rows[index];
 4507                    index += 1;
 4508
 4509                    let point = Point::new(row, 0);
 4510                    let boundary = map.next_line_boundary(point).1;
 4511                    let clipped = map.clip_point(boundary, Bias::Left);
 4512
 4513                    (clipped, SelectionGoal::None)
 4514                });
 4515            });
 4516
 4517            let mut indent_edits = Vec::new();
 4518            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4519            for row in rows {
 4520                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4521                for (row, indent) in indents {
 4522                    if indent.len == 0 {
 4523                        continue;
 4524                    }
 4525
 4526                    let text = match indent.kind {
 4527                        IndentKind::Space => " ".repeat(indent.len as usize),
 4528                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4529                    };
 4530                    let point = Point::new(row.0, 0);
 4531                    indent_edits.push((point..point, text));
 4532                }
 4533            }
 4534            editor.edit(indent_edits, cx);
 4535        });
 4536    }
 4537
 4538    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4539        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4540            original_indent_columns: Vec::new(),
 4541        });
 4542        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4543    }
 4544
 4545    fn insert_with_autoindent_mode(
 4546        &mut self,
 4547        text: &str,
 4548        autoindent_mode: Option<AutoindentMode>,
 4549        window: &mut Window,
 4550        cx: &mut Context<Self>,
 4551    ) {
 4552        if self.read_only(cx) {
 4553            return;
 4554        }
 4555
 4556        let text: Arc<str> = text.into();
 4557        self.transact(window, cx, |this, window, cx| {
 4558            let old_selections = this.selections.all_adjusted(cx);
 4559            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4560                let anchors = {
 4561                    let snapshot = buffer.read(cx);
 4562                    old_selections
 4563                        .iter()
 4564                        .map(|s| {
 4565                            let anchor = snapshot.anchor_after(s.head());
 4566                            s.map(|_| anchor)
 4567                        })
 4568                        .collect::<Vec<_>>()
 4569                };
 4570                buffer.edit(
 4571                    old_selections
 4572                        .iter()
 4573                        .map(|s| (s.start..s.end, text.clone())),
 4574                    autoindent_mode,
 4575                    cx,
 4576                );
 4577                anchors
 4578            });
 4579
 4580            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4581                s.select_anchors(selection_anchors);
 4582            });
 4583
 4584            cx.notify();
 4585        });
 4586    }
 4587
 4588    fn trigger_completion_on_input(
 4589        &mut self,
 4590        text: &str,
 4591        trigger_in_words: bool,
 4592        window: &mut Window,
 4593        cx: &mut Context<Self>,
 4594    ) {
 4595        let completions_source = self
 4596            .context_menu
 4597            .borrow()
 4598            .as_ref()
 4599            .and_then(|menu| match menu {
 4600                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4601                CodeContextMenu::CodeActions(_) => None,
 4602            });
 4603
 4604        match completions_source {
 4605            Some(CompletionsMenuSource::Words) => {
 4606                self.show_word_completions(&ShowWordCompletions, window, cx)
 4607            }
 4608            Some(CompletionsMenuSource::Normal)
 4609            | Some(CompletionsMenuSource::SnippetChoices)
 4610            | None
 4611                if self.is_completion_trigger(
 4612                    text,
 4613                    trigger_in_words,
 4614                    completions_source.is_some(),
 4615                    cx,
 4616                ) =>
 4617            {
 4618                self.show_completions(
 4619                    &ShowCompletions {
 4620                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4621                    },
 4622                    window,
 4623                    cx,
 4624                )
 4625            }
 4626            _ => {
 4627                self.hide_context_menu(window, cx);
 4628            }
 4629        }
 4630    }
 4631
 4632    fn is_completion_trigger(
 4633        &self,
 4634        text: &str,
 4635        trigger_in_words: bool,
 4636        menu_is_open: bool,
 4637        cx: &mut Context<Self>,
 4638    ) -> bool {
 4639        let position = self.selections.newest_anchor().head();
 4640        let multibuffer = self.buffer.read(cx);
 4641        let Some(buffer) = position
 4642            .buffer_id
 4643            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4644        else {
 4645            return false;
 4646        };
 4647
 4648        if let Some(completion_provider) = &self.completion_provider {
 4649            completion_provider.is_completion_trigger(
 4650                &buffer,
 4651                position.text_anchor,
 4652                text,
 4653                trigger_in_words,
 4654                menu_is_open,
 4655                cx,
 4656            )
 4657        } else {
 4658            false
 4659        }
 4660    }
 4661
 4662    /// If any empty selections is touching the start of its innermost containing autoclose
 4663    /// region, expand it to select the brackets.
 4664    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4665        let selections = self.selections.all::<usize>(cx);
 4666        let buffer = self.buffer.read(cx).read(cx);
 4667        let new_selections = self
 4668            .selections_with_autoclose_regions(selections, &buffer)
 4669            .map(|(mut selection, region)| {
 4670                if !selection.is_empty() {
 4671                    return selection;
 4672                }
 4673
 4674                if let Some(region) = region {
 4675                    let mut range = region.range.to_offset(&buffer);
 4676                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4677                        range.start -= region.pair.start.len();
 4678                        if buffer.contains_str_at(range.start, &region.pair.start)
 4679                            && buffer.contains_str_at(range.end, &region.pair.end)
 4680                        {
 4681                            range.end += region.pair.end.len();
 4682                            selection.start = range.start;
 4683                            selection.end = range.end;
 4684
 4685                            return selection;
 4686                        }
 4687                    }
 4688                }
 4689
 4690                let always_treat_brackets_as_autoclosed = buffer
 4691                    .language_settings_at(selection.start, cx)
 4692                    .always_treat_brackets_as_autoclosed;
 4693
 4694                if !always_treat_brackets_as_autoclosed {
 4695                    return selection;
 4696                }
 4697
 4698                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4699                    for (pair, enabled) in scope.brackets() {
 4700                        if !enabled || !pair.close {
 4701                            continue;
 4702                        }
 4703
 4704                        if buffer.contains_str_at(selection.start, &pair.end) {
 4705                            let pair_start_len = pair.start.len();
 4706                            if buffer.contains_str_at(
 4707                                selection.start.saturating_sub(pair_start_len),
 4708                                &pair.start,
 4709                            ) {
 4710                                selection.start -= pair_start_len;
 4711                                selection.end += pair.end.len();
 4712
 4713                                return selection;
 4714                            }
 4715                        }
 4716                    }
 4717                }
 4718
 4719                selection
 4720            })
 4721            .collect();
 4722
 4723        drop(buffer);
 4724        self.change_selections(None, window, cx, |selections| {
 4725            selections.select(new_selections)
 4726        });
 4727    }
 4728
 4729    /// Iterate the given selections, and for each one, find the smallest surrounding
 4730    /// autoclose region. This uses the ordering of the selections and the autoclose
 4731    /// regions to avoid repeated comparisons.
 4732    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4733        &'a self,
 4734        selections: impl IntoIterator<Item = Selection<D>>,
 4735        buffer: &'a MultiBufferSnapshot,
 4736    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4737        let mut i = 0;
 4738        let mut regions = self.autoclose_regions.as_slice();
 4739        selections.into_iter().map(move |selection| {
 4740            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4741
 4742            let mut enclosing = None;
 4743            while let Some(pair_state) = regions.get(i) {
 4744                if pair_state.range.end.to_offset(buffer) < range.start {
 4745                    regions = &regions[i + 1..];
 4746                    i = 0;
 4747                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4748                    break;
 4749                } else {
 4750                    if pair_state.selection_id == selection.id {
 4751                        enclosing = Some(pair_state);
 4752                    }
 4753                    i += 1;
 4754                }
 4755            }
 4756
 4757            (selection, enclosing)
 4758        })
 4759    }
 4760
 4761    /// Remove any autoclose regions that no longer contain their selection.
 4762    fn invalidate_autoclose_regions(
 4763        &mut self,
 4764        mut selections: &[Selection<Anchor>],
 4765        buffer: &MultiBufferSnapshot,
 4766    ) {
 4767        self.autoclose_regions.retain(|state| {
 4768            let mut i = 0;
 4769            while let Some(selection) = selections.get(i) {
 4770                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4771                    selections = &selections[1..];
 4772                    continue;
 4773                }
 4774                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4775                    break;
 4776                }
 4777                if selection.id == state.selection_id {
 4778                    return true;
 4779                } else {
 4780                    i += 1;
 4781                }
 4782            }
 4783            false
 4784        });
 4785    }
 4786
 4787    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4788        let offset = position.to_offset(buffer);
 4789        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4790        if offset > word_range.start && kind == Some(CharKind::Word) {
 4791            Some(
 4792                buffer
 4793                    .text_for_range(word_range.start..offset)
 4794                    .collect::<String>(),
 4795            )
 4796        } else {
 4797            None
 4798        }
 4799    }
 4800
 4801    pub fn toggle_inline_values(
 4802        &mut self,
 4803        _: &ToggleInlineValues,
 4804        _: &mut Window,
 4805        cx: &mut Context<Self>,
 4806    ) {
 4807        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4808
 4809        self.refresh_inline_values(cx);
 4810    }
 4811
 4812    pub fn toggle_inlay_hints(
 4813        &mut self,
 4814        _: &ToggleInlayHints,
 4815        _: &mut Window,
 4816        cx: &mut Context<Self>,
 4817    ) {
 4818        self.refresh_inlay_hints(
 4819            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4820            cx,
 4821        );
 4822    }
 4823
 4824    pub fn inlay_hints_enabled(&self) -> bool {
 4825        self.inlay_hint_cache.enabled
 4826    }
 4827
 4828    pub fn inline_values_enabled(&self) -> bool {
 4829        self.inline_value_cache.enabled
 4830    }
 4831
 4832    #[cfg(any(test, feature = "test-support"))]
 4833    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4834        self.display_map
 4835            .read(cx)
 4836            .current_inlays()
 4837            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4838            .cloned()
 4839            .collect()
 4840    }
 4841
 4842    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4843        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4844            return;
 4845        }
 4846
 4847        let reason_description = reason.description();
 4848        let ignore_debounce = matches!(
 4849            reason,
 4850            InlayHintRefreshReason::SettingsChange(_)
 4851                | InlayHintRefreshReason::Toggle(_)
 4852                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4853                | InlayHintRefreshReason::ModifiersChanged(_)
 4854        );
 4855        let (invalidate_cache, required_languages) = match reason {
 4856            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4857                match self.inlay_hint_cache.modifiers_override(enabled) {
 4858                    Some(enabled) => {
 4859                        if enabled {
 4860                            (InvalidationStrategy::RefreshRequested, None)
 4861                        } else {
 4862                            self.splice_inlays(
 4863                                &self
 4864                                    .visible_inlay_hints(cx)
 4865                                    .iter()
 4866                                    .map(|inlay| inlay.id)
 4867                                    .collect::<Vec<InlayId>>(),
 4868                                Vec::new(),
 4869                                cx,
 4870                            );
 4871                            return;
 4872                        }
 4873                    }
 4874                    None => return,
 4875                }
 4876            }
 4877            InlayHintRefreshReason::Toggle(enabled) => {
 4878                if self.inlay_hint_cache.toggle(enabled) {
 4879                    if enabled {
 4880                        (InvalidationStrategy::RefreshRequested, None)
 4881                    } else {
 4882                        self.splice_inlays(
 4883                            &self
 4884                                .visible_inlay_hints(cx)
 4885                                .iter()
 4886                                .map(|inlay| inlay.id)
 4887                                .collect::<Vec<InlayId>>(),
 4888                            Vec::new(),
 4889                            cx,
 4890                        );
 4891                        return;
 4892                    }
 4893                } else {
 4894                    return;
 4895                }
 4896            }
 4897            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4898                match self.inlay_hint_cache.update_settings(
 4899                    &self.buffer,
 4900                    new_settings,
 4901                    self.visible_inlay_hints(cx),
 4902                    cx,
 4903                ) {
 4904                    ControlFlow::Break(Some(InlaySplice {
 4905                        to_remove,
 4906                        to_insert,
 4907                    })) => {
 4908                        self.splice_inlays(&to_remove, to_insert, cx);
 4909                        return;
 4910                    }
 4911                    ControlFlow::Break(None) => return,
 4912                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4913                }
 4914            }
 4915            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4916                if let Some(InlaySplice {
 4917                    to_remove,
 4918                    to_insert,
 4919                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4920                {
 4921                    self.splice_inlays(&to_remove, to_insert, cx);
 4922                }
 4923                self.display_map.update(cx, |display_map, _| {
 4924                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4925                });
 4926                return;
 4927            }
 4928            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4929            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4930                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4931            }
 4932            InlayHintRefreshReason::RefreshRequested => {
 4933                (InvalidationStrategy::RefreshRequested, None)
 4934            }
 4935        };
 4936
 4937        if let Some(InlaySplice {
 4938            to_remove,
 4939            to_insert,
 4940        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4941            reason_description,
 4942            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4943            invalidate_cache,
 4944            ignore_debounce,
 4945            cx,
 4946        ) {
 4947            self.splice_inlays(&to_remove, to_insert, cx);
 4948        }
 4949    }
 4950
 4951    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4952        self.display_map
 4953            .read(cx)
 4954            .current_inlays()
 4955            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4956            .cloned()
 4957            .collect()
 4958    }
 4959
 4960    pub fn excerpts_for_inlay_hints_query(
 4961        &self,
 4962        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4963        cx: &mut Context<Editor>,
 4964    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4965        let Some(project) = self.project.as_ref() else {
 4966            return HashMap::default();
 4967        };
 4968        let project = project.read(cx);
 4969        let multi_buffer = self.buffer().read(cx);
 4970        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4971        let multi_buffer_visible_start = self
 4972            .scroll_manager
 4973            .anchor()
 4974            .anchor
 4975            .to_point(&multi_buffer_snapshot);
 4976        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4977            multi_buffer_visible_start
 4978                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4979            Bias::Left,
 4980        );
 4981        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4982        multi_buffer_snapshot
 4983            .range_to_buffer_ranges(multi_buffer_visible_range)
 4984            .into_iter()
 4985            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4986            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4987                let buffer_file = project::File::from_dyn(buffer.file())?;
 4988                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4989                let worktree_entry = buffer_worktree
 4990                    .read(cx)
 4991                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4992                if worktree_entry.is_ignored {
 4993                    return None;
 4994                }
 4995
 4996                let language = buffer.language()?;
 4997                if let Some(restrict_to_languages) = restrict_to_languages {
 4998                    if !restrict_to_languages.contains(language) {
 4999                        return None;
 5000                    }
 5001                }
 5002                Some((
 5003                    excerpt_id,
 5004                    (
 5005                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5006                        buffer.version().clone(),
 5007                        excerpt_visible_range,
 5008                    ),
 5009                ))
 5010            })
 5011            .collect()
 5012    }
 5013
 5014    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5015        TextLayoutDetails {
 5016            text_system: window.text_system().clone(),
 5017            editor_style: self.style.clone().unwrap(),
 5018            rem_size: window.rem_size(),
 5019            scroll_anchor: self.scroll_manager.anchor(),
 5020            visible_rows: self.visible_line_count(),
 5021            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5022        }
 5023    }
 5024
 5025    pub fn splice_inlays(
 5026        &self,
 5027        to_remove: &[InlayId],
 5028        to_insert: Vec<Inlay>,
 5029        cx: &mut Context<Self>,
 5030    ) {
 5031        self.display_map.update(cx, |display_map, cx| {
 5032            display_map.splice_inlays(to_remove, to_insert, cx)
 5033        });
 5034        cx.notify();
 5035    }
 5036
 5037    fn trigger_on_type_formatting(
 5038        &self,
 5039        input: String,
 5040        window: &mut Window,
 5041        cx: &mut Context<Self>,
 5042    ) -> Option<Task<Result<()>>> {
 5043        if input.len() != 1 {
 5044            return None;
 5045        }
 5046
 5047        let project = self.project.as_ref()?;
 5048        let position = self.selections.newest_anchor().head();
 5049        let (buffer, buffer_position) = self
 5050            .buffer
 5051            .read(cx)
 5052            .text_anchor_for_position(position, cx)?;
 5053
 5054        let settings = language_settings::language_settings(
 5055            buffer
 5056                .read(cx)
 5057                .language_at(buffer_position)
 5058                .map(|l| l.name()),
 5059            buffer.read(cx).file(),
 5060            cx,
 5061        );
 5062        if !settings.use_on_type_format {
 5063            return None;
 5064        }
 5065
 5066        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5067        // hence we do LSP request & edit on host side only — add formats to host's history.
 5068        let push_to_lsp_host_history = true;
 5069        // If this is not the host, append its history with new edits.
 5070        let push_to_client_history = project.read(cx).is_via_collab();
 5071
 5072        let on_type_formatting = project.update(cx, |project, cx| {
 5073            project.on_type_format(
 5074                buffer.clone(),
 5075                buffer_position,
 5076                input,
 5077                push_to_lsp_host_history,
 5078                cx,
 5079            )
 5080        });
 5081        Some(cx.spawn_in(window, async move |editor, cx| {
 5082            if let Some(transaction) = on_type_formatting.await? {
 5083                if push_to_client_history {
 5084                    buffer
 5085                        .update(cx, |buffer, _| {
 5086                            buffer.push_transaction(transaction, Instant::now());
 5087                            buffer.finalize_last_transaction();
 5088                        })
 5089                        .ok();
 5090                }
 5091                editor.update(cx, |editor, cx| {
 5092                    editor.refresh_document_highlights(cx);
 5093                })?;
 5094            }
 5095            Ok(())
 5096        }))
 5097    }
 5098
 5099    pub fn show_word_completions(
 5100        &mut self,
 5101        _: &ShowWordCompletions,
 5102        window: &mut Window,
 5103        cx: &mut Context<Self>,
 5104    ) {
 5105        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5106    }
 5107
 5108    pub fn show_completions(
 5109        &mut self,
 5110        options: &ShowCompletions,
 5111        window: &mut Window,
 5112        cx: &mut Context<Self>,
 5113    ) {
 5114        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5115    }
 5116
 5117    fn open_or_update_completions_menu(
 5118        &mut self,
 5119        requested_source: Option<CompletionsMenuSource>,
 5120        trigger: Option<&str>,
 5121        window: &mut Window,
 5122        cx: &mut Context<Self>,
 5123    ) {
 5124        if self.pending_rename.is_some() {
 5125            return;
 5126        }
 5127
 5128        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5129
 5130        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5131        // inserted and selected. To handle that case, the start of the selection is used so that
 5132        // the menu starts with all choices.
 5133        let position = self
 5134            .selections
 5135            .newest_anchor()
 5136            .start
 5137            .bias_right(&multibuffer_snapshot);
 5138        if position.diff_base_anchor.is_some() {
 5139            return;
 5140        }
 5141        let (buffer, buffer_position) =
 5142            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5143                output
 5144            } else {
 5145                return;
 5146            };
 5147        let buffer_snapshot = buffer.read(cx).snapshot();
 5148
 5149        let query: Option<Arc<String>> =
 5150            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5151
 5152        drop(multibuffer_snapshot);
 5153
 5154        let provider = match requested_source {
 5155            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5156            Some(CompletionsMenuSource::Words) => None,
 5157            Some(CompletionsMenuSource::SnippetChoices) => {
 5158                log::error!("bug: SnippetChoices requested_source is not handled");
 5159                None
 5160            }
 5161        };
 5162
 5163        let sort_completions = provider
 5164            .as_ref()
 5165            .map_or(false, |provider| provider.sort_completions());
 5166
 5167        let filter_completions = provider
 5168            .as_ref()
 5169            .map_or(true, |provider| provider.filter_completions());
 5170
 5171        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5172            if filter_completions {
 5173                menu.filter(query.clone(), provider.clone(), window, cx);
 5174            }
 5175            // When `is_incomplete` is false, no need to re-query completions when the current query
 5176            // is a suffix of the initial query.
 5177            if !menu.is_incomplete {
 5178                // If the new query is a suffix of the old query (typing more characters) and
 5179                // the previous result was complete, the existing completions can be filtered.
 5180                //
 5181                // Note that this is always true for snippet completions.
 5182                let query_matches = match (&menu.initial_query, &query) {
 5183                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5184                    (None, _) => true,
 5185                    _ => false,
 5186                };
 5187                if query_matches {
 5188                    let position_matches = if menu.initial_position == position {
 5189                        true
 5190                    } else {
 5191                        let snapshot = self.buffer.read(cx).read(cx);
 5192                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5193                    };
 5194                    if position_matches {
 5195                        return;
 5196                    }
 5197                }
 5198            }
 5199        };
 5200
 5201        let trigger_kind = match trigger {
 5202            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5203                CompletionTriggerKind::TRIGGER_CHARACTER
 5204            }
 5205            _ => CompletionTriggerKind::INVOKED,
 5206        };
 5207        let completion_context = CompletionContext {
 5208            trigger_character: trigger.and_then(|trigger| {
 5209                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5210                    Some(String::from(trigger))
 5211                } else {
 5212                    None
 5213                }
 5214            }),
 5215            trigger_kind,
 5216        };
 5217
 5218        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5219            buffer_snapshot.surrounding_word(buffer_position)
 5220        {
 5221            let word_to_exclude = buffer_snapshot
 5222                .text_for_range(word_range.clone())
 5223                .collect::<String>();
 5224            (
 5225                buffer_snapshot.anchor_before(word_range.start)
 5226                    ..buffer_snapshot.anchor_after(buffer_position),
 5227                Some(word_to_exclude),
 5228            )
 5229        } else {
 5230            (buffer_position..buffer_position, None)
 5231        };
 5232
 5233        let language = buffer_snapshot
 5234            .language_at(buffer_position)
 5235            .map(|language| language.name());
 5236
 5237        let completion_settings =
 5238            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5239
 5240        let show_completion_documentation = buffer_snapshot
 5241            .settings_at(buffer_position, cx)
 5242            .show_completion_documentation;
 5243
 5244        // The document can be large, so stay in reasonable bounds when searching for words,
 5245        // otherwise completion pop-up might be slow to appear.
 5246        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5247        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5248        let min_word_search = buffer_snapshot.clip_point(
 5249            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5250            Bias::Left,
 5251        );
 5252        let max_word_search = buffer_snapshot.clip_point(
 5253            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5254            Bias::Right,
 5255        );
 5256        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5257            ..buffer_snapshot.point_to_offset(max_word_search);
 5258
 5259        let skip_digits = query
 5260            .as_ref()
 5261            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5262
 5263        let (mut words, provider_responses) = match &provider {
 5264            Some(provider) => {
 5265                let provider_responses = provider.completions(
 5266                    position.excerpt_id,
 5267                    &buffer,
 5268                    buffer_position,
 5269                    completion_context,
 5270                    window,
 5271                    cx,
 5272                );
 5273
 5274                let words = match completion_settings.words {
 5275                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5276                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5277                        .background_spawn(async move {
 5278                            buffer_snapshot.words_in_range(WordsQuery {
 5279                                fuzzy_contents: None,
 5280                                range: word_search_range,
 5281                                skip_digits,
 5282                            })
 5283                        }),
 5284                };
 5285
 5286                (words, provider_responses)
 5287            }
 5288            None => (
 5289                cx.background_spawn(async move {
 5290                    buffer_snapshot.words_in_range(WordsQuery {
 5291                        fuzzy_contents: None,
 5292                        range: word_search_range,
 5293                        skip_digits,
 5294                    })
 5295                }),
 5296                Task::ready(Ok(Vec::new())),
 5297            ),
 5298        };
 5299
 5300        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5301
 5302        let id = post_inc(&mut self.next_completion_id);
 5303        let task = cx.spawn_in(window, async move |editor, cx| {
 5304            let Ok(()) = editor.update(cx, |this, _| {
 5305                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5306            }) else {
 5307                return;
 5308            };
 5309
 5310            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5311            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5312            let mut completions = Vec::new();
 5313            let mut is_incomplete = false;
 5314            if let Some(provider_responses) = provider_responses.await.log_err() {
 5315                if !provider_responses.is_empty() {
 5316                    for response in provider_responses {
 5317                        completions.extend(response.completions);
 5318                        is_incomplete = is_incomplete || response.is_incomplete;
 5319                    }
 5320                    if completion_settings.words == WordsCompletionMode::Fallback {
 5321                        words = Task::ready(BTreeMap::default());
 5322                    }
 5323                }
 5324            }
 5325
 5326            let mut words = words.await;
 5327            if let Some(word_to_exclude) = &word_to_exclude {
 5328                words.remove(word_to_exclude);
 5329            }
 5330            for lsp_completion in &completions {
 5331                words.remove(&lsp_completion.new_text);
 5332            }
 5333            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5334                replace_range: word_replace_range.clone(),
 5335                new_text: word.clone(),
 5336                label: CodeLabel::plain(word, None),
 5337                icon_path: None,
 5338                documentation: None,
 5339                source: CompletionSource::BufferWord {
 5340                    word_range,
 5341                    resolved: false,
 5342                },
 5343                insert_text_mode: Some(InsertTextMode::AS_IS),
 5344                confirm: None,
 5345            }));
 5346
 5347            let menu = if completions.is_empty() {
 5348                None
 5349            } else {
 5350                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5351                    let languages = editor
 5352                        .workspace
 5353                        .as_ref()
 5354                        .and_then(|(workspace, _)| workspace.upgrade())
 5355                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5356                    let menu = CompletionsMenu::new(
 5357                        id,
 5358                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5359                        sort_completions,
 5360                        show_completion_documentation,
 5361                        position,
 5362                        query.clone(),
 5363                        is_incomplete,
 5364                        buffer.clone(),
 5365                        completions.into(),
 5366                        snippet_sort_order,
 5367                        languages,
 5368                        language,
 5369                        cx,
 5370                    );
 5371
 5372                    let query = if filter_completions { query } else { None };
 5373                    let matches_task = if let Some(query) = query {
 5374                        menu.do_async_filtering(query, cx)
 5375                    } else {
 5376                        Task::ready(menu.unfiltered_matches())
 5377                    };
 5378                    (menu, matches_task)
 5379                }) else {
 5380                    return;
 5381                };
 5382
 5383                let matches = matches_task.await;
 5384
 5385                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5386                    // Newer menu already set, so exit.
 5387                    match editor.context_menu.borrow().as_ref() {
 5388                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5389                            if prev_menu.id > id {
 5390                                return;
 5391                            }
 5392                        }
 5393                        _ => {}
 5394                    };
 5395
 5396                    // Only valid to take prev_menu because it the new menu is immediately set
 5397                    // below, or the menu is hidden.
 5398                    match editor.context_menu.borrow_mut().take() {
 5399                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5400                            let position_matches =
 5401                                if prev_menu.initial_position == menu.initial_position {
 5402                                    true
 5403                                } else {
 5404                                    let snapshot = editor.buffer.read(cx).read(cx);
 5405                                    prev_menu.initial_position.to_offset(&snapshot)
 5406                                        == menu.initial_position.to_offset(&snapshot)
 5407                                };
 5408                            if position_matches {
 5409                                // Preserve markdown cache before `set_filter_results` because it will
 5410                                // try to populate the documentation cache.
 5411                                menu.preserve_markdown_cache(prev_menu);
 5412                            }
 5413                        }
 5414                        _ => {}
 5415                    };
 5416
 5417                    menu.set_filter_results(matches, provider, window, cx);
 5418                }) else {
 5419                    return;
 5420                };
 5421
 5422                menu.visible().then_some(menu)
 5423            };
 5424
 5425            editor
 5426                .update_in(cx, |editor, window, cx| {
 5427                    if editor.focus_handle.is_focused(window) {
 5428                        if let Some(menu) = menu {
 5429                            *editor.context_menu.borrow_mut() =
 5430                                Some(CodeContextMenu::Completions(menu));
 5431
 5432                            crate::hover_popover::hide_hover(editor, cx);
 5433                            if editor.show_edit_predictions_in_menu() {
 5434                                editor.update_visible_inline_completion(window, cx);
 5435                            } else {
 5436                                editor.discard_inline_completion(false, cx);
 5437                            }
 5438
 5439                            cx.notify();
 5440                            return;
 5441                        }
 5442                    }
 5443
 5444                    if editor.completion_tasks.len() <= 1 {
 5445                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5446                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5447                        // If it was already hidden and we don't show inline completions in the menu, we should
 5448                        // also show the inline-completion when available.
 5449                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5450                            editor.update_visible_inline_completion(window, cx);
 5451                        }
 5452                    }
 5453                })
 5454                .ok();
 5455        });
 5456
 5457        self.completion_tasks.push((id, task));
 5458    }
 5459
 5460    #[cfg(feature = "test-support")]
 5461    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5462        let menu = self.context_menu.borrow();
 5463        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5464            let completions = menu.completions.borrow();
 5465            Some(completions.to_vec())
 5466        } else {
 5467            None
 5468        }
 5469    }
 5470
 5471    pub fn with_completions_menu_matching_id<R>(
 5472        &self,
 5473        id: CompletionId,
 5474        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5475    ) -> R {
 5476        let mut context_menu = self.context_menu.borrow_mut();
 5477        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5478            return f(None);
 5479        };
 5480        if completions_menu.id != id {
 5481            return f(None);
 5482        }
 5483        f(Some(completions_menu))
 5484    }
 5485
 5486    pub fn confirm_completion(
 5487        &mut self,
 5488        action: &ConfirmCompletion,
 5489        window: &mut Window,
 5490        cx: &mut Context<Self>,
 5491    ) -> Option<Task<Result<()>>> {
 5492        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5493        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5494    }
 5495
 5496    pub fn confirm_completion_insert(
 5497        &mut self,
 5498        _: &ConfirmCompletionInsert,
 5499        window: &mut Window,
 5500        cx: &mut Context<Self>,
 5501    ) -> Option<Task<Result<()>>> {
 5502        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5503        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5504    }
 5505
 5506    pub fn confirm_completion_replace(
 5507        &mut self,
 5508        _: &ConfirmCompletionReplace,
 5509        window: &mut Window,
 5510        cx: &mut Context<Self>,
 5511    ) -> Option<Task<Result<()>>> {
 5512        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5513        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5514    }
 5515
 5516    pub fn compose_completion(
 5517        &mut self,
 5518        action: &ComposeCompletion,
 5519        window: &mut Window,
 5520        cx: &mut Context<Self>,
 5521    ) -> Option<Task<Result<()>>> {
 5522        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5523        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5524    }
 5525
 5526    fn do_completion(
 5527        &mut self,
 5528        item_ix: Option<usize>,
 5529        intent: CompletionIntent,
 5530        window: &mut Window,
 5531        cx: &mut Context<Editor>,
 5532    ) -> Option<Task<Result<()>>> {
 5533        use language::ToOffset as _;
 5534
 5535        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5536        else {
 5537            return None;
 5538        };
 5539
 5540        let candidate_id = {
 5541            let entries = completions_menu.entries.borrow();
 5542            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5543            if self.show_edit_predictions_in_menu() {
 5544                self.discard_inline_completion(true, cx);
 5545            }
 5546            mat.candidate_id
 5547        };
 5548
 5549        let completion = completions_menu
 5550            .completions
 5551            .borrow()
 5552            .get(candidate_id)?
 5553            .clone();
 5554        cx.stop_propagation();
 5555
 5556        let buffer_handle = completions_menu.buffer.clone();
 5557
 5558        let CompletionEdit {
 5559            new_text,
 5560            snippet,
 5561            replace_range,
 5562        } = process_completion_for_edit(
 5563            &completion,
 5564            intent,
 5565            &buffer_handle,
 5566            &completions_menu.initial_position.text_anchor,
 5567            cx,
 5568        );
 5569
 5570        let buffer = buffer_handle.read(cx);
 5571        let snapshot = self.buffer.read(cx).snapshot(cx);
 5572        let newest_anchor = self.selections.newest_anchor();
 5573        let replace_range_multibuffer = {
 5574            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5575            let multibuffer_anchor = snapshot
 5576                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5577                .unwrap()
 5578                ..snapshot
 5579                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5580                    .unwrap();
 5581            multibuffer_anchor.start.to_offset(&snapshot)
 5582                ..multibuffer_anchor.end.to_offset(&snapshot)
 5583        };
 5584        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5585            return None;
 5586        }
 5587
 5588        let old_text = buffer
 5589            .text_for_range(replace_range.clone())
 5590            .collect::<String>();
 5591        let lookbehind = newest_anchor
 5592            .start
 5593            .text_anchor
 5594            .to_offset(buffer)
 5595            .saturating_sub(replace_range.start);
 5596        let lookahead = replace_range
 5597            .end
 5598            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5599        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5600        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5601
 5602        let selections = self.selections.all::<usize>(cx);
 5603        let mut ranges = Vec::new();
 5604        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5605
 5606        for selection in &selections {
 5607            let range = if selection.id == newest_anchor.id {
 5608                replace_range_multibuffer.clone()
 5609            } else {
 5610                let mut range = selection.range();
 5611
 5612                // if prefix is present, don't duplicate it
 5613                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5614                    range.start = range.start.saturating_sub(lookbehind);
 5615
 5616                    // if suffix is also present, mimic the newest cursor and replace it
 5617                    if selection.id != newest_anchor.id
 5618                        && snapshot.contains_str_at(range.end, suffix)
 5619                    {
 5620                        range.end += lookahead;
 5621                    }
 5622                }
 5623                range
 5624            };
 5625
 5626            ranges.push(range.clone());
 5627
 5628            if !self.linked_edit_ranges.is_empty() {
 5629                let start_anchor = snapshot.anchor_before(range.start);
 5630                let end_anchor = snapshot.anchor_after(range.end);
 5631                if let Some(ranges) = self
 5632                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5633                {
 5634                    for (buffer, edits) in ranges {
 5635                        linked_edits
 5636                            .entry(buffer.clone())
 5637                            .or_default()
 5638                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5639                    }
 5640                }
 5641            }
 5642        }
 5643
 5644        let common_prefix_len = old_text
 5645            .chars()
 5646            .zip(new_text.chars())
 5647            .take_while(|(a, b)| a == b)
 5648            .map(|(a, _)| a.len_utf8())
 5649            .sum::<usize>();
 5650
 5651        cx.emit(EditorEvent::InputHandled {
 5652            utf16_range_to_replace: None,
 5653            text: new_text[common_prefix_len..].into(),
 5654        });
 5655
 5656        self.transact(window, cx, |this, window, cx| {
 5657            if let Some(mut snippet) = snippet {
 5658                snippet.text = new_text.to_string();
 5659                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5660            } else {
 5661                this.buffer.update(cx, |buffer, cx| {
 5662                    let auto_indent = match completion.insert_text_mode {
 5663                        Some(InsertTextMode::AS_IS) => None,
 5664                        _ => this.autoindent_mode.clone(),
 5665                    };
 5666                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5667                    buffer.edit(edits, auto_indent, cx);
 5668                });
 5669            }
 5670            for (buffer, edits) in linked_edits {
 5671                buffer.update(cx, |buffer, cx| {
 5672                    let snapshot = buffer.snapshot();
 5673                    let edits = edits
 5674                        .into_iter()
 5675                        .map(|(range, text)| {
 5676                            use text::ToPoint as TP;
 5677                            let end_point = TP::to_point(&range.end, &snapshot);
 5678                            let start_point = TP::to_point(&range.start, &snapshot);
 5679                            (start_point..end_point, text)
 5680                        })
 5681                        .sorted_by_key(|(range, _)| range.start);
 5682                    buffer.edit(edits, None, cx);
 5683                })
 5684            }
 5685
 5686            this.refresh_inline_completion(true, false, window, cx);
 5687        });
 5688
 5689        let show_new_completions_on_confirm = completion
 5690            .confirm
 5691            .as_ref()
 5692            .map_or(false, |confirm| confirm(intent, window, cx));
 5693        if show_new_completions_on_confirm {
 5694            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5695        }
 5696
 5697        let provider = self.completion_provider.as_ref()?;
 5698        drop(completion);
 5699        let apply_edits = provider.apply_additional_edits_for_completion(
 5700            buffer_handle,
 5701            completions_menu.completions.clone(),
 5702            candidate_id,
 5703            true,
 5704            cx,
 5705        );
 5706
 5707        let editor_settings = EditorSettings::get_global(cx);
 5708        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5709            // After the code completion is finished, users often want to know what signatures are needed.
 5710            // so we should automatically call signature_help
 5711            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5712        }
 5713
 5714        Some(cx.foreground_executor().spawn(async move {
 5715            apply_edits.await?;
 5716            Ok(())
 5717        }))
 5718    }
 5719
 5720    pub fn toggle_code_actions(
 5721        &mut self,
 5722        action: &ToggleCodeActions,
 5723        window: &mut Window,
 5724        cx: &mut Context<Self>,
 5725    ) {
 5726        let quick_launch = action.quick_launch;
 5727        let mut context_menu = self.context_menu.borrow_mut();
 5728        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5729            if code_actions.deployed_from == action.deployed_from {
 5730                // Toggle if we're selecting the same one
 5731                *context_menu = None;
 5732                cx.notify();
 5733                return;
 5734            } else {
 5735                // Otherwise, clear it and start a new one
 5736                *context_menu = None;
 5737                cx.notify();
 5738            }
 5739        }
 5740        drop(context_menu);
 5741        let snapshot = self.snapshot(window, cx);
 5742        let deployed_from = action.deployed_from.clone();
 5743        let action = action.clone();
 5744        self.completion_tasks.clear();
 5745        self.discard_inline_completion(false, cx);
 5746
 5747        let multibuffer_point = match &action.deployed_from {
 5748            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5749                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5750            }
 5751            _ => self.selections.newest::<Point>(cx).head(),
 5752        };
 5753        let Some((buffer, buffer_row)) = snapshot
 5754            .buffer_snapshot
 5755            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5756            .and_then(|(buffer_snapshot, range)| {
 5757                self.buffer()
 5758                    .read(cx)
 5759                    .buffer(buffer_snapshot.remote_id())
 5760                    .map(|buffer| (buffer, range.start.row))
 5761            })
 5762        else {
 5763            return;
 5764        };
 5765        let buffer_id = buffer.read(cx).remote_id();
 5766        let tasks = self
 5767            .tasks
 5768            .get(&(buffer_id, buffer_row))
 5769            .map(|t| Arc::new(t.to_owned()));
 5770
 5771        if !self.focus_handle.is_focused(window) {
 5772            return;
 5773        }
 5774        let project = self.project.clone();
 5775
 5776        let code_actions_task = match deployed_from {
 5777            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5778            _ => self.code_actions(buffer_row, window, cx),
 5779        };
 5780
 5781        let runnable_task = match deployed_from {
 5782            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5783            _ => {
 5784                let mut task_context_task = Task::ready(None);
 5785                if let Some(tasks) = &tasks {
 5786                    if let Some(project) = project {
 5787                        task_context_task =
 5788                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5789                    }
 5790                }
 5791
 5792                cx.spawn_in(window, {
 5793                    let buffer = buffer.clone();
 5794                    async move |editor, cx| {
 5795                        let task_context = task_context_task.await;
 5796
 5797                        let resolved_tasks =
 5798                            tasks
 5799                                .zip(task_context.clone())
 5800                                .map(|(tasks, task_context)| ResolvedTasks {
 5801                                    templates: tasks.resolve(&task_context).collect(),
 5802                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5803                                        multibuffer_point.row,
 5804                                        tasks.column,
 5805                                    )),
 5806                                });
 5807                        let debug_scenarios = editor
 5808                            .update(cx, |editor, cx| {
 5809                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5810                            })?
 5811                            .await;
 5812                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5813                    }
 5814                })
 5815            }
 5816        };
 5817
 5818        cx.spawn_in(window, async move |editor, cx| {
 5819            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5820            let code_actions = code_actions_task.await;
 5821            let spawn_straight_away = quick_launch
 5822                && resolved_tasks
 5823                    .as_ref()
 5824                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5825                && code_actions
 5826                    .as_ref()
 5827                    .map_or(true, |actions| actions.is_empty())
 5828                && debug_scenarios.is_empty();
 5829
 5830            editor.update_in(cx, |editor, window, cx| {
 5831                crate::hover_popover::hide_hover(editor, cx);
 5832                *editor.context_menu.borrow_mut() =
 5833                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5834                        buffer,
 5835                        actions: CodeActionContents::new(
 5836                            resolved_tasks,
 5837                            code_actions,
 5838                            debug_scenarios,
 5839                            task_context.unwrap_or_default(),
 5840                        ),
 5841                        selected_item: Default::default(),
 5842                        scroll_handle: UniformListScrollHandle::default(),
 5843                        deployed_from,
 5844                    }));
 5845                if spawn_straight_away {
 5846                    if let Some(task) = editor.confirm_code_action(
 5847                        &ConfirmCodeAction { item_ix: Some(0) },
 5848                        window,
 5849                        cx,
 5850                    ) {
 5851                        cx.notify();
 5852                        return task;
 5853                    }
 5854                }
 5855
 5856                Task::ready(Ok(()))
 5857            })
 5858        })
 5859        .detach_and_log_err(cx);
 5860    }
 5861
 5862    fn debug_scenarios(
 5863        &mut self,
 5864        resolved_tasks: &Option<ResolvedTasks>,
 5865        buffer: &Entity<Buffer>,
 5866        cx: &mut App,
 5867    ) -> Task<Vec<task::DebugScenario>> {
 5868        if cx.has_flag::<DebuggerFeatureFlag>() {
 5869            maybe!({
 5870                let project = self.project.as_ref()?;
 5871                let dap_store = project.read(cx).dap_store();
 5872                let mut scenarios = vec![];
 5873                let resolved_tasks = resolved_tasks.as_ref()?;
 5874                let buffer = buffer.read(cx);
 5875                let language = buffer.language()?;
 5876                let file = buffer.file();
 5877                let debug_adapter = language_settings(language.name().into(), file, cx)
 5878                    .debuggers
 5879                    .first()
 5880                    .map(SharedString::from)
 5881                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5882
 5883                dap_store.update(cx, |dap_store, cx| {
 5884                    for (_, task) in &resolved_tasks.templates {
 5885                        let maybe_scenario = dap_store.debug_scenario_for_build_task(
 5886                            task.original_task().clone(),
 5887                            debug_adapter.clone().into(),
 5888                            task.display_label().to_owned().into(),
 5889                            cx,
 5890                        );
 5891                        scenarios.push(maybe_scenario);
 5892                    }
 5893                });
 5894                Some(cx.background_spawn(async move {
 5895                    let scenarios = futures::future::join_all(scenarios)
 5896                        .await
 5897                        .into_iter()
 5898                        .flatten()
 5899                        .collect::<Vec<_>>();
 5900                    scenarios
 5901                }))
 5902            })
 5903            .unwrap_or_else(|| Task::ready(vec![]))
 5904        } else {
 5905            Task::ready(vec![])
 5906        }
 5907    }
 5908
 5909    fn code_actions(
 5910        &mut self,
 5911        buffer_row: u32,
 5912        window: &mut Window,
 5913        cx: &mut Context<Self>,
 5914    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5915        let mut task = self.code_actions_task.take();
 5916        cx.spawn_in(window, async move |editor, cx| {
 5917            while let Some(prev_task) = task {
 5918                prev_task.await.log_err();
 5919                task = editor
 5920                    .update(cx, |this, _| this.code_actions_task.take())
 5921                    .ok()?;
 5922            }
 5923
 5924            editor
 5925                .update(cx, |editor, cx| {
 5926                    editor
 5927                        .available_code_actions
 5928                        .clone()
 5929                        .and_then(|(location, code_actions)| {
 5930                            let snapshot = location.buffer.read(cx).snapshot();
 5931                            let point_range = location.range.to_point(&snapshot);
 5932                            let point_range = point_range.start.row..=point_range.end.row;
 5933                            if point_range.contains(&buffer_row) {
 5934                                Some(code_actions)
 5935                            } else {
 5936                                None
 5937                            }
 5938                        })
 5939                })
 5940                .ok()
 5941                .flatten()
 5942        })
 5943    }
 5944
 5945    pub fn confirm_code_action(
 5946        &mut self,
 5947        action: &ConfirmCodeAction,
 5948        window: &mut Window,
 5949        cx: &mut Context<Self>,
 5950    ) -> Option<Task<Result<()>>> {
 5951        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5952
 5953        let actions_menu =
 5954            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5955                menu
 5956            } else {
 5957                return None;
 5958            };
 5959
 5960        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5961        let action = actions_menu.actions.get(action_ix)?;
 5962        let title = action.label();
 5963        let buffer = actions_menu.buffer;
 5964        let workspace = self.workspace()?;
 5965
 5966        match action {
 5967            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5968                workspace.update(cx, |workspace, cx| {
 5969                    workspace.schedule_resolved_task(
 5970                        task_source_kind,
 5971                        resolved_task,
 5972                        false,
 5973                        window,
 5974                        cx,
 5975                    );
 5976
 5977                    Some(Task::ready(Ok(())))
 5978                })
 5979            }
 5980            CodeActionsItem::CodeAction {
 5981                excerpt_id,
 5982                action,
 5983                provider,
 5984            } => {
 5985                let apply_code_action =
 5986                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5987                let workspace = workspace.downgrade();
 5988                Some(cx.spawn_in(window, async move |editor, cx| {
 5989                    let project_transaction = apply_code_action.await?;
 5990                    Self::open_project_transaction(
 5991                        &editor,
 5992                        workspace,
 5993                        project_transaction,
 5994                        title,
 5995                        cx,
 5996                    )
 5997                    .await
 5998                }))
 5999            }
 6000            CodeActionsItem::DebugScenario(scenario) => {
 6001                let context = actions_menu.actions.context.clone();
 6002
 6003                workspace.update(cx, |workspace, cx| {
 6004                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6005                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6006                });
 6007                Some(Task::ready(Ok(())))
 6008            }
 6009        }
 6010    }
 6011
 6012    pub async fn open_project_transaction(
 6013        this: &WeakEntity<Editor>,
 6014        workspace: WeakEntity<Workspace>,
 6015        transaction: ProjectTransaction,
 6016        title: String,
 6017        cx: &mut AsyncWindowContext,
 6018    ) -> Result<()> {
 6019        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6020        cx.update(|_, cx| {
 6021            entries.sort_unstable_by_key(|(buffer, _)| {
 6022                buffer.read(cx).file().map(|f| f.path().clone())
 6023            });
 6024        })?;
 6025
 6026        // If the project transaction's edits are all contained within this editor, then
 6027        // avoid opening a new editor to display them.
 6028
 6029        if let Some((buffer, transaction)) = entries.first() {
 6030            if entries.len() == 1 {
 6031                let excerpt = this.update(cx, |editor, cx| {
 6032                    editor
 6033                        .buffer()
 6034                        .read(cx)
 6035                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6036                })?;
 6037                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6038                    if excerpted_buffer == *buffer {
 6039                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6040                            let excerpt_range = excerpt_range.to_offset(buffer);
 6041                            buffer
 6042                                .edited_ranges_for_transaction::<usize>(transaction)
 6043                                .all(|range| {
 6044                                    excerpt_range.start <= range.start
 6045                                        && excerpt_range.end >= range.end
 6046                                })
 6047                        })?;
 6048
 6049                        if all_edits_within_excerpt {
 6050                            return Ok(());
 6051                        }
 6052                    }
 6053                }
 6054            }
 6055        } else {
 6056            return Ok(());
 6057        }
 6058
 6059        let mut ranges_to_highlight = Vec::new();
 6060        let excerpt_buffer = cx.new(|cx| {
 6061            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6062            for (buffer_handle, transaction) in &entries {
 6063                let edited_ranges = buffer_handle
 6064                    .read(cx)
 6065                    .edited_ranges_for_transaction::<Point>(transaction)
 6066                    .collect::<Vec<_>>();
 6067                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6068                    PathKey::for_buffer(buffer_handle, cx),
 6069                    buffer_handle.clone(),
 6070                    edited_ranges,
 6071                    DEFAULT_MULTIBUFFER_CONTEXT,
 6072                    cx,
 6073                );
 6074
 6075                ranges_to_highlight.extend(ranges);
 6076            }
 6077            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6078            multibuffer
 6079        })?;
 6080
 6081        workspace.update_in(cx, |workspace, window, cx| {
 6082            let project = workspace.project().clone();
 6083            let editor =
 6084                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6085            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6086            editor.update(cx, |editor, cx| {
 6087                editor.highlight_background::<Self>(
 6088                    &ranges_to_highlight,
 6089                    |theme| theme.editor_highlighted_line_background,
 6090                    cx,
 6091                );
 6092            });
 6093        })?;
 6094
 6095        Ok(())
 6096    }
 6097
 6098    pub fn clear_code_action_providers(&mut self) {
 6099        self.code_action_providers.clear();
 6100        self.available_code_actions.take();
 6101    }
 6102
 6103    pub fn add_code_action_provider(
 6104        &mut self,
 6105        provider: Rc<dyn CodeActionProvider>,
 6106        window: &mut Window,
 6107        cx: &mut Context<Self>,
 6108    ) {
 6109        if self
 6110            .code_action_providers
 6111            .iter()
 6112            .any(|existing_provider| existing_provider.id() == provider.id())
 6113        {
 6114            return;
 6115        }
 6116
 6117        self.code_action_providers.push(provider);
 6118        self.refresh_code_actions(window, cx);
 6119    }
 6120
 6121    pub fn remove_code_action_provider(
 6122        &mut self,
 6123        id: Arc<str>,
 6124        window: &mut Window,
 6125        cx: &mut Context<Self>,
 6126    ) {
 6127        self.code_action_providers
 6128            .retain(|provider| provider.id() != id);
 6129        self.refresh_code_actions(window, cx);
 6130    }
 6131
 6132    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6133        !self.code_action_providers.is_empty()
 6134            && EditorSettings::get_global(cx).toolbar.code_actions
 6135    }
 6136
 6137    pub fn has_available_code_actions(&self) -> bool {
 6138        self.available_code_actions
 6139            .as_ref()
 6140            .is_some_and(|(_, actions)| !actions.is_empty())
 6141    }
 6142
 6143    fn render_inline_code_actions(
 6144        &self,
 6145        icon_size: ui::IconSize,
 6146        display_row: DisplayRow,
 6147        is_active: bool,
 6148        cx: &mut Context<Self>,
 6149    ) -> AnyElement {
 6150        let show_tooltip = !self.context_menu_visible();
 6151        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6152            .icon_size(icon_size)
 6153            .shape(ui::IconButtonShape::Square)
 6154            .style(ButtonStyle::Transparent)
 6155            .icon_color(ui::Color::Hidden)
 6156            .toggle_state(is_active)
 6157            .when(show_tooltip, |this| {
 6158                this.tooltip({
 6159                    let focus_handle = self.focus_handle.clone();
 6160                    move |window, cx| {
 6161                        Tooltip::for_action_in(
 6162                            "Toggle Code Actions",
 6163                            &ToggleCodeActions {
 6164                                deployed_from: None,
 6165                                quick_launch: false,
 6166                            },
 6167                            &focus_handle,
 6168                            window,
 6169                            cx,
 6170                        )
 6171                    }
 6172                })
 6173            })
 6174            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6175                window.focus(&editor.focus_handle(cx));
 6176                editor.toggle_code_actions(
 6177                    &crate::actions::ToggleCodeActions {
 6178                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6179                            display_row,
 6180                        )),
 6181                        quick_launch: false,
 6182                    },
 6183                    window,
 6184                    cx,
 6185                );
 6186            }))
 6187            .into_any_element()
 6188    }
 6189
 6190    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6191        &self.context_menu
 6192    }
 6193
 6194    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6195        let newest_selection = self.selections.newest_anchor().clone();
 6196        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6197        let buffer = self.buffer.read(cx);
 6198        if newest_selection.head().diff_base_anchor.is_some() {
 6199            return None;
 6200        }
 6201        let (start_buffer, start) =
 6202            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6203        let (end_buffer, end) =
 6204            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6205        if start_buffer != end_buffer {
 6206            return None;
 6207        }
 6208
 6209        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6210            cx.background_executor()
 6211                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6212                .await;
 6213
 6214            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6215                let providers = this.code_action_providers.clone();
 6216                let tasks = this
 6217                    .code_action_providers
 6218                    .iter()
 6219                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6220                    .collect::<Vec<_>>();
 6221                (providers, tasks)
 6222            })?;
 6223
 6224            let mut actions = Vec::new();
 6225            for (provider, provider_actions) in
 6226                providers.into_iter().zip(future::join_all(tasks).await)
 6227            {
 6228                if let Some(provider_actions) = provider_actions.log_err() {
 6229                    actions.extend(provider_actions.into_iter().map(|action| {
 6230                        AvailableCodeAction {
 6231                            excerpt_id: newest_selection.start.excerpt_id,
 6232                            action,
 6233                            provider: provider.clone(),
 6234                        }
 6235                    }));
 6236                }
 6237            }
 6238
 6239            this.update(cx, |this, cx| {
 6240                this.available_code_actions = if actions.is_empty() {
 6241                    None
 6242                } else {
 6243                    Some((
 6244                        Location {
 6245                            buffer: start_buffer,
 6246                            range: start..end,
 6247                        },
 6248                        actions.into(),
 6249                    ))
 6250                };
 6251                cx.notify();
 6252            })
 6253        }));
 6254        None
 6255    }
 6256
 6257    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6258        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6259            self.show_git_blame_inline = false;
 6260
 6261            self.show_git_blame_inline_delay_task =
 6262                Some(cx.spawn_in(window, async move |this, cx| {
 6263                    cx.background_executor().timer(delay).await;
 6264
 6265                    this.update(cx, |this, cx| {
 6266                        this.show_git_blame_inline = true;
 6267                        cx.notify();
 6268                    })
 6269                    .log_err();
 6270                }));
 6271        }
 6272    }
 6273
 6274    fn show_blame_popover(
 6275        &mut self,
 6276        blame_entry: &BlameEntry,
 6277        position: gpui::Point<Pixels>,
 6278        cx: &mut Context<Self>,
 6279    ) {
 6280        if let Some(state) = &mut self.inline_blame_popover {
 6281            state.hide_task.take();
 6282        } else {
 6283            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6284            let blame_entry = blame_entry.clone();
 6285            let show_task = cx.spawn(async move |editor, cx| {
 6286                cx.background_executor()
 6287                    .timer(std::time::Duration::from_millis(delay))
 6288                    .await;
 6289                editor
 6290                    .update(cx, |editor, cx| {
 6291                        editor.inline_blame_popover_show_task.take();
 6292                        let Some(blame) = editor.blame.as_ref() else {
 6293                            return;
 6294                        };
 6295                        let blame = blame.read(cx);
 6296                        let details = blame.details_for_entry(&blame_entry);
 6297                        let markdown = cx.new(|cx| {
 6298                            Markdown::new(
 6299                                details
 6300                                    .as_ref()
 6301                                    .map(|message| message.message.clone())
 6302                                    .unwrap_or_default(),
 6303                                None,
 6304                                None,
 6305                                cx,
 6306                            )
 6307                        });
 6308                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6309                            position,
 6310                            hide_task: None,
 6311                            popover_bounds: None,
 6312                            popover_state: InlineBlamePopoverState {
 6313                                scroll_handle: ScrollHandle::new(),
 6314                                commit_message: details,
 6315                                markdown,
 6316                            },
 6317                        });
 6318                        cx.notify();
 6319                    })
 6320                    .ok();
 6321            });
 6322            self.inline_blame_popover_show_task = Some(show_task);
 6323        }
 6324    }
 6325
 6326    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6327        self.inline_blame_popover_show_task.take();
 6328        if let Some(state) = &mut self.inline_blame_popover {
 6329            let hide_task = cx.spawn(async move |editor, cx| {
 6330                cx.background_executor()
 6331                    .timer(std::time::Duration::from_millis(100))
 6332                    .await;
 6333                editor
 6334                    .update(cx, |editor, cx| {
 6335                        editor.inline_blame_popover.take();
 6336                        cx.notify();
 6337                    })
 6338                    .ok();
 6339            });
 6340            state.hide_task = Some(hide_task);
 6341        }
 6342    }
 6343
 6344    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6345        if self.pending_rename.is_some() {
 6346            return None;
 6347        }
 6348
 6349        let provider = self.semantics_provider.clone()?;
 6350        let buffer = self.buffer.read(cx);
 6351        let newest_selection = self.selections.newest_anchor().clone();
 6352        let cursor_position = newest_selection.head();
 6353        let (cursor_buffer, cursor_buffer_position) =
 6354            buffer.text_anchor_for_position(cursor_position, cx)?;
 6355        let (tail_buffer, tail_buffer_position) =
 6356            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6357        if cursor_buffer != tail_buffer {
 6358            return None;
 6359        }
 6360
 6361        let snapshot = cursor_buffer.read(cx).snapshot();
 6362        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6363        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6364        if start_word_range != end_word_range {
 6365            self.document_highlights_task.take();
 6366            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6367            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6368            return None;
 6369        }
 6370
 6371        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6372        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6373            cx.background_executor()
 6374                .timer(Duration::from_millis(debounce))
 6375                .await;
 6376
 6377            let highlights = if let Some(highlights) = cx
 6378                .update(|cx| {
 6379                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6380                })
 6381                .ok()
 6382                .flatten()
 6383            {
 6384                highlights.await.log_err()
 6385            } else {
 6386                None
 6387            };
 6388
 6389            if let Some(highlights) = highlights {
 6390                this.update(cx, |this, cx| {
 6391                    if this.pending_rename.is_some() {
 6392                        return;
 6393                    }
 6394
 6395                    let buffer_id = cursor_position.buffer_id;
 6396                    let buffer = this.buffer.read(cx);
 6397                    if !buffer
 6398                        .text_anchor_for_position(cursor_position, cx)
 6399                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6400                    {
 6401                        return;
 6402                    }
 6403
 6404                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6405                    let mut write_ranges = Vec::new();
 6406                    let mut read_ranges = Vec::new();
 6407                    for highlight in highlights {
 6408                        for (excerpt_id, excerpt_range) in
 6409                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6410                        {
 6411                            let start = highlight
 6412                                .range
 6413                                .start
 6414                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6415                            let end = highlight
 6416                                .range
 6417                                .end
 6418                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6419                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6420                                continue;
 6421                            }
 6422
 6423                            let range = Anchor {
 6424                                buffer_id,
 6425                                excerpt_id,
 6426                                text_anchor: start,
 6427                                diff_base_anchor: None,
 6428                            }..Anchor {
 6429                                buffer_id,
 6430                                excerpt_id,
 6431                                text_anchor: end,
 6432                                diff_base_anchor: None,
 6433                            };
 6434                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6435                                write_ranges.push(range);
 6436                            } else {
 6437                                read_ranges.push(range);
 6438                            }
 6439                        }
 6440                    }
 6441
 6442                    this.highlight_background::<DocumentHighlightRead>(
 6443                        &read_ranges,
 6444                        |theme| theme.editor_document_highlight_read_background,
 6445                        cx,
 6446                    );
 6447                    this.highlight_background::<DocumentHighlightWrite>(
 6448                        &write_ranges,
 6449                        |theme| theme.editor_document_highlight_write_background,
 6450                        cx,
 6451                    );
 6452                    cx.notify();
 6453                })
 6454                .log_err();
 6455            }
 6456        }));
 6457        None
 6458    }
 6459
 6460    fn prepare_highlight_query_from_selection(
 6461        &mut self,
 6462        cx: &mut Context<Editor>,
 6463    ) -> Option<(String, Range<Anchor>)> {
 6464        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6465            return None;
 6466        }
 6467        if !EditorSettings::get_global(cx).selection_highlight {
 6468            return None;
 6469        }
 6470        if self.selections.count() != 1 || self.selections.line_mode {
 6471            return None;
 6472        }
 6473        let selection = self.selections.newest::<Point>(cx);
 6474        if selection.is_empty() || selection.start.row != selection.end.row {
 6475            return None;
 6476        }
 6477        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6478        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6479        let query = multi_buffer_snapshot
 6480            .text_for_range(selection_anchor_range.clone())
 6481            .collect::<String>();
 6482        if query.trim().is_empty() {
 6483            return None;
 6484        }
 6485        Some((query, selection_anchor_range))
 6486    }
 6487
 6488    fn update_selection_occurrence_highlights(
 6489        &mut self,
 6490        query_text: String,
 6491        query_range: Range<Anchor>,
 6492        multi_buffer_range_to_query: Range<Point>,
 6493        use_debounce: bool,
 6494        window: &mut Window,
 6495        cx: &mut Context<Editor>,
 6496    ) -> Task<()> {
 6497        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6498        cx.spawn_in(window, async move |editor, cx| {
 6499            if use_debounce {
 6500                cx.background_executor()
 6501                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6502                    .await;
 6503            }
 6504            let match_task = cx.background_spawn(async move {
 6505                let buffer_ranges = multi_buffer_snapshot
 6506                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6507                    .into_iter()
 6508                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6509                let mut match_ranges = Vec::new();
 6510                let Ok(regex) = project::search::SearchQuery::text(
 6511                    query_text.clone(),
 6512                    false,
 6513                    false,
 6514                    false,
 6515                    Default::default(),
 6516                    Default::default(),
 6517                    false,
 6518                    None,
 6519                ) else {
 6520                    return Vec::default();
 6521                };
 6522                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6523                    match_ranges.extend(
 6524                        regex
 6525                            .search(&buffer_snapshot, Some(search_range.clone()))
 6526                            .await
 6527                            .into_iter()
 6528                            .filter_map(|match_range| {
 6529                                let match_start = buffer_snapshot
 6530                                    .anchor_after(search_range.start + match_range.start);
 6531                                let match_end = buffer_snapshot
 6532                                    .anchor_before(search_range.start + match_range.end);
 6533                                let match_anchor_range = Anchor::range_in_buffer(
 6534                                    excerpt_id,
 6535                                    buffer_snapshot.remote_id(),
 6536                                    match_start..match_end,
 6537                                );
 6538                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6539                            }),
 6540                    );
 6541                }
 6542                match_ranges
 6543            });
 6544            let match_ranges = match_task.await;
 6545            editor
 6546                .update_in(cx, |editor, _, cx| {
 6547                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6548                    if !match_ranges.is_empty() {
 6549                        editor.highlight_background::<SelectedTextHighlight>(
 6550                            &match_ranges,
 6551                            |theme| theme.editor_document_highlight_bracket_background,
 6552                            cx,
 6553                        )
 6554                    }
 6555                })
 6556                .log_err();
 6557        })
 6558    }
 6559
 6560    fn refresh_selected_text_highlights(
 6561        &mut self,
 6562        on_buffer_edit: bool,
 6563        window: &mut Window,
 6564        cx: &mut Context<Editor>,
 6565    ) {
 6566        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6567        else {
 6568            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6569            self.quick_selection_highlight_task.take();
 6570            self.debounced_selection_highlight_task.take();
 6571            return;
 6572        };
 6573        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6574        if on_buffer_edit
 6575            || self
 6576                .quick_selection_highlight_task
 6577                .as_ref()
 6578                .map_or(true, |(prev_anchor_range, _)| {
 6579                    prev_anchor_range != &query_range
 6580                })
 6581        {
 6582            let multi_buffer_visible_start = self
 6583                .scroll_manager
 6584                .anchor()
 6585                .anchor
 6586                .to_point(&multi_buffer_snapshot);
 6587            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6588                multi_buffer_visible_start
 6589                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6590                Bias::Left,
 6591            );
 6592            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6593            self.quick_selection_highlight_task = Some((
 6594                query_range.clone(),
 6595                self.update_selection_occurrence_highlights(
 6596                    query_text.clone(),
 6597                    query_range.clone(),
 6598                    multi_buffer_visible_range,
 6599                    false,
 6600                    window,
 6601                    cx,
 6602                ),
 6603            ));
 6604        }
 6605        if on_buffer_edit
 6606            || self
 6607                .debounced_selection_highlight_task
 6608                .as_ref()
 6609                .map_or(true, |(prev_anchor_range, _)| {
 6610                    prev_anchor_range != &query_range
 6611                })
 6612        {
 6613            let multi_buffer_start = multi_buffer_snapshot
 6614                .anchor_before(0)
 6615                .to_point(&multi_buffer_snapshot);
 6616            let multi_buffer_end = multi_buffer_snapshot
 6617                .anchor_after(multi_buffer_snapshot.len())
 6618                .to_point(&multi_buffer_snapshot);
 6619            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6620            self.debounced_selection_highlight_task = Some((
 6621                query_range.clone(),
 6622                self.update_selection_occurrence_highlights(
 6623                    query_text,
 6624                    query_range,
 6625                    multi_buffer_full_range,
 6626                    true,
 6627                    window,
 6628                    cx,
 6629                ),
 6630            ));
 6631        }
 6632    }
 6633
 6634    pub fn refresh_inline_completion(
 6635        &mut self,
 6636        debounce: bool,
 6637        user_requested: bool,
 6638        window: &mut Window,
 6639        cx: &mut Context<Self>,
 6640    ) -> Option<()> {
 6641        let provider = self.edit_prediction_provider()?;
 6642        let cursor = self.selections.newest_anchor().head();
 6643        let (buffer, cursor_buffer_position) =
 6644            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6645
 6646        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6647            self.discard_inline_completion(false, cx);
 6648            return None;
 6649        }
 6650
 6651        if !user_requested
 6652            && (!self.should_show_edit_predictions()
 6653                || !self.is_focused(window)
 6654                || buffer.read(cx).is_empty())
 6655        {
 6656            self.discard_inline_completion(false, cx);
 6657            return None;
 6658        }
 6659
 6660        self.update_visible_inline_completion(window, cx);
 6661        provider.refresh(
 6662            self.project.clone(),
 6663            buffer,
 6664            cursor_buffer_position,
 6665            debounce,
 6666            cx,
 6667        );
 6668        Some(())
 6669    }
 6670
 6671    fn show_edit_predictions_in_menu(&self) -> bool {
 6672        match self.edit_prediction_settings {
 6673            EditPredictionSettings::Disabled => false,
 6674            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6675        }
 6676    }
 6677
 6678    pub fn edit_predictions_enabled(&self) -> bool {
 6679        match self.edit_prediction_settings {
 6680            EditPredictionSettings::Disabled => false,
 6681            EditPredictionSettings::Enabled { .. } => true,
 6682        }
 6683    }
 6684
 6685    fn edit_prediction_requires_modifier(&self) -> bool {
 6686        match self.edit_prediction_settings {
 6687            EditPredictionSettings::Disabled => false,
 6688            EditPredictionSettings::Enabled {
 6689                preview_requires_modifier,
 6690                ..
 6691            } => preview_requires_modifier,
 6692        }
 6693    }
 6694
 6695    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6696        if self.edit_prediction_provider.is_none() {
 6697            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6698        } else {
 6699            let selection = self.selections.newest_anchor();
 6700            let cursor = selection.head();
 6701
 6702            if let Some((buffer, cursor_buffer_position)) =
 6703                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6704            {
 6705                self.edit_prediction_settings =
 6706                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6707            }
 6708        }
 6709    }
 6710
 6711    fn edit_prediction_settings_at_position(
 6712        &self,
 6713        buffer: &Entity<Buffer>,
 6714        buffer_position: language::Anchor,
 6715        cx: &App,
 6716    ) -> EditPredictionSettings {
 6717        if !self.mode.is_full()
 6718            || !self.show_inline_completions_override.unwrap_or(true)
 6719            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6720        {
 6721            return EditPredictionSettings::Disabled;
 6722        }
 6723
 6724        let buffer = buffer.read(cx);
 6725
 6726        let file = buffer.file();
 6727
 6728        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6729            return EditPredictionSettings::Disabled;
 6730        };
 6731
 6732        let by_provider = matches!(
 6733            self.menu_inline_completions_policy,
 6734            MenuInlineCompletionsPolicy::ByProvider
 6735        );
 6736
 6737        let show_in_menu = by_provider
 6738            && self
 6739                .edit_prediction_provider
 6740                .as_ref()
 6741                .map_or(false, |provider| {
 6742                    provider.provider.show_completions_in_menu()
 6743                });
 6744
 6745        let preview_requires_modifier =
 6746            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6747
 6748        EditPredictionSettings::Enabled {
 6749            show_in_menu,
 6750            preview_requires_modifier,
 6751        }
 6752    }
 6753
 6754    fn should_show_edit_predictions(&self) -> bool {
 6755        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6756    }
 6757
 6758    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6759        matches!(
 6760            self.edit_prediction_preview,
 6761            EditPredictionPreview::Active { .. }
 6762        )
 6763    }
 6764
 6765    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6766        let cursor = self.selections.newest_anchor().head();
 6767        if let Some((buffer, cursor_position)) =
 6768            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6769        {
 6770            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6771        } else {
 6772            false
 6773        }
 6774    }
 6775
 6776    pub fn supports_minimap(&self, cx: &App) -> bool {
 6777        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6778    }
 6779
 6780    fn edit_predictions_enabled_in_buffer(
 6781        &self,
 6782        buffer: &Entity<Buffer>,
 6783        buffer_position: language::Anchor,
 6784        cx: &App,
 6785    ) -> bool {
 6786        maybe!({
 6787            if self.read_only(cx) {
 6788                return Some(false);
 6789            }
 6790            let provider = self.edit_prediction_provider()?;
 6791            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6792                return Some(false);
 6793            }
 6794            let buffer = buffer.read(cx);
 6795            let Some(file) = buffer.file() else {
 6796                return Some(true);
 6797            };
 6798            let settings = all_language_settings(Some(file), cx);
 6799            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6800        })
 6801        .unwrap_or(false)
 6802    }
 6803
 6804    fn cycle_inline_completion(
 6805        &mut self,
 6806        direction: Direction,
 6807        window: &mut Window,
 6808        cx: &mut Context<Self>,
 6809    ) -> Option<()> {
 6810        let provider = self.edit_prediction_provider()?;
 6811        let cursor = self.selections.newest_anchor().head();
 6812        let (buffer, cursor_buffer_position) =
 6813            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6814        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6815            return None;
 6816        }
 6817
 6818        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6819        self.update_visible_inline_completion(window, cx);
 6820
 6821        Some(())
 6822    }
 6823
 6824    pub fn show_inline_completion(
 6825        &mut self,
 6826        _: &ShowEditPrediction,
 6827        window: &mut Window,
 6828        cx: &mut Context<Self>,
 6829    ) {
 6830        if !self.has_active_inline_completion() {
 6831            self.refresh_inline_completion(false, true, window, cx);
 6832            return;
 6833        }
 6834
 6835        self.update_visible_inline_completion(window, cx);
 6836    }
 6837
 6838    pub fn display_cursor_names(
 6839        &mut self,
 6840        _: &DisplayCursorNames,
 6841        window: &mut Window,
 6842        cx: &mut Context<Self>,
 6843    ) {
 6844        self.show_cursor_names(window, cx);
 6845    }
 6846
 6847    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6848        self.show_cursor_names = true;
 6849        cx.notify();
 6850        cx.spawn_in(window, async move |this, cx| {
 6851            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6852            this.update(cx, |this, cx| {
 6853                this.show_cursor_names = false;
 6854                cx.notify()
 6855            })
 6856            .ok()
 6857        })
 6858        .detach();
 6859    }
 6860
 6861    pub fn next_edit_prediction(
 6862        &mut self,
 6863        _: &NextEditPrediction,
 6864        window: &mut Window,
 6865        cx: &mut Context<Self>,
 6866    ) {
 6867        if self.has_active_inline_completion() {
 6868            self.cycle_inline_completion(Direction::Next, window, cx);
 6869        } else {
 6870            let is_copilot_disabled = self
 6871                .refresh_inline_completion(false, true, window, cx)
 6872                .is_none();
 6873            if is_copilot_disabled {
 6874                cx.propagate();
 6875            }
 6876        }
 6877    }
 6878
 6879    pub fn previous_edit_prediction(
 6880        &mut self,
 6881        _: &PreviousEditPrediction,
 6882        window: &mut Window,
 6883        cx: &mut Context<Self>,
 6884    ) {
 6885        if self.has_active_inline_completion() {
 6886            self.cycle_inline_completion(Direction::Prev, window, cx);
 6887        } else {
 6888            let is_copilot_disabled = self
 6889                .refresh_inline_completion(false, true, window, cx)
 6890                .is_none();
 6891            if is_copilot_disabled {
 6892                cx.propagate();
 6893            }
 6894        }
 6895    }
 6896
 6897    pub fn accept_edit_prediction(
 6898        &mut self,
 6899        _: &AcceptEditPrediction,
 6900        window: &mut Window,
 6901        cx: &mut Context<Self>,
 6902    ) {
 6903        if self.show_edit_predictions_in_menu() {
 6904            self.hide_context_menu(window, cx);
 6905        }
 6906
 6907        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6908            return;
 6909        };
 6910
 6911        self.report_inline_completion_event(
 6912            active_inline_completion.completion_id.clone(),
 6913            true,
 6914            cx,
 6915        );
 6916
 6917        match &active_inline_completion.completion {
 6918            InlineCompletion::Move { target, .. } => {
 6919                let target = *target;
 6920
 6921                if let Some(position_map) = &self.last_position_map {
 6922                    if position_map
 6923                        .visible_row_range
 6924                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6925                        || !self.edit_prediction_requires_modifier()
 6926                    {
 6927                        self.unfold_ranges(&[target..target], true, false, cx);
 6928                        // Note that this is also done in vim's handler of the Tab action.
 6929                        self.change_selections(
 6930                            Some(Autoscroll::newest()),
 6931                            window,
 6932                            cx,
 6933                            |selections| {
 6934                                selections.select_anchor_ranges([target..target]);
 6935                            },
 6936                        );
 6937                        self.clear_row_highlights::<EditPredictionPreview>();
 6938
 6939                        self.edit_prediction_preview
 6940                            .set_previous_scroll_position(None);
 6941                    } else {
 6942                        self.edit_prediction_preview
 6943                            .set_previous_scroll_position(Some(
 6944                                position_map.snapshot.scroll_anchor,
 6945                            ));
 6946
 6947                        self.highlight_rows::<EditPredictionPreview>(
 6948                            target..target,
 6949                            cx.theme().colors().editor_highlighted_line_background,
 6950                            RowHighlightOptions {
 6951                                autoscroll: true,
 6952                                ..Default::default()
 6953                            },
 6954                            cx,
 6955                        );
 6956                        self.request_autoscroll(Autoscroll::fit(), cx);
 6957                    }
 6958                }
 6959            }
 6960            InlineCompletion::Edit { edits, .. } => {
 6961                if let Some(provider) = self.edit_prediction_provider() {
 6962                    provider.accept(cx);
 6963                }
 6964
 6965                // Store the transaction ID and selections before applying the edit
 6966                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6967
 6968                let snapshot = self.buffer.read(cx).snapshot(cx);
 6969                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6970
 6971                self.buffer.update(cx, |buffer, cx| {
 6972                    buffer.edit(edits.iter().cloned(), None, cx)
 6973                });
 6974
 6975                self.change_selections(None, window, cx, |s| {
 6976                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6977                });
 6978
 6979                let selections = self.selections.disjoint_anchors();
 6980                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6981                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6982                    if has_new_transaction {
 6983                        self.selection_history
 6984                            .insert_transaction(transaction_id_now, selections);
 6985                    }
 6986                }
 6987
 6988                self.update_visible_inline_completion(window, cx);
 6989                if self.active_inline_completion.is_none() {
 6990                    self.refresh_inline_completion(true, true, window, cx);
 6991                }
 6992
 6993                cx.notify();
 6994            }
 6995        }
 6996
 6997        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6998    }
 6999
 7000    pub fn accept_partial_inline_completion(
 7001        &mut self,
 7002        _: &AcceptPartialEditPrediction,
 7003        window: &mut Window,
 7004        cx: &mut Context<Self>,
 7005    ) {
 7006        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7007            return;
 7008        };
 7009        if self.selections.count() != 1 {
 7010            return;
 7011        }
 7012
 7013        self.report_inline_completion_event(
 7014            active_inline_completion.completion_id.clone(),
 7015            true,
 7016            cx,
 7017        );
 7018
 7019        match &active_inline_completion.completion {
 7020            InlineCompletion::Move { target, .. } => {
 7021                let target = *target;
 7022                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7023                    selections.select_anchor_ranges([target..target]);
 7024                });
 7025            }
 7026            InlineCompletion::Edit { edits, .. } => {
 7027                // Find an insertion that starts at the cursor position.
 7028                let snapshot = self.buffer.read(cx).snapshot(cx);
 7029                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7030                let insertion = edits.iter().find_map(|(range, text)| {
 7031                    let range = range.to_offset(&snapshot);
 7032                    if range.is_empty() && range.start == cursor_offset {
 7033                        Some(text)
 7034                    } else {
 7035                        None
 7036                    }
 7037                });
 7038
 7039                if let Some(text) = insertion {
 7040                    let mut partial_completion = text
 7041                        .chars()
 7042                        .by_ref()
 7043                        .take_while(|c| c.is_alphabetic())
 7044                        .collect::<String>();
 7045                    if partial_completion.is_empty() {
 7046                        partial_completion = text
 7047                            .chars()
 7048                            .by_ref()
 7049                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7050                            .collect::<String>();
 7051                    }
 7052
 7053                    cx.emit(EditorEvent::InputHandled {
 7054                        utf16_range_to_replace: None,
 7055                        text: partial_completion.clone().into(),
 7056                    });
 7057
 7058                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7059
 7060                    self.refresh_inline_completion(true, true, window, cx);
 7061                    cx.notify();
 7062                } else {
 7063                    self.accept_edit_prediction(&Default::default(), window, cx);
 7064                }
 7065            }
 7066        }
 7067    }
 7068
 7069    fn discard_inline_completion(
 7070        &mut self,
 7071        should_report_inline_completion_event: bool,
 7072        cx: &mut Context<Self>,
 7073    ) -> bool {
 7074        if should_report_inline_completion_event {
 7075            let completion_id = self
 7076                .active_inline_completion
 7077                .as_ref()
 7078                .and_then(|active_completion| active_completion.completion_id.clone());
 7079
 7080            self.report_inline_completion_event(completion_id, false, cx);
 7081        }
 7082
 7083        if let Some(provider) = self.edit_prediction_provider() {
 7084            provider.discard(cx);
 7085        }
 7086
 7087        self.take_active_inline_completion(cx)
 7088    }
 7089
 7090    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7091        let Some(provider) = self.edit_prediction_provider() else {
 7092            return;
 7093        };
 7094
 7095        let Some((_, buffer, _)) = self
 7096            .buffer
 7097            .read(cx)
 7098            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7099        else {
 7100            return;
 7101        };
 7102
 7103        let extension = buffer
 7104            .read(cx)
 7105            .file()
 7106            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7107
 7108        let event_type = match accepted {
 7109            true => "Edit Prediction Accepted",
 7110            false => "Edit Prediction Discarded",
 7111        };
 7112        telemetry::event!(
 7113            event_type,
 7114            provider = provider.name(),
 7115            prediction_id = id,
 7116            suggestion_accepted = accepted,
 7117            file_extension = extension,
 7118        );
 7119    }
 7120
 7121    pub fn has_active_inline_completion(&self) -> bool {
 7122        self.active_inline_completion.is_some()
 7123    }
 7124
 7125    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7126        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7127            return false;
 7128        };
 7129
 7130        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7131        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7132        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7133        true
 7134    }
 7135
 7136    /// Returns true when we're displaying the edit prediction popover below the cursor
 7137    /// like we are not previewing and the LSP autocomplete menu is visible
 7138    /// or we are in `when_holding_modifier` mode.
 7139    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7140        if self.edit_prediction_preview_is_active()
 7141            || !self.show_edit_predictions_in_menu()
 7142            || !self.edit_predictions_enabled()
 7143        {
 7144            return false;
 7145        }
 7146
 7147        if self.has_visible_completions_menu() {
 7148            return true;
 7149        }
 7150
 7151        has_completion && self.edit_prediction_requires_modifier()
 7152    }
 7153
 7154    fn handle_modifiers_changed(
 7155        &mut self,
 7156        modifiers: Modifiers,
 7157        position_map: &PositionMap,
 7158        window: &mut Window,
 7159        cx: &mut Context<Self>,
 7160    ) {
 7161        if self.show_edit_predictions_in_menu() {
 7162            self.update_edit_prediction_preview(&modifiers, window, cx);
 7163        }
 7164
 7165        self.update_selection_mode(&modifiers, position_map, window, cx);
 7166
 7167        let mouse_position = window.mouse_position();
 7168        if !position_map.text_hitbox.is_hovered(window) {
 7169            return;
 7170        }
 7171
 7172        self.update_hovered_link(
 7173            position_map.point_for_position(mouse_position),
 7174            &position_map.snapshot,
 7175            modifiers,
 7176            window,
 7177            cx,
 7178        )
 7179    }
 7180
 7181    fn multi_cursor_modifier(
 7182        cursor_event: bool,
 7183        modifiers: &Modifiers,
 7184        cx: &mut Context<Self>,
 7185    ) -> bool {
 7186        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7187        if cursor_event {
 7188            match multi_cursor_setting {
 7189                MultiCursorModifier::Alt => modifiers.alt,
 7190                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7191            }
 7192        } else {
 7193            match multi_cursor_setting {
 7194                MultiCursorModifier::Alt => modifiers.secondary(),
 7195                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7196            }
 7197        }
 7198    }
 7199
 7200    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7201        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7202    }
 7203
 7204    fn update_selection_mode(
 7205        &mut self,
 7206        modifiers: &Modifiers,
 7207        position_map: &PositionMap,
 7208        window: &mut Window,
 7209        cx: &mut Context<Self>,
 7210    ) {
 7211        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7212        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7213            || self.selections.pending.is_none()
 7214        {
 7215            return;
 7216        }
 7217
 7218        let mouse_position = window.mouse_position();
 7219        let point_for_position = position_map.point_for_position(mouse_position);
 7220        let position = point_for_position.previous_valid;
 7221
 7222        self.select(
 7223            SelectPhase::BeginColumnar {
 7224                position,
 7225                reset: false,
 7226                goal_column: point_for_position.exact_unclipped.column(),
 7227            },
 7228            window,
 7229            cx,
 7230        );
 7231    }
 7232
 7233    fn update_edit_prediction_preview(
 7234        &mut self,
 7235        modifiers: &Modifiers,
 7236        window: &mut Window,
 7237        cx: &mut Context<Self>,
 7238    ) {
 7239        let mut modifiers_held = false;
 7240        if let Some(accept_keystroke) = self
 7241            .accept_edit_prediction_keybind(false, window, cx)
 7242            .keystroke()
 7243        {
 7244            modifiers_held = modifiers_held
 7245                || (&accept_keystroke.modifiers == modifiers
 7246                    && accept_keystroke.modifiers.modified());
 7247        };
 7248        if let Some(accept_partial_keystroke) = self
 7249            .accept_edit_prediction_keybind(true, window, cx)
 7250            .keystroke()
 7251        {
 7252            modifiers_held = modifiers_held
 7253                || (&accept_partial_keystroke.modifiers == modifiers
 7254                    && accept_partial_keystroke.modifiers.modified());
 7255        }
 7256
 7257        if modifiers_held {
 7258            if matches!(
 7259                self.edit_prediction_preview,
 7260                EditPredictionPreview::Inactive { .. }
 7261            ) {
 7262                self.edit_prediction_preview = EditPredictionPreview::Active {
 7263                    previous_scroll_position: None,
 7264                    since: Instant::now(),
 7265                };
 7266
 7267                self.update_visible_inline_completion(window, cx);
 7268                cx.notify();
 7269            }
 7270        } else if let EditPredictionPreview::Active {
 7271            previous_scroll_position,
 7272            since,
 7273        } = self.edit_prediction_preview
 7274        {
 7275            if let (Some(previous_scroll_position), Some(position_map)) =
 7276                (previous_scroll_position, self.last_position_map.as_ref())
 7277            {
 7278                self.set_scroll_position(
 7279                    previous_scroll_position
 7280                        .scroll_position(&position_map.snapshot.display_snapshot),
 7281                    window,
 7282                    cx,
 7283                );
 7284            }
 7285
 7286            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7287                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7288            };
 7289            self.clear_row_highlights::<EditPredictionPreview>();
 7290            self.update_visible_inline_completion(window, cx);
 7291            cx.notify();
 7292        }
 7293    }
 7294
 7295    fn update_visible_inline_completion(
 7296        &mut self,
 7297        _window: &mut Window,
 7298        cx: &mut Context<Self>,
 7299    ) -> Option<()> {
 7300        let selection = self.selections.newest_anchor();
 7301        let cursor = selection.head();
 7302        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7303        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7304        let excerpt_id = cursor.excerpt_id;
 7305
 7306        let show_in_menu = self.show_edit_predictions_in_menu();
 7307        let completions_menu_has_precedence = !show_in_menu
 7308            && (self.context_menu.borrow().is_some()
 7309                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7310
 7311        if completions_menu_has_precedence
 7312            || !offset_selection.is_empty()
 7313            || self
 7314                .active_inline_completion
 7315                .as_ref()
 7316                .map_or(false, |completion| {
 7317                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7318                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7319                    !invalidation_range.contains(&offset_selection.head())
 7320                })
 7321        {
 7322            self.discard_inline_completion(false, cx);
 7323            return None;
 7324        }
 7325
 7326        self.take_active_inline_completion(cx);
 7327        let Some(provider) = self.edit_prediction_provider() else {
 7328            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7329            return None;
 7330        };
 7331
 7332        let (buffer, cursor_buffer_position) =
 7333            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7334
 7335        self.edit_prediction_settings =
 7336            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7337
 7338        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7339
 7340        if self.edit_prediction_indent_conflict {
 7341            let cursor_point = cursor.to_point(&multibuffer);
 7342
 7343            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7344
 7345            if let Some((_, indent)) = indents.iter().next() {
 7346                if indent.len == cursor_point.column {
 7347                    self.edit_prediction_indent_conflict = false;
 7348                }
 7349            }
 7350        }
 7351
 7352        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7353        let edits = inline_completion
 7354            .edits
 7355            .into_iter()
 7356            .flat_map(|(range, new_text)| {
 7357                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7358                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7359                Some((start..end, new_text))
 7360            })
 7361            .collect::<Vec<_>>();
 7362        if edits.is_empty() {
 7363            return None;
 7364        }
 7365
 7366        let first_edit_start = edits.first().unwrap().0.start;
 7367        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7368        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7369
 7370        let last_edit_end = edits.last().unwrap().0.end;
 7371        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7372        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7373
 7374        let cursor_row = cursor.to_point(&multibuffer).row;
 7375
 7376        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7377
 7378        let mut inlay_ids = Vec::new();
 7379        let invalidation_row_range;
 7380        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7381            Some(cursor_row..edit_end_row)
 7382        } else if cursor_row > edit_end_row {
 7383            Some(edit_start_row..cursor_row)
 7384        } else {
 7385            None
 7386        };
 7387        let is_move =
 7388            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7389        let completion = if is_move {
 7390            invalidation_row_range =
 7391                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7392            let target = first_edit_start;
 7393            InlineCompletion::Move { target, snapshot }
 7394        } else {
 7395            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7396                && !self.inline_completions_hidden_for_vim_mode;
 7397
 7398            if show_completions_in_buffer {
 7399                if edits
 7400                    .iter()
 7401                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7402                {
 7403                    let mut inlays = Vec::new();
 7404                    for (range, new_text) in &edits {
 7405                        let inlay = Inlay::inline_completion(
 7406                            post_inc(&mut self.next_inlay_id),
 7407                            range.start,
 7408                            new_text.as_str(),
 7409                        );
 7410                        inlay_ids.push(inlay.id);
 7411                        inlays.push(inlay);
 7412                    }
 7413
 7414                    self.splice_inlays(&[], inlays, cx);
 7415                } else {
 7416                    let background_color = cx.theme().status().deleted_background;
 7417                    self.highlight_text::<InlineCompletionHighlight>(
 7418                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7419                        HighlightStyle {
 7420                            background_color: Some(background_color),
 7421                            ..Default::default()
 7422                        },
 7423                        cx,
 7424                    );
 7425                }
 7426            }
 7427
 7428            invalidation_row_range = edit_start_row..edit_end_row;
 7429
 7430            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7431                if provider.show_tab_accept_marker() {
 7432                    EditDisplayMode::TabAccept
 7433                } else {
 7434                    EditDisplayMode::Inline
 7435                }
 7436            } else {
 7437                EditDisplayMode::DiffPopover
 7438            };
 7439
 7440            InlineCompletion::Edit {
 7441                edits,
 7442                edit_preview: inline_completion.edit_preview,
 7443                display_mode,
 7444                snapshot,
 7445            }
 7446        };
 7447
 7448        let invalidation_range = multibuffer
 7449            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7450            ..multibuffer.anchor_after(Point::new(
 7451                invalidation_row_range.end,
 7452                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7453            ));
 7454
 7455        self.stale_inline_completion_in_menu = None;
 7456        self.active_inline_completion = Some(InlineCompletionState {
 7457            inlay_ids,
 7458            completion,
 7459            completion_id: inline_completion.id,
 7460            invalidation_range,
 7461        });
 7462
 7463        cx.notify();
 7464
 7465        Some(())
 7466    }
 7467
 7468    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7469        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7470    }
 7471
 7472    fn clear_tasks(&mut self) {
 7473        self.tasks.clear()
 7474    }
 7475
 7476    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7477        if self.tasks.insert(key, value).is_some() {
 7478            // This case should hopefully be rare, but just in case...
 7479            log::error!(
 7480                "multiple different run targets found on a single line, only the last target will be rendered"
 7481            )
 7482        }
 7483    }
 7484
 7485    /// Get all display points of breakpoints that will be rendered within editor
 7486    ///
 7487    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7488    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7489    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7490    fn active_breakpoints(
 7491        &self,
 7492        range: Range<DisplayRow>,
 7493        window: &mut Window,
 7494        cx: &mut Context<Self>,
 7495    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7496        let mut breakpoint_display_points = HashMap::default();
 7497
 7498        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7499            return breakpoint_display_points;
 7500        };
 7501
 7502        let snapshot = self.snapshot(window, cx);
 7503
 7504        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7505        let Some(project) = self.project.as_ref() else {
 7506            return breakpoint_display_points;
 7507        };
 7508
 7509        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7510            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7511
 7512        for (buffer_snapshot, range, excerpt_id) in
 7513            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7514        {
 7515            let Some(buffer) = project
 7516                .read(cx)
 7517                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7518            else {
 7519                continue;
 7520            };
 7521            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7522                &buffer,
 7523                Some(
 7524                    buffer_snapshot.anchor_before(range.start)
 7525                        ..buffer_snapshot.anchor_after(range.end),
 7526                ),
 7527                buffer_snapshot,
 7528                cx,
 7529            );
 7530            for (breakpoint, state) in breakpoints {
 7531                let multi_buffer_anchor =
 7532                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7533                let position = multi_buffer_anchor
 7534                    .to_point(&multi_buffer_snapshot)
 7535                    .to_display_point(&snapshot);
 7536
 7537                breakpoint_display_points.insert(
 7538                    position.row(),
 7539                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7540                );
 7541            }
 7542        }
 7543
 7544        breakpoint_display_points
 7545    }
 7546
 7547    fn breakpoint_context_menu(
 7548        &self,
 7549        anchor: Anchor,
 7550        window: &mut Window,
 7551        cx: &mut Context<Self>,
 7552    ) -> Entity<ui::ContextMenu> {
 7553        let weak_editor = cx.weak_entity();
 7554        let focus_handle = self.focus_handle(cx);
 7555
 7556        let row = self
 7557            .buffer
 7558            .read(cx)
 7559            .snapshot(cx)
 7560            .summary_for_anchor::<Point>(&anchor)
 7561            .row;
 7562
 7563        let breakpoint = self
 7564            .breakpoint_at_row(row, window, cx)
 7565            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7566
 7567        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7568            "Edit Log Breakpoint"
 7569        } else {
 7570            "Set Log Breakpoint"
 7571        };
 7572
 7573        let condition_breakpoint_msg = if breakpoint
 7574            .as_ref()
 7575            .is_some_and(|bp| bp.1.condition.is_some())
 7576        {
 7577            "Edit Condition Breakpoint"
 7578        } else {
 7579            "Set Condition Breakpoint"
 7580        };
 7581
 7582        let hit_condition_breakpoint_msg = if breakpoint
 7583            .as_ref()
 7584            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7585        {
 7586            "Edit Hit Condition Breakpoint"
 7587        } else {
 7588            "Set Hit Condition Breakpoint"
 7589        };
 7590
 7591        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7592            "Unset Breakpoint"
 7593        } else {
 7594            "Set Breakpoint"
 7595        };
 7596
 7597        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7598
 7599        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7600            BreakpointState::Enabled => Some("Disable"),
 7601            BreakpointState::Disabled => Some("Enable"),
 7602        });
 7603
 7604        let (anchor, breakpoint) =
 7605            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7606
 7607        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7608            menu.on_blur_subscription(Subscription::new(|| {}))
 7609                .context(focus_handle)
 7610                .when(run_to_cursor, |this| {
 7611                    let weak_editor = weak_editor.clone();
 7612                    this.entry("Run to cursor", None, move |window, cx| {
 7613                        weak_editor
 7614                            .update(cx, |editor, cx| {
 7615                                editor.change_selections(None, window, cx, |s| {
 7616                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7617                                });
 7618                            })
 7619                            .ok();
 7620
 7621                        window.dispatch_action(Box::new(RunToCursor), cx);
 7622                    })
 7623                    .separator()
 7624                })
 7625                .when_some(toggle_state_msg, |this, msg| {
 7626                    this.entry(msg, None, {
 7627                        let weak_editor = weak_editor.clone();
 7628                        let breakpoint = breakpoint.clone();
 7629                        move |_window, cx| {
 7630                            weak_editor
 7631                                .update(cx, |this, cx| {
 7632                                    this.edit_breakpoint_at_anchor(
 7633                                        anchor,
 7634                                        breakpoint.as_ref().clone(),
 7635                                        BreakpointEditAction::InvertState,
 7636                                        cx,
 7637                                    );
 7638                                })
 7639                                .log_err();
 7640                        }
 7641                    })
 7642                })
 7643                .entry(set_breakpoint_msg, None, {
 7644                    let weak_editor = weak_editor.clone();
 7645                    let breakpoint = breakpoint.clone();
 7646                    move |_window, cx| {
 7647                        weak_editor
 7648                            .update(cx, |this, cx| {
 7649                                this.edit_breakpoint_at_anchor(
 7650                                    anchor,
 7651                                    breakpoint.as_ref().clone(),
 7652                                    BreakpointEditAction::Toggle,
 7653                                    cx,
 7654                                );
 7655                            })
 7656                            .log_err();
 7657                    }
 7658                })
 7659                .entry(log_breakpoint_msg, None, {
 7660                    let breakpoint = breakpoint.clone();
 7661                    let weak_editor = weak_editor.clone();
 7662                    move |window, cx| {
 7663                        weak_editor
 7664                            .update(cx, |this, cx| {
 7665                                this.add_edit_breakpoint_block(
 7666                                    anchor,
 7667                                    breakpoint.as_ref(),
 7668                                    BreakpointPromptEditAction::Log,
 7669                                    window,
 7670                                    cx,
 7671                                );
 7672                            })
 7673                            .log_err();
 7674                    }
 7675                })
 7676                .entry(condition_breakpoint_msg, None, {
 7677                    let breakpoint = breakpoint.clone();
 7678                    let weak_editor = weak_editor.clone();
 7679                    move |window, cx| {
 7680                        weak_editor
 7681                            .update(cx, |this, cx| {
 7682                                this.add_edit_breakpoint_block(
 7683                                    anchor,
 7684                                    breakpoint.as_ref(),
 7685                                    BreakpointPromptEditAction::Condition,
 7686                                    window,
 7687                                    cx,
 7688                                );
 7689                            })
 7690                            .log_err();
 7691                    }
 7692                })
 7693                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7694                    weak_editor
 7695                        .update(cx, |this, cx| {
 7696                            this.add_edit_breakpoint_block(
 7697                                anchor,
 7698                                breakpoint.as_ref(),
 7699                                BreakpointPromptEditAction::HitCondition,
 7700                                window,
 7701                                cx,
 7702                            );
 7703                        })
 7704                        .log_err();
 7705                })
 7706        })
 7707    }
 7708
 7709    fn render_breakpoint(
 7710        &self,
 7711        position: Anchor,
 7712        row: DisplayRow,
 7713        breakpoint: &Breakpoint,
 7714        state: Option<BreakpointSessionState>,
 7715        cx: &mut Context<Self>,
 7716    ) -> IconButton {
 7717        let is_rejected = state.is_some_and(|s| !s.verified);
 7718        // Is it a breakpoint that shows up when hovering over gutter?
 7719        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7720            (false, false),
 7721            |PhantomBreakpointIndicator {
 7722                 is_active,
 7723                 display_row,
 7724                 collides_with_existing_breakpoint,
 7725             }| {
 7726                (
 7727                    is_active && display_row == row,
 7728                    collides_with_existing_breakpoint,
 7729                )
 7730            },
 7731        );
 7732
 7733        let (color, icon) = {
 7734            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7735                (false, false) => ui::IconName::DebugBreakpoint,
 7736                (true, false) => ui::IconName::DebugLogBreakpoint,
 7737                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7738                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7739            };
 7740
 7741            let color = if is_phantom {
 7742                Color::Hint
 7743            } else if is_rejected {
 7744                Color::Disabled
 7745            } else {
 7746                Color::Debugger
 7747            };
 7748
 7749            (color, icon)
 7750        };
 7751
 7752        let breakpoint = Arc::from(breakpoint.clone());
 7753
 7754        let alt_as_text = gpui::Keystroke {
 7755            modifiers: Modifiers::secondary_key(),
 7756            ..Default::default()
 7757        };
 7758        let primary_action_text = if breakpoint.is_disabled() {
 7759            "Enable breakpoint"
 7760        } else if is_phantom && !collides_with_existing {
 7761            "Set breakpoint"
 7762        } else {
 7763            "Unset breakpoint"
 7764        };
 7765        let focus_handle = self.focus_handle.clone();
 7766
 7767        let meta = if is_rejected {
 7768            SharedString::from("No executable code is associated with this line.")
 7769        } else if collides_with_existing && !breakpoint.is_disabled() {
 7770            SharedString::from(format!(
 7771                "{alt_as_text}-click to disable,\nright-click for more options."
 7772            ))
 7773        } else {
 7774            SharedString::from("Right-click for more options.")
 7775        };
 7776        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7777            .icon_size(IconSize::XSmall)
 7778            .size(ui::ButtonSize::None)
 7779            .when(is_rejected, |this| {
 7780                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7781            })
 7782            .icon_color(color)
 7783            .style(ButtonStyle::Transparent)
 7784            .on_click(cx.listener({
 7785                let breakpoint = breakpoint.clone();
 7786
 7787                move |editor, event: &ClickEvent, window, cx| {
 7788                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7789                        BreakpointEditAction::InvertState
 7790                    } else {
 7791                        BreakpointEditAction::Toggle
 7792                    };
 7793
 7794                    window.focus(&editor.focus_handle(cx));
 7795                    editor.edit_breakpoint_at_anchor(
 7796                        position,
 7797                        breakpoint.as_ref().clone(),
 7798                        edit_action,
 7799                        cx,
 7800                    );
 7801                }
 7802            }))
 7803            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7804                editor.set_breakpoint_context_menu(
 7805                    row,
 7806                    Some(position),
 7807                    event.down.position,
 7808                    window,
 7809                    cx,
 7810                );
 7811            }))
 7812            .tooltip(move |window, cx| {
 7813                Tooltip::with_meta_in(
 7814                    primary_action_text,
 7815                    Some(&ToggleBreakpoint),
 7816                    meta.clone(),
 7817                    &focus_handle,
 7818                    window,
 7819                    cx,
 7820                )
 7821            })
 7822    }
 7823
 7824    fn build_tasks_context(
 7825        project: &Entity<Project>,
 7826        buffer: &Entity<Buffer>,
 7827        buffer_row: u32,
 7828        tasks: &Arc<RunnableTasks>,
 7829        cx: &mut Context<Self>,
 7830    ) -> Task<Option<task::TaskContext>> {
 7831        let position = Point::new(buffer_row, tasks.column);
 7832        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7833        let location = Location {
 7834            buffer: buffer.clone(),
 7835            range: range_start..range_start,
 7836        };
 7837        // Fill in the environmental variables from the tree-sitter captures
 7838        let mut captured_task_variables = TaskVariables::default();
 7839        for (capture_name, value) in tasks.extra_variables.clone() {
 7840            captured_task_variables.insert(
 7841                task::VariableName::Custom(capture_name.into()),
 7842                value.clone(),
 7843            );
 7844        }
 7845        project.update(cx, |project, cx| {
 7846            project.task_store().update(cx, |task_store, cx| {
 7847                task_store.task_context_for_location(captured_task_variables, location, cx)
 7848            })
 7849        })
 7850    }
 7851
 7852    pub fn spawn_nearest_task(
 7853        &mut self,
 7854        action: &SpawnNearestTask,
 7855        window: &mut Window,
 7856        cx: &mut Context<Self>,
 7857    ) {
 7858        let Some((workspace, _)) = self.workspace.clone() else {
 7859            return;
 7860        };
 7861        let Some(project) = self.project.clone() else {
 7862            return;
 7863        };
 7864
 7865        // Try to find a closest, enclosing node using tree-sitter that has a
 7866        // task
 7867        let Some((buffer, buffer_row, tasks)) = self
 7868            .find_enclosing_node_task(cx)
 7869            // Or find the task that's closest in row-distance.
 7870            .or_else(|| self.find_closest_task(cx))
 7871        else {
 7872            return;
 7873        };
 7874
 7875        let reveal_strategy = action.reveal;
 7876        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7877        cx.spawn_in(window, async move |_, cx| {
 7878            let context = task_context.await?;
 7879            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7880
 7881            let resolved = &mut resolved_task.resolved;
 7882            resolved.reveal = reveal_strategy;
 7883
 7884            workspace
 7885                .update_in(cx, |workspace, window, cx| {
 7886                    workspace.schedule_resolved_task(
 7887                        task_source_kind,
 7888                        resolved_task,
 7889                        false,
 7890                        window,
 7891                        cx,
 7892                    );
 7893                })
 7894                .ok()
 7895        })
 7896        .detach();
 7897    }
 7898
 7899    fn find_closest_task(
 7900        &mut self,
 7901        cx: &mut Context<Self>,
 7902    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7903        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7904
 7905        let ((buffer_id, row), tasks) = self
 7906            .tasks
 7907            .iter()
 7908            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7909
 7910        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7911        let tasks = Arc::new(tasks.to_owned());
 7912        Some((buffer, *row, tasks))
 7913    }
 7914
 7915    fn find_enclosing_node_task(
 7916        &mut self,
 7917        cx: &mut Context<Self>,
 7918    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7919        let snapshot = self.buffer.read(cx).snapshot(cx);
 7920        let offset = self.selections.newest::<usize>(cx).head();
 7921        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7922        let buffer_id = excerpt.buffer().remote_id();
 7923
 7924        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7925        let mut cursor = layer.node().walk();
 7926
 7927        while cursor.goto_first_child_for_byte(offset).is_some() {
 7928            if cursor.node().end_byte() == offset {
 7929                cursor.goto_next_sibling();
 7930            }
 7931        }
 7932
 7933        // Ascend to the smallest ancestor that contains the range and has a task.
 7934        loop {
 7935            let node = cursor.node();
 7936            let node_range = node.byte_range();
 7937            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7938
 7939            // Check if this node contains our offset
 7940            if node_range.start <= offset && node_range.end >= offset {
 7941                // If it contains offset, check for task
 7942                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7943                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7944                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7945                }
 7946            }
 7947
 7948            if !cursor.goto_parent() {
 7949                break;
 7950            }
 7951        }
 7952        None
 7953    }
 7954
 7955    fn render_run_indicator(
 7956        &self,
 7957        _style: &EditorStyle,
 7958        is_active: bool,
 7959        row: DisplayRow,
 7960        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7961        cx: &mut Context<Self>,
 7962    ) -> IconButton {
 7963        let color = Color::Muted;
 7964        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7965
 7966        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7967            .shape(ui::IconButtonShape::Square)
 7968            .icon_size(IconSize::XSmall)
 7969            .icon_color(color)
 7970            .toggle_state(is_active)
 7971            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7972                let quick_launch = e.down.button == MouseButton::Left;
 7973                window.focus(&editor.focus_handle(cx));
 7974                editor.toggle_code_actions(
 7975                    &ToggleCodeActions {
 7976                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 7977                        quick_launch,
 7978                    },
 7979                    window,
 7980                    cx,
 7981                );
 7982            }))
 7983            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7984                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7985            }))
 7986    }
 7987
 7988    pub fn context_menu_visible(&self) -> bool {
 7989        !self.edit_prediction_preview_is_active()
 7990            && self
 7991                .context_menu
 7992                .borrow()
 7993                .as_ref()
 7994                .map_or(false, |menu| menu.visible())
 7995    }
 7996
 7997    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7998        self.context_menu
 7999            .borrow()
 8000            .as_ref()
 8001            .map(|menu| menu.origin())
 8002    }
 8003
 8004    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8005        self.context_menu_options = Some(options);
 8006    }
 8007
 8008    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8009    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8010
 8011    fn render_edit_prediction_popover(
 8012        &mut self,
 8013        text_bounds: &Bounds<Pixels>,
 8014        content_origin: gpui::Point<Pixels>,
 8015        right_margin: Pixels,
 8016        editor_snapshot: &EditorSnapshot,
 8017        visible_row_range: Range<DisplayRow>,
 8018        scroll_top: f32,
 8019        scroll_bottom: f32,
 8020        line_layouts: &[LineWithInvisibles],
 8021        line_height: Pixels,
 8022        scroll_pixel_position: gpui::Point<Pixels>,
 8023        newest_selection_head: Option<DisplayPoint>,
 8024        editor_width: Pixels,
 8025        style: &EditorStyle,
 8026        window: &mut Window,
 8027        cx: &mut App,
 8028    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8029        if self.mode().is_minimap() {
 8030            return None;
 8031        }
 8032        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8033
 8034        if self.edit_prediction_visible_in_cursor_popover(true) {
 8035            return None;
 8036        }
 8037
 8038        match &active_inline_completion.completion {
 8039            InlineCompletion::Move { target, .. } => {
 8040                let target_display_point = target.to_display_point(editor_snapshot);
 8041
 8042                if self.edit_prediction_requires_modifier() {
 8043                    if !self.edit_prediction_preview_is_active() {
 8044                        return None;
 8045                    }
 8046
 8047                    self.render_edit_prediction_modifier_jump_popover(
 8048                        text_bounds,
 8049                        content_origin,
 8050                        visible_row_range,
 8051                        line_layouts,
 8052                        line_height,
 8053                        scroll_pixel_position,
 8054                        newest_selection_head,
 8055                        target_display_point,
 8056                        window,
 8057                        cx,
 8058                    )
 8059                } else {
 8060                    self.render_edit_prediction_eager_jump_popover(
 8061                        text_bounds,
 8062                        content_origin,
 8063                        editor_snapshot,
 8064                        visible_row_range,
 8065                        scroll_top,
 8066                        scroll_bottom,
 8067                        line_height,
 8068                        scroll_pixel_position,
 8069                        target_display_point,
 8070                        editor_width,
 8071                        window,
 8072                        cx,
 8073                    )
 8074                }
 8075            }
 8076            InlineCompletion::Edit {
 8077                display_mode: EditDisplayMode::Inline,
 8078                ..
 8079            } => None,
 8080            InlineCompletion::Edit {
 8081                display_mode: EditDisplayMode::TabAccept,
 8082                edits,
 8083                ..
 8084            } => {
 8085                let range = &edits.first()?.0;
 8086                let target_display_point = range.end.to_display_point(editor_snapshot);
 8087
 8088                self.render_edit_prediction_end_of_line_popover(
 8089                    "Accept",
 8090                    editor_snapshot,
 8091                    visible_row_range,
 8092                    target_display_point,
 8093                    line_height,
 8094                    scroll_pixel_position,
 8095                    content_origin,
 8096                    editor_width,
 8097                    window,
 8098                    cx,
 8099                )
 8100            }
 8101            InlineCompletion::Edit {
 8102                edits,
 8103                edit_preview,
 8104                display_mode: EditDisplayMode::DiffPopover,
 8105                snapshot,
 8106            } => self.render_edit_prediction_diff_popover(
 8107                text_bounds,
 8108                content_origin,
 8109                right_margin,
 8110                editor_snapshot,
 8111                visible_row_range,
 8112                line_layouts,
 8113                line_height,
 8114                scroll_pixel_position,
 8115                newest_selection_head,
 8116                editor_width,
 8117                style,
 8118                edits,
 8119                edit_preview,
 8120                snapshot,
 8121                window,
 8122                cx,
 8123            ),
 8124        }
 8125    }
 8126
 8127    fn render_edit_prediction_modifier_jump_popover(
 8128        &mut self,
 8129        text_bounds: &Bounds<Pixels>,
 8130        content_origin: gpui::Point<Pixels>,
 8131        visible_row_range: Range<DisplayRow>,
 8132        line_layouts: &[LineWithInvisibles],
 8133        line_height: Pixels,
 8134        scroll_pixel_position: gpui::Point<Pixels>,
 8135        newest_selection_head: Option<DisplayPoint>,
 8136        target_display_point: DisplayPoint,
 8137        window: &mut Window,
 8138        cx: &mut App,
 8139    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8140        let scrolled_content_origin =
 8141            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8142
 8143        const SCROLL_PADDING_Y: Pixels = px(12.);
 8144
 8145        if target_display_point.row() < visible_row_range.start {
 8146            return self.render_edit_prediction_scroll_popover(
 8147                |_| SCROLL_PADDING_Y,
 8148                IconName::ArrowUp,
 8149                visible_row_range,
 8150                line_layouts,
 8151                newest_selection_head,
 8152                scrolled_content_origin,
 8153                window,
 8154                cx,
 8155            );
 8156        } else if target_display_point.row() >= visible_row_range.end {
 8157            return self.render_edit_prediction_scroll_popover(
 8158                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8159                IconName::ArrowDown,
 8160                visible_row_range,
 8161                line_layouts,
 8162                newest_selection_head,
 8163                scrolled_content_origin,
 8164                window,
 8165                cx,
 8166            );
 8167        }
 8168
 8169        const POLE_WIDTH: Pixels = px(2.);
 8170
 8171        let line_layout =
 8172            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8173        let target_column = target_display_point.column() as usize;
 8174
 8175        let target_x = line_layout.x_for_index(target_column);
 8176        let target_y =
 8177            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8178
 8179        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8180
 8181        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8182        border_color.l += 0.001;
 8183
 8184        let mut element = v_flex()
 8185            .items_end()
 8186            .when(flag_on_right, |el| el.items_start())
 8187            .child(if flag_on_right {
 8188                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8189                    .rounded_bl(px(0.))
 8190                    .rounded_tl(px(0.))
 8191                    .border_l_2()
 8192                    .border_color(border_color)
 8193            } else {
 8194                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8195                    .rounded_br(px(0.))
 8196                    .rounded_tr(px(0.))
 8197                    .border_r_2()
 8198                    .border_color(border_color)
 8199            })
 8200            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8201            .into_any();
 8202
 8203        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8204
 8205        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8206            - point(
 8207                if flag_on_right {
 8208                    POLE_WIDTH
 8209                } else {
 8210                    size.width - POLE_WIDTH
 8211                },
 8212                size.height - line_height,
 8213            );
 8214
 8215        origin.x = origin.x.max(content_origin.x);
 8216
 8217        element.prepaint_at(origin, window, cx);
 8218
 8219        Some((element, origin))
 8220    }
 8221
 8222    fn render_edit_prediction_scroll_popover(
 8223        &mut self,
 8224        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8225        scroll_icon: IconName,
 8226        visible_row_range: Range<DisplayRow>,
 8227        line_layouts: &[LineWithInvisibles],
 8228        newest_selection_head: Option<DisplayPoint>,
 8229        scrolled_content_origin: gpui::Point<Pixels>,
 8230        window: &mut Window,
 8231        cx: &mut App,
 8232    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8233        let mut element = self
 8234            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8235            .into_any();
 8236
 8237        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8238
 8239        let cursor = newest_selection_head?;
 8240        let cursor_row_layout =
 8241            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8242        let cursor_column = cursor.column() as usize;
 8243
 8244        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8245
 8246        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8247
 8248        element.prepaint_at(origin, window, cx);
 8249        Some((element, origin))
 8250    }
 8251
 8252    fn render_edit_prediction_eager_jump_popover(
 8253        &mut self,
 8254        text_bounds: &Bounds<Pixels>,
 8255        content_origin: gpui::Point<Pixels>,
 8256        editor_snapshot: &EditorSnapshot,
 8257        visible_row_range: Range<DisplayRow>,
 8258        scroll_top: f32,
 8259        scroll_bottom: f32,
 8260        line_height: Pixels,
 8261        scroll_pixel_position: gpui::Point<Pixels>,
 8262        target_display_point: DisplayPoint,
 8263        editor_width: Pixels,
 8264        window: &mut Window,
 8265        cx: &mut App,
 8266    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8267        if target_display_point.row().as_f32() < scroll_top {
 8268            let mut element = self
 8269                .render_edit_prediction_line_popover(
 8270                    "Jump to Edit",
 8271                    Some(IconName::ArrowUp),
 8272                    window,
 8273                    cx,
 8274                )?
 8275                .into_any();
 8276
 8277            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8278            let offset = point(
 8279                (text_bounds.size.width - size.width) / 2.,
 8280                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8281            );
 8282
 8283            let origin = text_bounds.origin + offset;
 8284            element.prepaint_at(origin, window, cx);
 8285            Some((element, origin))
 8286        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8287            let mut element = self
 8288                .render_edit_prediction_line_popover(
 8289                    "Jump to Edit",
 8290                    Some(IconName::ArrowDown),
 8291                    window,
 8292                    cx,
 8293                )?
 8294                .into_any();
 8295
 8296            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8297            let offset = point(
 8298                (text_bounds.size.width - size.width) / 2.,
 8299                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8300            );
 8301
 8302            let origin = text_bounds.origin + offset;
 8303            element.prepaint_at(origin, window, cx);
 8304            Some((element, origin))
 8305        } else {
 8306            self.render_edit_prediction_end_of_line_popover(
 8307                "Jump to Edit",
 8308                editor_snapshot,
 8309                visible_row_range,
 8310                target_display_point,
 8311                line_height,
 8312                scroll_pixel_position,
 8313                content_origin,
 8314                editor_width,
 8315                window,
 8316                cx,
 8317            )
 8318        }
 8319    }
 8320
 8321    fn render_edit_prediction_end_of_line_popover(
 8322        self: &mut Editor,
 8323        label: &'static str,
 8324        editor_snapshot: &EditorSnapshot,
 8325        visible_row_range: Range<DisplayRow>,
 8326        target_display_point: DisplayPoint,
 8327        line_height: Pixels,
 8328        scroll_pixel_position: gpui::Point<Pixels>,
 8329        content_origin: gpui::Point<Pixels>,
 8330        editor_width: Pixels,
 8331        window: &mut Window,
 8332        cx: &mut App,
 8333    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8334        let target_line_end = DisplayPoint::new(
 8335            target_display_point.row(),
 8336            editor_snapshot.line_len(target_display_point.row()),
 8337        );
 8338
 8339        let mut element = self
 8340            .render_edit_prediction_line_popover(label, None, window, cx)?
 8341            .into_any();
 8342
 8343        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8344
 8345        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8346
 8347        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8348        let mut origin = start_point
 8349            + line_origin
 8350            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8351        origin.x = origin.x.max(content_origin.x);
 8352
 8353        let max_x = content_origin.x + editor_width - size.width;
 8354
 8355        if origin.x > max_x {
 8356            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8357
 8358            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8359                origin.y += offset;
 8360                IconName::ArrowUp
 8361            } else {
 8362                origin.y -= offset;
 8363                IconName::ArrowDown
 8364            };
 8365
 8366            element = self
 8367                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8368                .into_any();
 8369
 8370            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8371
 8372            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8373        }
 8374
 8375        element.prepaint_at(origin, window, cx);
 8376        Some((element, origin))
 8377    }
 8378
 8379    fn render_edit_prediction_diff_popover(
 8380        self: &Editor,
 8381        text_bounds: &Bounds<Pixels>,
 8382        content_origin: gpui::Point<Pixels>,
 8383        right_margin: Pixels,
 8384        editor_snapshot: &EditorSnapshot,
 8385        visible_row_range: Range<DisplayRow>,
 8386        line_layouts: &[LineWithInvisibles],
 8387        line_height: Pixels,
 8388        scroll_pixel_position: gpui::Point<Pixels>,
 8389        newest_selection_head: Option<DisplayPoint>,
 8390        editor_width: Pixels,
 8391        style: &EditorStyle,
 8392        edits: &Vec<(Range<Anchor>, String)>,
 8393        edit_preview: &Option<language::EditPreview>,
 8394        snapshot: &language::BufferSnapshot,
 8395        window: &mut Window,
 8396        cx: &mut App,
 8397    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8398        let edit_start = edits
 8399            .first()
 8400            .unwrap()
 8401            .0
 8402            .start
 8403            .to_display_point(editor_snapshot);
 8404        let edit_end = edits
 8405            .last()
 8406            .unwrap()
 8407            .0
 8408            .end
 8409            .to_display_point(editor_snapshot);
 8410
 8411        let is_visible = visible_row_range.contains(&edit_start.row())
 8412            || visible_row_range.contains(&edit_end.row());
 8413        if !is_visible {
 8414            return None;
 8415        }
 8416
 8417        let highlighted_edits =
 8418            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8419
 8420        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8421        let line_count = highlighted_edits.text.lines().count();
 8422
 8423        const BORDER_WIDTH: Pixels = px(1.);
 8424
 8425        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8426        let has_keybind = keybind.is_some();
 8427
 8428        let mut element = h_flex()
 8429            .items_start()
 8430            .child(
 8431                h_flex()
 8432                    .bg(cx.theme().colors().editor_background)
 8433                    .border(BORDER_WIDTH)
 8434                    .shadow_sm()
 8435                    .border_color(cx.theme().colors().border)
 8436                    .rounded_l_lg()
 8437                    .when(line_count > 1, |el| el.rounded_br_lg())
 8438                    .pr_1()
 8439                    .child(styled_text),
 8440            )
 8441            .child(
 8442                h_flex()
 8443                    .h(line_height + BORDER_WIDTH * 2.)
 8444                    .px_1p5()
 8445                    .gap_1()
 8446                    // Workaround: For some reason, there's a gap if we don't do this
 8447                    .ml(-BORDER_WIDTH)
 8448                    .shadow(vec![gpui::BoxShadow {
 8449                        color: gpui::black().opacity(0.05),
 8450                        offset: point(px(1.), px(1.)),
 8451                        blur_radius: px(2.),
 8452                        spread_radius: px(0.),
 8453                    }])
 8454                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8455                    .border(BORDER_WIDTH)
 8456                    .border_color(cx.theme().colors().border)
 8457                    .rounded_r_lg()
 8458                    .id("edit_prediction_diff_popover_keybind")
 8459                    .when(!has_keybind, |el| {
 8460                        let status_colors = cx.theme().status();
 8461
 8462                        el.bg(status_colors.error_background)
 8463                            .border_color(status_colors.error.opacity(0.6))
 8464                            .child(Icon::new(IconName::Info).color(Color::Error))
 8465                            .cursor_default()
 8466                            .hoverable_tooltip(move |_window, cx| {
 8467                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8468                            })
 8469                    })
 8470                    .children(keybind),
 8471            )
 8472            .into_any();
 8473
 8474        let longest_row =
 8475            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8476        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8477            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8478        } else {
 8479            layout_line(
 8480                longest_row,
 8481                editor_snapshot,
 8482                style,
 8483                editor_width,
 8484                |_| false,
 8485                window,
 8486                cx,
 8487            )
 8488            .width
 8489        };
 8490
 8491        let viewport_bounds =
 8492            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8493                right: -right_margin,
 8494                ..Default::default()
 8495            });
 8496
 8497        let x_after_longest =
 8498            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8499                - scroll_pixel_position.x;
 8500
 8501        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8502
 8503        // Fully visible if it can be displayed within the window (allow overlapping other
 8504        // panes). However, this is only allowed if the popover starts within text_bounds.
 8505        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8506            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8507
 8508        let mut origin = if can_position_to_the_right {
 8509            point(
 8510                x_after_longest,
 8511                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8512                    - scroll_pixel_position.y,
 8513            )
 8514        } else {
 8515            let cursor_row = newest_selection_head.map(|head| head.row());
 8516            let above_edit = edit_start
 8517                .row()
 8518                .0
 8519                .checked_sub(line_count as u32)
 8520                .map(DisplayRow);
 8521            let below_edit = Some(edit_end.row() + 1);
 8522            let above_cursor =
 8523                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8524            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8525
 8526            // Place the edit popover adjacent to the edit if there is a location
 8527            // available that is onscreen and does not obscure the cursor. Otherwise,
 8528            // place it adjacent to the cursor.
 8529            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8530                .into_iter()
 8531                .flatten()
 8532                .find(|&start_row| {
 8533                    let end_row = start_row + line_count as u32;
 8534                    visible_row_range.contains(&start_row)
 8535                        && visible_row_range.contains(&end_row)
 8536                        && cursor_row.map_or(true, |cursor_row| {
 8537                            !((start_row..end_row).contains(&cursor_row))
 8538                        })
 8539                })?;
 8540
 8541            content_origin
 8542                + point(
 8543                    -scroll_pixel_position.x,
 8544                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8545                )
 8546        };
 8547
 8548        origin.x -= BORDER_WIDTH;
 8549
 8550        window.defer_draw(element, origin, 1);
 8551
 8552        // Do not return an element, since it will already be drawn due to defer_draw.
 8553        None
 8554    }
 8555
 8556    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8557        px(30.)
 8558    }
 8559
 8560    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8561        if self.read_only(cx) {
 8562            cx.theme().players().read_only()
 8563        } else {
 8564            self.style.as_ref().unwrap().local_player
 8565        }
 8566    }
 8567
 8568    fn render_edit_prediction_accept_keybind(
 8569        &self,
 8570        window: &mut Window,
 8571        cx: &App,
 8572    ) -> Option<AnyElement> {
 8573        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8574        let accept_keystroke = accept_binding.keystroke()?;
 8575
 8576        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8577
 8578        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8579            Color::Accent
 8580        } else {
 8581            Color::Muted
 8582        };
 8583
 8584        h_flex()
 8585            .px_0p5()
 8586            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8587            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8588            .text_size(TextSize::XSmall.rems(cx))
 8589            .child(h_flex().children(ui::render_modifiers(
 8590                &accept_keystroke.modifiers,
 8591                PlatformStyle::platform(),
 8592                Some(modifiers_color),
 8593                Some(IconSize::XSmall.rems().into()),
 8594                true,
 8595            )))
 8596            .when(is_platform_style_mac, |parent| {
 8597                parent.child(accept_keystroke.key.clone())
 8598            })
 8599            .when(!is_platform_style_mac, |parent| {
 8600                parent.child(
 8601                    Key::new(
 8602                        util::capitalize(&accept_keystroke.key),
 8603                        Some(Color::Default),
 8604                    )
 8605                    .size(Some(IconSize::XSmall.rems().into())),
 8606                )
 8607            })
 8608            .into_any()
 8609            .into()
 8610    }
 8611
 8612    fn render_edit_prediction_line_popover(
 8613        &self,
 8614        label: impl Into<SharedString>,
 8615        icon: Option<IconName>,
 8616        window: &mut Window,
 8617        cx: &App,
 8618    ) -> Option<Stateful<Div>> {
 8619        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8620
 8621        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8622        let has_keybind = keybind.is_some();
 8623
 8624        let result = h_flex()
 8625            .id("ep-line-popover")
 8626            .py_0p5()
 8627            .pl_1()
 8628            .pr(padding_right)
 8629            .gap_1()
 8630            .rounded_md()
 8631            .border_1()
 8632            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8633            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8634            .shadow_sm()
 8635            .when(!has_keybind, |el| {
 8636                let status_colors = cx.theme().status();
 8637
 8638                el.bg(status_colors.error_background)
 8639                    .border_color(status_colors.error.opacity(0.6))
 8640                    .pl_2()
 8641                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8642                    .cursor_default()
 8643                    .hoverable_tooltip(move |_window, cx| {
 8644                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8645                    })
 8646            })
 8647            .children(keybind)
 8648            .child(
 8649                Label::new(label)
 8650                    .size(LabelSize::Small)
 8651                    .when(!has_keybind, |el| {
 8652                        el.color(cx.theme().status().error.into()).strikethrough()
 8653                    }),
 8654            )
 8655            .when(!has_keybind, |el| {
 8656                el.child(
 8657                    h_flex().ml_1().child(
 8658                        Icon::new(IconName::Info)
 8659                            .size(IconSize::Small)
 8660                            .color(cx.theme().status().error.into()),
 8661                    ),
 8662                )
 8663            })
 8664            .when_some(icon, |element, icon| {
 8665                element.child(
 8666                    div()
 8667                        .mt(px(1.5))
 8668                        .child(Icon::new(icon).size(IconSize::Small)),
 8669                )
 8670            });
 8671
 8672        Some(result)
 8673    }
 8674
 8675    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8676        let accent_color = cx.theme().colors().text_accent;
 8677        let editor_bg_color = cx.theme().colors().editor_background;
 8678        editor_bg_color.blend(accent_color.opacity(0.1))
 8679    }
 8680
 8681    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8682        let accent_color = cx.theme().colors().text_accent;
 8683        let editor_bg_color = cx.theme().colors().editor_background;
 8684        editor_bg_color.blend(accent_color.opacity(0.6))
 8685    }
 8686
 8687    fn render_edit_prediction_cursor_popover(
 8688        &self,
 8689        min_width: Pixels,
 8690        max_width: Pixels,
 8691        cursor_point: Point,
 8692        style: &EditorStyle,
 8693        accept_keystroke: Option<&gpui::Keystroke>,
 8694        _window: &Window,
 8695        cx: &mut Context<Editor>,
 8696    ) -> Option<AnyElement> {
 8697        let provider = self.edit_prediction_provider.as_ref()?;
 8698
 8699        if provider.provider.needs_terms_acceptance(cx) {
 8700            return Some(
 8701                h_flex()
 8702                    .min_w(min_width)
 8703                    .flex_1()
 8704                    .px_2()
 8705                    .py_1()
 8706                    .gap_3()
 8707                    .elevation_2(cx)
 8708                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8709                    .id("accept-terms")
 8710                    .cursor_pointer()
 8711                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8712                    .on_click(cx.listener(|this, _event, window, cx| {
 8713                        cx.stop_propagation();
 8714                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8715                        window.dispatch_action(
 8716                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8717                            cx,
 8718                        );
 8719                    }))
 8720                    .child(
 8721                        h_flex()
 8722                            .flex_1()
 8723                            .gap_2()
 8724                            .child(Icon::new(IconName::ZedPredict))
 8725                            .child(Label::new("Accept Terms of Service"))
 8726                            .child(div().w_full())
 8727                            .child(
 8728                                Icon::new(IconName::ArrowUpRight)
 8729                                    .color(Color::Muted)
 8730                                    .size(IconSize::Small),
 8731                            )
 8732                            .into_any_element(),
 8733                    )
 8734                    .into_any(),
 8735            );
 8736        }
 8737
 8738        let is_refreshing = provider.provider.is_refreshing(cx);
 8739
 8740        fn pending_completion_container() -> Div {
 8741            h_flex()
 8742                .h_full()
 8743                .flex_1()
 8744                .gap_2()
 8745                .child(Icon::new(IconName::ZedPredict))
 8746        }
 8747
 8748        let completion = match &self.active_inline_completion {
 8749            Some(prediction) => {
 8750                if !self.has_visible_completions_menu() {
 8751                    const RADIUS: Pixels = px(6.);
 8752                    const BORDER_WIDTH: Pixels = px(1.);
 8753
 8754                    return Some(
 8755                        h_flex()
 8756                            .elevation_2(cx)
 8757                            .border(BORDER_WIDTH)
 8758                            .border_color(cx.theme().colors().border)
 8759                            .when(accept_keystroke.is_none(), |el| {
 8760                                el.border_color(cx.theme().status().error)
 8761                            })
 8762                            .rounded(RADIUS)
 8763                            .rounded_tl(px(0.))
 8764                            .overflow_hidden()
 8765                            .child(div().px_1p5().child(match &prediction.completion {
 8766                                InlineCompletion::Move { target, snapshot } => {
 8767                                    use text::ToPoint as _;
 8768                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8769                                    {
 8770                                        Icon::new(IconName::ZedPredictDown)
 8771                                    } else {
 8772                                        Icon::new(IconName::ZedPredictUp)
 8773                                    }
 8774                                }
 8775                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8776                            }))
 8777                            .child(
 8778                                h_flex()
 8779                                    .gap_1()
 8780                                    .py_1()
 8781                                    .px_2()
 8782                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8783                                    .border_l_1()
 8784                                    .border_color(cx.theme().colors().border)
 8785                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8786                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8787                                        el.child(
 8788                                            Label::new("Hold")
 8789                                                .size(LabelSize::Small)
 8790                                                .when(accept_keystroke.is_none(), |el| {
 8791                                                    el.strikethrough()
 8792                                                })
 8793                                                .line_height_style(LineHeightStyle::UiLabel),
 8794                                        )
 8795                                    })
 8796                                    .id("edit_prediction_cursor_popover_keybind")
 8797                                    .when(accept_keystroke.is_none(), |el| {
 8798                                        let status_colors = cx.theme().status();
 8799
 8800                                        el.bg(status_colors.error_background)
 8801                                            .border_color(status_colors.error.opacity(0.6))
 8802                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8803                                            .cursor_default()
 8804                                            .hoverable_tooltip(move |_window, cx| {
 8805                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8806                                                    .into()
 8807                                            })
 8808                                    })
 8809                                    .when_some(
 8810                                        accept_keystroke.as_ref(),
 8811                                        |el, accept_keystroke| {
 8812                                            el.child(h_flex().children(ui::render_modifiers(
 8813                                                &accept_keystroke.modifiers,
 8814                                                PlatformStyle::platform(),
 8815                                                Some(Color::Default),
 8816                                                Some(IconSize::XSmall.rems().into()),
 8817                                                false,
 8818                                            )))
 8819                                        },
 8820                                    ),
 8821                            )
 8822                            .into_any(),
 8823                    );
 8824                }
 8825
 8826                self.render_edit_prediction_cursor_popover_preview(
 8827                    prediction,
 8828                    cursor_point,
 8829                    style,
 8830                    cx,
 8831                )?
 8832            }
 8833
 8834            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8835                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8836                    stale_completion,
 8837                    cursor_point,
 8838                    style,
 8839                    cx,
 8840                )?,
 8841
 8842                None => {
 8843                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8844                }
 8845            },
 8846
 8847            None => pending_completion_container().child(Label::new("No Prediction")),
 8848        };
 8849
 8850        let completion = if is_refreshing {
 8851            completion
 8852                .with_animation(
 8853                    "loading-completion",
 8854                    Animation::new(Duration::from_secs(2))
 8855                        .repeat()
 8856                        .with_easing(pulsating_between(0.4, 0.8)),
 8857                    |label, delta| label.opacity(delta),
 8858                )
 8859                .into_any_element()
 8860        } else {
 8861            completion.into_any_element()
 8862        };
 8863
 8864        let has_completion = self.active_inline_completion.is_some();
 8865
 8866        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8867        Some(
 8868            h_flex()
 8869                .min_w(min_width)
 8870                .max_w(max_width)
 8871                .flex_1()
 8872                .elevation_2(cx)
 8873                .border_color(cx.theme().colors().border)
 8874                .child(
 8875                    div()
 8876                        .flex_1()
 8877                        .py_1()
 8878                        .px_2()
 8879                        .overflow_hidden()
 8880                        .child(completion),
 8881                )
 8882                .when_some(accept_keystroke, |el, accept_keystroke| {
 8883                    if !accept_keystroke.modifiers.modified() {
 8884                        return el;
 8885                    }
 8886
 8887                    el.child(
 8888                        h_flex()
 8889                            .h_full()
 8890                            .border_l_1()
 8891                            .rounded_r_lg()
 8892                            .border_color(cx.theme().colors().border)
 8893                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8894                            .gap_1()
 8895                            .py_1()
 8896                            .px_2()
 8897                            .child(
 8898                                h_flex()
 8899                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8900                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8901                                    .child(h_flex().children(ui::render_modifiers(
 8902                                        &accept_keystroke.modifiers,
 8903                                        PlatformStyle::platform(),
 8904                                        Some(if !has_completion {
 8905                                            Color::Muted
 8906                                        } else {
 8907                                            Color::Default
 8908                                        }),
 8909                                        None,
 8910                                        false,
 8911                                    ))),
 8912                            )
 8913                            .child(Label::new("Preview").into_any_element())
 8914                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8915                    )
 8916                })
 8917                .into_any(),
 8918        )
 8919    }
 8920
 8921    fn render_edit_prediction_cursor_popover_preview(
 8922        &self,
 8923        completion: &InlineCompletionState,
 8924        cursor_point: Point,
 8925        style: &EditorStyle,
 8926        cx: &mut Context<Editor>,
 8927    ) -> Option<Div> {
 8928        use text::ToPoint as _;
 8929
 8930        fn render_relative_row_jump(
 8931            prefix: impl Into<String>,
 8932            current_row: u32,
 8933            target_row: u32,
 8934        ) -> Div {
 8935            let (row_diff, arrow) = if target_row < current_row {
 8936                (current_row - target_row, IconName::ArrowUp)
 8937            } else {
 8938                (target_row - current_row, IconName::ArrowDown)
 8939            };
 8940
 8941            h_flex()
 8942                .child(
 8943                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8944                        .color(Color::Muted)
 8945                        .size(LabelSize::Small),
 8946                )
 8947                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8948        }
 8949
 8950        match &completion.completion {
 8951            InlineCompletion::Move {
 8952                target, snapshot, ..
 8953            } => Some(
 8954                h_flex()
 8955                    .px_2()
 8956                    .gap_2()
 8957                    .flex_1()
 8958                    .child(
 8959                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8960                            Icon::new(IconName::ZedPredictDown)
 8961                        } else {
 8962                            Icon::new(IconName::ZedPredictUp)
 8963                        },
 8964                    )
 8965                    .child(Label::new("Jump to Edit")),
 8966            ),
 8967
 8968            InlineCompletion::Edit {
 8969                edits,
 8970                edit_preview,
 8971                snapshot,
 8972                display_mode: _,
 8973            } => {
 8974                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8975
 8976                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8977                    &snapshot,
 8978                    &edits,
 8979                    edit_preview.as_ref()?,
 8980                    true,
 8981                    cx,
 8982                )
 8983                .first_line_preview();
 8984
 8985                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8986                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8987
 8988                let preview = h_flex()
 8989                    .gap_1()
 8990                    .min_w_16()
 8991                    .child(styled_text)
 8992                    .when(has_more_lines, |parent| parent.child(""));
 8993
 8994                let left = if first_edit_row != cursor_point.row {
 8995                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8996                        .into_any_element()
 8997                } else {
 8998                    Icon::new(IconName::ZedPredict).into_any_element()
 8999                };
 9000
 9001                Some(
 9002                    h_flex()
 9003                        .h_full()
 9004                        .flex_1()
 9005                        .gap_2()
 9006                        .pr_1()
 9007                        .overflow_x_hidden()
 9008                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9009                        .child(left)
 9010                        .child(preview),
 9011                )
 9012            }
 9013        }
 9014    }
 9015
 9016    pub fn render_context_menu(
 9017        &self,
 9018        style: &EditorStyle,
 9019        max_height_in_lines: u32,
 9020        window: &mut Window,
 9021        cx: &mut Context<Editor>,
 9022    ) -> Option<AnyElement> {
 9023        let menu = self.context_menu.borrow();
 9024        let menu = menu.as_ref()?;
 9025        if !menu.visible() {
 9026            return None;
 9027        };
 9028        Some(menu.render(style, max_height_in_lines, window, cx))
 9029    }
 9030
 9031    fn render_context_menu_aside(
 9032        &mut self,
 9033        max_size: Size<Pixels>,
 9034        window: &mut Window,
 9035        cx: &mut Context<Editor>,
 9036    ) -> Option<AnyElement> {
 9037        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9038            if menu.visible() {
 9039                menu.render_aside(max_size, window, cx)
 9040            } else {
 9041                None
 9042            }
 9043        })
 9044    }
 9045
 9046    fn hide_context_menu(
 9047        &mut self,
 9048        window: &mut Window,
 9049        cx: &mut Context<Self>,
 9050    ) -> Option<CodeContextMenu> {
 9051        cx.notify();
 9052        self.completion_tasks.clear();
 9053        let context_menu = self.context_menu.borrow_mut().take();
 9054        self.stale_inline_completion_in_menu.take();
 9055        self.update_visible_inline_completion(window, cx);
 9056        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9057            if let Some(completion_provider) = &self.completion_provider {
 9058                completion_provider.selection_changed(None, window, cx);
 9059            }
 9060        }
 9061        context_menu
 9062    }
 9063
 9064    fn show_snippet_choices(
 9065        &mut self,
 9066        choices: &Vec<String>,
 9067        selection: Range<Anchor>,
 9068        cx: &mut Context<Self>,
 9069    ) {
 9070        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9071            (Some(a), Some(b)) if a == b => a,
 9072            _ => {
 9073                log::error!("expected anchor range to have matching buffer IDs");
 9074                return;
 9075            }
 9076        };
 9077        let multi_buffer = self.buffer().read(cx);
 9078        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9079            return;
 9080        };
 9081
 9082        let id = post_inc(&mut self.next_completion_id);
 9083        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9084        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9085            CompletionsMenu::new_snippet_choices(
 9086                id,
 9087                true,
 9088                choices,
 9089                selection,
 9090                buffer,
 9091                snippet_sort_order,
 9092            ),
 9093        ));
 9094    }
 9095
 9096    pub fn insert_snippet(
 9097        &mut self,
 9098        insertion_ranges: &[Range<usize>],
 9099        snippet: Snippet,
 9100        window: &mut Window,
 9101        cx: &mut Context<Self>,
 9102    ) -> Result<()> {
 9103        struct Tabstop<T> {
 9104            is_end_tabstop: bool,
 9105            ranges: Vec<Range<T>>,
 9106            choices: Option<Vec<String>>,
 9107        }
 9108
 9109        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9110            let snippet_text: Arc<str> = snippet.text.clone().into();
 9111            let edits = insertion_ranges
 9112                .iter()
 9113                .cloned()
 9114                .map(|range| (range, snippet_text.clone()));
 9115            let autoindent_mode = AutoindentMode::Block {
 9116                original_indent_columns: Vec::new(),
 9117            };
 9118            buffer.edit(edits, Some(autoindent_mode), cx);
 9119
 9120            let snapshot = &*buffer.read(cx);
 9121            let snippet = &snippet;
 9122            snippet
 9123                .tabstops
 9124                .iter()
 9125                .map(|tabstop| {
 9126                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9127                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9128                    });
 9129                    let mut tabstop_ranges = tabstop
 9130                        .ranges
 9131                        .iter()
 9132                        .flat_map(|tabstop_range| {
 9133                            let mut delta = 0_isize;
 9134                            insertion_ranges.iter().map(move |insertion_range| {
 9135                                let insertion_start = insertion_range.start as isize + delta;
 9136                                delta +=
 9137                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9138
 9139                                let start = ((insertion_start + tabstop_range.start) as usize)
 9140                                    .min(snapshot.len());
 9141                                let end = ((insertion_start + tabstop_range.end) as usize)
 9142                                    .min(snapshot.len());
 9143                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9144                            })
 9145                        })
 9146                        .collect::<Vec<_>>();
 9147                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9148
 9149                    Tabstop {
 9150                        is_end_tabstop,
 9151                        ranges: tabstop_ranges,
 9152                        choices: tabstop.choices.clone(),
 9153                    }
 9154                })
 9155                .collect::<Vec<_>>()
 9156        });
 9157        if let Some(tabstop) = tabstops.first() {
 9158            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9159                // Reverse order so that the first range is the newest created selection.
 9160                // Completions will use it and autoscroll will prioritize it.
 9161                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9162            });
 9163
 9164            if let Some(choices) = &tabstop.choices {
 9165                if let Some(selection) = tabstop.ranges.first() {
 9166                    self.show_snippet_choices(choices, selection.clone(), cx)
 9167                }
 9168            }
 9169
 9170            // If we're already at the last tabstop and it's at the end of the snippet,
 9171            // we're done, we don't need to keep the state around.
 9172            if !tabstop.is_end_tabstop {
 9173                let choices = tabstops
 9174                    .iter()
 9175                    .map(|tabstop| tabstop.choices.clone())
 9176                    .collect();
 9177
 9178                let ranges = tabstops
 9179                    .into_iter()
 9180                    .map(|tabstop| tabstop.ranges)
 9181                    .collect::<Vec<_>>();
 9182
 9183                self.snippet_stack.push(SnippetState {
 9184                    active_index: 0,
 9185                    ranges,
 9186                    choices,
 9187                });
 9188            }
 9189
 9190            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9191            if self.autoclose_regions.is_empty() {
 9192                let snapshot = self.buffer.read(cx).snapshot(cx);
 9193                for selection in &mut self.selections.all::<Point>(cx) {
 9194                    let selection_head = selection.head();
 9195                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9196                        continue;
 9197                    };
 9198
 9199                    let mut bracket_pair = None;
 9200                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9201                    let prev_chars = snapshot
 9202                        .reversed_chars_at(selection_head)
 9203                        .collect::<String>();
 9204                    for (pair, enabled) in scope.brackets() {
 9205                        if enabled
 9206                            && pair.close
 9207                            && prev_chars.starts_with(pair.start.as_str())
 9208                            && next_chars.starts_with(pair.end.as_str())
 9209                        {
 9210                            bracket_pair = Some(pair.clone());
 9211                            break;
 9212                        }
 9213                    }
 9214                    if let Some(pair) = bracket_pair {
 9215                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9216                        let autoclose_enabled =
 9217                            self.use_autoclose && snapshot_settings.use_autoclose;
 9218                        if autoclose_enabled {
 9219                            let start = snapshot.anchor_after(selection_head);
 9220                            let end = snapshot.anchor_after(selection_head);
 9221                            self.autoclose_regions.push(AutocloseRegion {
 9222                                selection_id: selection.id,
 9223                                range: start..end,
 9224                                pair,
 9225                            });
 9226                        }
 9227                    }
 9228                }
 9229            }
 9230        }
 9231        Ok(())
 9232    }
 9233
 9234    pub fn move_to_next_snippet_tabstop(
 9235        &mut self,
 9236        window: &mut Window,
 9237        cx: &mut Context<Self>,
 9238    ) -> bool {
 9239        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9240    }
 9241
 9242    pub fn move_to_prev_snippet_tabstop(
 9243        &mut self,
 9244        window: &mut Window,
 9245        cx: &mut Context<Self>,
 9246    ) -> bool {
 9247        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9248    }
 9249
 9250    pub fn move_to_snippet_tabstop(
 9251        &mut self,
 9252        bias: Bias,
 9253        window: &mut Window,
 9254        cx: &mut Context<Self>,
 9255    ) -> bool {
 9256        if let Some(mut snippet) = self.snippet_stack.pop() {
 9257            match bias {
 9258                Bias::Left => {
 9259                    if snippet.active_index > 0 {
 9260                        snippet.active_index -= 1;
 9261                    } else {
 9262                        self.snippet_stack.push(snippet);
 9263                        return false;
 9264                    }
 9265                }
 9266                Bias::Right => {
 9267                    if snippet.active_index + 1 < snippet.ranges.len() {
 9268                        snippet.active_index += 1;
 9269                    } else {
 9270                        self.snippet_stack.push(snippet);
 9271                        return false;
 9272                    }
 9273                }
 9274            }
 9275            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9276                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9277                    // Reverse order so that the first range is the newest created selection.
 9278                    // Completions will use it and autoscroll will prioritize it.
 9279                    s.select_ranges(current_ranges.iter().rev().cloned())
 9280                });
 9281
 9282                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9283                    if let Some(selection) = current_ranges.first() {
 9284                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9285                    }
 9286                }
 9287
 9288                // If snippet state is not at the last tabstop, push it back on the stack
 9289                if snippet.active_index + 1 < snippet.ranges.len() {
 9290                    self.snippet_stack.push(snippet);
 9291                }
 9292                return true;
 9293            }
 9294        }
 9295
 9296        false
 9297    }
 9298
 9299    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9300        self.transact(window, cx, |this, window, cx| {
 9301            this.select_all(&SelectAll, window, cx);
 9302            this.insert("", window, cx);
 9303        });
 9304    }
 9305
 9306    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9307        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9308        self.transact(window, cx, |this, window, cx| {
 9309            this.select_autoclose_pair(window, cx);
 9310            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9311            if !this.linked_edit_ranges.is_empty() {
 9312                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9313                let snapshot = this.buffer.read(cx).snapshot(cx);
 9314
 9315                for selection in selections.iter() {
 9316                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9317                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9318                    if selection_start.buffer_id != selection_end.buffer_id {
 9319                        continue;
 9320                    }
 9321                    if let Some(ranges) =
 9322                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9323                    {
 9324                        for (buffer, entries) in ranges {
 9325                            linked_ranges.entry(buffer).or_default().extend(entries);
 9326                        }
 9327                    }
 9328                }
 9329            }
 9330
 9331            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9332            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9333            for selection in &mut selections {
 9334                if selection.is_empty() {
 9335                    let old_head = selection.head();
 9336                    let mut new_head =
 9337                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9338                            .to_point(&display_map);
 9339                    if let Some((buffer, line_buffer_range)) = display_map
 9340                        .buffer_snapshot
 9341                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9342                    {
 9343                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9344                        let indent_len = match indent_size.kind {
 9345                            IndentKind::Space => {
 9346                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9347                            }
 9348                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9349                        };
 9350                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9351                            let indent_len = indent_len.get();
 9352                            new_head = cmp::min(
 9353                                new_head,
 9354                                MultiBufferPoint::new(
 9355                                    old_head.row,
 9356                                    ((old_head.column - 1) / indent_len) * indent_len,
 9357                                ),
 9358                            );
 9359                        }
 9360                    }
 9361
 9362                    selection.set_head(new_head, SelectionGoal::None);
 9363                }
 9364            }
 9365
 9366            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9367                s.select(selections)
 9368            });
 9369            this.insert("", window, cx);
 9370            let empty_str: Arc<str> = Arc::from("");
 9371            for (buffer, edits) in linked_ranges {
 9372                let snapshot = buffer.read(cx).snapshot();
 9373                use text::ToPoint as TP;
 9374
 9375                let edits = edits
 9376                    .into_iter()
 9377                    .map(|range| {
 9378                        let end_point = TP::to_point(&range.end, &snapshot);
 9379                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9380
 9381                        if end_point == start_point {
 9382                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9383                                .saturating_sub(1);
 9384                            start_point =
 9385                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9386                        };
 9387
 9388                        (start_point..end_point, empty_str.clone())
 9389                    })
 9390                    .sorted_by_key(|(range, _)| range.start)
 9391                    .collect::<Vec<_>>();
 9392                buffer.update(cx, |this, cx| {
 9393                    this.edit(edits, None, cx);
 9394                })
 9395            }
 9396            this.refresh_inline_completion(true, false, window, cx);
 9397            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9398        });
 9399    }
 9400
 9401    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9402        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9403        self.transact(window, cx, |this, window, cx| {
 9404            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9405                s.move_with(|map, selection| {
 9406                    if selection.is_empty() {
 9407                        let cursor = movement::right(map, selection.head());
 9408                        selection.end = cursor;
 9409                        selection.reversed = true;
 9410                        selection.goal = SelectionGoal::None;
 9411                    }
 9412                })
 9413            });
 9414            this.insert("", window, cx);
 9415            this.refresh_inline_completion(true, false, window, cx);
 9416        });
 9417    }
 9418
 9419    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9420        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9421        if self.move_to_prev_snippet_tabstop(window, cx) {
 9422            return;
 9423        }
 9424        self.outdent(&Outdent, window, cx);
 9425    }
 9426
 9427    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9428        if self.move_to_next_snippet_tabstop(window, cx) {
 9429            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9430            return;
 9431        }
 9432        if self.read_only(cx) {
 9433            return;
 9434        }
 9435        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9436        let mut selections = self.selections.all_adjusted(cx);
 9437        let buffer = self.buffer.read(cx);
 9438        let snapshot = buffer.snapshot(cx);
 9439        let rows_iter = selections.iter().map(|s| s.head().row);
 9440        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9441
 9442        let has_some_cursor_in_whitespace = selections
 9443            .iter()
 9444            .filter(|selection| selection.is_empty())
 9445            .any(|selection| {
 9446                let cursor = selection.head();
 9447                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9448                cursor.column < current_indent.len
 9449            });
 9450
 9451        let mut edits = Vec::new();
 9452        let mut prev_edited_row = 0;
 9453        let mut row_delta = 0;
 9454        for selection in &mut selections {
 9455            if selection.start.row != prev_edited_row {
 9456                row_delta = 0;
 9457            }
 9458            prev_edited_row = selection.end.row;
 9459
 9460            // If the selection is non-empty, then increase the indentation of the selected lines.
 9461            if !selection.is_empty() {
 9462                row_delta =
 9463                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9464                continue;
 9465            }
 9466
 9467            let cursor = selection.head();
 9468            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9469            if let Some(suggested_indent) =
 9470                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9471            {
 9472                // Don't do anything if already at suggested indent
 9473                // and there is any other cursor which is not
 9474                if has_some_cursor_in_whitespace
 9475                    && cursor.column == current_indent.len
 9476                    && current_indent.len == suggested_indent.len
 9477                {
 9478                    continue;
 9479                }
 9480
 9481                // Adjust line and move cursor to suggested indent
 9482                // if cursor is not at suggested indent
 9483                if cursor.column < suggested_indent.len
 9484                    && cursor.column <= current_indent.len
 9485                    && current_indent.len <= suggested_indent.len
 9486                {
 9487                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9488                    selection.end = selection.start;
 9489                    if row_delta == 0 {
 9490                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9491                            cursor.row,
 9492                            current_indent,
 9493                            suggested_indent,
 9494                        ));
 9495                        row_delta = suggested_indent.len - current_indent.len;
 9496                    }
 9497                    continue;
 9498                }
 9499
 9500                // If current indent is more than suggested indent
 9501                // only move cursor to current indent and skip indent
 9502                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9503                    selection.start = Point::new(cursor.row, current_indent.len);
 9504                    selection.end = selection.start;
 9505                    continue;
 9506                }
 9507            }
 9508
 9509            // Otherwise, insert a hard or soft tab.
 9510            let settings = buffer.language_settings_at(cursor, cx);
 9511            let tab_size = if settings.hard_tabs {
 9512                IndentSize::tab()
 9513            } else {
 9514                let tab_size = settings.tab_size.get();
 9515                let indent_remainder = snapshot
 9516                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9517                    .flat_map(str::chars)
 9518                    .fold(row_delta % tab_size, |counter: u32, c| {
 9519                        if c == '\t' {
 9520                            0
 9521                        } else {
 9522                            (counter + 1) % tab_size
 9523                        }
 9524                    });
 9525
 9526                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9527                IndentSize::spaces(chars_to_next_tab_stop)
 9528            };
 9529            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9530            selection.end = selection.start;
 9531            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9532            row_delta += tab_size.len;
 9533        }
 9534
 9535        self.transact(window, cx, |this, window, cx| {
 9536            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9537            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9538                s.select(selections)
 9539            });
 9540            this.refresh_inline_completion(true, false, window, cx);
 9541        });
 9542    }
 9543
 9544    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9545        if self.read_only(cx) {
 9546            return;
 9547        }
 9548        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9549        let mut selections = self.selections.all::<Point>(cx);
 9550        let mut prev_edited_row = 0;
 9551        let mut row_delta = 0;
 9552        let mut edits = Vec::new();
 9553        let buffer = self.buffer.read(cx);
 9554        let snapshot = buffer.snapshot(cx);
 9555        for selection in &mut selections {
 9556            if selection.start.row != prev_edited_row {
 9557                row_delta = 0;
 9558            }
 9559            prev_edited_row = selection.end.row;
 9560
 9561            row_delta =
 9562                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9563        }
 9564
 9565        self.transact(window, cx, |this, window, cx| {
 9566            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9567            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9568                s.select(selections)
 9569            });
 9570        });
 9571    }
 9572
 9573    fn indent_selection(
 9574        buffer: &MultiBuffer,
 9575        snapshot: &MultiBufferSnapshot,
 9576        selection: &mut Selection<Point>,
 9577        edits: &mut Vec<(Range<Point>, String)>,
 9578        delta_for_start_row: u32,
 9579        cx: &App,
 9580    ) -> u32 {
 9581        let settings = buffer.language_settings_at(selection.start, cx);
 9582        let tab_size = settings.tab_size.get();
 9583        let indent_kind = if settings.hard_tabs {
 9584            IndentKind::Tab
 9585        } else {
 9586            IndentKind::Space
 9587        };
 9588        let mut start_row = selection.start.row;
 9589        let mut end_row = selection.end.row + 1;
 9590
 9591        // If a selection ends at the beginning of a line, don't indent
 9592        // that last line.
 9593        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9594            end_row -= 1;
 9595        }
 9596
 9597        // Avoid re-indenting a row that has already been indented by a
 9598        // previous selection, but still update this selection's column
 9599        // to reflect that indentation.
 9600        if delta_for_start_row > 0 {
 9601            start_row += 1;
 9602            selection.start.column += delta_for_start_row;
 9603            if selection.end.row == selection.start.row {
 9604                selection.end.column += delta_for_start_row;
 9605            }
 9606        }
 9607
 9608        let mut delta_for_end_row = 0;
 9609        let has_multiple_rows = start_row + 1 != end_row;
 9610        for row in start_row..end_row {
 9611            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9612            let indent_delta = match (current_indent.kind, indent_kind) {
 9613                (IndentKind::Space, IndentKind::Space) => {
 9614                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9615                    IndentSize::spaces(columns_to_next_tab_stop)
 9616                }
 9617                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9618                (_, IndentKind::Tab) => IndentSize::tab(),
 9619            };
 9620
 9621            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9622                0
 9623            } else {
 9624                selection.start.column
 9625            };
 9626            let row_start = Point::new(row, start);
 9627            edits.push((
 9628                row_start..row_start,
 9629                indent_delta.chars().collect::<String>(),
 9630            ));
 9631
 9632            // Update this selection's endpoints to reflect the indentation.
 9633            if row == selection.start.row {
 9634                selection.start.column += indent_delta.len;
 9635            }
 9636            if row == selection.end.row {
 9637                selection.end.column += indent_delta.len;
 9638                delta_for_end_row = indent_delta.len;
 9639            }
 9640        }
 9641
 9642        if selection.start.row == selection.end.row {
 9643            delta_for_start_row + delta_for_end_row
 9644        } else {
 9645            delta_for_end_row
 9646        }
 9647    }
 9648
 9649    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9650        if self.read_only(cx) {
 9651            return;
 9652        }
 9653        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9654        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9655        let selections = self.selections.all::<Point>(cx);
 9656        let mut deletion_ranges = Vec::new();
 9657        let mut last_outdent = None;
 9658        {
 9659            let buffer = self.buffer.read(cx);
 9660            let snapshot = buffer.snapshot(cx);
 9661            for selection in &selections {
 9662                let settings = buffer.language_settings_at(selection.start, cx);
 9663                let tab_size = settings.tab_size.get();
 9664                let mut rows = selection.spanned_rows(false, &display_map);
 9665
 9666                // Avoid re-outdenting a row that has already been outdented by a
 9667                // previous selection.
 9668                if let Some(last_row) = last_outdent {
 9669                    if last_row == rows.start {
 9670                        rows.start = rows.start.next_row();
 9671                    }
 9672                }
 9673                let has_multiple_rows = rows.len() > 1;
 9674                for row in rows.iter_rows() {
 9675                    let indent_size = snapshot.indent_size_for_line(row);
 9676                    if indent_size.len > 0 {
 9677                        let deletion_len = match indent_size.kind {
 9678                            IndentKind::Space => {
 9679                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9680                                if columns_to_prev_tab_stop == 0 {
 9681                                    tab_size
 9682                                } else {
 9683                                    columns_to_prev_tab_stop
 9684                                }
 9685                            }
 9686                            IndentKind::Tab => 1,
 9687                        };
 9688                        let start = if has_multiple_rows
 9689                            || deletion_len > selection.start.column
 9690                            || indent_size.len < selection.start.column
 9691                        {
 9692                            0
 9693                        } else {
 9694                            selection.start.column - deletion_len
 9695                        };
 9696                        deletion_ranges.push(
 9697                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9698                        );
 9699                        last_outdent = Some(row);
 9700                    }
 9701                }
 9702            }
 9703        }
 9704
 9705        self.transact(window, cx, |this, window, cx| {
 9706            this.buffer.update(cx, |buffer, cx| {
 9707                let empty_str: Arc<str> = Arc::default();
 9708                buffer.edit(
 9709                    deletion_ranges
 9710                        .into_iter()
 9711                        .map(|range| (range, empty_str.clone())),
 9712                    None,
 9713                    cx,
 9714                );
 9715            });
 9716            let selections = this.selections.all::<usize>(cx);
 9717            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9718                s.select(selections)
 9719            });
 9720        });
 9721    }
 9722
 9723    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9724        if self.read_only(cx) {
 9725            return;
 9726        }
 9727        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9728        let selections = self
 9729            .selections
 9730            .all::<usize>(cx)
 9731            .into_iter()
 9732            .map(|s| s.range());
 9733
 9734        self.transact(window, cx, |this, window, cx| {
 9735            this.buffer.update(cx, |buffer, cx| {
 9736                buffer.autoindent_ranges(selections, cx);
 9737            });
 9738            let selections = this.selections.all::<usize>(cx);
 9739            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9740                s.select(selections)
 9741            });
 9742        });
 9743    }
 9744
 9745    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9746        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9747        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9748        let selections = self.selections.all::<Point>(cx);
 9749
 9750        let mut new_cursors = Vec::new();
 9751        let mut edit_ranges = Vec::new();
 9752        let mut selections = selections.iter().peekable();
 9753        while let Some(selection) = selections.next() {
 9754            let mut rows = selection.spanned_rows(false, &display_map);
 9755            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9756
 9757            // Accumulate contiguous regions of rows that we want to delete.
 9758            while let Some(next_selection) = selections.peek() {
 9759                let next_rows = next_selection.spanned_rows(false, &display_map);
 9760                if next_rows.start <= rows.end {
 9761                    rows.end = next_rows.end;
 9762                    selections.next().unwrap();
 9763                } else {
 9764                    break;
 9765                }
 9766            }
 9767
 9768            let buffer = &display_map.buffer_snapshot;
 9769            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9770            let edit_end;
 9771            let cursor_buffer_row;
 9772            if buffer.max_point().row >= rows.end.0 {
 9773                // If there's a line after the range, delete the \n from the end of the row range
 9774                // and position the cursor on the next line.
 9775                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9776                cursor_buffer_row = rows.end;
 9777            } else {
 9778                // If there isn't a line after the range, delete the \n from the line before the
 9779                // start of the row range and position the cursor there.
 9780                edit_start = edit_start.saturating_sub(1);
 9781                edit_end = buffer.len();
 9782                cursor_buffer_row = rows.start.previous_row();
 9783            }
 9784
 9785            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9786            *cursor.column_mut() =
 9787                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9788
 9789            new_cursors.push((
 9790                selection.id,
 9791                buffer.anchor_after(cursor.to_point(&display_map)),
 9792            ));
 9793            edit_ranges.push(edit_start..edit_end);
 9794        }
 9795
 9796        self.transact(window, cx, |this, window, cx| {
 9797            let buffer = this.buffer.update(cx, |buffer, cx| {
 9798                let empty_str: Arc<str> = Arc::default();
 9799                buffer.edit(
 9800                    edit_ranges
 9801                        .into_iter()
 9802                        .map(|range| (range, empty_str.clone())),
 9803                    None,
 9804                    cx,
 9805                );
 9806                buffer.snapshot(cx)
 9807            });
 9808            let new_selections = new_cursors
 9809                .into_iter()
 9810                .map(|(id, cursor)| {
 9811                    let cursor = cursor.to_point(&buffer);
 9812                    Selection {
 9813                        id,
 9814                        start: cursor,
 9815                        end: cursor,
 9816                        reversed: false,
 9817                        goal: SelectionGoal::None,
 9818                    }
 9819                })
 9820                .collect();
 9821
 9822            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9823                s.select(new_selections);
 9824            });
 9825        });
 9826    }
 9827
 9828    pub fn join_lines_impl(
 9829        &mut self,
 9830        insert_whitespace: bool,
 9831        window: &mut Window,
 9832        cx: &mut Context<Self>,
 9833    ) {
 9834        if self.read_only(cx) {
 9835            return;
 9836        }
 9837        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9838        for selection in self.selections.all::<Point>(cx) {
 9839            let start = MultiBufferRow(selection.start.row);
 9840            // Treat single line selections as if they include the next line. Otherwise this action
 9841            // would do nothing for single line selections individual cursors.
 9842            let end = if selection.start.row == selection.end.row {
 9843                MultiBufferRow(selection.start.row + 1)
 9844            } else {
 9845                MultiBufferRow(selection.end.row)
 9846            };
 9847
 9848            if let Some(last_row_range) = row_ranges.last_mut() {
 9849                if start <= last_row_range.end {
 9850                    last_row_range.end = end;
 9851                    continue;
 9852                }
 9853            }
 9854            row_ranges.push(start..end);
 9855        }
 9856
 9857        let snapshot = self.buffer.read(cx).snapshot(cx);
 9858        let mut cursor_positions = Vec::new();
 9859        for row_range in &row_ranges {
 9860            let anchor = snapshot.anchor_before(Point::new(
 9861                row_range.end.previous_row().0,
 9862                snapshot.line_len(row_range.end.previous_row()),
 9863            ));
 9864            cursor_positions.push(anchor..anchor);
 9865        }
 9866
 9867        self.transact(window, cx, |this, window, cx| {
 9868            for row_range in row_ranges.into_iter().rev() {
 9869                for row in row_range.iter_rows().rev() {
 9870                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9871                    let next_line_row = row.next_row();
 9872                    let indent = snapshot.indent_size_for_line(next_line_row);
 9873                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9874
 9875                    let replace =
 9876                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9877                            " "
 9878                        } else {
 9879                            ""
 9880                        };
 9881
 9882                    this.buffer.update(cx, |buffer, cx| {
 9883                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9884                    });
 9885                }
 9886            }
 9887
 9888            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9889                s.select_anchor_ranges(cursor_positions)
 9890            });
 9891        });
 9892    }
 9893
 9894    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9895        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9896        self.join_lines_impl(true, window, cx);
 9897    }
 9898
 9899    pub fn sort_lines_case_sensitive(
 9900        &mut self,
 9901        _: &SortLinesCaseSensitive,
 9902        window: &mut Window,
 9903        cx: &mut Context<Self>,
 9904    ) {
 9905        self.manipulate_lines(window, cx, |lines| lines.sort())
 9906    }
 9907
 9908    pub fn sort_lines_case_insensitive(
 9909        &mut self,
 9910        _: &SortLinesCaseInsensitive,
 9911        window: &mut Window,
 9912        cx: &mut Context<Self>,
 9913    ) {
 9914        self.manipulate_lines(window, cx, |lines| {
 9915            lines.sort_by_key(|line| line.to_lowercase())
 9916        })
 9917    }
 9918
 9919    pub fn unique_lines_case_insensitive(
 9920        &mut self,
 9921        _: &UniqueLinesCaseInsensitive,
 9922        window: &mut Window,
 9923        cx: &mut Context<Self>,
 9924    ) {
 9925        self.manipulate_lines(window, cx, |lines| {
 9926            let mut seen = HashSet::default();
 9927            lines.retain(|line| seen.insert(line.to_lowercase()));
 9928        })
 9929    }
 9930
 9931    pub fn unique_lines_case_sensitive(
 9932        &mut self,
 9933        _: &UniqueLinesCaseSensitive,
 9934        window: &mut Window,
 9935        cx: &mut Context<Self>,
 9936    ) {
 9937        self.manipulate_lines(window, cx, |lines| {
 9938            let mut seen = HashSet::default();
 9939            lines.retain(|line| seen.insert(*line));
 9940        })
 9941    }
 9942
 9943    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9944        let Some(project) = self.project.clone() else {
 9945            return;
 9946        };
 9947        self.reload(project, window, cx)
 9948            .detach_and_notify_err(window, cx);
 9949    }
 9950
 9951    pub fn restore_file(
 9952        &mut self,
 9953        _: &::git::RestoreFile,
 9954        window: &mut Window,
 9955        cx: &mut Context<Self>,
 9956    ) {
 9957        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9958        let mut buffer_ids = HashSet::default();
 9959        let snapshot = self.buffer().read(cx).snapshot(cx);
 9960        for selection in self.selections.all::<usize>(cx) {
 9961            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9962        }
 9963
 9964        let buffer = self.buffer().read(cx);
 9965        let ranges = buffer_ids
 9966            .into_iter()
 9967            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9968            .collect::<Vec<_>>();
 9969
 9970        self.restore_hunks_in_ranges(ranges, window, cx);
 9971    }
 9972
 9973    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9974        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9975        let selections = self
 9976            .selections
 9977            .all(cx)
 9978            .into_iter()
 9979            .map(|s| s.range())
 9980            .collect();
 9981        self.restore_hunks_in_ranges(selections, window, cx);
 9982    }
 9983
 9984    pub fn restore_hunks_in_ranges(
 9985        &mut self,
 9986        ranges: Vec<Range<Point>>,
 9987        window: &mut Window,
 9988        cx: &mut Context<Editor>,
 9989    ) {
 9990        let mut revert_changes = HashMap::default();
 9991        let chunk_by = self
 9992            .snapshot(window, cx)
 9993            .hunks_for_ranges(ranges)
 9994            .into_iter()
 9995            .chunk_by(|hunk| hunk.buffer_id);
 9996        for (buffer_id, hunks) in &chunk_by {
 9997            let hunks = hunks.collect::<Vec<_>>();
 9998            for hunk in &hunks {
 9999                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10000            }
10001            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10002        }
10003        drop(chunk_by);
10004        if !revert_changes.is_empty() {
10005            self.transact(window, cx, |editor, window, cx| {
10006                editor.restore(revert_changes, window, cx);
10007            });
10008        }
10009    }
10010
10011    pub fn open_active_item_in_terminal(
10012        &mut self,
10013        _: &OpenInTerminal,
10014        window: &mut Window,
10015        cx: &mut Context<Self>,
10016    ) {
10017        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10018            let project_path = buffer.read(cx).project_path(cx)?;
10019            let project = self.project.as_ref()?.read(cx);
10020            let entry = project.entry_for_path(&project_path, cx)?;
10021            let parent = match &entry.canonical_path {
10022                Some(canonical_path) => canonical_path.to_path_buf(),
10023                None => project.absolute_path(&project_path, cx)?,
10024            }
10025            .parent()?
10026            .to_path_buf();
10027            Some(parent)
10028        }) {
10029            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10030        }
10031    }
10032
10033    fn set_breakpoint_context_menu(
10034        &mut self,
10035        display_row: DisplayRow,
10036        position: Option<Anchor>,
10037        clicked_point: gpui::Point<Pixels>,
10038        window: &mut Window,
10039        cx: &mut Context<Self>,
10040    ) {
10041        if !cx.has_flag::<DebuggerFeatureFlag>() {
10042            return;
10043        }
10044        let source = self
10045            .buffer
10046            .read(cx)
10047            .snapshot(cx)
10048            .anchor_before(Point::new(display_row.0, 0u32));
10049
10050        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10051
10052        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10053            self,
10054            source,
10055            clicked_point,
10056            context_menu,
10057            window,
10058            cx,
10059        );
10060    }
10061
10062    fn add_edit_breakpoint_block(
10063        &mut self,
10064        anchor: Anchor,
10065        breakpoint: &Breakpoint,
10066        edit_action: BreakpointPromptEditAction,
10067        window: &mut Window,
10068        cx: &mut Context<Self>,
10069    ) {
10070        let weak_editor = cx.weak_entity();
10071        let bp_prompt = cx.new(|cx| {
10072            BreakpointPromptEditor::new(
10073                weak_editor,
10074                anchor,
10075                breakpoint.clone(),
10076                edit_action,
10077                window,
10078                cx,
10079            )
10080        });
10081
10082        let height = bp_prompt.update(cx, |this, cx| {
10083            this.prompt
10084                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10085        });
10086        let cloned_prompt = bp_prompt.clone();
10087        let blocks = vec![BlockProperties {
10088            style: BlockStyle::Sticky,
10089            placement: BlockPlacement::Above(anchor),
10090            height: Some(height),
10091            render: Arc::new(move |cx| {
10092                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10093                cloned_prompt.clone().into_any_element()
10094            }),
10095            priority: 0,
10096            render_in_minimap: true,
10097        }];
10098
10099        let focus_handle = bp_prompt.focus_handle(cx);
10100        window.focus(&focus_handle);
10101
10102        let block_ids = self.insert_blocks(blocks, None, cx);
10103        bp_prompt.update(cx, |prompt, _| {
10104            prompt.add_block_ids(block_ids);
10105        });
10106    }
10107
10108    pub(crate) fn breakpoint_at_row(
10109        &self,
10110        row: u32,
10111        window: &mut Window,
10112        cx: &mut Context<Self>,
10113    ) -> Option<(Anchor, Breakpoint)> {
10114        let snapshot = self.snapshot(window, cx);
10115        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10116
10117        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10118    }
10119
10120    pub(crate) fn breakpoint_at_anchor(
10121        &self,
10122        breakpoint_position: Anchor,
10123        snapshot: &EditorSnapshot,
10124        cx: &mut Context<Self>,
10125    ) -> Option<(Anchor, Breakpoint)> {
10126        let project = self.project.clone()?;
10127
10128        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10129            snapshot
10130                .buffer_snapshot
10131                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10132        })?;
10133
10134        let enclosing_excerpt = breakpoint_position.excerpt_id;
10135        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10136        let buffer_snapshot = buffer.read(cx).snapshot();
10137
10138        let row = buffer_snapshot
10139            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10140            .row;
10141
10142        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10143        let anchor_end = snapshot
10144            .buffer_snapshot
10145            .anchor_after(Point::new(row, line_len));
10146
10147        let bp = self
10148            .breakpoint_store
10149            .as_ref()?
10150            .read_with(cx, |breakpoint_store, cx| {
10151                breakpoint_store
10152                    .breakpoints(
10153                        &buffer,
10154                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10155                        &buffer_snapshot,
10156                        cx,
10157                    )
10158                    .next()
10159                    .and_then(|(bp, _)| {
10160                        let breakpoint_row = buffer_snapshot
10161                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10162                            .row;
10163
10164                        if breakpoint_row == row {
10165                            snapshot
10166                                .buffer_snapshot
10167                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10168                                .map(|position| (position, bp.bp.clone()))
10169                        } else {
10170                            None
10171                        }
10172                    })
10173            });
10174        bp
10175    }
10176
10177    pub fn edit_log_breakpoint(
10178        &mut self,
10179        _: &EditLogBreakpoint,
10180        window: &mut Window,
10181        cx: &mut Context<Self>,
10182    ) {
10183        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10184            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10185                message: None,
10186                state: BreakpointState::Enabled,
10187                condition: None,
10188                hit_condition: None,
10189            });
10190
10191            self.add_edit_breakpoint_block(
10192                anchor,
10193                &breakpoint,
10194                BreakpointPromptEditAction::Log,
10195                window,
10196                cx,
10197            );
10198        }
10199    }
10200
10201    fn breakpoints_at_cursors(
10202        &self,
10203        window: &mut Window,
10204        cx: &mut Context<Self>,
10205    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10206        let snapshot = self.snapshot(window, cx);
10207        let cursors = self
10208            .selections
10209            .disjoint_anchors()
10210            .into_iter()
10211            .map(|selection| {
10212                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10213
10214                let breakpoint_position = self
10215                    .breakpoint_at_row(cursor_position.row, window, cx)
10216                    .map(|bp| bp.0)
10217                    .unwrap_or_else(|| {
10218                        snapshot
10219                            .display_snapshot
10220                            .buffer_snapshot
10221                            .anchor_after(Point::new(cursor_position.row, 0))
10222                    });
10223
10224                let breakpoint = self
10225                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10226                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10227
10228                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10229            })
10230            // 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.
10231            .collect::<HashMap<Anchor, _>>();
10232
10233        cursors.into_iter().collect()
10234    }
10235
10236    pub fn enable_breakpoint(
10237        &mut self,
10238        _: &crate::actions::EnableBreakpoint,
10239        window: &mut Window,
10240        cx: &mut Context<Self>,
10241    ) {
10242        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10243            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10244                continue;
10245            };
10246            self.edit_breakpoint_at_anchor(
10247                anchor,
10248                breakpoint,
10249                BreakpointEditAction::InvertState,
10250                cx,
10251            );
10252        }
10253    }
10254
10255    pub fn disable_breakpoint(
10256        &mut self,
10257        _: &crate::actions::DisableBreakpoint,
10258        window: &mut Window,
10259        cx: &mut Context<Self>,
10260    ) {
10261        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10262            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10263                continue;
10264            };
10265            self.edit_breakpoint_at_anchor(
10266                anchor,
10267                breakpoint,
10268                BreakpointEditAction::InvertState,
10269                cx,
10270            );
10271        }
10272    }
10273
10274    pub fn toggle_breakpoint(
10275        &mut self,
10276        _: &crate::actions::ToggleBreakpoint,
10277        window: &mut Window,
10278        cx: &mut Context<Self>,
10279    ) {
10280        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10281            if let Some(breakpoint) = breakpoint {
10282                self.edit_breakpoint_at_anchor(
10283                    anchor,
10284                    breakpoint,
10285                    BreakpointEditAction::Toggle,
10286                    cx,
10287                );
10288            } else {
10289                self.edit_breakpoint_at_anchor(
10290                    anchor,
10291                    Breakpoint::new_standard(),
10292                    BreakpointEditAction::Toggle,
10293                    cx,
10294                );
10295            }
10296        }
10297    }
10298
10299    pub fn edit_breakpoint_at_anchor(
10300        &mut self,
10301        breakpoint_position: Anchor,
10302        breakpoint: Breakpoint,
10303        edit_action: BreakpointEditAction,
10304        cx: &mut Context<Self>,
10305    ) {
10306        let Some(breakpoint_store) = &self.breakpoint_store else {
10307            return;
10308        };
10309
10310        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10311            if breakpoint_position == Anchor::min() {
10312                self.buffer()
10313                    .read(cx)
10314                    .excerpt_buffer_ids()
10315                    .into_iter()
10316                    .next()
10317            } else {
10318                None
10319            }
10320        }) else {
10321            return;
10322        };
10323
10324        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10325            return;
10326        };
10327
10328        breakpoint_store.update(cx, |breakpoint_store, cx| {
10329            breakpoint_store.toggle_breakpoint(
10330                buffer,
10331                BreakpointWithPosition {
10332                    position: breakpoint_position.text_anchor,
10333                    bp: breakpoint,
10334                },
10335                edit_action,
10336                cx,
10337            );
10338        });
10339
10340        cx.notify();
10341    }
10342
10343    #[cfg(any(test, feature = "test-support"))]
10344    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10345        self.breakpoint_store.clone()
10346    }
10347
10348    pub fn prepare_restore_change(
10349        &self,
10350        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10351        hunk: &MultiBufferDiffHunk,
10352        cx: &mut App,
10353    ) -> Option<()> {
10354        if hunk.is_created_file() {
10355            return None;
10356        }
10357        let buffer = self.buffer.read(cx);
10358        let diff = buffer.diff_for(hunk.buffer_id)?;
10359        let buffer = buffer.buffer(hunk.buffer_id)?;
10360        let buffer = buffer.read(cx);
10361        let original_text = diff
10362            .read(cx)
10363            .base_text()
10364            .as_rope()
10365            .slice(hunk.diff_base_byte_range.clone());
10366        let buffer_snapshot = buffer.snapshot();
10367        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10368        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10369            probe
10370                .0
10371                .start
10372                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10373                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10374        }) {
10375            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10376            Some(())
10377        } else {
10378            None
10379        }
10380    }
10381
10382    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10383        self.manipulate_lines(window, cx, |lines| lines.reverse())
10384    }
10385
10386    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10387        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10388    }
10389
10390    fn manipulate_lines<Fn>(
10391        &mut self,
10392        window: &mut Window,
10393        cx: &mut Context<Self>,
10394        mut callback: Fn,
10395    ) where
10396        Fn: FnMut(&mut Vec<&str>),
10397    {
10398        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10399
10400        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10401        let buffer = self.buffer.read(cx).snapshot(cx);
10402
10403        let mut edits = Vec::new();
10404
10405        let selections = self.selections.all::<Point>(cx);
10406        let mut selections = selections.iter().peekable();
10407        let mut contiguous_row_selections = Vec::new();
10408        let mut new_selections = Vec::new();
10409        let mut added_lines = 0;
10410        let mut removed_lines = 0;
10411
10412        while let Some(selection) = selections.next() {
10413            let (start_row, end_row) = consume_contiguous_rows(
10414                &mut contiguous_row_selections,
10415                selection,
10416                &display_map,
10417                &mut selections,
10418            );
10419
10420            let start_point = Point::new(start_row.0, 0);
10421            let end_point = Point::new(
10422                end_row.previous_row().0,
10423                buffer.line_len(end_row.previous_row()),
10424            );
10425            let text = buffer
10426                .text_for_range(start_point..end_point)
10427                .collect::<String>();
10428
10429            let mut lines = text.split('\n').collect_vec();
10430
10431            let lines_before = lines.len();
10432            callback(&mut lines);
10433            let lines_after = lines.len();
10434
10435            edits.push((start_point..end_point, lines.join("\n")));
10436
10437            // Selections must change based on added and removed line count
10438            let start_row =
10439                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10440            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10441            new_selections.push(Selection {
10442                id: selection.id,
10443                start: start_row,
10444                end: end_row,
10445                goal: SelectionGoal::None,
10446                reversed: selection.reversed,
10447            });
10448
10449            if lines_after > lines_before {
10450                added_lines += lines_after - lines_before;
10451            } else if lines_before > lines_after {
10452                removed_lines += lines_before - lines_after;
10453            }
10454        }
10455
10456        self.transact(window, cx, |this, window, cx| {
10457            let buffer = this.buffer.update(cx, |buffer, cx| {
10458                buffer.edit(edits, None, cx);
10459                buffer.snapshot(cx)
10460            });
10461
10462            // Recalculate offsets on newly edited buffer
10463            let new_selections = new_selections
10464                .iter()
10465                .map(|s| {
10466                    let start_point = Point::new(s.start.0, 0);
10467                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10468                    Selection {
10469                        id: s.id,
10470                        start: buffer.point_to_offset(start_point),
10471                        end: buffer.point_to_offset(end_point),
10472                        goal: s.goal,
10473                        reversed: s.reversed,
10474                    }
10475                })
10476                .collect();
10477
10478            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10479                s.select(new_selections);
10480            });
10481
10482            this.request_autoscroll(Autoscroll::fit(), cx);
10483        });
10484    }
10485
10486    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10487        self.manipulate_text(window, cx, |text| {
10488            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10489            if has_upper_case_characters {
10490                text.to_lowercase()
10491            } else {
10492                text.to_uppercase()
10493            }
10494        })
10495    }
10496
10497    pub fn convert_to_upper_case(
10498        &mut self,
10499        _: &ConvertToUpperCase,
10500        window: &mut Window,
10501        cx: &mut Context<Self>,
10502    ) {
10503        self.manipulate_text(window, cx, |text| text.to_uppercase())
10504    }
10505
10506    pub fn convert_to_lower_case(
10507        &mut self,
10508        _: &ConvertToLowerCase,
10509        window: &mut Window,
10510        cx: &mut Context<Self>,
10511    ) {
10512        self.manipulate_text(window, cx, |text| text.to_lowercase())
10513    }
10514
10515    pub fn convert_to_title_case(
10516        &mut self,
10517        _: &ConvertToTitleCase,
10518        window: &mut Window,
10519        cx: &mut Context<Self>,
10520    ) {
10521        self.manipulate_text(window, cx, |text| {
10522            text.split('\n')
10523                .map(|line| line.to_case(Case::Title))
10524                .join("\n")
10525        })
10526    }
10527
10528    pub fn convert_to_snake_case(
10529        &mut self,
10530        _: &ConvertToSnakeCase,
10531        window: &mut Window,
10532        cx: &mut Context<Self>,
10533    ) {
10534        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10535    }
10536
10537    pub fn convert_to_kebab_case(
10538        &mut self,
10539        _: &ConvertToKebabCase,
10540        window: &mut Window,
10541        cx: &mut Context<Self>,
10542    ) {
10543        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10544    }
10545
10546    pub fn convert_to_upper_camel_case(
10547        &mut self,
10548        _: &ConvertToUpperCamelCase,
10549        window: &mut Window,
10550        cx: &mut Context<Self>,
10551    ) {
10552        self.manipulate_text(window, cx, |text| {
10553            text.split('\n')
10554                .map(|line| line.to_case(Case::UpperCamel))
10555                .join("\n")
10556        })
10557    }
10558
10559    pub fn convert_to_lower_camel_case(
10560        &mut self,
10561        _: &ConvertToLowerCamelCase,
10562        window: &mut Window,
10563        cx: &mut Context<Self>,
10564    ) {
10565        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10566    }
10567
10568    pub fn convert_to_opposite_case(
10569        &mut self,
10570        _: &ConvertToOppositeCase,
10571        window: &mut Window,
10572        cx: &mut Context<Self>,
10573    ) {
10574        self.manipulate_text(window, cx, |text| {
10575            text.chars()
10576                .fold(String::with_capacity(text.len()), |mut t, c| {
10577                    if c.is_uppercase() {
10578                        t.extend(c.to_lowercase());
10579                    } else {
10580                        t.extend(c.to_uppercase());
10581                    }
10582                    t
10583                })
10584        })
10585    }
10586
10587    pub fn convert_to_rot13(
10588        &mut self,
10589        _: &ConvertToRot13,
10590        window: &mut Window,
10591        cx: &mut Context<Self>,
10592    ) {
10593        self.manipulate_text(window, cx, |text| {
10594            text.chars()
10595                .map(|c| match c {
10596                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10597                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10598                    _ => c,
10599                })
10600                .collect()
10601        })
10602    }
10603
10604    pub fn convert_to_rot47(
10605        &mut self,
10606        _: &ConvertToRot47,
10607        window: &mut Window,
10608        cx: &mut Context<Self>,
10609    ) {
10610        self.manipulate_text(window, cx, |text| {
10611            text.chars()
10612                .map(|c| {
10613                    let code_point = c as u32;
10614                    if code_point >= 33 && code_point <= 126 {
10615                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10616                    }
10617                    c
10618                })
10619                .collect()
10620        })
10621    }
10622
10623    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10624    where
10625        Fn: FnMut(&str) -> String,
10626    {
10627        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10628        let buffer = self.buffer.read(cx).snapshot(cx);
10629
10630        let mut new_selections = Vec::new();
10631        let mut edits = Vec::new();
10632        let mut selection_adjustment = 0i32;
10633
10634        for selection in self.selections.all::<usize>(cx) {
10635            let selection_is_empty = selection.is_empty();
10636
10637            let (start, end) = if selection_is_empty {
10638                let word_range = movement::surrounding_word(
10639                    &display_map,
10640                    selection.start.to_display_point(&display_map),
10641                );
10642                let start = word_range.start.to_offset(&display_map, Bias::Left);
10643                let end = word_range.end.to_offset(&display_map, Bias::Left);
10644                (start, end)
10645            } else {
10646                (selection.start, selection.end)
10647            };
10648
10649            let text = buffer.text_for_range(start..end).collect::<String>();
10650            let old_length = text.len() as i32;
10651            let text = callback(&text);
10652
10653            new_selections.push(Selection {
10654                start: (start as i32 - selection_adjustment) as usize,
10655                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10656                goal: SelectionGoal::None,
10657                ..selection
10658            });
10659
10660            selection_adjustment += old_length - text.len() as i32;
10661
10662            edits.push((start..end, text));
10663        }
10664
10665        self.transact(window, cx, |this, window, cx| {
10666            this.buffer.update(cx, |buffer, cx| {
10667                buffer.edit(edits, None, cx);
10668            });
10669
10670            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10671                s.select(new_selections);
10672            });
10673
10674            this.request_autoscroll(Autoscroll::fit(), cx);
10675        });
10676    }
10677
10678    pub fn move_selection_on_drop(
10679        &mut self,
10680        selection: &Selection<Anchor>,
10681        target: DisplayPoint,
10682        is_cut: bool,
10683        window: &mut Window,
10684        cx: &mut Context<Self>,
10685    ) {
10686        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10687        let buffer = &display_map.buffer_snapshot;
10688        let mut edits = Vec::new();
10689        let insert_point = display_map
10690            .clip_point(target, Bias::Left)
10691            .to_point(&display_map);
10692        let text = buffer
10693            .text_for_range(selection.start..selection.end)
10694            .collect::<String>();
10695        if is_cut {
10696            edits.push(((selection.start..selection.end), String::new()));
10697        }
10698        let insert_anchor = buffer.anchor_before(insert_point);
10699        edits.push(((insert_anchor..insert_anchor), text));
10700        let last_edit_start = insert_anchor.bias_left(buffer);
10701        let last_edit_end = insert_anchor.bias_right(buffer);
10702        self.transact(window, cx, |this, window, cx| {
10703            this.buffer.update(cx, |buffer, cx| {
10704                buffer.edit(edits, None, cx);
10705            });
10706            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10707                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10708            });
10709        });
10710    }
10711
10712    pub fn clear_selection_drag_state(&mut self) {
10713        self.selection_drag_state = SelectionDragState::None;
10714    }
10715
10716    pub fn duplicate(
10717        &mut self,
10718        upwards: bool,
10719        whole_lines: bool,
10720        window: &mut Window,
10721        cx: &mut Context<Self>,
10722    ) {
10723        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10724
10725        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10726        let buffer = &display_map.buffer_snapshot;
10727        let selections = self.selections.all::<Point>(cx);
10728
10729        let mut edits = Vec::new();
10730        let mut selections_iter = selections.iter().peekable();
10731        while let Some(selection) = selections_iter.next() {
10732            let mut rows = selection.spanned_rows(false, &display_map);
10733            // duplicate line-wise
10734            if whole_lines || selection.start == selection.end {
10735                // Avoid duplicating the same lines twice.
10736                while let Some(next_selection) = selections_iter.peek() {
10737                    let next_rows = next_selection.spanned_rows(false, &display_map);
10738                    if next_rows.start < rows.end {
10739                        rows.end = next_rows.end;
10740                        selections_iter.next().unwrap();
10741                    } else {
10742                        break;
10743                    }
10744                }
10745
10746                // Copy the text from the selected row region and splice it either at the start
10747                // or end of the region.
10748                let start = Point::new(rows.start.0, 0);
10749                let end = Point::new(
10750                    rows.end.previous_row().0,
10751                    buffer.line_len(rows.end.previous_row()),
10752                );
10753                let text = buffer
10754                    .text_for_range(start..end)
10755                    .chain(Some("\n"))
10756                    .collect::<String>();
10757                let insert_location = if upwards {
10758                    Point::new(rows.end.0, 0)
10759                } else {
10760                    start
10761                };
10762                edits.push((insert_location..insert_location, text));
10763            } else {
10764                // duplicate character-wise
10765                let start = selection.start;
10766                let end = selection.end;
10767                let text = buffer.text_for_range(start..end).collect::<String>();
10768                edits.push((selection.end..selection.end, text));
10769            }
10770        }
10771
10772        self.transact(window, cx, |this, _, cx| {
10773            this.buffer.update(cx, |buffer, cx| {
10774                buffer.edit(edits, None, cx);
10775            });
10776
10777            this.request_autoscroll(Autoscroll::fit(), cx);
10778        });
10779    }
10780
10781    pub fn duplicate_line_up(
10782        &mut self,
10783        _: &DuplicateLineUp,
10784        window: &mut Window,
10785        cx: &mut Context<Self>,
10786    ) {
10787        self.duplicate(true, true, window, cx);
10788    }
10789
10790    pub fn duplicate_line_down(
10791        &mut self,
10792        _: &DuplicateLineDown,
10793        window: &mut Window,
10794        cx: &mut Context<Self>,
10795    ) {
10796        self.duplicate(false, true, window, cx);
10797    }
10798
10799    pub fn duplicate_selection(
10800        &mut self,
10801        _: &DuplicateSelection,
10802        window: &mut Window,
10803        cx: &mut Context<Self>,
10804    ) {
10805        self.duplicate(false, false, window, cx);
10806    }
10807
10808    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10809        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10810
10811        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10812        let buffer = self.buffer.read(cx).snapshot(cx);
10813
10814        let mut edits = Vec::new();
10815        let mut unfold_ranges = Vec::new();
10816        let mut refold_creases = Vec::new();
10817
10818        let selections = self.selections.all::<Point>(cx);
10819        let mut selections = selections.iter().peekable();
10820        let mut contiguous_row_selections = Vec::new();
10821        let mut new_selections = Vec::new();
10822
10823        while let Some(selection) = selections.next() {
10824            // Find all the selections that span a contiguous row range
10825            let (start_row, end_row) = consume_contiguous_rows(
10826                &mut contiguous_row_selections,
10827                selection,
10828                &display_map,
10829                &mut selections,
10830            );
10831
10832            // Move the text spanned by the row range to be before the line preceding the row range
10833            if start_row.0 > 0 {
10834                let range_to_move = Point::new(
10835                    start_row.previous_row().0,
10836                    buffer.line_len(start_row.previous_row()),
10837                )
10838                    ..Point::new(
10839                        end_row.previous_row().0,
10840                        buffer.line_len(end_row.previous_row()),
10841                    );
10842                let insertion_point = display_map
10843                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10844                    .0;
10845
10846                // Don't move lines across excerpts
10847                if buffer
10848                    .excerpt_containing(insertion_point..range_to_move.end)
10849                    .is_some()
10850                {
10851                    let text = buffer
10852                        .text_for_range(range_to_move.clone())
10853                        .flat_map(|s| s.chars())
10854                        .skip(1)
10855                        .chain(['\n'])
10856                        .collect::<String>();
10857
10858                    edits.push((
10859                        buffer.anchor_after(range_to_move.start)
10860                            ..buffer.anchor_before(range_to_move.end),
10861                        String::new(),
10862                    ));
10863                    let insertion_anchor = buffer.anchor_after(insertion_point);
10864                    edits.push((insertion_anchor..insertion_anchor, text));
10865
10866                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10867
10868                    // Move selections up
10869                    new_selections.extend(contiguous_row_selections.drain(..).map(
10870                        |mut selection| {
10871                            selection.start.row -= row_delta;
10872                            selection.end.row -= row_delta;
10873                            selection
10874                        },
10875                    ));
10876
10877                    // Move folds up
10878                    unfold_ranges.push(range_to_move.clone());
10879                    for fold in display_map.folds_in_range(
10880                        buffer.anchor_before(range_to_move.start)
10881                            ..buffer.anchor_after(range_to_move.end),
10882                    ) {
10883                        let mut start = fold.range.start.to_point(&buffer);
10884                        let mut end = fold.range.end.to_point(&buffer);
10885                        start.row -= row_delta;
10886                        end.row -= row_delta;
10887                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10888                    }
10889                }
10890            }
10891
10892            // If we didn't move line(s), preserve the existing selections
10893            new_selections.append(&mut contiguous_row_selections);
10894        }
10895
10896        self.transact(window, cx, |this, window, cx| {
10897            this.unfold_ranges(&unfold_ranges, true, true, cx);
10898            this.buffer.update(cx, |buffer, cx| {
10899                for (range, text) in edits {
10900                    buffer.edit([(range, text)], None, cx);
10901                }
10902            });
10903            this.fold_creases(refold_creases, true, window, cx);
10904            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10905                s.select(new_selections);
10906            })
10907        });
10908    }
10909
10910    pub fn move_line_down(
10911        &mut self,
10912        _: &MoveLineDown,
10913        window: &mut Window,
10914        cx: &mut Context<Self>,
10915    ) {
10916        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10917
10918        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10919        let buffer = self.buffer.read(cx).snapshot(cx);
10920
10921        let mut edits = Vec::new();
10922        let mut unfold_ranges = Vec::new();
10923        let mut refold_creases = Vec::new();
10924
10925        let selections = self.selections.all::<Point>(cx);
10926        let mut selections = selections.iter().peekable();
10927        let mut contiguous_row_selections = Vec::new();
10928        let mut new_selections = Vec::new();
10929
10930        while let Some(selection) = selections.next() {
10931            // Find all the selections that span a contiguous row range
10932            let (start_row, end_row) = consume_contiguous_rows(
10933                &mut contiguous_row_selections,
10934                selection,
10935                &display_map,
10936                &mut selections,
10937            );
10938
10939            // Move the text spanned by the row range to be after the last line of the row range
10940            if end_row.0 <= buffer.max_point().row {
10941                let range_to_move =
10942                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10943                let insertion_point = display_map
10944                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10945                    .0;
10946
10947                // Don't move lines across excerpt boundaries
10948                if buffer
10949                    .excerpt_containing(range_to_move.start..insertion_point)
10950                    .is_some()
10951                {
10952                    let mut text = String::from("\n");
10953                    text.extend(buffer.text_for_range(range_to_move.clone()));
10954                    text.pop(); // Drop trailing newline
10955                    edits.push((
10956                        buffer.anchor_after(range_to_move.start)
10957                            ..buffer.anchor_before(range_to_move.end),
10958                        String::new(),
10959                    ));
10960                    let insertion_anchor = buffer.anchor_after(insertion_point);
10961                    edits.push((insertion_anchor..insertion_anchor, text));
10962
10963                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10964
10965                    // Move selections down
10966                    new_selections.extend(contiguous_row_selections.drain(..).map(
10967                        |mut selection| {
10968                            selection.start.row += row_delta;
10969                            selection.end.row += row_delta;
10970                            selection
10971                        },
10972                    ));
10973
10974                    // Move folds down
10975                    unfold_ranges.push(range_to_move.clone());
10976                    for fold in display_map.folds_in_range(
10977                        buffer.anchor_before(range_to_move.start)
10978                            ..buffer.anchor_after(range_to_move.end),
10979                    ) {
10980                        let mut start = fold.range.start.to_point(&buffer);
10981                        let mut end = fold.range.end.to_point(&buffer);
10982                        start.row += row_delta;
10983                        end.row += row_delta;
10984                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10985                    }
10986                }
10987            }
10988
10989            // If we didn't move line(s), preserve the existing selections
10990            new_selections.append(&mut contiguous_row_selections);
10991        }
10992
10993        self.transact(window, cx, |this, window, cx| {
10994            this.unfold_ranges(&unfold_ranges, true, true, cx);
10995            this.buffer.update(cx, |buffer, cx| {
10996                for (range, text) in edits {
10997                    buffer.edit([(range, text)], None, cx);
10998                }
10999            });
11000            this.fold_creases(refold_creases, true, window, cx);
11001            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11002                s.select(new_selections)
11003            });
11004        });
11005    }
11006
11007    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11008        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11009        let text_layout_details = &self.text_layout_details(window);
11010        self.transact(window, cx, |this, window, cx| {
11011            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11012                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11013                s.move_with(|display_map, selection| {
11014                    if !selection.is_empty() {
11015                        return;
11016                    }
11017
11018                    let mut head = selection.head();
11019                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11020                    if head.column() == display_map.line_len(head.row()) {
11021                        transpose_offset = display_map
11022                            .buffer_snapshot
11023                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11024                    }
11025
11026                    if transpose_offset == 0 {
11027                        return;
11028                    }
11029
11030                    *head.column_mut() += 1;
11031                    head = display_map.clip_point(head, Bias::Right);
11032                    let goal = SelectionGoal::HorizontalPosition(
11033                        display_map
11034                            .x_for_display_point(head, text_layout_details)
11035                            .into(),
11036                    );
11037                    selection.collapse_to(head, goal);
11038
11039                    let transpose_start = display_map
11040                        .buffer_snapshot
11041                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11042                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11043                        let transpose_end = display_map
11044                            .buffer_snapshot
11045                            .clip_offset(transpose_offset + 1, Bias::Right);
11046                        if let Some(ch) =
11047                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11048                        {
11049                            edits.push((transpose_start..transpose_offset, String::new()));
11050                            edits.push((transpose_end..transpose_end, ch.to_string()));
11051                        }
11052                    }
11053                });
11054                edits
11055            });
11056            this.buffer
11057                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11058            let selections = this.selections.all::<usize>(cx);
11059            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11060                s.select(selections);
11061            });
11062        });
11063    }
11064
11065    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11066        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11067        self.rewrap_impl(RewrapOptions::default(), cx)
11068    }
11069
11070    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11071        let buffer = self.buffer.read(cx).snapshot(cx);
11072        let selections = self.selections.all::<Point>(cx);
11073
11074        // Shrink and split selections to respect paragraph boundaries.
11075        let ranges = selections.into_iter().flat_map(|selection| {
11076            let language_settings = buffer.language_settings_at(selection.head(), cx);
11077            let language_scope = buffer.language_scope_at(selection.head());
11078
11079            let Some(start_row) = (selection.start.row..=selection.end.row)
11080                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11081            else {
11082                return vec![];
11083            };
11084            let Some(end_row) = (selection.start.row..=selection.end.row)
11085                .rev()
11086                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11087            else {
11088                return vec![];
11089            };
11090
11091            let mut row = start_row;
11092            let mut ranges = Vec::new();
11093            while let Some(blank_row) =
11094                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11095            {
11096                let next_paragraph_start = (blank_row + 1..=end_row)
11097                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11098                    .unwrap();
11099                ranges.push((
11100                    language_settings.clone(),
11101                    language_scope.clone(),
11102                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11103                ));
11104                row = next_paragraph_start;
11105            }
11106            ranges.push((
11107                language_settings.clone(),
11108                language_scope.clone(),
11109                Point::new(row, 0)..Point::new(end_row, 0),
11110            ));
11111
11112            ranges
11113        });
11114
11115        let mut edits = Vec::new();
11116        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11117
11118        for (language_settings, language_scope, range) in ranges {
11119            let mut start_row = range.start.row;
11120            let mut end_row = range.end.row;
11121
11122            // Skip selections that overlap with a range that has already been rewrapped.
11123            let selection_range = start_row..end_row;
11124            if rewrapped_row_ranges
11125                .iter()
11126                .any(|range| range.overlaps(&selection_range))
11127            {
11128                continue;
11129            }
11130
11131            let tab_size = language_settings.tab_size;
11132
11133            // Since not all lines in the selection may be at the same indent
11134            // level, choose the indent size that is the most common between all
11135            // of the lines.
11136            //
11137            // If there is a tie, we use the deepest indent.
11138            let (indent_size, indent_end) = {
11139                let mut indent_size_occurrences = HashMap::default();
11140                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11141
11142                for row in start_row..=end_row {
11143                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11144                    rows_by_indent_size.entry(indent).or_default().push(row);
11145                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11146                }
11147
11148                let indent_size = indent_size_occurrences
11149                    .into_iter()
11150                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11151                    .map(|(indent, _)| indent)
11152                    .unwrap_or_default();
11153                let row = rows_by_indent_size[&indent_size][0];
11154                let indent_end = Point::new(row, indent_size.len);
11155
11156                (indent_size, indent_end)
11157            };
11158
11159            let mut line_prefix = indent_size.chars().collect::<String>();
11160
11161            let mut inside_comment = false;
11162            if let Some(comment_prefix) = language_scope.and_then(|language| {
11163                language
11164                    .line_comment_prefixes()
11165                    .iter()
11166                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11167                    .cloned()
11168            }) {
11169                line_prefix.push_str(&comment_prefix);
11170                inside_comment = true;
11171            }
11172
11173            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11174                RewrapBehavior::InComments => inside_comment,
11175                RewrapBehavior::InSelections => !range.is_empty(),
11176                RewrapBehavior::Anywhere => true,
11177            };
11178
11179            let should_rewrap = options.override_language_settings
11180                || allow_rewrap_based_on_language
11181                || self.hard_wrap.is_some();
11182            if !should_rewrap {
11183                continue;
11184            }
11185
11186            if range.is_empty() {
11187                'expand_upwards: while start_row > 0 {
11188                    let prev_row = start_row - 1;
11189                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11190                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11191                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11192                    {
11193                        start_row = prev_row;
11194                    } else {
11195                        break 'expand_upwards;
11196                    }
11197                }
11198
11199                'expand_downwards: while end_row < buffer.max_point().row {
11200                    let next_row = end_row + 1;
11201                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11202                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11203                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11204                    {
11205                        end_row = next_row;
11206                    } else {
11207                        break 'expand_downwards;
11208                    }
11209                }
11210            }
11211
11212            let start = Point::new(start_row, 0);
11213            let start_offset = start.to_offset(&buffer);
11214            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11215            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11216            let Some(lines_without_prefixes) = selection_text
11217                .lines()
11218                .map(|line| {
11219                    line.strip_prefix(&line_prefix)
11220                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11221                        .with_context(|| {
11222                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11223                        })
11224                })
11225                .collect::<Result<Vec<_>, _>>()
11226                .log_err()
11227            else {
11228                continue;
11229            };
11230
11231            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11232                buffer
11233                    .language_settings_at(Point::new(start_row, 0), cx)
11234                    .preferred_line_length as usize
11235            });
11236            let wrapped_text = wrap_with_prefix(
11237                line_prefix,
11238                lines_without_prefixes.join("\n"),
11239                wrap_column,
11240                tab_size,
11241                options.preserve_existing_whitespace,
11242            );
11243
11244            // TODO: should always use char-based diff while still supporting cursor behavior that
11245            // matches vim.
11246            let mut diff_options = DiffOptions::default();
11247            if options.override_language_settings {
11248                diff_options.max_word_diff_len = 0;
11249                diff_options.max_word_diff_line_count = 0;
11250            } else {
11251                diff_options.max_word_diff_len = usize::MAX;
11252                diff_options.max_word_diff_line_count = usize::MAX;
11253            }
11254
11255            for (old_range, new_text) in
11256                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11257            {
11258                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11259                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11260                edits.push((edit_start..edit_end, new_text));
11261            }
11262
11263            rewrapped_row_ranges.push(start_row..=end_row);
11264        }
11265
11266        self.buffer
11267            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11268    }
11269
11270    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11271        let mut text = String::new();
11272        let buffer = self.buffer.read(cx).snapshot(cx);
11273        let mut selections = self.selections.all::<Point>(cx);
11274        let mut clipboard_selections = Vec::with_capacity(selections.len());
11275        {
11276            let max_point = buffer.max_point();
11277            let mut is_first = true;
11278            for selection in &mut selections {
11279                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11280                if is_entire_line {
11281                    selection.start = Point::new(selection.start.row, 0);
11282                    if !selection.is_empty() && selection.end.column == 0 {
11283                        selection.end = cmp::min(max_point, selection.end);
11284                    } else {
11285                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11286                    }
11287                    selection.goal = SelectionGoal::None;
11288                }
11289                if is_first {
11290                    is_first = false;
11291                } else {
11292                    text += "\n";
11293                }
11294                let mut len = 0;
11295                for chunk in buffer.text_for_range(selection.start..selection.end) {
11296                    text.push_str(chunk);
11297                    len += chunk.len();
11298                }
11299                clipboard_selections.push(ClipboardSelection {
11300                    len,
11301                    is_entire_line,
11302                    first_line_indent: buffer
11303                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11304                        .len,
11305                });
11306            }
11307        }
11308
11309        self.transact(window, cx, |this, window, cx| {
11310            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11311                s.select(selections);
11312            });
11313            this.insert("", window, cx);
11314        });
11315        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11316    }
11317
11318    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11319        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11320        let item = self.cut_common(window, cx);
11321        cx.write_to_clipboard(item);
11322    }
11323
11324    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11325        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11326        self.change_selections(None, window, cx, |s| {
11327            s.move_with(|snapshot, sel| {
11328                if sel.is_empty() {
11329                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11330                }
11331            });
11332        });
11333        let item = self.cut_common(window, cx);
11334        cx.set_global(KillRing(item))
11335    }
11336
11337    pub fn kill_ring_yank(
11338        &mut self,
11339        _: &KillRingYank,
11340        window: &mut Window,
11341        cx: &mut Context<Self>,
11342    ) {
11343        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11344        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11345            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11346                (kill_ring.text().to_string(), kill_ring.metadata_json())
11347            } else {
11348                return;
11349            }
11350        } else {
11351            return;
11352        };
11353        self.do_paste(&text, metadata, false, window, cx);
11354    }
11355
11356    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11357        self.do_copy(true, cx);
11358    }
11359
11360    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11361        self.do_copy(false, cx);
11362    }
11363
11364    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11365        let selections = self.selections.all::<Point>(cx);
11366        let buffer = self.buffer.read(cx).read(cx);
11367        let mut text = String::new();
11368
11369        let mut clipboard_selections = Vec::with_capacity(selections.len());
11370        {
11371            let max_point = buffer.max_point();
11372            let mut is_first = true;
11373            for selection in &selections {
11374                let mut start = selection.start;
11375                let mut end = selection.end;
11376                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11377                if is_entire_line {
11378                    start = Point::new(start.row, 0);
11379                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11380                }
11381
11382                let mut trimmed_selections = Vec::new();
11383                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11384                    let row = MultiBufferRow(start.row);
11385                    let first_indent = buffer.indent_size_for_line(row);
11386                    if first_indent.len == 0 || start.column > first_indent.len {
11387                        trimmed_selections.push(start..end);
11388                    } else {
11389                        trimmed_selections.push(
11390                            Point::new(row.0, first_indent.len)
11391                                ..Point::new(row.0, buffer.line_len(row)),
11392                        );
11393                        for row in start.row + 1..=end.row {
11394                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11395                            if row == end.row {
11396                                line_len = end.column;
11397                            }
11398                            if line_len == 0 {
11399                                trimmed_selections
11400                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11401                                continue;
11402                            }
11403                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11404                            if row_indent_size.len >= first_indent.len {
11405                                trimmed_selections.push(
11406                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11407                                );
11408                            } else {
11409                                trimmed_selections.clear();
11410                                trimmed_selections.push(start..end);
11411                                break;
11412                            }
11413                        }
11414                    }
11415                } else {
11416                    trimmed_selections.push(start..end);
11417                }
11418
11419                for trimmed_range in trimmed_selections {
11420                    if is_first {
11421                        is_first = false;
11422                    } else {
11423                        text += "\n";
11424                    }
11425                    let mut len = 0;
11426                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11427                        text.push_str(chunk);
11428                        len += chunk.len();
11429                    }
11430                    clipboard_selections.push(ClipboardSelection {
11431                        len,
11432                        is_entire_line,
11433                        first_line_indent: buffer
11434                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11435                            .len,
11436                    });
11437                }
11438            }
11439        }
11440
11441        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11442            text,
11443            clipboard_selections,
11444        ));
11445    }
11446
11447    pub fn do_paste(
11448        &mut self,
11449        text: &String,
11450        clipboard_selections: Option<Vec<ClipboardSelection>>,
11451        handle_entire_lines: bool,
11452        window: &mut Window,
11453        cx: &mut Context<Self>,
11454    ) {
11455        if self.read_only(cx) {
11456            return;
11457        }
11458
11459        let clipboard_text = Cow::Borrowed(text);
11460
11461        self.transact(window, cx, |this, window, cx| {
11462            if let Some(mut clipboard_selections) = clipboard_selections {
11463                let old_selections = this.selections.all::<usize>(cx);
11464                let all_selections_were_entire_line =
11465                    clipboard_selections.iter().all(|s| s.is_entire_line);
11466                let first_selection_indent_column =
11467                    clipboard_selections.first().map(|s| s.first_line_indent);
11468                if clipboard_selections.len() != old_selections.len() {
11469                    clipboard_selections.drain(..);
11470                }
11471                let cursor_offset = this.selections.last::<usize>(cx).head();
11472                let mut auto_indent_on_paste = true;
11473
11474                this.buffer.update(cx, |buffer, cx| {
11475                    let snapshot = buffer.read(cx);
11476                    auto_indent_on_paste = snapshot
11477                        .language_settings_at(cursor_offset, cx)
11478                        .auto_indent_on_paste;
11479
11480                    let mut start_offset = 0;
11481                    let mut edits = Vec::new();
11482                    let mut original_indent_columns = Vec::new();
11483                    for (ix, selection) in old_selections.iter().enumerate() {
11484                        let to_insert;
11485                        let entire_line;
11486                        let original_indent_column;
11487                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11488                            let end_offset = start_offset + clipboard_selection.len;
11489                            to_insert = &clipboard_text[start_offset..end_offset];
11490                            entire_line = clipboard_selection.is_entire_line;
11491                            start_offset = end_offset + 1;
11492                            original_indent_column = Some(clipboard_selection.first_line_indent);
11493                        } else {
11494                            to_insert = clipboard_text.as_str();
11495                            entire_line = all_selections_were_entire_line;
11496                            original_indent_column = first_selection_indent_column
11497                        }
11498
11499                        // If the corresponding selection was empty when this slice of the
11500                        // clipboard text was written, then the entire line containing the
11501                        // selection was copied. If this selection is also currently empty,
11502                        // then paste the line before the current line of the buffer.
11503                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11504                            let column = selection.start.to_point(&snapshot).column as usize;
11505                            let line_start = selection.start - column;
11506                            line_start..line_start
11507                        } else {
11508                            selection.range()
11509                        };
11510
11511                        edits.push((range, to_insert));
11512                        original_indent_columns.push(original_indent_column);
11513                    }
11514                    drop(snapshot);
11515
11516                    buffer.edit(
11517                        edits,
11518                        if auto_indent_on_paste {
11519                            Some(AutoindentMode::Block {
11520                                original_indent_columns,
11521                            })
11522                        } else {
11523                            None
11524                        },
11525                        cx,
11526                    );
11527                });
11528
11529                let selections = this.selections.all::<usize>(cx);
11530                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11531                    s.select(selections)
11532                });
11533            } else {
11534                this.insert(&clipboard_text, window, cx);
11535            }
11536        });
11537    }
11538
11539    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11540        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11541        if let Some(item) = cx.read_from_clipboard() {
11542            let entries = item.entries();
11543
11544            match entries.first() {
11545                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11546                // of all the pasted entries.
11547                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11548                    .do_paste(
11549                        clipboard_string.text(),
11550                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11551                        true,
11552                        window,
11553                        cx,
11554                    ),
11555                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11556            }
11557        }
11558    }
11559
11560    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11561        if self.read_only(cx) {
11562            return;
11563        }
11564
11565        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11566
11567        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11568            if let Some((selections, _)) =
11569                self.selection_history.transaction(transaction_id).cloned()
11570            {
11571                self.change_selections(None, window, cx, |s| {
11572                    s.select_anchors(selections.to_vec());
11573                });
11574            } else {
11575                log::error!(
11576                    "No entry in selection_history found for undo. \
11577                     This may correspond to a bug where undo does not update the selection. \
11578                     If this is occurring, please add details to \
11579                     https://github.com/zed-industries/zed/issues/22692"
11580                );
11581            }
11582            self.request_autoscroll(Autoscroll::fit(), cx);
11583            self.unmark_text(window, cx);
11584            self.refresh_inline_completion(true, false, window, cx);
11585            cx.emit(EditorEvent::Edited { transaction_id });
11586            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11587        }
11588    }
11589
11590    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11591        if self.read_only(cx) {
11592            return;
11593        }
11594
11595        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11596
11597        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11598            if let Some((_, Some(selections))) =
11599                self.selection_history.transaction(transaction_id).cloned()
11600            {
11601                self.change_selections(None, window, cx, |s| {
11602                    s.select_anchors(selections.to_vec());
11603                });
11604            } else {
11605                log::error!(
11606                    "No entry in selection_history found for redo. \
11607                     This may correspond to a bug where undo does not update the selection. \
11608                     If this is occurring, please add details to \
11609                     https://github.com/zed-industries/zed/issues/22692"
11610                );
11611            }
11612            self.request_autoscroll(Autoscroll::fit(), cx);
11613            self.unmark_text(window, cx);
11614            self.refresh_inline_completion(true, false, window, cx);
11615            cx.emit(EditorEvent::Edited { transaction_id });
11616        }
11617    }
11618
11619    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11620        self.buffer
11621            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11622    }
11623
11624    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11625        self.buffer
11626            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11627    }
11628
11629    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11630        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11631        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11632            s.move_with(|map, selection| {
11633                let cursor = if selection.is_empty() {
11634                    movement::left(map, selection.start)
11635                } else {
11636                    selection.start
11637                };
11638                selection.collapse_to(cursor, SelectionGoal::None);
11639            });
11640        })
11641    }
11642
11643    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11644        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11645        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11646            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11647        })
11648    }
11649
11650    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11651        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11652        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11653            s.move_with(|map, selection| {
11654                let cursor = if selection.is_empty() {
11655                    movement::right(map, selection.end)
11656                } else {
11657                    selection.end
11658                };
11659                selection.collapse_to(cursor, SelectionGoal::None)
11660            });
11661        })
11662    }
11663
11664    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11665        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11666        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11667            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11668        })
11669    }
11670
11671    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11672        if self.take_rename(true, window, cx).is_some() {
11673            return;
11674        }
11675
11676        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11677            cx.propagate();
11678            return;
11679        }
11680
11681        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11682
11683        let text_layout_details = &self.text_layout_details(window);
11684        let selection_count = self.selections.count();
11685        let first_selection = self.selections.first_anchor();
11686
11687        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11688            s.move_with(|map, selection| {
11689                if !selection.is_empty() {
11690                    selection.goal = SelectionGoal::None;
11691                }
11692                let (cursor, goal) = movement::up(
11693                    map,
11694                    selection.start,
11695                    selection.goal,
11696                    false,
11697                    text_layout_details,
11698                );
11699                selection.collapse_to(cursor, goal);
11700            });
11701        });
11702
11703        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11704        {
11705            cx.propagate();
11706        }
11707    }
11708
11709    pub fn move_up_by_lines(
11710        &mut self,
11711        action: &MoveUpByLines,
11712        window: &mut Window,
11713        cx: &mut Context<Self>,
11714    ) {
11715        if self.take_rename(true, window, cx).is_some() {
11716            return;
11717        }
11718
11719        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11720            cx.propagate();
11721            return;
11722        }
11723
11724        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11725
11726        let text_layout_details = &self.text_layout_details(window);
11727
11728        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11729            s.move_with(|map, selection| {
11730                if !selection.is_empty() {
11731                    selection.goal = SelectionGoal::None;
11732                }
11733                let (cursor, goal) = movement::up_by_rows(
11734                    map,
11735                    selection.start,
11736                    action.lines,
11737                    selection.goal,
11738                    false,
11739                    text_layout_details,
11740                );
11741                selection.collapse_to(cursor, goal);
11742            });
11743        })
11744    }
11745
11746    pub fn move_down_by_lines(
11747        &mut self,
11748        action: &MoveDownByLines,
11749        window: &mut Window,
11750        cx: &mut Context<Self>,
11751    ) {
11752        if self.take_rename(true, window, cx).is_some() {
11753            return;
11754        }
11755
11756        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11757            cx.propagate();
11758            return;
11759        }
11760
11761        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11762
11763        let text_layout_details = &self.text_layout_details(window);
11764
11765        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11766            s.move_with(|map, selection| {
11767                if !selection.is_empty() {
11768                    selection.goal = SelectionGoal::None;
11769                }
11770                let (cursor, goal) = movement::down_by_rows(
11771                    map,
11772                    selection.start,
11773                    action.lines,
11774                    selection.goal,
11775                    false,
11776                    text_layout_details,
11777                );
11778                selection.collapse_to(cursor, goal);
11779            });
11780        })
11781    }
11782
11783    pub fn select_down_by_lines(
11784        &mut self,
11785        action: &SelectDownByLines,
11786        window: &mut Window,
11787        cx: &mut Context<Self>,
11788    ) {
11789        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11790        let text_layout_details = &self.text_layout_details(window);
11791        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11792            s.move_heads_with(|map, head, goal| {
11793                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11794            })
11795        })
11796    }
11797
11798    pub fn select_up_by_lines(
11799        &mut self,
11800        action: &SelectUpByLines,
11801        window: &mut Window,
11802        cx: &mut Context<Self>,
11803    ) {
11804        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11805        let text_layout_details = &self.text_layout_details(window);
11806        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11807            s.move_heads_with(|map, head, goal| {
11808                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11809            })
11810        })
11811    }
11812
11813    pub fn select_page_up(
11814        &mut self,
11815        _: &SelectPageUp,
11816        window: &mut Window,
11817        cx: &mut Context<Self>,
11818    ) {
11819        let Some(row_count) = self.visible_row_count() else {
11820            return;
11821        };
11822
11823        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11824
11825        let text_layout_details = &self.text_layout_details(window);
11826
11827        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11828            s.move_heads_with(|map, head, goal| {
11829                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11830            })
11831        })
11832    }
11833
11834    pub fn move_page_up(
11835        &mut self,
11836        action: &MovePageUp,
11837        window: &mut Window,
11838        cx: &mut Context<Self>,
11839    ) {
11840        if self.take_rename(true, window, cx).is_some() {
11841            return;
11842        }
11843
11844        if self
11845            .context_menu
11846            .borrow_mut()
11847            .as_mut()
11848            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11849            .unwrap_or(false)
11850        {
11851            return;
11852        }
11853
11854        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11855            cx.propagate();
11856            return;
11857        }
11858
11859        let Some(row_count) = self.visible_row_count() else {
11860            return;
11861        };
11862
11863        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11864
11865        let autoscroll = if action.center_cursor {
11866            Autoscroll::center()
11867        } else {
11868            Autoscroll::fit()
11869        };
11870
11871        let text_layout_details = &self.text_layout_details(window);
11872
11873        self.change_selections(Some(autoscroll), window, cx, |s| {
11874            s.move_with(|map, selection| {
11875                if !selection.is_empty() {
11876                    selection.goal = SelectionGoal::None;
11877                }
11878                let (cursor, goal) = movement::up_by_rows(
11879                    map,
11880                    selection.end,
11881                    row_count,
11882                    selection.goal,
11883                    false,
11884                    text_layout_details,
11885                );
11886                selection.collapse_to(cursor, goal);
11887            });
11888        });
11889    }
11890
11891    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11892        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11893        let text_layout_details = &self.text_layout_details(window);
11894        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11895            s.move_heads_with(|map, head, goal| {
11896                movement::up(map, head, goal, false, text_layout_details)
11897            })
11898        })
11899    }
11900
11901    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11902        self.take_rename(true, window, cx);
11903
11904        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11905            cx.propagate();
11906            return;
11907        }
11908
11909        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11910
11911        let text_layout_details = &self.text_layout_details(window);
11912        let selection_count = self.selections.count();
11913        let first_selection = self.selections.first_anchor();
11914
11915        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11916            s.move_with(|map, selection| {
11917                if !selection.is_empty() {
11918                    selection.goal = SelectionGoal::None;
11919                }
11920                let (cursor, goal) = movement::down(
11921                    map,
11922                    selection.end,
11923                    selection.goal,
11924                    false,
11925                    text_layout_details,
11926                );
11927                selection.collapse_to(cursor, goal);
11928            });
11929        });
11930
11931        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11932        {
11933            cx.propagate();
11934        }
11935    }
11936
11937    pub fn select_page_down(
11938        &mut self,
11939        _: &SelectPageDown,
11940        window: &mut Window,
11941        cx: &mut Context<Self>,
11942    ) {
11943        let Some(row_count) = self.visible_row_count() else {
11944            return;
11945        };
11946
11947        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11948
11949        let text_layout_details = &self.text_layout_details(window);
11950
11951        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11952            s.move_heads_with(|map, head, goal| {
11953                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11954            })
11955        })
11956    }
11957
11958    pub fn move_page_down(
11959        &mut self,
11960        action: &MovePageDown,
11961        window: &mut Window,
11962        cx: &mut Context<Self>,
11963    ) {
11964        if self.take_rename(true, window, cx).is_some() {
11965            return;
11966        }
11967
11968        if self
11969            .context_menu
11970            .borrow_mut()
11971            .as_mut()
11972            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11973            .unwrap_or(false)
11974        {
11975            return;
11976        }
11977
11978        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11979            cx.propagate();
11980            return;
11981        }
11982
11983        let Some(row_count) = self.visible_row_count() else {
11984            return;
11985        };
11986
11987        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11988
11989        let autoscroll = if action.center_cursor {
11990            Autoscroll::center()
11991        } else {
11992            Autoscroll::fit()
11993        };
11994
11995        let text_layout_details = &self.text_layout_details(window);
11996        self.change_selections(Some(autoscroll), window, cx, |s| {
11997            s.move_with(|map, selection| {
11998                if !selection.is_empty() {
11999                    selection.goal = SelectionGoal::None;
12000                }
12001                let (cursor, goal) = movement::down_by_rows(
12002                    map,
12003                    selection.end,
12004                    row_count,
12005                    selection.goal,
12006                    false,
12007                    text_layout_details,
12008                );
12009                selection.collapse_to(cursor, goal);
12010            });
12011        });
12012    }
12013
12014    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12015        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12016        let text_layout_details = &self.text_layout_details(window);
12017        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12018            s.move_heads_with(|map, head, goal| {
12019                movement::down(map, head, goal, false, text_layout_details)
12020            })
12021        });
12022    }
12023
12024    pub fn context_menu_first(
12025        &mut self,
12026        _: &ContextMenuFirst,
12027        window: &mut Window,
12028        cx: &mut Context<Self>,
12029    ) {
12030        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12031            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12032        }
12033    }
12034
12035    pub fn context_menu_prev(
12036        &mut self,
12037        _: &ContextMenuPrevious,
12038        window: &mut Window,
12039        cx: &mut Context<Self>,
12040    ) {
12041        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12042            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12043        }
12044    }
12045
12046    pub fn context_menu_next(
12047        &mut self,
12048        _: &ContextMenuNext,
12049        window: &mut Window,
12050        cx: &mut Context<Self>,
12051    ) {
12052        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12053            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12054        }
12055    }
12056
12057    pub fn context_menu_last(
12058        &mut self,
12059        _: &ContextMenuLast,
12060        window: &mut Window,
12061        cx: &mut Context<Self>,
12062    ) {
12063        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12064            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12065        }
12066    }
12067
12068    pub fn move_to_previous_word_start(
12069        &mut self,
12070        _: &MoveToPreviousWordStart,
12071        window: &mut Window,
12072        cx: &mut Context<Self>,
12073    ) {
12074        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12075        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12076            s.move_cursors_with(|map, head, _| {
12077                (
12078                    movement::previous_word_start(map, head),
12079                    SelectionGoal::None,
12080                )
12081            });
12082        })
12083    }
12084
12085    pub fn move_to_previous_subword_start(
12086        &mut self,
12087        _: &MoveToPreviousSubwordStart,
12088        window: &mut Window,
12089        cx: &mut Context<Self>,
12090    ) {
12091        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12092        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12093            s.move_cursors_with(|map, head, _| {
12094                (
12095                    movement::previous_subword_start(map, head),
12096                    SelectionGoal::None,
12097                )
12098            });
12099        })
12100    }
12101
12102    pub fn select_to_previous_word_start(
12103        &mut self,
12104        _: &SelectToPreviousWordStart,
12105        window: &mut Window,
12106        cx: &mut Context<Self>,
12107    ) {
12108        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12109        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12110            s.move_heads_with(|map, head, _| {
12111                (
12112                    movement::previous_word_start(map, head),
12113                    SelectionGoal::None,
12114                )
12115            });
12116        })
12117    }
12118
12119    pub fn select_to_previous_subword_start(
12120        &mut self,
12121        _: &SelectToPreviousSubwordStart,
12122        window: &mut Window,
12123        cx: &mut Context<Self>,
12124    ) {
12125        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12126        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12127            s.move_heads_with(|map, head, _| {
12128                (
12129                    movement::previous_subword_start(map, head),
12130                    SelectionGoal::None,
12131                )
12132            });
12133        })
12134    }
12135
12136    pub fn delete_to_previous_word_start(
12137        &mut self,
12138        action: &DeleteToPreviousWordStart,
12139        window: &mut Window,
12140        cx: &mut Context<Self>,
12141    ) {
12142        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12143        self.transact(window, cx, |this, window, cx| {
12144            this.select_autoclose_pair(window, cx);
12145            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12146                s.move_with(|map, selection| {
12147                    if selection.is_empty() {
12148                        let cursor = if action.ignore_newlines {
12149                            movement::previous_word_start(map, selection.head())
12150                        } else {
12151                            movement::previous_word_start_or_newline(map, selection.head())
12152                        };
12153                        selection.set_head(cursor, SelectionGoal::None);
12154                    }
12155                });
12156            });
12157            this.insert("", window, cx);
12158        });
12159    }
12160
12161    pub fn delete_to_previous_subword_start(
12162        &mut self,
12163        _: &DeleteToPreviousSubwordStart,
12164        window: &mut Window,
12165        cx: &mut Context<Self>,
12166    ) {
12167        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12168        self.transact(window, cx, |this, window, cx| {
12169            this.select_autoclose_pair(window, cx);
12170            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12171                s.move_with(|map, selection| {
12172                    if selection.is_empty() {
12173                        let cursor = movement::previous_subword_start(map, selection.head());
12174                        selection.set_head(cursor, SelectionGoal::None);
12175                    }
12176                });
12177            });
12178            this.insert("", window, cx);
12179        });
12180    }
12181
12182    pub fn move_to_next_word_end(
12183        &mut self,
12184        _: &MoveToNextWordEnd,
12185        window: &mut Window,
12186        cx: &mut Context<Self>,
12187    ) {
12188        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12189        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12190            s.move_cursors_with(|map, head, _| {
12191                (movement::next_word_end(map, head), SelectionGoal::None)
12192            });
12193        })
12194    }
12195
12196    pub fn move_to_next_subword_end(
12197        &mut self,
12198        _: &MoveToNextSubwordEnd,
12199        window: &mut Window,
12200        cx: &mut Context<Self>,
12201    ) {
12202        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12203        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12204            s.move_cursors_with(|map, head, _| {
12205                (movement::next_subword_end(map, head), SelectionGoal::None)
12206            });
12207        })
12208    }
12209
12210    pub fn select_to_next_word_end(
12211        &mut self,
12212        _: &SelectToNextWordEnd,
12213        window: &mut Window,
12214        cx: &mut Context<Self>,
12215    ) {
12216        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12217        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12218            s.move_heads_with(|map, head, _| {
12219                (movement::next_word_end(map, head), SelectionGoal::None)
12220            });
12221        })
12222    }
12223
12224    pub fn select_to_next_subword_end(
12225        &mut self,
12226        _: &SelectToNextSubwordEnd,
12227        window: &mut Window,
12228        cx: &mut Context<Self>,
12229    ) {
12230        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12231        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12232            s.move_heads_with(|map, head, _| {
12233                (movement::next_subword_end(map, head), SelectionGoal::None)
12234            });
12235        })
12236    }
12237
12238    pub fn delete_to_next_word_end(
12239        &mut self,
12240        action: &DeleteToNextWordEnd,
12241        window: &mut Window,
12242        cx: &mut Context<Self>,
12243    ) {
12244        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12245        self.transact(window, cx, |this, window, cx| {
12246            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12247                s.move_with(|map, selection| {
12248                    if selection.is_empty() {
12249                        let cursor = if action.ignore_newlines {
12250                            movement::next_word_end(map, selection.head())
12251                        } else {
12252                            movement::next_word_end_or_newline(map, selection.head())
12253                        };
12254                        selection.set_head(cursor, SelectionGoal::None);
12255                    }
12256                });
12257            });
12258            this.insert("", window, cx);
12259        });
12260    }
12261
12262    pub fn delete_to_next_subword_end(
12263        &mut self,
12264        _: &DeleteToNextSubwordEnd,
12265        window: &mut Window,
12266        cx: &mut Context<Self>,
12267    ) {
12268        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12269        self.transact(window, cx, |this, window, cx| {
12270            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12271                s.move_with(|map, selection| {
12272                    if selection.is_empty() {
12273                        let cursor = movement::next_subword_end(map, selection.head());
12274                        selection.set_head(cursor, SelectionGoal::None);
12275                    }
12276                });
12277            });
12278            this.insert("", window, cx);
12279        });
12280    }
12281
12282    pub fn move_to_beginning_of_line(
12283        &mut self,
12284        action: &MoveToBeginningOfLine,
12285        window: &mut Window,
12286        cx: &mut Context<Self>,
12287    ) {
12288        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12289        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12290            s.move_cursors_with(|map, head, _| {
12291                (
12292                    movement::indented_line_beginning(
12293                        map,
12294                        head,
12295                        action.stop_at_soft_wraps,
12296                        action.stop_at_indent,
12297                    ),
12298                    SelectionGoal::None,
12299                )
12300            });
12301        })
12302    }
12303
12304    pub fn select_to_beginning_of_line(
12305        &mut self,
12306        action: &SelectToBeginningOfLine,
12307        window: &mut Window,
12308        cx: &mut Context<Self>,
12309    ) {
12310        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12311        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12312            s.move_heads_with(|map, head, _| {
12313                (
12314                    movement::indented_line_beginning(
12315                        map,
12316                        head,
12317                        action.stop_at_soft_wraps,
12318                        action.stop_at_indent,
12319                    ),
12320                    SelectionGoal::None,
12321                )
12322            });
12323        });
12324    }
12325
12326    pub fn delete_to_beginning_of_line(
12327        &mut self,
12328        action: &DeleteToBeginningOfLine,
12329        window: &mut Window,
12330        cx: &mut Context<Self>,
12331    ) {
12332        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12333        self.transact(window, cx, |this, window, cx| {
12334            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12335                s.move_with(|_, selection| {
12336                    selection.reversed = true;
12337                });
12338            });
12339
12340            this.select_to_beginning_of_line(
12341                &SelectToBeginningOfLine {
12342                    stop_at_soft_wraps: false,
12343                    stop_at_indent: action.stop_at_indent,
12344                },
12345                window,
12346                cx,
12347            );
12348            this.backspace(&Backspace, window, cx);
12349        });
12350    }
12351
12352    pub fn move_to_end_of_line(
12353        &mut self,
12354        action: &MoveToEndOfLine,
12355        window: &mut Window,
12356        cx: &mut Context<Self>,
12357    ) {
12358        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12359        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12360            s.move_cursors_with(|map, head, _| {
12361                (
12362                    movement::line_end(map, head, action.stop_at_soft_wraps),
12363                    SelectionGoal::None,
12364                )
12365            });
12366        })
12367    }
12368
12369    pub fn select_to_end_of_line(
12370        &mut self,
12371        action: &SelectToEndOfLine,
12372        window: &mut Window,
12373        cx: &mut Context<Self>,
12374    ) {
12375        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12376        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12377            s.move_heads_with(|map, head, _| {
12378                (
12379                    movement::line_end(map, head, action.stop_at_soft_wraps),
12380                    SelectionGoal::None,
12381                )
12382            });
12383        })
12384    }
12385
12386    pub fn delete_to_end_of_line(
12387        &mut self,
12388        _: &DeleteToEndOfLine,
12389        window: &mut Window,
12390        cx: &mut Context<Self>,
12391    ) {
12392        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12393        self.transact(window, cx, |this, window, cx| {
12394            this.select_to_end_of_line(
12395                &SelectToEndOfLine {
12396                    stop_at_soft_wraps: false,
12397                },
12398                window,
12399                cx,
12400            );
12401            this.delete(&Delete, window, cx);
12402        });
12403    }
12404
12405    pub fn cut_to_end_of_line(
12406        &mut self,
12407        _: &CutToEndOfLine,
12408        window: &mut Window,
12409        cx: &mut Context<Self>,
12410    ) {
12411        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12412        self.transact(window, cx, |this, window, cx| {
12413            this.select_to_end_of_line(
12414                &SelectToEndOfLine {
12415                    stop_at_soft_wraps: false,
12416                },
12417                window,
12418                cx,
12419            );
12420            this.cut(&Cut, window, cx);
12421        });
12422    }
12423
12424    pub fn move_to_start_of_paragraph(
12425        &mut self,
12426        _: &MoveToStartOfParagraph,
12427        window: &mut Window,
12428        cx: &mut Context<Self>,
12429    ) {
12430        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12431            cx.propagate();
12432            return;
12433        }
12434        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12435        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12436            s.move_with(|map, selection| {
12437                selection.collapse_to(
12438                    movement::start_of_paragraph(map, selection.head(), 1),
12439                    SelectionGoal::None,
12440                )
12441            });
12442        })
12443    }
12444
12445    pub fn move_to_end_of_paragraph(
12446        &mut self,
12447        _: &MoveToEndOfParagraph,
12448        window: &mut Window,
12449        cx: &mut Context<Self>,
12450    ) {
12451        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12452            cx.propagate();
12453            return;
12454        }
12455        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12456        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12457            s.move_with(|map, selection| {
12458                selection.collapse_to(
12459                    movement::end_of_paragraph(map, selection.head(), 1),
12460                    SelectionGoal::None,
12461                )
12462            });
12463        })
12464    }
12465
12466    pub fn select_to_start_of_paragraph(
12467        &mut self,
12468        _: &SelectToStartOfParagraph,
12469        window: &mut Window,
12470        cx: &mut Context<Self>,
12471    ) {
12472        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12473            cx.propagate();
12474            return;
12475        }
12476        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12477        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12478            s.move_heads_with(|map, head, _| {
12479                (
12480                    movement::start_of_paragraph(map, head, 1),
12481                    SelectionGoal::None,
12482                )
12483            });
12484        })
12485    }
12486
12487    pub fn select_to_end_of_paragraph(
12488        &mut self,
12489        _: &SelectToEndOfParagraph,
12490        window: &mut Window,
12491        cx: &mut Context<Self>,
12492    ) {
12493        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12494            cx.propagate();
12495            return;
12496        }
12497        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12498        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12499            s.move_heads_with(|map, head, _| {
12500                (
12501                    movement::end_of_paragraph(map, head, 1),
12502                    SelectionGoal::None,
12503                )
12504            });
12505        })
12506    }
12507
12508    pub fn move_to_start_of_excerpt(
12509        &mut self,
12510        _: &MoveToStartOfExcerpt,
12511        window: &mut Window,
12512        cx: &mut Context<Self>,
12513    ) {
12514        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12515            cx.propagate();
12516            return;
12517        }
12518        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12519        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12520            s.move_with(|map, selection| {
12521                selection.collapse_to(
12522                    movement::start_of_excerpt(
12523                        map,
12524                        selection.head(),
12525                        workspace::searchable::Direction::Prev,
12526                    ),
12527                    SelectionGoal::None,
12528                )
12529            });
12530        })
12531    }
12532
12533    pub fn move_to_start_of_next_excerpt(
12534        &mut self,
12535        _: &MoveToStartOfNextExcerpt,
12536        window: &mut Window,
12537        cx: &mut Context<Self>,
12538    ) {
12539        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12540            cx.propagate();
12541            return;
12542        }
12543
12544        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12545            s.move_with(|map, selection| {
12546                selection.collapse_to(
12547                    movement::start_of_excerpt(
12548                        map,
12549                        selection.head(),
12550                        workspace::searchable::Direction::Next,
12551                    ),
12552                    SelectionGoal::None,
12553                )
12554            });
12555        })
12556    }
12557
12558    pub fn move_to_end_of_excerpt(
12559        &mut self,
12560        _: &MoveToEndOfExcerpt,
12561        window: &mut Window,
12562        cx: &mut Context<Self>,
12563    ) {
12564        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12565            cx.propagate();
12566            return;
12567        }
12568        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12569        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12570            s.move_with(|map, selection| {
12571                selection.collapse_to(
12572                    movement::end_of_excerpt(
12573                        map,
12574                        selection.head(),
12575                        workspace::searchable::Direction::Next,
12576                    ),
12577                    SelectionGoal::None,
12578                )
12579            });
12580        })
12581    }
12582
12583    pub fn move_to_end_of_previous_excerpt(
12584        &mut self,
12585        _: &MoveToEndOfPreviousExcerpt,
12586        window: &mut Window,
12587        cx: &mut Context<Self>,
12588    ) {
12589        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12590            cx.propagate();
12591            return;
12592        }
12593        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12594        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12595            s.move_with(|map, selection| {
12596                selection.collapse_to(
12597                    movement::end_of_excerpt(
12598                        map,
12599                        selection.head(),
12600                        workspace::searchable::Direction::Prev,
12601                    ),
12602                    SelectionGoal::None,
12603                )
12604            });
12605        })
12606    }
12607
12608    pub fn select_to_start_of_excerpt(
12609        &mut self,
12610        _: &SelectToStartOfExcerpt,
12611        window: &mut Window,
12612        cx: &mut Context<Self>,
12613    ) {
12614        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12615            cx.propagate();
12616            return;
12617        }
12618        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12619        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12620            s.move_heads_with(|map, head, _| {
12621                (
12622                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12623                    SelectionGoal::None,
12624                )
12625            });
12626        })
12627    }
12628
12629    pub fn select_to_start_of_next_excerpt(
12630        &mut self,
12631        _: &SelectToStartOfNextExcerpt,
12632        window: &mut Window,
12633        cx: &mut Context<Self>,
12634    ) {
12635        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12636            cx.propagate();
12637            return;
12638        }
12639        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12640        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12641            s.move_heads_with(|map, head, _| {
12642                (
12643                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12644                    SelectionGoal::None,
12645                )
12646            });
12647        })
12648    }
12649
12650    pub fn select_to_end_of_excerpt(
12651        &mut self,
12652        _: &SelectToEndOfExcerpt,
12653        window: &mut Window,
12654        cx: &mut Context<Self>,
12655    ) {
12656        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12657            cx.propagate();
12658            return;
12659        }
12660        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12661        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12662            s.move_heads_with(|map, head, _| {
12663                (
12664                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12665                    SelectionGoal::None,
12666                )
12667            });
12668        })
12669    }
12670
12671    pub fn select_to_end_of_previous_excerpt(
12672        &mut self,
12673        _: &SelectToEndOfPreviousExcerpt,
12674        window: &mut Window,
12675        cx: &mut Context<Self>,
12676    ) {
12677        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12678            cx.propagate();
12679            return;
12680        }
12681        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12682        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12683            s.move_heads_with(|map, head, _| {
12684                (
12685                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12686                    SelectionGoal::None,
12687                )
12688            });
12689        })
12690    }
12691
12692    pub fn move_to_beginning(
12693        &mut self,
12694        _: &MoveToBeginning,
12695        window: &mut Window,
12696        cx: &mut Context<Self>,
12697    ) {
12698        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12699            cx.propagate();
12700            return;
12701        }
12702        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12703        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12704            s.select_ranges(vec![0..0]);
12705        });
12706    }
12707
12708    pub fn select_to_beginning(
12709        &mut self,
12710        _: &SelectToBeginning,
12711        window: &mut Window,
12712        cx: &mut Context<Self>,
12713    ) {
12714        let mut selection = self.selections.last::<Point>(cx);
12715        selection.set_head(Point::zero(), SelectionGoal::None);
12716        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12717        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12718            s.select(vec![selection]);
12719        });
12720    }
12721
12722    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12723        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12724            cx.propagate();
12725            return;
12726        }
12727        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12728        let cursor = self.buffer.read(cx).read(cx).len();
12729        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12730            s.select_ranges(vec![cursor..cursor])
12731        });
12732    }
12733
12734    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12735        self.nav_history = nav_history;
12736    }
12737
12738    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12739        self.nav_history.as_ref()
12740    }
12741
12742    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12743        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12744    }
12745
12746    fn push_to_nav_history(
12747        &mut self,
12748        cursor_anchor: Anchor,
12749        new_position: Option<Point>,
12750        is_deactivate: bool,
12751        cx: &mut Context<Self>,
12752    ) {
12753        if let Some(nav_history) = self.nav_history.as_mut() {
12754            let buffer = self.buffer.read(cx).read(cx);
12755            let cursor_position = cursor_anchor.to_point(&buffer);
12756            let scroll_state = self.scroll_manager.anchor();
12757            let scroll_top_row = scroll_state.top_row(&buffer);
12758            drop(buffer);
12759
12760            if let Some(new_position) = new_position {
12761                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12762                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12763                    return;
12764                }
12765            }
12766
12767            nav_history.push(
12768                Some(NavigationData {
12769                    cursor_anchor,
12770                    cursor_position,
12771                    scroll_anchor: scroll_state,
12772                    scroll_top_row,
12773                }),
12774                cx,
12775            );
12776            cx.emit(EditorEvent::PushedToNavHistory {
12777                anchor: cursor_anchor,
12778                is_deactivate,
12779            })
12780        }
12781    }
12782
12783    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12784        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12785        let buffer = self.buffer.read(cx).snapshot(cx);
12786        let mut selection = self.selections.first::<usize>(cx);
12787        selection.set_head(buffer.len(), SelectionGoal::None);
12788        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12789            s.select(vec![selection]);
12790        });
12791    }
12792
12793    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12794        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12795        let end = self.buffer.read(cx).read(cx).len();
12796        self.change_selections(None, window, cx, |s| {
12797            s.select_ranges(vec![0..end]);
12798        });
12799    }
12800
12801    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12802        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12803        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12804        let mut selections = self.selections.all::<Point>(cx);
12805        let max_point = display_map.buffer_snapshot.max_point();
12806        for selection in &mut selections {
12807            let rows = selection.spanned_rows(true, &display_map);
12808            selection.start = Point::new(rows.start.0, 0);
12809            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12810            selection.reversed = false;
12811        }
12812        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12813            s.select(selections);
12814        });
12815    }
12816
12817    pub fn split_selection_into_lines(
12818        &mut self,
12819        _: &SplitSelectionIntoLines,
12820        window: &mut Window,
12821        cx: &mut Context<Self>,
12822    ) {
12823        let selections = self
12824            .selections
12825            .all::<Point>(cx)
12826            .into_iter()
12827            .map(|selection| selection.start..selection.end)
12828            .collect::<Vec<_>>();
12829        self.unfold_ranges(&selections, true, true, cx);
12830
12831        let mut new_selection_ranges = Vec::new();
12832        {
12833            let buffer = self.buffer.read(cx).read(cx);
12834            for selection in selections {
12835                for row in selection.start.row..selection.end.row {
12836                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12837                    new_selection_ranges.push(cursor..cursor);
12838                }
12839
12840                let is_multiline_selection = selection.start.row != selection.end.row;
12841                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12842                // so this action feels more ergonomic when paired with other selection operations
12843                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12844                if !should_skip_last {
12845                    new_selection_ranges.push(selection.end..selection.end);
12846                }
12847            }
12848        }
12849        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12850            s.select_ranges(new_selection_ranges);
12851        });
12852    }
12853
12854    pub fn add_selection_above(
12855        &mut self,
12856        _: &AddSelectionAbove,
12857        window: &mut Window,
12858        cx: &mut Context<Self>,
12859    ) {
12860        self.add_selection(true, window, cx);
12861    }
12862
12863    pub fn add_selection_below(
12864        &mut self,
12865        _: &AddSelectionBelow,
12866        window: &mut Window,
12867        cx: &mut Context<Self>,
12868    ) {
12869        self.add_selection(false, window, cx);
12870    }
12871
12872    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12873        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12874
12875        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12876        let all_selections = self.selections.all::<Point>(cx);
12877        let text_layout_details = self.text_layout_details(window);
12878
12879        let (mut columnar_selections, new_selections_to_columnarize) = {
12880            if let Some(state) = self.add_selections_state.as_ref() {
12881                let columnar_selection_ids: HashSet<_> = state
12882                    .groups
12883                    .iter()
12884                    .flat_map(|group| group.stack.iter())
12885                    .copied()
12886                    .collect();
12887
12888                all_selections
12889                    .into_iter()
12890                    .partition(|s| columnar_selection_ids.contains(&s.id))
12891            } else {
12892                (Vec::new(), all_selections)
12893            }
12894        };
12895
12896        let mut state = self
12897            .add_selections_state
12898            .take()
12899            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12900
12901        for selection in new_selections_to_columnarize {
12902            let range = selection.display_range(&display_map).sorted();
12903            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12904            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12905            let positions = start_x.min(end_x)..start_x.max(end_x);
12906            let mut stack = Vec::new();
12907            for row in range.start.row().0..=range.end.row().0 {
12908                if let Some(selection) = self.selections.build_columnar_selection(
12909                    &display_map,
12910                    DisplayRow(row),
12911                    &positions,
12912                    selection.reversed,
12913                    &text_layout_details,
12914                ) {
12915                    stack.push(selection.id);
12916                    columnar_selections.push(selection);
12917                }
12918            }
12919            if !stack.is_empty() {
12920                if above {
12921                    stack.reverse();
12922                }
12923                state.groups.push(AddSelectionsGroup { above, stack });
12924            }
12925        }
12926
12927        let mut final_selections = Vec::new();
12928        let end_row = if above {
12929            DisplayRow(0)
12930        } else {
12931            display_map.max_point().row()
12932        };
12933
12934        let mut last_added_item_per_group = HashMap::default();
12935        for group in state.groups.iter_mut() {
12936            if let Some(last_id) = group.stack.last() {
12937                last_added_item_per_group.insert(*last_id, group);
12938            }
12939        }
12940
12941        for selection in columnar_selections {
12942            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12943                if above == group.above {
12944                    let range = selection.display_range(&display_map).sorted();
12945                    debug_assert_eq!(range.start.row(), range.end.row());
12946                    let mut row = range.start.row();
12947                    let positions =
12948                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12949                            px(start)..px(end)
12950                        } else {
12951                            let start_x =
12952                                display_map.x_for_display_point(range.start, &text_layout_details);
12953                            let end_x =
12954                                display_map.x_for_display_point(range.end, &text_layout_details);
12955                            start_x.min(end_x)..start_x.max(end_x)
12956                        };
12957
12958                    let mut maybe_new_selection = None;
12959                    while row != end_row {
12960                        if above {
12961                            row.0 -= 1;
12962                        } else {
12963                            row.0 += 1;
12964                        }
12965                        if let Some(new_selection) = self.selections.build_columnar_selection(
12966                            &display_map,
12967                            row,
12968                            &positions,
12969                            selection.reversed,
12970                            &text_layout_details,
12971                        ) {
12972                            maybe_new_selection = Some(new_selection);
12973                            break;
12974                        }
12975                    }
12976
12977                    if let Some(new_selection) = maybe_new_selection {
12978                        group.stack.push(new_selection.id);
12979                        if above {
12980                            final_selections.push(new_selection);
12981                            final_selections.push(selection);
12982                        } else {
12983                            final_selections.push(selection);
12984                            final_selections.push(new_selection);
12985                        }
12986                    } else {
12987                        final_selections.push(selection);
12988                    }
12989                } else {
12990                    group.stack.pop();
12991                }
12992            } else {
12993                final_selections.push(selection);
12994            }
12995        }
12996
12997        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12998            s.select(final_selections);
12999        });
13000
13001        let final_selection_ids: HashSet<_> = self
13002            .selections
13003            .all::<Point>(cx)
13004            .iter()
13005            .map(|s| s.id)
13006            .collect();
13007        state.groups.retain_mut(|group| {
13008            // selections might get merged above so we remove invalid items from stacks
13009            group.stack.retain(|id| final_selection_ids.contains(id));
13010
13011            // single selection in stack can be treated as initial state
13012            group.stack.len() > 1
13013        });
13014
13015        if !state.groups.is_empty() {
13016            self.add_selections_state = Some(state);
13017        }
13018    }
13019
13020    fn select_match_ranges(
13021        &mut self,
13022        range: Range<usize>,
13023        reversed: bool,
13024        replace_newest: bool,
13025        auto_scroll: Option<Autoscroll>,
13026        window: &mut Window,
13027        cx: &mut Context<Editor>,
13028    ) {
13029        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13030        self.change_selections(auto_scroll, window, cx, |s| {
13031            if replace_newest {
13032                s.delete(s.newest_anchor().id);
13033            }
13034            if reversed {
13035                s.insert_range(range.end..range.start);
13036            } else {
13037                s.insert_range(range);
13038            }
13039        });
13040    }
13041
13042    pub fn select_next_match_internal(
13043        &mut self,
13044        display_map: &DisplaySnapshot,
13045        replace_newest: bool,
13046        autoscroll: Option<Autoscroll>,
13047        window: &mut Window,
13048        cx: &mut Context<Self>,
13049    ) -> Result<()> {
13050        let buffer = &display_map.buffer_snapshot;
13051        let mut selections = self.selections.all::<usize>(cx);
13052        if let Some(mut select_next_state) = self.select_next_state.take() {
13053            let query = &select_next_state.query;
13054            if !select_next_state.done {
13055                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13056                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13057                let mut next_selected_range = None;
13058
13059                let bytes_after_last_selection =
13060                    buffer.bytes_in_range(last_selection.end..buffer.len());
13061                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13062                let query_matches = query
13063                    .stream_find_iter(bytes_after_last_selection)
13064                    .map(|result| (last_selection.end, result))
13065                    .chain(
13066                        query
13067                            .stream_find_iter(bytes_before_first_selection)
13068                            .map(|result| (0, result)),
13069                    );
13070
13071                for (start_offset, query_match) in query_matches {
13072                    let query_match = query_match.unwrap(); // can only fail due to I/O
13073                    let offset_range =
13074                        start_offset + query_match.start()..start_offset + query_match.end();
13075                    let display_range = offset_range.start.to_display_point(display_map)
13076                        ..offset_range.end.to_display_point(display_map);
13077
13078                    if !select_next_state.wordwise
13079                        || (!movement::is_inside_word(display_map, display_range.start)
13080                            && !movement::is_inside_word(display_map, display_range.end))
13081                    {
13082                        // TODO: This is n^2, because we might check all the selections
13083                        if !selections
13084                            .iter()
13085                            .any(|selection| selection.range().overlaps(&offset_range))
13086                        {
13087                            next_selected_range = Some(offset_range);
13088                            break;
13089                        }
13090                    }
13091                }
13092
13093                if let Some(next_selected_range) = next_selected_range {
13094                    self.select_match_ranges(
13095                        next_selected_range,
13096                        last_selection.reversed,
13097                        replace_newest,
13098                        autoscroll,
13099                        window,
13100                        cx,
13101                    );
13102                } else {
13103                    select_next_state.done = true;
13104                }
13105            }
13106
13107            self.select_next_state = Some(select_next_state);
13108        } else {
13109            let mut only_carets = true;
13110            let mut same_text_selected = true;
13111            let mut selected_text = None;
13112
13113            let mut selections_iter = selections.iter().peekable();
13114            while let Some(selection) = selections_iter.next() {
13115                if selection.start != selection.end {
13116                    only_carets = false;
13117                }
13118
13119                if same_text_selected {
13120                    if selected_text.is_none() {
13121                        selected_text =
13122                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13123                    }
13124
13125                    if let Some(next_selection) = selections_iter.peek() {
13126                        if next_selection.range().len() == selection.range().len() {
13127                            let next_selected_text = buffer
13128                                .text_for_range(next_selection.range())
13129                                .collect::<String>();
13130                            if Some(next_selected_text) != selected_text {
13131                                same_text_selected = false;
13132                                selected_text = None;
13133                            }
13134                        } else {
13135                            same_text_selected = false;
13136                            selected_text = None;
13137                        }
13138                    }
13139                }
13140            }
13141
13142            if only_carets {
13143                for selection in &mut selections {
13144                    let word_range = movement::surrounding_word(
13145                        display_map,
13146                        selection.start.to_display_point(display_map),
13147                    );
13148                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13149                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13150                    selection.goal = SelectionGoal::None;
13151                    selection.reversed = false;
13152                    self.select_match_ranges(
13153                        selection.start..selection.end,
13154                        selection.reversed,
13155                        replace_newest,
13156                        autoscroll,
13157                        window,
13158                        cx,
13159                    );
13160                }
13161
13162                if selections.len() == 1 {
13163                    let selection = selections
13164                        .last()
13165                        .expect("ensured that there's only one selection");
13166                    let query = buffer
13167                        .text_for_range(selection.start..selection.end)
13168                        .collect::<String>();
13169                    let is_empty = query.is_empty();
13170                    let select_state = SelectNextState {
13171                        query: AhoCorasick::new(&[query])?,
13172                        wordwise: true,
13173                        done: is_empty,
13174                    };
13175                    self.select_next_state = Some(select_state);
13176                } else {
13177                    self.select_next_state = None;
13178                }
13179            } else if let Some(selected_text) = selected_text {
13180                self.select_next_state = Some(SelectNextState {
13181                    query: AhoCorasick::new(&[selected_text])?,
13182                    wordwise: false,
13183                    done: false,
13184                });
13185                self.select_next_match_internal(
13186                    display_map,
13187                    replace_newest,
13188                    autoscroll,
13189                    window,
13190                    cx,
13191                )?;
13192            }
13193        }
13194        Ok(())
13195    }
13196
13197    pub fn select_all_matches(
13198        &mut self,
13199        _action: &SelectAllMatches,
13200        window: &mut Window,
13201        cx: &mut Context<Self>,
13202    ) -> Result<()> {
13203        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13204
13205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13206
13207        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13208        let Some(select_next_state) = self.select_next_state.as_mut() else {
13209            return Ok(());
13210        };
13211        if select_next_state.done {
13212            return Ok(());
13213        }
13214
13215        let mut new_selections = Vec::new();
13216
13217        let reversed = self.selections.oldest::<usize>(cx).reversed;
13218        let buffer = &display_map.buffer_snapshot;
13219        let query_matches = select_next_state
13220            .query
13221            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13222
13223        for query_match in query_matches.into_iter() {
13224            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13225            let offset_range = if reversed {
13226                query_match.end()..query_match.start()
13227            } else {
13228                query_match.start()..query_match.end()
13229            };
13230            let display_range = offset_range.start.to_display_point(&display_map)
13231                ..offset_range.end.to_display_point(&display_map);
13232
13233            if !select_next_state.wordwise
13234                || (!movement::is_inside_word(&display_map, display_range.start)
13235                    && !movement::is_inside_word(&display_map, display_range.end))
13236            {
13237                new_selections.push(offset_range.start..offset_range.end);
13238            }
13239        }
13240
13241        select_next_state.done = true;
13242        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13243        self.change_selections(None, window, cx, |selections| {
13244            selections.select_ranges(new_selections)
13245        });
13246
13247        Ok(())
13248    }
13249
13250    pub fn select_next(
13251        &mut self,
13252        action: &SelectNext,
13253        window: &mut Window,
13254        cx: &mut Context<Self>,
13255    ) -> Result<()> {
13256        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13257        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13258        self.select_next_match_internal(
13259            &display_map,
13260            action.replace_newest,
13261            Some(Autoscroll::newest()),
13262            window,
13263            cx,
13264        )?;
13265        Ok(())
13266    }
13267
13268    pub fn select_previous(
13269        &mut self,
13270        action: &SelectPrevious,
13271        window: &mut Window,
13272        cx: &mut Context<Self>,
13273    ) -> Result<()> {
13274        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13275        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13276        let buffer = &display_map.buffer_snapshot;
13277        let mut selections = self.selections.all::<usize>(cx);
13278        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13279            let query = &select_prev_state.query;
13280            if !select_prev_state.done {
13281                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13282                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13283                let mut next_selected_range = None;
13284                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13285                let bytes_before_last_selection =
13286                    buffer.reversed_bytes_in_range(0..last_selection.start);
13287                let bytes_after_first_selection =
13288                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13289                let query_matches = query
13290                    .stream_find_iter(bytes_before_last_selection)
13291                    .map(|result| (last_selection.start, result))
13292                    .chain(
13293                        query
13294                            .stream_find_iter(bytes_after_first_selection)
13295                            .map(|result| (buffer.len(), result)),
13296                    );
13297                for (end_offset, query_match) in query_matches {
13298                    let query_match = query_match.unwrap(); // can only fail due to I/O
13299                    let offset_range =
13300                        end_offset - query_match.end()..end_offset - query_match.start();
13301                    let display_range = offset_range.start.to_display_point(&display_map)
13302                        ..offset_range.end.to_display_point(&display_map);
13303
13304                    if !select_prev_state.wordwise
13305                        || (!movement::is_inside_word(&display_map, display_range.start)
13306                            && !movement::is_inside_word(&display_map, display_range.end))
13307                    {
13308                        next_selected_range = Some(offset_range);
13309                        break;
13310                    }
13311                }
13312
13313                if let Some(next_selected_range) = next_selected_range {
13314                    self.select_match_ranges(
13315                        next_selected_range,
13316                        last_selection.reversed,
13317                        action.replace_newest,
13318                        Some(Autoscroll::newest()),
13319                        window,
13320                        cx,
13321                    );
13322                } else {
13323                    select_prev_state.done = true;
13324                }
13325            }
13326
13327            self.select_prev_state = Some(select_prev_state);
13328        } else {
13329            let mut only_carets = true;
13330            let mut same_text_selected = true;
13331            let mut selected_text = None;
13332
13333            let mut selections_iter = selections.iter().peekable();
13334            while let Some(selection) = selections_iter.next() {
13335                if selection.start != selection.end {
13336                    only_carets = false;
13337                }
13338
13339                if same_text_selected {
13340                    if selected_text.is_none() {
13341                        selected_text =
13342                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13343                    }
13344
13345                    if let Some(next_selection) = selections_iter.peek() {
13346                        if next_selection.range().len() == selection.range().len() {
13347                            let next_selected_text = buffer
13348                                .text_for_range(next_selection.range())
13349                                .collect::<String>();
13350                            if Some(next_selected_text) != selected_text {
13351                                same_text_selected = false;
13352                                selected_text = None;
13353                            }
13354                        } else {
13355                            same_text_selected = false;
13356                            selected_text = None;
13357                        }
13358                    }
13359                }
13360            }
13361
13362            if only_carets {
13363                for selection in &mut selections {
13364                    let word_range = movement::surrounding_word(
13365                        &display_map,
13366                        selection.start.to_display_point(&display_map),
13367                    );
13368                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13369                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13370                    selection.goal = SelectionGoal::None;
13371                    selection.reversed = false;
13372                    self.select_match_ranges(
13373                        selection.start..selection.end,
13374                        selection.reversed,
13375                        action.replace_newest,
13376                        Some(Autoscroll::newest()),
13377                        window,
13378                        cx,
13379                    );
13380                }
13381                if selections.len() == 1 {
13382                    let selection = selections
13383                        .last()
13384                        .expect("ensured that there's only one selection");
13385                    let query = buffer
13386                        .text_for_range(selection.start..selection.end)
13387                        .collect::<String>();
13388                    let is_empty = query.is_empty();
13389                    let select_state = SelectNextState {
13390                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13391                        wordwise: true,
13392                        done: is_empty,
13393                    };
13394                    self.select_prev_state = Some(select_state);
13395                } else {
13396                    self.select_prev_state = None;
13397                }
13398            } else if let Some(selected_text) = selected_text {
13399                self.select_prev_state = Some(SelectNextState {
13400                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13401                    wordwise: false,
13402                    done: false,
13403                });
13404                self.select_previous(action, window, cx)?;
13405            }
13406        }
13407        Ok(())
13408    }
13409
13410    pub fn find_next_match(
13411        &mut self,
13412        _: &FindNextMatch,
13413        window: &mut Window,
13414        cx: &mut Context<Self>,
13415    ) -> Result<()> {
13416        let selections = self.selections.disjoint_anchors();
13417        match selections.first() {
13418            Some(first) if selections.len() >= 2 => {
13419                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13420                    s.select_ranges([first.range()]);
13421                });
13422            }
13423            _ => self.select_next(
13424                &SelectNext {
13425                    replace_newest: true,
13426                },
13427                window,
13428                cx,
13429            )?,
13430        }
13431        Ok(())
13432    }
13433
13434    pub fn find_previous_match(
13435        &mut self,
13436        _: &FindPreviousMatch,
13437        window: &mut Window,
13438        cx: &mut Context<Self>,
13439    ) -> Result<()> {
13440        let selections = self.selections.disjoint_anchors();
13441        match selections.last() {
13442            Some(last) if selections.len() >= 2 => {
13443                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13444                    s.select_ranges([last.range()]);
13445                });
13446            }
13447            _ => self.select_previous(
13448                &SelectPrevious {
13449                    replace_newest: true,
13450                },
13451                window,
13452                cx,
13453            )?,
13454        }
13455        Ok(())
13456    }
13457
13458    pub fn toggle_comments(
13459        &mut self,
13460        action: &ToggleComments,
13461        window: &mut Window,
13462        cx: &mut Context<Self>,
13463    ) {
13464        if self.read_only(cx) {
13465            return;
13466        }
13467        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13468        let text_layout_details = &self.text_layout_details(window);
13469        self.transact(window, cx, |this, window, cx| {
13470            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13471            let mut edits = Vec::new();
13472            let mut selection_edit_ranges = Vec::new();
13473            let mut last_toggled_row = None;
13474            let snapshot = this.buffer.read(cx).read(cx);
13475            let empty_str: Arc<str> = Arc::default();
13476            let mut suffixes_inserted = Vec::new();
13477            let ignore_indent = action.ignore_indent;
13478
13479            fn comment_prefix_range(
13480                snapshot: &MultiBufferSnapshot,
13481                row: MultiBufferRow,
13482                comment_prefix: &str,
13483                comment_prefix_whitespace: &str,
13484                ignore_indent: bool,
13485            ) -> Range<Point> {
13486                let indent_size = if ignore_indent {
13487                    0
13488                } else {
13489                    snapshot.indent_size_for_line(row).len
13490                };
13491
13492                let start = Point::new(row.0, indent_size);
13493
13494                let mut line_bytes = snapshot
13495                    .bytes_in_range(start..snapshot.max_point())
13496                    .flatten()
13497                    .copied();
13498
13499                // If this line currently begins with the line comment prefix, then record
13500                // the range containing the prefix.
13501                if line_bytes
13502                    .by_ref()
13503                    .take(comment_prefix.len())
13504                    .eq(comment_prefix.bytes())
13505                {
13506                    // Include any whitespace that matches the comment prefix.
13507                    let matching_whitespace_len = line_bytes
13508                        .zip(comment_prefix_whitespace.bytes())
13509                        .take_while(|(a, b)| a == b)
13510                        .count() as u32;
13511                    let end = Point::new(
13512                        start.row,
13513                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13514                    );
13515                    start..end
13516                } else {
13517                    start..start
13518                }
13519            }
13520
13521            fn comment_suffix_range(
13522                snapshot: &MultiBufferSnapshot,
13523                row: MultiBufferRow,
13524                comment_suffix: &str,
13525                comment_suffix_has_leading_space: bool,
13526            ) -> Range<Point> {
13527                let end = Point::new(row.0, snapshot.line_len(row));
13528                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13529
13530                let mut line_end_bytes = snapshot
13531                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13532                    .flatten()
13533                    .copied();
13534
13535                let leading_space_len = if suffix_start_column > 0
13536                    && line_end_bytes.next() == Some(b' ')
13537                    && comment_suffix_has_leading_space
13538                {
13539                    1
13540                } else {
13541                    0
13542                };
13543
13544                // If this line currently begins with the line comment prefix, then record
13545                // the range containing the prefix.
13546                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13547                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13548                    start..end
13549                } else {
13550                    end..end
13551                }
13552            }
13553
13554            // TODO: Handle selections that cross excerpts
13555            for selection in &mut selections {
13556                let start_column = snapshot
13557                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13558                    .len;
13559                let language = if let Some(language) =
13560                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13561                {
13562                    language
13563                } else {
13564                    continue;
13565                };
13566
13567                selection_edit_ranges.clear();
13568
13569                // If multiple selections contain a given row, avoid processing that
13570                // row more than once.
13571                let mut start_row = MultiBufferRow(selection.start.row);
13572                if last_toggled_row == Some(start_row) {
13573                    start_row = start_row.next_row();
13574                }
13575                let end_row =
13576                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13577                        MultiBufferRow(selection.end.row - 1)
13578                    } else {
13579                        MultiBufferRow(selection.end.row)
13580                    };
13581                last_toggled_row = Some(end_row);
13582
13583                if start_row > end_row {
13584                    continue;
13585                }
13586
13587                // If the language has line comments, toggle those.
13588                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13589
13590                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13591                if ignore_indent {
13592                    full_comment_prefixes = full_comment_prefixes
13593                        .into_iter()
13594                        .map(|s| Arc::from(s.trim_end()))
13595                        .collect();
13596                }
13597
13598                if !full_comment_prefixes.is_empty() {
13599                    let first_prefix = full_comment_prefixes
13600                        .first()
13601                        .expect("prefixes is non-empty");
13602                    let prefix_trimmed_lengths = full_comment_prefixes
13603                        .iter()
13604                        .map(|p| p.trim_end_matches(' ').len())
13605                        .collect::<SmallVec<[usize; 4]>>();
13606
13607                    let mut all_selection_lines_are_comments = true;
13608
13609                    for row in start_row.0..=end_row.0 {
13610                        let row = MultiBufferRow(row);
13611                        if start_row < end_row && snapshot.is_line_blank(row) {
13612                            continue;
13613                        }
13614
13615                        let prefix_range = full_comment_prefixes
13616                            .iter()
13617                            .zip(prefix_trimmed_lengths.iter().copied())
13618                            .map(|(prefix, trimmed_prefix_len)| {
13619                                comment_prefix_range(
13620                                    snapshot.deref(),
13621                                    row,
13622                                    &prefix[..trimmed_prefix_len],
13623                                    &prefix[trimmed_prefix_len..],
13624                                    ignore_indent,
13625                                )
13626                            })
13627                            .max_by_key(|range| range.end.column - range.start.column)
13628                            .expect("prefixes is non-empty");
13629
13630                        if prefix_range.is_empty() {
13631                            all_selection_lines_are_comments = false;
13632                        }
13633
13634                        selection_edit_ranges.push(prefix_range);
13635                    }
13636
13637                    if all_selection_lines_are_comments {
13638                        edits.extend(
13639                            selection_edit_ranges
13640                                .iter()
13641                                .cloned()
13642                                .map(|range| (range, empty_str.clone())),
13643                        );
13644                    } else {
13645                        let min_column = selection_edit_ranges
13646                            .iter()
13647                            .map(|range| range.start.column)
13648                            .min()
13649                            .unwrap_or(0);
13650                        edits.extend(selection_edit_ranges.iter().map(|range| {
13651                            let position = Point::new(range.start.row, min_column);
13652                            (position..position, first_prefix.clone())
13653                        }));
13654                    }
13655                } else if let Some((full_comment_prefix, comment_suffix)) =
13656                    language.block_comment_delimiters()
13657                {
13658                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13659                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13660                    let prefix_range = comment_prefix_range(
13661                        snapshot.deref(),
13662                        start_row,
13663                        comment_prefix,
13664                        comment_prefix_whitespace,
13665                        ignore_indent,
13666                    );
13667                    let suffix_range = comment_suffix_range(
13668                        snapshot.deref(),
13669                        end_row,
13670                        comment_suffix.trim_start_matches(' '),
13671                        comment_suffix.starts_with(' '),
13672                    );
13673
13674                    if prefix_range.is_empty() || suffix_range.is_empty() {
13675                        edits.push((
13676                            prefix_range.start..prefix_range.start,
13677                            full_comment_prefix.clone(),
13678                        ));
13679                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13680                        suffixes_inserted.push((end_row, comment_suffix.len()));
13681                    } else {
13682                        edits.push((prefix_range, empty_str.clone()));
13683                        edits.push((suffix_range, empty_str.clone()));
13684                    }
13685                } else {
13686                    continue;
13687                }
13688            }
13689
13690            drop(snapshot);
13691            this.buffer.update(cx, |buffer, cx| {
13692                buffer.edit(edits, None, cx);
13693            });
13694
13695            // Adjust selections so that they end before any comment suffixes that
13696            // were inserted.
13697            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13698            let mut selections = this.selections.all::<Point>(cx);
13699            let snapshot = this.buffer.read(cx).read(cx);
13700            for selection in &mut selections {
13701                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13702                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13703                        Ordering::Less => {
13704                            suffixes_inserted.next();
13705                            continue;
13706                        }
13707                        Ordering::Greater => break,
13708                        Ordering::Equal => {
13709                            if selection.end.column == snapshot.line_len(row) {
13710                                if selection.is_empty() {
13711                                    selection.start.column -= suffix_len as u32;
13712                                }
13713                                selection.end.column -= suffix_len as u32;
13714                            }
13715                            break;
13716                        }
13717                    }
13718                }
13719            }
13720
13721            drop(snapshot);
13722            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13723                s.select(selections)
13724            });
13725
13726            let selections = this.selections.all::<Point>(cx);
13727            let selections_on_single_row = selections.windows(2).all(|selections| {
13728                selections[0].start.row == selections[1].start.row
13729                    && selections[0].end.row == selections[1].end.row
13730                    && selections[0].start.row == selections[0].end.row
13731            });
13732            let selections_selecting = selections
13733                .iter()
13734                .any(|selection| selection.start != selection.end);
13735            let advance_downwards = action.advance_downwards
13736                && selections_on_single_row
13737                && !selections_selecting
13738                && !matches!(this.mode, EditorMode::SingleLine { .. });
13739
13740            if advance_downwards {
13741                let snapshot = this.buffer.read(cx).snapshot(cx);
13742
13743                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13744                    s.move_cursors_with(|display_snapshot, display_point, _| {
13745                        let mut point = display_point.to_point(display_snapshot);
13746                        point.row += 1;
13747                        point = snapshot.clip_point(point, Bias::Left);
13748                        let display_point = point.to_display_point(display_snapshot);
13749                        let goal = SelectionGoal::HorizontalPosition(
13750                            display_snapshot
13751                                .x_for_display_point(display_point, text_layout_details)
13752                                .into(),
13753                        );
13754                        (display_point, goal)
13755                    })
13756                });
13757            }
13758        });
13759    }
13760
13761    pub fn select_enclosing_symbol(
13762        &mut self,
13763        _: &SelectEnclosingSymbol,
13764        window: &mut Window,
13765        cx: &mut Context<Self>,
13766    ) {
13767        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13768
13769        let buffer = self.buffer.read(cx).snapshot(cx);
13770        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13771
13772        fn update_selection(
13773            selection: &Selection<usize>,
13774            buffer_snap: &MultiBufferSnapshot,
13775        ) -> Option<Selection<usize>> {
13776            let cursor = selection.head();
13777            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13778            for symbol in symbols.iter().rev() {
13779                let start = symbol.range.start.to_offset(buffer_snap);
13780                let end = symbol.range.end.to_offset(buffer_snap);
13781                let new_range = start..end;
13782                if start < selection.start || end > selection.end {
13783                    return Some(Selection {
13784                        id: selection.id,
13785                        start: new_range.start,
13786                        end: new_range.end,
13787                        goal: SelectionGoal::None,
13788                        reversed: selection.reversed,
13789                    });
13790                }
13791            }
13792            None
13793        }
13794
13795        let mut selected_larger_symbol = false;
13796        let new_selections = old_selections
13797            .iter()
13798            .map(|selection| match update_selection(selection, &buffer) {
13799                Some(new_selection) => {
13800                    if new_selection.range() != selection.range() {
13801                        selected_larger_symbol = true;
13802                    }
13803                    new_selection
13804                }
13805                None => selection.clone(),
13806            })
13807            .collect::<Vec<_>>();
13808
13809        if selected_larger_symbol {
13810            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13811                s.select(new_selections);
13812            });
13813        }
13814    }
13815
13816    pub fn select_larger_syntax_node(
13817        &mut self,
13818        _: &SelectLargerSyntaxNode,
13819        window: &mut Window,
13820        cx: &mut Context<Self>,
13821    ) {
13822        let Some(visible_row_count) = self.visible_row_count() else {
13823            return;
13824        };
13825        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13826        if old_selections.is_empty() {
13827            return;
13828        }
13829
13830        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13831
13832        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13833        let buffer = self.buffer.read(cx).snapshot(cx);
13834
13835        let mut selected_larger_node = false;
13836        let mut new_selections = old_selections
13837            .iter()
13838            .map(|selection| {
13839                let old_range = selection.start..selection.end;
13840
13841                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13842                    // manually select word at selection
13843                    if ["string_content", "inline"].contains(&node.kind()) {
13844                        let word_range = {
13845                            let display_point = buffer
13846                                .offset_to_point(old_range.start)
13847                                .to_display_point(&display_map);
13848                            let Range { start, end } =
13849                                movement::surrounding_word(&display_map, display_point);
13850                            start.to_point(&display_map).to_offset(&buffer)
13851                                ..end.to_point(&display_map).to_offset(&buffer)
13852                        };
13853                        // ignore if word is already selected
13854                        if !word_range.is_empty() && old_range != word_range {
13855                            let last_word_range = {
13856                                let display_point = buffer
13857                                    .offset_to_point(old_range.end)
13858                                    .to_display_point(&display_map);
13859                                let Range { start, end } =
13860                                    movement::surrounding_word(&display_map, display_point);
13861                                start.to_point(&display_map).to_offset(&buffer)
13862                                    ..end.to_point(&display_map).to_offset(&buffer)
13863                            };
13864                            // only select word if start and end point belongs to same word
13865                            if word_range == last_word_range {
13866                                selected_larger_node = true;
13867                                return Selection {
13868                                    id: selection.id,
13869                                    start: word_range.start,
13870                                    end: word_range.end,
13871                                    goal: SelectionGoal::None,
13872                                    reversed: selection.reversed,
13873                                };
13874                            }
13875                        }
13876                    }
13877                }
13878
13879                let mut new_range = old_range.clone();
13880                while let Some((_node, containing_range)) =
13881                    buffer.syntax_ancestor(new_range.clone())
13882                {
13883                    new_range = match containing_range {
13884                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13885                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13886                    };
13887                    if !display_map.intersects_fold(new_range.start)
13888                        && !display_map.intersects_fold(new_range.end)
13889                    {
13890                        break;
13891                    }
13892                }
13893
13894                selected_larger_node |= new_range != old_range;
13895                Selection {
13896                    id: selection.id,
13897                    start: new_range.start,
13898                    end: new_range.end,
13899                    goal: SelectionGoal::None,
13900                    reversed: selection.reversed,
13901                }
13902            })
13903            .collect::<Vec<_>>();
13904
13905        if !selected_larger_node {
13906            return; // don't put this call in the history
13907        }
13908
13909        // scroll based on transformation done to the last selection created by the user
13910        let (last_old, last_new) = old_selections
13911            .last()
13912            .zip(new_selections.last().cloned())
13913            .expect("old_selections isn't empty");
13914
13915        // revert selection
13916        let is_selection_reversed = {
13917            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13918            new_selections.last_mut().expect("checked above").reversed =
13919                should_newest_selection_be_reversed;
13920            should_newest_selection_be_reversed
13921        };
13922
13923        if selected_larger_node {
13924            self.select_syntax_node_history.disable_clearing = true;
13925            self.change_selections(None, window, cx, |s| {
13926                s.select(new_selections.clone());
13927            });
13928            self.select_syntax_node_history.disable_clearing = false;
13929        }
13930
13931        let start_row = last_new.start.to_display_point(&display_map).row().0;
13932        let end_row = last_new.end.to_display_point(&display_map).row().0;
13933        let selection_height = end_row - start_row + 1;
13934        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13935
13936        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13937        let scroll_behavior = if fits_on_the_screen {
13938            self.request_autoscroll(Autoscroll::fit(), cx);
13939            SelectSyntaxNodeScrollBehavior::FitSelection
13940        } else if is_selection_reversed {
13941            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13942            SelectSyntaxNodeScrollBehavior::CursorTop
13943        } else {
13944            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13945            SelectSyntaxNodeScrollBehavior::CursorBottom
13946        };
13947
13948        self.select_syntax_node_history.push((
13949            old_selections,
13950            scroll_behavior,
13951            is_selection_reversed,
13952        ));
13953    }
13954
13955    pub fn select_smaller_syntax_node(
13956        &mut self,
13957        _: &SelectSmallerSyntaxNode,
13958        window: &mut Window,
13959        cx: &mut Context<Self>,
13960    ) {
13961        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13962
13963        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13964            self.select_syntax_node_history.pop()
13965        {
13966            if let Some(selection) = selections.last_mut() {
13967                selection.reversed = is_selection_reversed;
13968            }
13969
13970            self.select_syntax_node_history.disable_clearing = true;
13971            self.change_selections(None, window, cx, |s| {
13972                s.select(selections.to_vec());
13973            });
13974            self.select_syntax_node_history.disable_clearing = false;
13975
13976            match scroll_behavior {
13977                SelectSyntaxNodeScrollBehavior::CursorTop => {
13978                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13979                }
13980                SelectSyntaxNodeScrollBehavior::FitSelection => {
13981                    self.request_autoscroll(Autoscroll::fit(), cx);
13982                }
13983                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13984                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13985                }
13986            }
13987        }
13988    }
13989
13990    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13991        if !EditorSettings::get_global(cx).gutter.runnables {
13992            self.clear_tasks();
13993            return Task::ready(());
13994        }
13995        let project = self.project.as_ref().map(Entity::downgrade);
13996        let task_sources = self.lsp_task_sources(cx);
13997        let multi_buffer = self.buffer.downgrade();
13998        cx.spawn_in(window, async move |editor, cx| {
13999            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14000            let Some(project) = project.and_then(|p| p.upgrade()) else {
14001                return;
14002            };
14003            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14004                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14005            }) else {
14006                return;
14007            };
14008
14009            let hide_runnables = project
14010                .update(cx, |project, cx| {
14011                    // Do not display any test indicators in non-dev server remote projects.
14012                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14013                })
14014                .unwrap_or(true);
14015            if hide_runnables {
14016                return;
14017            }
14018            let new_rows =
14019                cx.background_spawn({
14020                    let snapshot = display_snapshot.clone();
14021                    async move {
14022                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14023                    }
14024                })
14025                    .await;
14026            let Ok(lsp_tasks) =
14027                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14028            else {
14029                return;
14030            };
14031            let lsp_tasks = lsp_tasks.await;
14032
14033            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14034                lsp_tasks
14035                    .into_iter()
14036                    .flat_map(|(kind, tasks)| {
14037                        tasks.into_iter().filter_map(move |(location, task)| {
14038                            Some((kind.clone(), location?, task))
14039                        })
14040                    })
14041                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14042                        let buffer = location.target.buffer;
14043                        let buffer_snapshot = buffer.read(cx).snapshot();
14044                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14045                            |(excerpt_id, snapshot, _)| {
14046                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14047                                    display_snapshot
14048                                        .buffer_snapshot
14049                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14050                                } else {
14051                                    None
14052                                }
14053                            },
14054                        );
14055                        if let Some(offset) = offset {
14056                            let task_buffer_range =
14057                                location.target.range.to_point(&buffer_snapshot);
14058                            let context_buffer_range =
14059                                task_buffer_range.to_offset(&buffer_snapshot);
14060                            let context_range = BufferOffset(context_buffer_range.start)
14061                                ..BufferOffset(context_buffer_range.end);
14062
14063                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14064                                .or_insert_with(|| RunnableTasks {
14065                                    templates: Vec::new(),
14066                                    offset,
14067                                    column: task_buffer_range.start.column,
14068                                    extra_variables: HashMap::default(),
14069                                    context_range,
14070                                })
14071                                .templates
14072                                .push((kind, task.original_task().clone()));
14073                        }
14074
14075                        acc
14076                    })
14077            }) else {
14078                return;
14079            };
14080
14081            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14082                buffer.language_settings(cx).tasks.prefer_lsp
14083            }) else {
14084                return;
14085            };
14086
14087            let rows = Self::runnable_rows(
14088                project,
14089                display_snapshot,
14090                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14091                new_rows,
14092                cx.clone(),
14093            )
14094            .await;
14095            editor
14096                .update(cx, |editor, _| {
14097                    editor.clear_tasks();
14098                    for (key, mut value) in rows {
14099                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14100                            value.templates.extend(lsp_tasks.templates);
14101                        }
14102
14103                        editor.insert_tasks(key, value);
14104                    }
14105                    for (key, value) in lsp_tasks_by_rows {
14106                        editor.insert_tasks(key, value);
14107                    }
14108                })
14109                .ok();
14110        })
14111    }
14112    fn fetch_runnable_ranges(
14113        snapshot: &DisplaySnapshot,
14114        range: Range<Anchor>,
14115    ) -> Vec<language::RunnableRange> {
14116        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14117    }
14118
14119    fn runnable_rows(
14120        project: Entity<Project>,
14121        snapshot: DisplaySnapshot,
14122        prefer_lsp: bool,
14123        runnable_ranges: Vec<RunnableRange>,
14124        cx: AsyncWindowContext,
14125    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14126        cx.spawn(async move |cx| {
14127            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14128            for mut runnable in runnable_ranges {
14129                let Some(tasks) = cx
14130                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14131                    .ok()
14132                else {
14133                    continue;
14134                };
14135                let mut tasks = tasks.await;
14136
14137                if prefer_lsp {
14138                    tasks.retain(|(task_kind, _)| {
14139                        !matches!(task_kind, TaskSourceKind::Language { .. })
14140                    });
14141                }
14142                if tasks.is_empty() {
14143                    continue;
14144                }
14145
14146                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14147                let Some(row) = snapshot
14148                    .buffer_snapshot
14149                    .buffer_line_for_row(MultiBufferRow(point.row))
14150                    .map(|(_, range)| range.start.row)
14151                else {
14152                    continue;
14153                };
14154
14155                let context_range =
14156                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14157                runnable_rows.push((
14158                    (runnable.buffer_id, row),
14159                    RunnableTasks {
14160                        templates: tasks,
14161                        offset: snapshot
14162                            .buffer_snapshot
14163                            .anchor_before(runnable.run_range.start),
14164                        context_range,
14165                        column: point.column,
14166                        extra_variables: runnable.extra_captures,
14167                    },
14168                ));
14169            }
14170            runnable_rows
14171        })
14172    }
14173
14174    fn templates_with_tags(
14175        project: &Entity<Project>,
14176        runnable: &mut Runnable,
14177        cx: &mut App,
14178    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14179        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14180            let (worktree_id, file) = project
14181                .buffer_for_id(runnable.buffer, cx)
14182                .and_then(|buffer| buffer.read(cx).file())
14183                .map(|file| (file.worktree_id(cx), file.clone()))
14184                .unzip();
14185
14186            (
14187                project.task_store().read(cx).task_inventory().cloned(),
14188                worktree_id,
14189                file,
14190            )
14191        });
14192
14193        let tags = mem::take(&mut runnable.tags);
14194        let language = runnable.language.clone();
14195        cx.spawn(async move |cx| {
14196            let mut templates_with_tags = Vec::new();
14197            if let Some(inventory) = inventory {
14198                for RunnableTag(tag) in tags {
14199                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14200                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14201                    }) else {
14202                        return templates_with_tags;
14203                    };
14204                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14205                        move |(_, template)| {
14206                            template.tags.iter().any(|source_tag| source_tag == &tag)
14207                        },
14208                    ));
14209                }
14210            }
14211            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14212
14213            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14214                // Strongest source wins; if we have worktree tag binding, prefer that to
14215                // global and language bindings;
14216                // if we have a global binding, prefer that to language binding.
14217                let first_mismatch = templates_with_tags
14218                    .iter()
14219                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14220                if let Some(index) = first_mismatch {
14221                    templates_with_tags.truncate(index);
14222                }
14223            }
14224
14225            templates_with_tags
14226        })
14227    }
14228
14229    pub fn move_to_enclosing_bracket(
14230        &mut self,
14231        _: &MoveToEnclosingBracket,
14232        window: &mut Window,
14233        cx: &mut Context<Self>,
14234    ) {
14235        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14236        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14237            s.move_offsets_with(|snapshot, selection| {
14238                let Some(enclosing_bracket_ranges) =
14239                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14240                else {
14241                    return;
14242                };
14243
14244                let mut best_length = usize::MAX;
14245                let mut best_inside = false;
14246                let mut best_in_bracket_range = false;
14247                let mut best_destination = None;
14248                for (open, close) in enclosing_bracket_ranges {
14249                    let close = close.to_inclusive();
14250                    let length = close.end() - open.start;
14251                    let inside = selection.start >= open.end && selection.end <= *close.start();
14252                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14253                        || close.contains(&selection.head());
14254
14255                    // If best is next to a bracket and current isn't, skip
14256                    if !in_bracket_range && best_in_bracket_range {
14257                        continue;
14258                    }
14259
14260                    // Prefer smaller lengths unless best is inside and current isn't
14261                    if length > best_length && (best_inside || !inside) {
14262                        continue;
14263                    }
14264
14265                    best_length = length;
14266                    best_inside = inside;
14267                    best_in_bracket_range = in_bracket_range;
14268                    best_destination = Some(
14269                        if close.contains(&selection.start) && close.contains(&selection.end) {
14270                            if inside { open.end } else { open.start }
14271                        } else if inside {
14272                            *close.start()
14273                        } else {
14274                            *close.end()
14275                        },
14276                    );
14277                }
14278
14279                if let Some(destination) = best_destination {
14280                    selection.collapse_to(destination, SelectionGoal::None);
14281                }
14282            })
14283        });
14284    }
14285
14286    pub fn undo_selection(
14287        &mut self,
14288        _: &UndoSelection,
14289        window: &mut Window,
14290        cx: &mut Context<Self>,
14291    ) {
14292        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14293        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14294            self.selection_history.mode = SelectionHistoryMode::Undoing;
14295            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14296                this.end_selection(window, cx);
14297                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14298                    s.select_anchors(entry.selections.to_vec())
14299                });
14300            });
14301            self.selection_history.mode = SelectionHistoryMode::Normal;
14302
14303            self.select_next_state = entry.select_next_state;
14304            self.select_prev_state = entry.select_prev_state;
14305            self.add_selections_state = entry.add_selections_state;
14306        }
14307    }
14308
14309    pub fn redo_selection(
14310        &mut self,
14311        _: &RedoSelection,
14312        window: &mut Window,
14313        cx: &mut Context<Self>,
14314    ) {
14315        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14316        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14317            self.selection_history.mode = SelectionHistoryMode::Redoing;
14318            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14319                this.end_selection(window, cx);
14320                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14321                    s.select_anchors(entry.selections.to_vec())
14322                });
14323            });
14324            self.selection_history.mode = SelectionHistoryMode::Normal;
14325
14326            self.select_next_state = entry.select_next_state;
14327            self.select_prev_state = entry.select_prev_state;
14328            self.add_selections_state = entry.add_selections_state;
14329        }
14330    }
14331
14332    pub fn expand_excerpts(
14333        &mut self,
14334        action: &ExpandExcerpts,
14335        _: &mut Window,
14336        cx: &mut Context<Self>,
14337    ) {
14338        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14339    }
14340
14341    pub fn expand_excerpts_down(
14342        &mut self,
14343        action: &ExpandExcerptsDown,
14344        _: &mut Window,
14345        cx: &mut Context<Self>,
14346    ) {
14347        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14348    }
14349
14350    pub fn expand_excerpts_up(
14351        &mut self,
14352        action: &ExpandExcerptsUp,
14353        _: &mut Window,
14354        cx: &mut Context<Self>,
14355    ) {
14356        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14357    }
14358
14359    pub fn expand_excerpts_for_direction(
14360        &mut self,
14361        lines: u32,
14362        direction: ExpandExcerptDirection,
14363
14364        cx: &mut Context<Self>,
14365    ) {
14366        let selections = self.selections.disjoint_anchors();
14367
14368        let lines = if lines == 0 {
14369            EditorSettings::get_global(cx).expand_excerpt_lines
14370        } else {
14371            lines
14372        };
14373
14374        self.buffer.update(cx, |buffer, cx| {
14375            let snapshot = buffer.snapshot(cx);
14376            let mut excerpt_ids = selections
14377                .iter()
14378                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14379                .collect::<Vec<_>>();
14380            excerpt_ids.sort();
14381            excerpt_ids.dedup();
14382            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14383        })
14384    }
14385
14386    pub fn expand_excerpt(
14387        &mut self,
14388        excerpt: ExcerptId,
14389        direction: ExpandExcerptDirection,
14390        window: &mut Window,
14391        cx: &mut Context<Self>,
14392    ) {
14393        let current_scroll_position = self.scroll_position(cx);
14394        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14395        let mut should_scroll_up = false;
14396
14397        if direction == ExpandExcerptDirection::Down {
14398            let multi_buffer = self.buffer.read(cx);
14399            let snapshot = multi_buffer.snapshot(cx);
14400            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14401                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14402                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14403                        let buffer_snapshot = buffer.read(cx).snapshot();
14404                        let excerpt_end_row =
14405                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14406                        let last_row = buffer_snapshot.max_point().row;
14407                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14408                        should_scroll_up = lines_below >= lines_to_expand;
14409                    }
14410                }
14411            }
14412        }
14413
14414        self.buffer.update(cx, |buffer, cx| {
14415            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14416        });
14417
14418        if should_scroll_up {
14419            let new_scroll_position =
14420                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14421            self.set_scroll_position(new_scroll_position, window, cx);
14422        }
14423    }
14424
14425    pub fn go_to_singleton_buffer_point(
14426        &mut self,
14427        point: Point,
14428        window: &mut Window,
14429        cx: &mut Context<Self>,
14430    ) {
14431        self.go_to_singleton_buffer_range(point..point, window, cx);
14432    }
14433
14434    pub fn go_to_singleton_buffer_range(
14435        &mut self,
14436        range: Range<Point>,
14437        window: &mut Window,
14438        cx: &mut Context<Self>,
14439    ) {
14440        let multibuffer = self.buffer().read(cx);
14441        let Some(buffer) = multibuffer.as_singleton() else {
14442            return;
14443        };
14444        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14445            return;
14446        };
14447        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14448            return;
14449        };
14450        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14451            s.select_anchor_ranges([start..end])
14452        });
14453    }
14454
14455    pub fn go_to_diagnostic(
14456        &mut self,
14457        _: &GoToDiagnostic,
14458        window: &mut Window,
14459        cx: &mut Context<Self>,
14460    ) {
14461        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14462        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14463    }
14464
14465    pub fn go_to_prev_diagnostic(
14466        &mut self,
14467        _: &GoToPreviousDiagnostic,
14468        window: &mut Window,
14469        cx: &mut Context<Self>,
14470    ) {
14471        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14472        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14473    }
14474
14475    pub fn go_to_diagnostic_impl(
14476        &mut self,
14477        direction: Direction,
14478        window: &mut Window,
14479        cx: &mut Context<Self>,
14480    ) {
14481        let buffer = self.buffer.read(cx).snapshot(cx);
14482        let selection = self.selections.newest::<usize>(cx);
14483
14484        let mut active_group_id = None;
14485        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14486            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14487                active_group_id = Some(active_group.group_id);
14488            }
14489        }
14490
14491        fn filtered(
14492            snapshot: EditorSnapshot,
14493            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14494        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14495            diagnostics
14496                .filter(|entry| entry.range.start != entry.range.end)
14497                .filter(|entry| !entry.diagnostic.is_unnecessary)
14498                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14499        }
14500
14501        let snapshot = self.snapshot(window, cx);
14502        let before = filtered(
14503            snapshot.clone(),
14504            buffer
14505                .diagnostics_in_range(0..selection.start)
14506                .filter(|entry| entry.range.start <= selection.start),
14507        );
14508        let after = filtered(
14509            snapshot,
14510            buffer
14511                .diagnostics_in_range(selection.start..buffer.len())
14512                .filter(|entry| entry.range.start >= selection.start),
14513        );
14514
14515        let mut found: Option<DiagnosticEntry<usize>> = None;
14516        if direction == Direction::Prev {
14517            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14518            {
14519                for diagnostic in prev_diagnostics.into_iter().rev() {
14520                    if diagnostic.range.start != selection.start
14521                        || active_group_id
14522                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14523                    {
14524                        found = Some(diagnostic);
14525                        break 'outer;
14526                    }
14527                }
14528            }
14529        } else {
14530            for diagnostic in after.chain(before) {
14531                if diagnostic.range.start != selection.start
14532                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14533                {
14534                    found = Some(diagnostic);
14535                    break;
14536                }
14537            }
14538        }
14539        let Some(next_diagnostic) = found else {
14540            return;
14541        };
14542
14543        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14544            return;
14545        };
14546        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14547            s.select_ranges(vec![
14548                next_diagnostic.range.start..next_diagnostic.range.start,
14549            ])
14550        });
14551        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14552        self.refresh_inline_completion(false, true, window, cx);
14553    }
14554
14555    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14556        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14557        let snapshot = self.snapshot(window, cx);
14558        let selection = self.selections.newest::<Point>(cx);
14559        self.go_to_hunk_before_or_after_position(
14560            &snapshot,
14561            selection.head(),
14562            Direction::Next,
14563            window,
14564            cx,
14565        );
14566    }
14567
14568    pub fn go_to_hunk_before_or_after_position(
14569        &mut self,
14570        snapshot: &EditorSnapshot,
14571        position: Point,
14572        direction: Direction,
14573        window: &mut Window,
14574        cx: &mut Context<Editor>,
14575    ) {
14576        let row = if direction == Direction::Next {
14577            self.hunk_after_position(snapshot, position)
14578                .map(|hunk| hunk.row_range.start)
14579        } else {
14580            self.hunk_before_position(snapshot, position)
14581        };
14582
14583        if let Some(row) = row {
14584            let destination = Point::new(row.0, 0);
14585            let autoscroll = Autoscroll::center();
14586
14587            self.unfold_ranges(&[destination..destination], false, false, cx);
14588            self.change_selections(Some(autoscroll), window, cx, |s| {
14589                s.select_ranges([destination..destination]);
14590            });
14591        }
14592    }
14593
14594    fn hunk_after_position(
14595        &mut self,
14596        snapshot: &EditorSnapshot,
14597        position: Point,
14598    ) -> Option<MultiBufferDiffHunk> {
14599        snapshot
14600            .buffer_snapshot
14601            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14602            .find(|hunk| hunk.row_range.start.0 > position.row)
14603            .or_else(|| {
14604                snapshot
14605                    .buffer_snapshot
14606                    .diff_hunks_in_range(Point::zero()..position)
14607                    .find(|hunk| hunk.row_range.end.0 < position.row)
14608            })
14609    }
14610
14611    fn go_to_prev_hunk(
14612        &mut self,
14613        _: &GoToPreviousHunk,
14614        window: &mut Window,
14615        cx: &mut Context<Self>,
14616    ) {
14617        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14618        let snapshot = self.snapshot(window, cx);
14619        let selection = self.selections.newest::<Point>(cx);
14620        self.go_to_hunk_before_or_after_position(
14621            &snapshot,
14622            selection.head(),
14623            Direction::Prev,
14624            window,
14625            cx,
14626        );
14627    }
14628
14629    fn hunk_before_position(
14630        &mut self,
14631        snapshot: &EditorSnapshot,
14632        position: Point,
14633    ) -> Option<MultiBufferRow> {
14634        snapshot
14635            .buffer_snapshot
14636            .diff_hunk_before(position)
14637            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14638    }
14639
14640    fn go_to_next_change(
14641        &mut self,
14642        _: &GoToNextChange,
14643        window: &mut Window,
14644        cx: &mut Context<Self>,
14645    ) {
14646        if let Some(selections) = self
14647            .change_list
14648            .next_change(1, Direction::Next)
14649            .map(|s| s.to_vec())
14650        {
14651            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14652                let map = s.display_map();
14653                s.select_display_ranges(selections.iter().map(|a| {
14654                    let point = a.to_display_point(&map);
14655                    point..point
14656                }))
14657            })
14658        }
14659    }
14660
14661    fn go_to_previous_change(
14662        &mut self,
14663        _: &GoToPreviousChange,
14664        window: &mut Window,
14665        cx: &mut Context<Self>,
14666    ) {
14667        if let Some(selections) = self
14668            .change_list
14669            .next_change(1, Direction::Prev)
14670            .map(|s| s.to_vec())
14671        {
14672            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14673                let map = s.display_map();
14674                s.select_display_ranges(selections.iter().map(|a| {
14675                    let point = a.to_display_point(&map);
14676                    point..point
14677                }))
14678            })
14679        }
14680    }
14681
14682    fn go_to_line<T: 'static>(
14683        &mut self,
14684        position: Anchor,
14685        highlight_color: Option<Hsla>,
14686        window: &mut Window,
14687        cx: &mut Context<Self>,
14688    ) {
14689        let snapshot = self.snapshot(window, cx).display_snapshot;
14690        let position = position.to_point(&snapshot.buffer_snapshot);
14691        let start = snapshot
14692            .buffer_snapshot
14693            .clip_point(Point::new(position.row, 0), Bias::Left);
14694        let end = start + Point::new(1, 0);
14695        let start = snapshot.buffer_snapshot.anchor_before(start);
14696        let end = snapshot.buffer_snapshot.anchor_before(end);
14697
14698        self.highlight_rows::<T>(
14699            start..end,
14700            highlight_color
14701                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14702            Default::default(),
14703            cx,
14704        );
14705
14706        if self.buffer.read(cx).is_singleton() {
14707            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14708        }
14709    }
14710
14711    pub fn go_to_definition(
14712        &mut self,
14713        _: &GoToDefinition,
14714        window: &mut Window,
14715        cx: &mut Context<Self>,
14716    ) -> Task<Result<Navigated>> {
14717        let definition =
14718            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14719        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14720        cx.spawn_in(window, async move |editor, cx| {
14721            if definition.await? == Navigated::Yes {
14722                return Ok(Navigated::Yes);
14723            }
14724            match fallback_strategy {
14725                GoToDefinitionFallback::None => Ok(Navigated::No),
14726                GoToDefinitionFallback::FindAllReferences => {
14727                    match editor.update_in(cx, |editor, window, cx| {
14728                        editor.find_all_references(&FindAllReferences, window, cx)
14729                    })? {
14730                        Some(references) => references.await,
14731                        None => Ok(Navigated::No),
14732                    }
14733                }
14734            }
14735        })
14736    }
14737
14738    pub fn go_to_declaration(
14739        &mut self,
14740        _: &GoToDeclaration,
14741        window: &mut Window,
14742        cx: &mut Context<Self>,
14743    ) -> Task<Result<Navigated>> {
14744        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14745    }
14746
14747    pub fn go_to_declaration_split(
14748        &mut self,
14749        _: &GoToDeclaration,
14750        window: &mut Window,
14751        cx: &mut Context<Self>,
14752    ) -> Task<Result<Navigated>> {
14753        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14754    }
14755
14756    pub fn go_to_implementation(
14757        &mut self,
14758        _: &GoToImplementation,
14759        window: &mut Window,
14760        cx: &mut Context<Self>,
14761    ) -> Task<Result<Navigated>> {
14762        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14763    }
14764
14765    pub fn go_to_implementation_split(
14766        &mut self,
14767        _: &GoToImplementationSplit,
14768        window: &mut Window,
14769        cx: &mut Context<Self>,
14770    ) -> Task<Result<Navigated>> {
14771        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14772    }
14773
14774    pub fn go_to_type_definition(
14775        &mut self,
14776        _: &GoToTypeDefinition,
14777        window: &mut Window,
14778        cx: &mut Context<Self>,
14779    ) -> Task<Result<Navigated>> {
14780        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14781    }
14782
14783    pub fn go_to_definition_split(
14784        &mut self,
14785        _: &GoToDefinitionSplit,
14786        window: &mut Window,
14787        cx: &mut Context<Self>,
14788    ) -> Task<Result<Navigated>> {
14789        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14790    }
14791
14792    pub fn go_to_type_definition_split(
14793        &mut self,
14794        _: &GoToTypeDefinitionSplit,
14795        window: &mut Window,
14796        cx: &mut Context<Self>,
14797    ) -> Task<Result<Navigated>> {
14798        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14799    }
14800
14801    fn go_to_definition_of_kind(
14802        &mut self,
14803        kind: GotoDefinitionKind,
14804        split: bool,
14805        window: &mut Window,
14806        cx: &mut Context<Self>,
14807    ) -> Task<Result<Navigated>> {
14808        let Some(provider) = self.semantics_provider.clone() else {
14809            return Task::ready(Ok(Navigated::No));
14810        };
14811        let head = self.selections.newest::<usize>(cx).head();
14812        let buffer = self.buffer.read(cx);
14813        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14814            text_anchor
14815        } else {
14816            return Task::ready(Ok(Navigated::No));
14817        };
14818
14819        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14820            return Task::ready(Ok(Navigated::No));
14821        };
14822
14823        cx.spawn_in(window, async move |editor, cx| {
14824            let definitions = definitions.await?;
14825            let navigated = editor
14826                .update_in(cx, |editor, window, cx| {
14827                    editor.navigate_to_hover_links(
14828                        Some(kind),
14829                        definitions
14830                            .into_iter()
14831                            .filter(|location| {
14832                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14833                            })
14834                            .map(HoverLink::Text)
14835                            .collect::<Vec<_>>(),
14836                        split,
14837                        window,
14838                        cx,
14839                    )
14840                })?
14841                .await?;
14842            anyhow::Ok(navigated)
14843        })
14844    }
14845
14846    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14847        let selection = self.selections.newest_anchor();
14848        let head = selection.head();
14849        let tail = selection.tail();
14850
14851        let Some((buffer, start_position)) =
14852            self.buffer.read(cx).text_anchor_for_position(head, cx)
14853        else {
14854            return;
14855        };
14856
14857        let end_position = if head != tail {
14858            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14859                return;
14860            };
14861            Some(pos)
14862        } else {
14863            None
14864        };
14865
14866        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14867            let url = if let Some(end_pos) = end_position {
14868                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14869            } else {
14870                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14871            };
14872
14873            if let Some(url) = url {
14874                editor.update(cx, |_, cx| {
14875                    cx.open_url(&url);
14876                })
14877            } else {
14878                Ok(())
14879            }
14880        });
14881
14882        url_finder.detach();
14883    }
14884
14885    pub fn open_selected_filename(
14886        &mut self,
14887        _: &OpenSelectedFilename,
14888        window: &mut Window,
14889        cx: &mut Context<Self>,
14890    ) {
14891        let Some(workspace) = self.workspace() else {
14892            return;
14893        };
14894
14895        let position = self.selections.newest_anchor().head();
14896
14897        let Some((buffer, buffer_position)) =
14898            self.buffer.read(cx).text_anchor_for_position(position, cx)
14899        else {
14900            return;
14901        };
14902
14903        let project = self.project.clone();
14904
14905        cx.spawn_in(window, async move |_, cx| {
14906            let result = find_file(&buffer, project, buffer_position, cx).await;
14907
14908            if let Some((_, path)) = result {
14909                workspace
14910                    .update_in(cx, |workspace, window, cx| {
14911                        workspace.open_resolved_path(path, window, cx)
14912                    })?
14913                    .await?;
14914            }
14915            anyhow::Ok(())
14916        })
14917        .detach();
14918    }
14919
14920    pub(crate) fn navigate_to_hover_links(
14921        &mut self,
14922        kind: Option<GotoDefinitionKind>,
14923        mut definitions: Vec<HoverLink>,
14924        split: bool,
14925        window: &mut Window,
14926        cx: &mut Context<Editor>,
14927    ) -> Task<Result<Navigated>> {
14928        // If there is one definition, just open it directly
14929        if definitions.len() == 1 {
14930            let definition = definitions.pop().unwrap();
14931
14932            enum TargetTaskResult {
14933                Location(Option<Location>),
14934                AlreadyNavigated,
14935            }
14936
14937            let target_task = match definition {
14938                HoverLink::Text(link) => {
14939                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14940                }
14941                HoverLink::InlayHint(lsp_location, server_id) => {
14942                    let computation =
14943                        self.compute_target_location(lsp_location, server_id, window, cx);
14944                    cx.background_spawn(async move {
14945                        let location = computation.await?;
14946                        Ok(TargetTaskResult::Location(location))
14947                    })
14948                }
14949                HoverLink::Url(url) => {
14950                    cx.open_url(&url);
14951                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14952                }
14953                HoverLink::File(path) => {
14954                    if let Some(workspace) = self.workspace() {
14955                        cx.spawn_in(window, async move |_, cx| {
14956                            workspace
14957                                .update_in(cx, |workspace, window, cx| {
14958                                    workspace.open_resolved_path(path, window, cx)
14959                                })?
14960                                .await
14961                                .map(|_| TargetTaskResult::AlreadyNavigated)
14962                        })
14963                    } else {
14964                        Task::ready(Ok(TargetTaskResult::Location(None)))
14965                    }
14966                }
14967            };
14968            cx.spawn_in(window, async move |editor, cx| {
14969                let target = match target_task.await.context("target resolution task")? {
14970                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14971                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14972                    TargetTaskResult::Location(Some(target)) => target,
14973                };
14974
14975                editor.update_in(cx, |editor, window, cx| {
14976                    let Some(workspace) = editor.workspace() else {
14977                        return Navigated::No;
14978                    };
14979                    let pane = workspace.read(cx).active_pane().clone();
14980
14981                    let range = target.range.to_point(target.buffer.read(cx));
14982                    let range = editor.range_for_match(&range);
14983                    let range = collapse_multiline_range(range);
14984
14985                    if !split
14986                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14987                    {
14988                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14989                    } else {
14990                        window.defer(cx, move |window, cx| {
14991                            let target_editor: Entity<Self> =
14992                                workspace.update(cx, |workspace, cx| {
14993                                    let pane = if split {
14994                                        workspace.adjacent_pane(window, cx)
14995                                    } else {
14996                                        workspace.active_pane().clone()
14997                                    };
14998
14999                                    workspace.open_project_item(
15000                                        pane,
15001                                        target.buffer.clone(),
15002                                        true,
15003                                        true,
15004                                        window,
15005                                        cx,
15006                                    )
15007                                });
15008                            target_editor.update(cx, |target_editor, cx| {
15009                                // When selecting a definition in a different buffer, disable the nav history
15010                                // to avoid creating a history entry at the previous cursor location.
15011                                pane.update(cx, |pane, _| pane.disable_history());
15012                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15013                                pane.update(cx, |pane, _| pane.enable_history());
15014                            });
15015                        });
15016                    }
15017                    Navigated::Yes
15018                })
15019            })
15020        } else if !definitions.is_empty() {
15021            cx.spawn_in(window, async move |editor, cx| {
15022                let (title, location_tasks, workspace) = editor
15023                    .update_in(cx, |editor, window, cx| {
15024                        let tab_kind = match kind {
15025                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15026                            _ => "Definitions",
15027                        };
15028                        let title = definitions
15029                            .iter()
15030                            .find_map(|definition| match definition {
15031                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15032                                    let buffer = origin.buffer.read(cx);
15033                                    format!(
15034                                        "{} for {}",
15035                                        tab_kind,
15036                                        buffer
15037                                            .text_for_range(origin.range.clone())
15038                                            .collect::<String>()
15039                                    )
15040                                }),
15041                                HoverLink::InlayHint(_, _) => None,
15042                                HoverLink::Url(_) => None,
15043                                HoverLink::File(_) => None,
15044                            })
15045                            .unwrap_or(tab_kind.to_string());
15046                        let location_tasks = definitions
15047                            .into_iter()
15048                            .map(|definition| match definition {
15049                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15050                                HoverLink::InlayHint(lsp_location, server_id) => editor
15051                                    .compute_target_location(lsp_location, server_id, window, cx),
15052                                HoverLink::Url(_) => Task::ready(Ok(None)),
15053                                HoverLink::File(_) => Task::ready(Ok(None)),
15054                            })
15055                            .collect::<Vec<_>>();
15056                        (title, location_tasks, editor.workspace().clone())
15057                    })
15058                    .context("location tasks preparation")?;
15059
15060                let locations = future::join_all(location_tasks)
15061                    .await
15062                    .into_iter()
15063                    .filter_map(|location| location.transpose())
15064                    .collect::<Result<_>>()
15065                    .context("location tasks")?;
15066
15067                let Some(workspace) = workspace else {
15068                    return Ok(Navigated::No);
15069                };
15070                let opened = workspace
15071                    .update_in(cx, |workspace, window, cx| {
15072                        Self::open_locations_in_multibuffer(
15073                            workspace,
15074                            locations,
15075                            title,
15076                            split,
15077                            MultibufferSelectionMode::First,
15078                            window,
15079                            cx,
15080                        )
15081                    })
15082                    .ok();
15083
15084                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15085            })
15086        } else {
15087            Task::ready(Ok(Navigated::No))
15088        }
15089    }
15090
15091    fn compute_target_location(
15092        &self,
15093        lsp_location: lsp::Location,
15094        server_id: LanguageServerId,
15095        window: &mut Window,
15096        cx: &mut Context<Self>,
15097    ) -> Task<anyhow::Result<Option<Location>>> {
15098        let Some(project) = self.project.clone() else {
15099            return Task::ready(Ok(None));
15100        };
15101
15102        cx.spawn_in(window, async move |editor, cx| {
15103            let location_task = editor.update(cx, |_, cx| {
15104                project.update(cx, |project, cx| {
15105                    let language_server_name = project
15106                        .language_server_statuses(cx)
15107                        .find(|(id, _)| server_id == *id)
15108                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15109                    language_server_name.map(|language_server_name| {
15110                        project.open_local_buffer_via_lsp(
15111                            lsp_location.uri.clone(),
15112                            server_id,
15113                            language_server_name,
15114                            cx,
15115                        )
15116                    })
15117                })
15118            })?;
15119            let location = match location_task {
15120                Some(task) => Some({
15121                    let target_buffer_handle = task.await.context("open local buffer")?;
15122                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15123                        let target_start = target_buffer
15124                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15125                        let target_end = target_buffer
15126                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15127                        target_buffer.anchor_after(target_start)
15128                            ..target_buffer.anchor_before(target_end)
15129                    })?;
15130                    Location {
15131                        buffer: target_buffer_handle,
15132                        range,
15133                    }
15134                }),
15135                None => None,
15136            };
15137            Ok(location)
15138        })
15139    }
15140
15141    pub fn find_all_references(
15142        &mut self,
15143        _: &FindAllReferences,
15144        window: &mut Window,
15145        cx: &mut Context<Self>,
15146    ) -> Option<Task<Result<Navigated>>> {
15147        let selection = self.selections.newest::<usize>(cx);
15148        let multi_buffer = self.buffer.read(cx);
15149        let head = selection.head();
15150
15151        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15152        let head_anchor = multi_buffer_snapshot.anchor_at(
15153            head,
15154            if head < selection.tail() {
15155                Bias::Right
15156            } else {
15157                Bias::Left
15158            },
15159        );
15160
15161        match self
15162            .find_all_references_task_sources
15163            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15164        {
15165            Ok(_) => {
15166                log::info!(
15167                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15168                );
15169                return None;
15170            }
15171            Err(i) => {
15172                self.find_all_references_task_sources.insert(i, head_anchor);
15173            }
15174        }
15175
15176        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15177        let workspace = self.workspace()?;
15178        let project = workspace.read(cx).project().clone();
15179        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15180        Some(cx.spawn_in(window, async move |editor, cx| {
15181            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15182                if let Ok(i) = editor
15183                    .find_all_references_task_sources
15184                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15185                {
15186                    editor.find_all_references_task_sources.remove(i);
15187                }
15188            });
15189
15190            let locations = references.await?;
15191            if locations.is_empty() {
15192                return anyhow::Ok(Navigated::No);
15193            }
15194
15195            workspace.update_in(cx, |workspace, window, cx| {
15196                let title = locations
15197                    .first()
15198                    .as_ref()
15199                    .map(|location| {
15200                        let buffer = location.buffer.read(cx);
15201                        format!(
15202                            "References to `{}`",
15203                            buffer
15204                                .text_for_range(location.range.clone())
15205                                .collect::<String>()
15206                        )
15207                    })
15208                    .unwrap();
15209                Self::open_locations_in_multibuffer(
15210                    workspace,
15211                    locations,
15212                    title,
15213                    false,
15214                    MultibufferSelectionMode::First,
15215                    window,
15216                    cx,
15217                );
15218                Navigated::Yes
15219            })
15220        }))
15221    }
15222
15223    /// Opens a multibuffer with the given project locations in it
15224    pub fn open_locations_in_multibuffer(
15225        workspace: &mut Workspace,
15226        mut locations: Vec<Location>,
15227        title: String,
15228        split: bool,
15229        multibuffer_selection_mode: MultibufferSelectionMode,
15230        window: &mut Window,
15231        cx: &mut Context<Workspace>,
15232    ) {
15233        // If there are multiple definitions, open them in a multibuffer
15234        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15235        let mut locations = locations.into_iter().peekable();
15236        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15237        let capability = workspace.project().read(cx).capability();
15238
15239        let excerpt_buffer = cx.new(|cx| {
15240            let mut multibuffer = MultiBuffer::new(capability);
15241            while let Some(location) = locations.next() {
15242                let buffer = location.buffer.read(cx);
15243                let mut ranges_for_buffer = Vec::new();
15244                let range = location.range.to_point(buffer);
15245                ranges_for_buffer.push(range.clone());
15246
15247                while let Some(next_location) = locations.peek() {
15248                    if next_location.buffer == location.buffer {
15249                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15250                        locations.next();
15251                    } else {
15252                        break;
15253                    }
15254                }
15255
15256                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15257                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15258                    PathKey::for_buffer(&location.buffer, cx),
15259                    location.buffer.clone(),
15260                    ranges_for_buffer,
15261                    DEFAULT_MULTIBUFFER_CONTEXT,
15262                    cx,
15263                );
15264                ranges.extend(new_ranges)
15265            }
15266
15267            multibuffer.with_title(title)
15268        });
15269
15270        let editor = cx.new(|cx| {
15271            Editor::for_multibuffer(
15272                excerpt_buffer,
15273                Some(workspace.project().clone()),
15274                window,
15275                cx,
15276            )
15277        });
15278        editor.update(cx, |editor, cx| {
15279            match multibuffer_selection_mode {
15280                MultibufferSelectionMode::First => {
15281                    if let Some(first_range) = ranges.first() {
15282                        editor.change_selections(None, window, cx, |selections| {
15283                            selections.clear_disjoint();
15284                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15285                        });
15286                    }
15287                    editor.highlight_background::<Self>(
15288                        &ranges,
15289                        |theme| theme.editor_highlighted_line_background,
15290                        cx,
15291                    );
15292                }
15293                MultibufferSelectionMode::All => {
15294                    editor.change_selections(None, window, cx, |selections| {
15295                        selections.clear_disjoint();
15296                        selections.select_anchor_ranges(ranges);
15297                    });
15298                }
15299            }
15300            editor.register_buffers_with_language_servers(cx);
15301        });
15302
15303        let item = Box::new(editor);
15304        let item_id = item.item_id();
15305
15306        if split {
15307            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15308        } else {
15309            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15310                let (preview_item_id, preview_item_idx) =
15311                    workspace.active_pane().read_with(cx, |pane, _| {
15312                        (pane.preview_item_id(), pane.preview_item_idx())
15313                    });
15314
15315                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15316
15317                if let Some(preview_item_id) = preview_item_id {
15318                    workspace.active_pane().update(cx, |pane, cx| {
15319                        pane.remove_item(preview_item_id, false, false, window, cx);
15320                    });
15321                }
15322            } else {
15323                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15324            }
15325        }
15326        workspace.active_pane().update(cx, |pane, cx| {
15327            pane.set_preview_item_id(Some(item_id), cx);
15328        });
15329    }
15330
15331    pub fn rename(
15332        &mut self,
15333        _: &Rename,
15334        window: &mut Window,
15335        cx: &mut Context<Self>,
15336    ) -> Option<Task<Result<()>>> {
15337        use language::ToOffset as _;
15338
15339        let provider = self.semantics_provider.clone()?;
15340        let selection = self.selections.newest_anchor().clone();
15341        let (cursor_buffer, cursor_buffer_position) = self
15342            .buffer
15343            .read(cx)
15344            .text_anchor_for_position(selection.head(), cx)?;
15345        let (tail_buffer, cursor_buffer_position_end) = self
15346            .buffer
15347            .read(cx)
15348            .text_anchor_for_position(selection.tail(), cx)?;
15349        if tail_buffer != cursor_buffer {
15350            return None;
15351        }
15352
15353        let snapshot = cursor_buffer.read(cx).snapshot();
15354        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15355        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15356        let prepare_rename = provider
15357            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15358            .unwrap_or_else(|| Task::ready(Ok(None)));
15359        drop(snapshot);
15360
15361        Some(cx.spawn_in(window, async move |this, cx| {
15362            let rename_range = if let Some(range) = prepare_rename.await? {
15363                Some(range)
15364            } else {
15365                this.update(cx, |this, cx| {
15366                    let buffer = this.buffer.read(cx).snapshot(cx);
15367                    let mut buffer_highlights = this
15368                        .document_highlights_for_position(selection.head(), &buffer)
15369                        .filter(|highlight| {
15370                            highlight.start.excerpt_id == selection.head().excerpt_id
15371                                && highlight.end.excerpt_id == selection.head().excerpt_id
15372                        });
15373                    buffer_highlights
15374                        .next()
15375                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15376                })?
15377            };
15378            if let Some(rename_range) = rename_range {
15379                this.update_in(cx, |this, window, cx| {
15380                    let snapshot = cursor_buffer.read(cx).snapshot();
15381                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15382                    let cursor_offset_in_rename_range =
15383                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15384                    let cursor_offset_in_rename_range_end =
15385                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15386
15387                    this.take_rename(false, window, cx);
15388                    let buffer = this.buffer.read(cx).read(cx);
15389                    let cursor_offset = selection.head().to_offset(&buffer);
15390                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15391                    let rename_end = rename_start + rename_buffer_range.len();
15392                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15393                    let mut old_highlight_id = None;
15394                    let old_name: Arc<str> = buffer
15395                        .chunks(rename_start..rename_end, true)
15396                        .map(|chunk| {
15397                            if old_highlight_id.is_none() {
15398                                old_highlight_id = chunk.syntax_highlight_id;
15399                            }
15400                            chunk.text
15401                        })
15402                        .collect::<String>()
15403                        .into();
15404
15405                    drop(buffer);
15406
15407                    // Position the selection in the rename editor so that it matches the current selection.
15408                    this.show_local_selections = false;
15409                    let rename_editor = cx.new(|cx| {
15410                        let mut editor = Editor::single_line(window, cx);
15411                        editor.buffer.update(cx, |buffer, cx| {
15412                            buffer.edit([(0..0, old_name.clone())], None, cx)
15413                        });
15414                        let rename_selection_range = match cursor_offset_in_rename_range
15415                            .cmp(&cursor_offset_in_rename_range_end)
15416                        {
15417                            Ordering::Equal => {
15418                                editor.select_all(&SelectAll, window, cx);
15419                                return editor;
15420                            }
15421                            Ordering::Less => {
15422                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15423                            }
15424                            Ordering::Greater => {
15425                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15426                            }
15427                        };
15428                        if rename_selection_range.end > old_name.len() {
15429                            editor.select_all(&SelectAll, window, cx);
15430                        } else {
15431                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15432                                s.select_ranges([rename_selection_range]);
15433                            });
15434                        }
15435                        editor
15436                    });
15437                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15438                        if e == &EditorEvent::Focused {
15439                            cx.emit(EditorEvent::FocusedIn)
15440                        }
15441                    })
15442                    .detach();
15443
15444                    let write_highlights =
15445                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15446                    let read_highlights =
15447                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15448                    let ranges = write_highlights
15449                        .iter()
15450                        .flat_map(|(_, ranges)| ranges.iter())
15451                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15452                        .cloned()
15453                        .collect();
15454
15455                    this.highlight_text::<Rename>(
15456                        ranges,
15457                        HighlightStyle {
15458                            fade_out: Some(0.6),
15459                            ..Default::default()
15460                        },
15461                        cx,
15462                    );
15463                    let rename_focus_handle = rename_editor.focus_handle(cx);
15464                    window.focus(&rename_focus_handle);
15465                    let block_id = this.insert_blocks(
15466                        [BlockProperties {
15467                            style: BlockStyle::Flex,
15468                            placement: BlockPlacement::Below(range.start),
15469                            height: Some(1),
15470                            render: Arc::new({
15471                                let rename_editor = rename_editor.clone();
15472                                move |cx: &mut BlockContext| {
15473                                    let mut text_style = cx.editor_style.text.clone();
15474                                    if let Some(highlight_style) = old_highlight_id
15475                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15476                                    {
15477                                        text_style = text_style.highlight(highlight_style);
15478                                    }
15479                                    div()
15480                                        .block_mouse_except_scroll()
15481                                        .pl(cx.anchor_x)
15482                                        .child(EditorElement::new(
15483                                            &rename_editor,
15484                                            EditorStyle {
15485                                                background: cx.theme().system().transparent,
15486                                                local_player: cx.editor_style.local_player,
15487                                                text: text_style,
15488                                                scrollbar_width: cx.editor_style.scrollbar_width,
15489                                                syntax: cx.editor_style.syntax.clone(),
15490                                                status: cx.editor_style.status.clone(),
15491                                                inlay_hints_style: HighlightStyle {
15492                                                    font_weight: Some(FontWeight::BOLD),
15493                                                    ..make_inlay_hints_style(cx.app)
15494                                                },
15495                                                inline_completion_styles: make_suggestion_styles(
15496                                                    cx.app,
15497                                                ),
15498                                                ..EditorStyle::default()
15499                                            },
15500                                        ))
15501                                        .into_any_element()
15502                                }
15503                            }),
15504                            priority: 0,
15505                            render_in_minimap: true,
15506                        }],
15507                        Some(Autoscroll::fit()),
15508                        cx,
15509                    )[0];
15510                    this.pending_rename = Some(RenameState {
15511                        range,
15512                        old_name,
15513                        editor: rename_editor,
15514                        block_id,
15515                    });
15516                })?;
15517            }
15518
15519            Ok(())
15520        }))
15521    }
15522
15523    pub fn confirm_rename(
15524        &mut self,
15525        _: &ConfirmRename,
15526        window: &mut Window,
15527        cx: &mut Context<Self>,
15528    ) -> Option<Task<Result<()>>> {
15529        let rename = self.take_rename(false, window, cx)?;
15530        let workspace = self.workspace()?.downgrade();
15531        let (buffer, start) = self
15532            .buffer
15533            .read(cx)
15534            .text_anchor_for_position(rename.range.start, cx)?;
15535        let (end_buffer, _) = self
15536            .buffer
15537            .read(cx)
15538            .text_anchor_for_position(rename.range.end, cx)?;
15539        if buffer != end_buffer {
15540            return None;
15541        }
15542
15543        let old_name = rename.old_name;
15544        let new_name = rename.editor.read(cx).text(cx);
15545
15546        let rename = self.semantics_provider.as_ref()?.perform_rename(
15547            &buffer,
15548            start,
15549            new_name.clone(),
15550            cx,
15551        )?;
15552
15553        Some(cx.spawn_in(window, async move |editor, cx| {
15554            let project_transaction = rename.await?;
15555            Self::open_project_transaction(
15556                &editor,
15557                workspace,
15558                project_transaction,
15559                format!("Rename: {}{}", old_name, new_name),
15560                cx,
15561            )
15562            .await?;
15563
15564            editor.update(cx, |editor, cx| {
15565                editor.refresh_document_highlights(cx);
15566            })?;
15567            Ok(())
15568        }))
15569    }
15570
15571    fn take_rename(
15572        &mut self,
15573        moving_cursor: bool,
15574        window: &mut Window,
15575        cx: &mut Context<Self>,
15576    ) -> Option<RenameState> {
15577        let rename = self.pending_rename.take()?;
15578        if rename.editor.focus_handle(cx).is_focused(window) {
15579            window.focus(&self.focus_handle);
15580        }
15581
15582        self.remove_blocks(
15583            [rename.block_id].into_iter().collect(),
15584            Some(Autoscroll::fit()),
15585            cx,
15586        );
15587        self.clear_highlights::<Rename>(cx);
15588        self.show_local_selections = true;
15589
15590        if moving_cursor {
15591            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15592                editor.selections.newest::<usize>(cx).head()
15593            });
15594
15595            // Update the selection to match the position of the selection inside
15596            // the rename editor.
15597            let snapshot = self.buffer.read(cx).read(cx);
15598            let rename_range = rename.range.to_offset(&snapshot);
15599            let cursor_in_editor = snapshot
15600                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15601                .min(rename_range.end);
15602            drop(snapshot);
15603
15604            self.change_selections(None, window, cx, |s| {
15605                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15606            });
15607        } else {
15608            self.refresh_document_highlights(cx);
15609        }
15610
15611        Some(rename)
15612    }
15613
15614    pub fn pending_rename(&self) -> Option<&RenameState> {
15615        self.pending_rename.as_ref()
15616    }
15617
15618    fn format(
15619        &mut self,
15620        _: &Format,
15621        window: &mut Window,
15622        cx: &mut Context<Self>,
15623    ) -> Option<Task<Result<()>>> {
15624        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15625
15626        let project = match &self.project {
15627            Some(project) => project.clone(),
15628            None => return None,
15629        };
15630
15631        Some(self.perform_format(
15632            project,
15633            FormatTrigger::Manual,
15634            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15635            window,
15636            cx,
15637        ))
15638    }
15639
15640    fn format_selections(
15641        &mut self,
15642        _: &FormatSelections,
15643        window: &mut Window,
15644        cx: &mut Context<Self>,
15645    ) -> Option<Task<Result<()>>> {
15646        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15647
15648        let project = match &self.project {
15649            Some(project) => project.clone(),
15650            None => return None,
15651        };
15652
15653        let ranges = self
15654            .selections
15655            .all_adjusted(cx)
15656            .into_iter()
15657            .map(|selection| selection.range())
15658            .collect_vec();
15659
15660        Some(self.perform_format(
15661            project,
15662            FormatTrigger::Manual,
15663            FormatTarget::Ranges(ranges),
15664            window,
15665            cx,
15666        ))
15667    }
15668
15669    fn perform_format(
15670        &mut self,
15671        project: Entity<Project>,
15672        trigger: FormatTrigger,
15673        target: FormatTarget,
15674        window: &mut Window,
15675        cx: &mut Context<Self>,
15676    ) -> Task<Result<()>> {
15677        let buffer = self.buffer.clone();
15678        let (buffers, target) = match target {
15679            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15680            FormatTarget::Ranges(selection_ranges) => {
15681                let multi_buffer = buffer.read(cx);
15682                let snapshot = multi_buffer.read(cx);
15683                let mut buffers = HashSet::default();
15684                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15685                    BTreeMap::new();
15686                for selection_range in selection_ranges {
15687                    for (buffer, buffer_range, _) in
15688                        snapshot.range_to_buffer_ranges(selection_range)
15689                    {
15690                        let buffer_id = buffer.remote_id();
15691                        let start = buffer.anchor_before(buffer_range.start);
15692                        let end = buffer.anchor_after(buffer_range.end);
15693                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15694                        buffer_id_to_ranges
15695                            .entry(buffer_id)
15696                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15697                            .or_insert_with(|| vec![start..end]);
15698                    }
15699                }
15700                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15701            }
15702        };
15703
15704        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15705        let selections_prev = transaction_id_prev
15706            .and_then(|transaction_id_prev| {
15707                // default to selections as they were after the last edit, if we have them,
15708                // instead of how they are now.
15709                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15710                // will take you back to where you made the last edit, instead of staying where you scrolled
15711                self.selection_history
15712                    .transaction(transaction_id_prev)
15713                    .map(|t| t.0.clone())
15714            })
15715            .unwrap_or_else(|| {
15716                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15717                self.selections.disjoint_anchors()
15718            });
15719
15720        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15721        let format = project.update(cx, |project, cx| {
15722            project.format(buffers, target, true, trigger, cx)
15723        });
15724
15725        cx.spawn_in(window, async move |editor, cx| {
15726            let transaction = futures::select_biased! {
15727                transaction = format.log_err().fuse() => transaction,
15728                () = timeout => {
15729                    log::warn!("timed out waiting for formatting");
15730                    None
15731                }
15732            };
15733
15734            buffer
15735                .update(cx, |buffer, cx| {
15736                    if let Some(transaction) = transaction {
15737                        if !buffer.is_singleton() {
15738                            buffer.push_transaction(&transaction.0, cx);
15739                        }
15740                    }
15741                    cx.notify();
15742                })
15743                .ok();
15744
15745            if let Some(transaction_id_now) =
15746                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15747            {
15748                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15749                if has_new_transaction {
15750                    _ = editor.update(cx, |editor, _| {
15751                        editor
15752                            .selection_history
15753                            .insert_transaction(transaction_id_now, selections_prev);
15754                    });
15755                }
15756            }
15757
15758            Ok(())
15759        })
15760    }
15761
15762    fn organize_imports(
15763        &mut self,
15764        _: &OrganizeImports,
15765        window: &mut Window,
15766        cx: &mut Context<Self>,
15767    ) -> Option<Task<Result<()>>> {
15768        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15769        let project = match &self.project {
15770            Some(project) => project.clone(),
15771            None => return None,
15772        };
15773        Some(self.perform_code_action_kind(
15774            project,
15775            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15776            window,
15777            cx,
15778        ))
15779    }
15780
15781    fn perform_code_action_kind(
15782        &mut self,
15783        project: Entity<Project>,
15784        kind: CodeActionKind,
15785        window: &mut Window,
15786        cx: &mut Context<Self>,
15787    ) -> Task<Result<()>> {
15788        let buffer = self.buffer.clone();
15789        let buffers = buffer.read(cx).all_buffers();
15790        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15791        let apply_action = project.update(cx, |project, cx| {
15792            project.apply_code_action_kind(buffers, kind, true, cx)
15793        });
15794        cx.spawn_in(window, async move |_, cx| {
15795            let transaction = futures::select_biased! {
15796                () = timeout => {
15797                    log::warn!("timed out waiting for executing code action");
15798                    None
15799                }
15800                transaction = apply_action.log_err().fuse() => transaction,
15801            };
15802            buffer
15803                .update(cx, |buffer, cx| {
15804                    // check if we need this
15805                    if let Some(transaction) = transaction {
15806                        if !buffer.is_singleton() {
15807                            buffer.push_transaction(&transaction.0, cx);
15808                        }
15809                    }
15810                    cx.notify();
15811                })
15812                .ok();
15813            Ok(())
15814        })
15815    }
15816
15817    fn restart_language_server(
15818        &mut self,
15819        _: &RestartLanguageServer,
15820        _: &mut Window,
15821        cx: &mut Context<Self>,
15822    ) {
15823        if let Some(project) = self.project.clone() {
15824            self.buffer.update(cx, |multi_buffer, cx| {
15825                project.update(cx, |project, cx| {
15826                    project.restart_language_servers_for_buffers(
15827                        multi_buffer.all_buffers().into_iter().collect(),
15828                        cx,
15829                    );
15830                });
15831            })
15832        }
15833    }
15834
15835    fn stop_language_server(
15836        &mut self,
15837        _: &StopLanguageServer,
15838        _: &mut Window,
15839        cx: &mut Context<Self>,
15840    ) {
15841        if let Some(project) = self.project.clone() {
15842            self.buffer.update(cx, |multi_buffer, cx| {
15843                project.update(cx, |project, cx| {
15844                    project.stop_language_servers_for_buffers(
15845                        multi_buffer.all_buffers().into_iter().collect(),
15846                        cx,
15847                    );
15848                    cx.emit(project::Event::RefreshInlayHints);
15849                });
15850            });
15851        }
15852    }
15853
15854    fn cancel_language_server_work(
15855        workspace: &mut Workspace,
15856        _: &actions::CancelLanguageServerWork,
15857        _: &mut Window,
15858        cx: &mut Context<Workspace>,
15859    ) {
15860        let project = workspace.project();
15861        let buffers = workspace
15862            .active_item(cx)
15863            .and_then(|item| item.act_as::<Editor>(cx))
15864            .map_or(HashSet::default(), |editor| {
15865                editor.read(cx).buffer.read(cx).all_buffers()
15866            });
15867        project.update(cx, |project, cx| {
15868            project.cancel_language_server_work_for_buffers(buffers, cx);
15869        });
15870    }
15871
15872    fn show_character_palette(
15873        &mut self,
15874        _: &ShowCharacterPalette,
15875        window: &mut Window,
15876        _: &mut Context<Self>,
15877    ) {
15878        window.show_character_palette();
15879    }
15880
15881    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15882        if self.mode.is_minimap() {
15883            return;
15884        }
15885
15886        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15887            let buffer = self.buffer.read(cx).snapshot(cx);
15888            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15889            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15890            let is_valid = buffer
15891                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15892                .any(|entry| {
15893                    entry.diagnostic.is_primary
15894                        && !entry.range.is_empty()
15895                        && entry.range.start == primary_range_start
15896                        && entry.diagnostic.message == active_diagnostics.active_message
15897                });
15898
15899            if !is_valid {
15900                self.dismiss_diagnostics(cx);
15901            }
15902        }
15903    }
15904
15905    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15906        match &self.active_diagnostics {
15907            ActiveDiagnostic::Group(group) => Some(group),
15908            _ => None,
15909        }
15910    }
15911
15912    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15913        self.dismiss_diagnostics(cx);
15914        self.active_diagnostics = ActiveDiagnostic::All;
15915    }
15916
15917    fn activate_diagnostics(
15918        &mut self,
15919        buffer_id: BufferId,
15920        diagnostic: DiagnosticEntry<usize>,
15921        window: &mut Window,
15922        cx: &mut Context<Self>,
15923    ) {
15924        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15925            return;
15926        }
15927        self.dismiss_diagnostics(cx);
15928        let snapshot = self.snapshot(window, cx);
15929        let buffer = self.buffer.read(cx).snapshot(cx);
15930        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15931            return;
15932        };
15933
15934        let diagnostic_group = buffer
15935            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15936            .collect::<Vec<_>>();
15937
15938        let blocks =
15939            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15940
15941        let blocks = self.display_map.update(cx, |display_map, cx| {
15942            display_map.insert_blocks(blocks, cx).into_iter().collect()
15943        });
15944        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15945            active_range: buffer.anchor_before(diagnostic.range.start)
15946                ..buffer.anchor_after(diagnostic.range.end),
15947            active_message: diagnostic.diagnostic.message.clone(),
15948            group_id: diagnostic.diagnostic.group_id,
15949            blocks,
15950        });
15951        cx.notify();
15952    }
15953
15954    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15955        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15956            return;
15957        };
15958
15959        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15960        if let ActiveDiagnostic::Group(group) = prev {
15961            self.display_map.update(cx, |display_map, cx| {
15962                display_map.remove_blocks(group.blocks, cx);
15963            });
15964            cx.notify();
15965        }
15966    }
15967
15968    /// Disable inline diagnostics rendering for this editor.
15969    pub fn disable_inline_diagnostics(&mut self) {
15970        self.inline_diagnostics_enabled = false;
15971        self.inline_diagnostics_update = Task::ready(());
15972        self.inline_diagnostics.clear();
15973    }
15974
15975    pub fn diagnostics_enabled(&self) -> bool {
15976        self.mode.is_full()
15977    }
15978
15979    pub fn inline_diagnostics_enabled(&self) -> bool {
15980        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15981    }
15982
15983    pub fn show_inline_diagnostics(&self) -> bool {
15984        self.show_inline_diagnostics
15985    }
15986
15987    pub fn toggle_inline_diagnostics(
15988        &mut self,
15989        _: &ToggleInlineDiagnostics,
15990        window: &mut Window,
15991        cx: &mut Context<Editor>,
15992    ) {
15993        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15994        self.refresh_inline_diagnostics(false, window, cx);
15995    }
15996
15997    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15998        self.diagnostics_max_severity = severity;
15999        self.display_map.update(cx, |display_map, _| {
16000            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16001        });
16002    }
16003
16004    pub fn toggle_diagnostics(
16005        &mut self,
16006        _: &ToggleDiagnostics,
16007        window: &mut Window,
16008        cx: &mut Context<Editor>,
16009    ) {
16010        if !self.diagnostics_enabled() {
16011            return;
16012        }
16013
16014        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16015            EditorSettings::get_global(cx)
16016                .diagnostics_max_severity
16017                .filter(|severity| severity != &DiagnosticSeverity::Off)
16018                .unwrap_or(DiagnosticSeverity::Hint)
16019        } else {
16020            DiagnosticSeverity::Off
16021        };
16022        self.set_max_diagnostics_severity(new_severity, cx);
16023        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16024            self.active_diagnostics = ActiveDiagnostic::None;
16025            self.inline_diagnostics_update = Task::ready(());
16026            self.inline_diagnostics.clear();
16027        } else {
16028            self.refresh_inline_diagnostics(false, window, cx);
16029        }
16030
16031        cx.notify();
16032    }
16033
16034    pub fn toggle_minimap(
16035        &mut self,
16036        _: &ToggleMinimap,
16037        window: &mut Window,
16038        cx: &mut Context<Editor>,
16039    ) {
16040        if self.supports_minimap(cx) {
16041            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16042        }
16043    }
16044
16045    fn refresh_inline_diagnostics(
16046        &mut self,
16047        debounce: bool,
16048        window: &mut Window,
16049        cx: &mut Context<Self>,
16050    ) {
16051        let max_severity = ProjectSettings::get_global(cx)
16052            .diagnostics
16053            .inline
16054            .max_severity
16055            .unwrap_or(self.diagnostics_max_severity);
16056
16057        if !self.inline_diagnostics_enabled()
16058            || !self.show_inline_diagnostics
16059            || max_severity == DiagnosticSeverity::Off
16060        {
16061            self.inline_diagnostics_update = Task::ready(());
16062            self.inline_diagnostics.clear();
16063            return;
16064        }
16065
16066        let debounce_ms = ProjectSettings::get_global(cx)
16067            .diagnostics
16068            .inline
16069            .update_debounce_ms;
16070        let debounce = if debounce && debounce_ms > 0 {
16071            Some(Duration::from_millis(debounce_ms))
16072        } else {
16073            None
16074        };
16075        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16076            if let Some(debounce) = debounce {
16077                cx.background_executor().timer(debounce).await;
16078            }
16079            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16080                editor
16081                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16082                    .ok()
16083            }) else {
16084                return;
16085            };
16086
16087            let new_inline_diagnostics = cx
16088                .background_spawn(async move {
16089                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16090                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16091                        let message = diagnostic_entry
16092                            .diagnostic
16093                            .message
16094                            .split_once('\n')
16095                            .map(|(line, _)| line)
16096                            .map(SharedString::new)
16097                            .unwrap_or_else(|| {
16098                                SharedString::from(diagnostic_entry.diagnostic.message)
16099                            });
16100                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16101                        let (Ok(i) | Err(i)) = inline_diagnostics
16102                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16103                        inline_diagnostics.insert(
16104                            i,
16105                            (
16106                                start_anchor,
16107                                InlineDiagnostic {
16108                                    message,
16109                                    group_id: diagnostic_entry.diagnostic.group_id,
16110                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16111                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16112                                    severity: diagnostic_entry.diagnostic.severity,
16113                                },
16114                            ),
16115                        );
16116                    }
16117                    inline_diagnostics
16118                })
16119                .await;
16120
16121            editor
16122                .update(cx, |editor, cx| {
16123                    editor.inline_diagnostics = new_inline_diagnostics;
16124                    cx.notify();
16125                })
16126                .ok();
16127        });
16128    }
16129
16130    fn pull_diagnostics(
16131        &mut self,
16132        buffer_id: Option<BufferId>,
16133        window: &Window,
16134        cx: &mut Context<Self>,
16135    ) -> Option<()> {
16136        if !self.mode().is_full() {
16137            return None;
16138        }
16139        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16140            .diagnostics
16141            .lsp_pull_diagnostics;
16142        if !pull_diagnostics_settings.enabled {
16143            return None;
16144        }
16145        let project = self.project.as_ref()?.downgrade();
16146        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16147        let mut buffers = self.buffer.read(cx).all_buffers();
16148        if let Some(buffer_id) = buffer_id {
16149            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16150        }
16151
16152        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16153            cx.background_executor().timer(debounce).await;
16154
16155            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16156                buffers
16157                    .into_iter()
16158                    .flat_map(|buffer| {
16159                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16160                    })
16161                    .collect::<FuturesUnordered<_>>()
16162            }) else {
16163                return;
16164            };
16165
16166            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16167                match pull_task {
16168                    Ok(()) => {
16169                        if editor
16170                            .update_in(cx, |editor, window, cx| {
16171                                editor.update_diagnostics_state(window, cx);
16172                            })
16173                            .is_err()
16174                        {
16175                            return;
16176                        }
16177                    }
16178                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16179                }
16180            }
16181        });
16182
16183        Some(())
16184    }
16185
16186    pub fn set_selections_from_remote(
16187        &mut self,
16188        selections: Vec<Selection<Anchor>>,
16189        pending_selection: Option<Selection<Anchor>>,
16190        window: &mut Window,
16191        cx: &mut Context<Self>,
16192    ) {
16193        let old_cursor_position = self.selections.newest_anchor().head();
16194        self.selections.change_with(cx, |s| {
16195            s.select_anchors(selections);
16196            if let Some(pending_selection) = pending_selection {
16197                s.set_pending(pending_selection, SelectMode::Character);
16198            } else {
16199                s.clear_pending();
16200            }
16201        });
16202        self.selections_did_change(
16203            false,
16204            &old_cursor_position,
16205            SelectionEffects::default(),
16206            window,
16207            cx,
16208        );
16209    }
16210
16211    pub fn transact(
16212        &mut self,
16213        window: &mut Window,
16214        cx: &mut Context<Self>,
16215        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16216    ) -> Option<TransactionId> {
16217        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16218            this.start_transaction_at(Instant::now(), window, cx);
16219            update(this, window, cx);
16220            this.end_transaction_at(Instant::now(), cx)
16221        })
16222    }
16223
16224    pub fn start_transaction_at(
16225        &mut self,
16226        now: Instant,
16227        window: &mut Window,
16228        cx: &mut Context<Self>,
16229    ) {
16230        self.end_selection(window, cx);
16231        if let Some(tx_id) = self
16232            .buffer
16233            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16234        {
16235            self.selection_history
16236                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16237            cx.emit(EditorEvent::TransactionBegun {
16238                transaction_id: tx_id,
16239            })
16240        }
16241    }
16242
16243    pub fn end_transaction_at(
16244        &mut self,
16245        now: Instant,
16246        cx: &mut Context<Self>,
16247    ) -> Option<TransactionId> {
16248        if let Some(transaction_id) = self
16249            .buffer
16250            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16251        {
16252            if let Some((_, end_selections)) =
16253                self.selection_history.transaction_mut(transaction_id)
16254            {
16255                *end_selections = Some(self.selections.disjoint_anchors());
16256            } else {
16257                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16258            }
16259
16260            cx.emit(EditorEvent::Edited { transaction_id });
16261            Some(transaction_id)
16262        } else {
16263            None
16264        }
16265    }
16266
16267    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16268        if self.selection_mark_mode {
16269            self.change_selections(None, window, cx, |s| {
16270                s.move_with(|_, sel| {
16271                    sel.collapse_to(sel.head(), SelectionGoal::None);
16272                });
16273            })
16274        }
16275        self.selection_mark_mode = true;
16276        cx.notify();
16277    }
16278
16279    pub fn swap_selection_ends(
16280        &mut self,
16281        _: &actions::SwapSelectionEnds,
16282        window: &mut Window,
16283        cx: &mut Context<Self>,
16284    ) {
16285        self.change_selections(None, window, cx, |s| {
16286            s.move_with(|_, sel| {
16287                if sel.start != sel.end {
16288                    sel.reversed = !sel.reversed
16289                }
16290            });
16291        });
16292        self.request_autoscroll(Autoscroll::newest(), cx);
16293        cx.notify();
16294    }
16295
16296    pub fn toggle_fold(
16297        &mut self,
16298        _: &actions::ToggleFold,
16299        window: &mut Window,
16300        cx: &mut Context<Self>,
16301    ) {
16302        if self.is_singleton(cx) {
16303            let selection = self.selections.newest::<Point>(cx);
16304
16305            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16306            let range = if selection.is_empty() {
16307                let point = selection.head().to_display_point(&display_map);
16308                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16309                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16310                    .to_point(&display_map);
16311                start..end
16312            } else {
16313                selection.range()
16314            };
16315            if display_map.folds_in_range(range).next().is_some() {
16316                self.unfold_lines(&Default::default(), window, cx)
16317            } else {
16318                self.fold(&Default::default(), window, cx)
16319            }
16320        } else {
16321            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16322            let buffer_ids: HashSet<_> = self
16323                .selections
16324                .disjoint_anchor_ranges()
16325                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16326                .collect();
16327
16328            let should_unfold = buffer_ids
16329                .iter()
16330                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16331
16332            for buffer_id in buffer_ids {
16333                if should_unfold {
16334                    self.unfold_buffer(buffer_id, cx);
16335                } else {
16336                    self.fold_buffer(buffer_id, cx);
16337                }
16338            }
16339        }
16340    }
16341
16342    pub fn toggle_fold_recursive(
16343        &mut self,
16344        _: &actions::ToggleFoldRecursive,
16345        window: &mut Window,
16346        cx: &mut Context<Self>,
16347    ) {
16348        let selection = self.selections.newest::<Point>(cx);
16349
16350        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16351        let range = if selection.is_empty() {
16352            let point = selection.head().to_display_point(&display_map);
16353            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16354            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16355                .to_point(&display_map);
16356            start..end
16357        } else {
16358            selection.range()
16359        };
16360        if display_map.folds_in_range(range).next().is_some() {
16361            self.unfold_recursive(&Default::default(), window, cx)
16362        } else {
16363            self.fold_recursive(&Default::default(), window, cx)
16364        }
16365    }
16366
16367    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16368        if self.is_singleton(cx) {
16369            let mut to_fold = Vec::new();
16370            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16371            let selections = self.selections.all_adjusted(cx);
16372
16373            for selection in selections {
16374                let range = selection.range().sorted();
16375                let buffer_start_row = range.start.row;
16376
16377                if range.start.row != range.end.row {
16378                    let mut found = false;
16379                    let mut row = range.start.row;
16380                    while row <= range.end.row {
16381                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16382                        {
16383                            found = true;
16384                            row = crease.range().end.row + 1;
16385                            to_fold.push(crease);
16386                        } else {
16387                            row += 1
16388                        }
16389                    }
16390                    if found {
16391                        continue;
16392                    }
16393                }
16394
16395                for row in (0..=range.start.row).rev() {
16396                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16397                        if crease.range().end.row >= buffer_start_row {
16398                            to_fold.push(crease);
16399                            if row <= range.start.row {
16400                                break;
16401                            }
16402                        }
16403                    }
16404                }
16405            }
16406
16407            self.fold_creases(to_fold, true, window, cx);
16408        } else {
16409            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16410            let buffer_ids = self
16411                .selections
16412                .disjoint_anchor_ranges()
16413                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16414                .collect::<HashSet<_>>();
16415            for buffer_id in buffer_ids {
16416                self.fold_buffer(buffer_id, cx);
16417            }
16418        }
16419    }
16420
16421    fn fold_at_level(
16422        &mut self,
16423        fold_at: &FoldAtLevel,
16424        window: &mut Window,
16425        cx: &mut Context<Self>,
16426    ) {
16427        if !self.buffer.read(cx).is_singleton() {
16428            return;
16429        }
16430
16431        let fold_at_level = fold_at.0;
16432        let snapshot = self.buffer.read(cx).snapshot(cx);
16433        let mut to_fold = Vec::new();
16434        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16435
16436        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16437            while start_row < end_row {
16438                match self
16439                    .snapshot(window, cx)
16440                    .crease_for_buffer_row(MultiBufferRow(start_row))
16441                {
16442                    Some(crease) => {
16443                        let nested_start_row = crease.range().start.row + 1;
16444                        let nested_end_row = crease.range().end.row;
16445
16446                        if current_level < fold_at_level {
16447                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16448                        } else if current_level == fold_at_level {
16449                            to_fold.push(crease);
16450                        }
16451
16452                        start_row = nested_end_row + 1;
16453                    }
16454                    None => start_row += 1,
16455                }
16456            }
16457        }
16458
16459        self.fold_creases(to_fold, true, window, cx);
16460    }
16461
16462    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16463        if self.buffer.read(cx).is_singleton() {
16464            let mut fold_ranges = Vec::new();
16465            let snapshot = self.buffer.read(cx).snapshot(cx);
16466
16467            for row in 0..snapshot.max_row().0 {
16468                if let Some(foldable_range) = self
16469                    .snapshot(window, cx)
16470                    .crease_for_buffer_row(MultiBufferRow(row))
16471                {
16472                    fold_ranges.push(foldable_range);
16473                }
16474            }
16475
16476            self.fold_creases(fold_ranges, true, window, cx);
16477        } else {
16478            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16479                editor
16480                    .update_in(cx, |editor, _, cx| {
16481                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16482                            editor.fold_buffer(buffer_id, cx);
16483                        }
16484                    })
16485                    .ok();
16486            });
16487        }
16488    }
16489
16490    pub fn fold_function_bodies(
16491        &mut self,
16492        _: &actions::FoldFunctionBodies,
16493        window: &mut Window,
16494        cx: &mut Context<Self>,
16495    ) {
16496        let snapshot = self.buffer.read(cx).snapshot(cx);
16497
16498        let ranges = snapshot
16499            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16500            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16501            .collect::<Vec<_>>();
16502
16503        let creases = ranges
16504            .into_iter()
16505            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16506            .collect();
16507
16508        self.fold_creases(creases, true, window, cx);
16509    }
16510
16511    pub fn fold_recursive(
16512        &mut self,
16513        _: &actions::FoldRecursive,
16514        window: &mut Window,
16515        cx: &mut Context<Self>,
16516    ) {
16517        let mut to_fold = Vec::new();
16518        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16519        let selections = self.selections.all_adjusted(cx);
16520
16521        for selection in selections {
16522            let range = selection.range().sorted();
16523            let buffer_start_row = range.start.row;
16524
16525            if range.start.row != range.end.row {
16526                let mut found = false;
16527                for row in range.start.row..=range.end.row {
16528                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16529                        found = true;
16530                        to_fold.push(crease);
16531                    }
16532                }
16533                if found {
16534                    continue;
16535                }
16536            }
16537
16538            for row in (0..=range.start.row).rev() {
16539                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16540                    if crease.range().end.row >= buffer_start_row {
16541                        to_fold.push(crease);
16542                    } else {
16543                        break;
16544                    }
16545                }
16546            }
16547        }
16548
16549        self.fold_creases(to_fold, true, window, cx);
16550    }
16551
16552    pub fn fold_at(
16553        &mut self,
16554        buffer_row: MultiBufferRow,
16555        window: &mut Window,
16556        cx: &mut Context<Self>,
16557    ) {
16558        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16559
16560        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16561            let autoscroll = self
16562                .selections
16563                .all::<Point>(cx)
16564                .iter()
16565                .any(|selection| crease.range().overlaps(&selection.range()));
16566
16567            self.fold_creases(vec![crease], autoscroll, window, cx);
16568        }
16569    }
16570
16571    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16572        if self.is_singleton(cx) {
16573            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16574            let buffer = &display_map.buffer_snapshot;
16575            let selections = self.selections.all::<Point>(cx);
16576            let ranges = selections
16577                .iter()
16578                .map(|s| {
16579                    let range = s.display_range(&display_map).sorted();
16580                    let mut start = range.start.to_point(&display_map);
16581                    let mut end = range.end.to_point(&display_map);
16582                    start.column = 0;
16583                    end.column = buffer.line_len(MultiBufferRow(end.row));
16584                    start..end
16585                })
16586                .collect::<Vec<_>>();
16587
16588            self.unfold_ranges(&ranges, true, true, cx);
16589        } else {
16590            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16591            let buffer_ids = self
16592                .selections
16593                .disjoint_anchor_ranges()
16594                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16595                .collect::<HashSet<_>>();
16596            for buffer_id in buffer_ids {
16597                self.unfold_buffer(buffer_id, cx);
16598            }
16599        }
16600    }
16601
16602    pub fn unfold_recursive(
16603        &mut self,
16604        _: &UnfoldRecursive,
16605        _window: &mut Window,
16606        cx: &mut Context<Self>,
16607    ) {
16608        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16609        let selections = self.selections.all::<Point>(cx);
16610        let ranges = selections
16611            .iter()
16612            .map(|s| {
16613                let mut range = s.display_range(&display_map).sorted();
16614                *range.start.column_mut() = 0;
16615                *range.end.column_mut() = display_map.line_len(range.end.row());
16616                let start = range.start.to_point(&display_map);
16617                let end = range.end.to_point(&display_map);
16618                start..end
16619            })
16620            .collect::<Vec<_>>();
16621
16622        self.unfold_ranges(&ranges, true, true, cx);
16623    }
16624
16625    pub fn unfold_at(
16626        &mut self,
16627        buffer_row: MultiBufferRow,
16628        _window: &mut Window,
16629        cx: &mut Context<Self>,
16630    ) {
16631        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16632
16633        let intersection_range = Point::new(buffer_row.0, 0)
16634            ..Point::new(
16635                buffer_row.0,
16636                display_map.buffer_snapshot.line_len(buffer_row),
16637            );
16638
16639        let autoscroll = self
16640            .selections
16641            .all::<Point>(cx)
16642            .iter()
16643            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16644
16645        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16646    }
16647
16648    pub fn unfold_all(
16649        &mut self,
16650        _: &actions::UnfoldAll,
16651        _window: &mut Window,
16652        cx: &mut Context<Self>,
16653    ) {
16654        if self.buffer.read(cx).is_singleton() {
16655            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16656            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16657        } else {
16658            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16659                editor
16660                    .update(cx, |editor, cx| {
16661                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16662                            editor.unfold_buffer(buffer_id, cx);
16663                        }
16664                    })
16665                    .ok();
16666            });
16667        }
16668    }
16669
16670    pub fn fold_selected_ranges(
16671        &mut self,
16672        _: &FoldSelectedRanges,
16673        window: &mut Window,
16674        cx: &mut Context<Self>,
16675    ) {
16676        let selections = self.selections.all_adjusted(cx);
16677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16678        let ranges = selections
16679            .into_iter()
16680            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16681            .collect::<Vec<_>>();
16682        self.fold_creases(ranges, true, window, cx);
16683    }
16684
16685    pub fn fold_ranges<T: ToOffset + Clone>(
16686        &mut self,
16687        ranges: Vec<Range<T>>,
16688        auto_scroll: bool,
16689        window: &mut Window,
16690        cx: &mut Context<Self>,
16691    ) {
16692        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16693        let ranges = ranges
16694            .into_iter()
16695            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16696            .collect::<Vec<_>>();
16697        self.fold_creases(ranges, auto_scroll, window, cx);
16698    }
16699
16700    pub fn fold_creases<T: ToOffset + Clone>(
16701        &mut self,
16702        creases: Vec<Crease<T>>,
16703        auto_scroll: bool,
16704        _window: &mut Window,
16705        cx: &mut Context<Self>,
16706    ) {
16707        if creases.is_empty() {
16708            return;
16709        }
16710
16711        let mut buffers_affected = HashSet::default();
16712        let multi_buffer = self.buffer().read(cx);
16713        for crease in &creases {
16714            if let Some((_, buffer, _)) =
16715                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16716            {
16717                buffers_affected.insert(buffer.read(cx).remote_id());
16718            };
16719        }
16720
16721        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16722
16723        if auto_scroll {
16724            self.request_autoscroll(Autoscroll::fit(), cx);
16725        }
16726
16727        cx.notify();
16728
16729        self.scrollbar_marker_state.dirty = true;
16730        self.folds_did_change(cx);
16731    }
16732
16733    /// Removes any folds whose ranges intersect any of the given ranges.
16734    pub fn unfold_ranges<T: ToOffset + Clone>(
16735        &mut self,
16736        ranges: &[Range<T>],
16737        inclusive: bool,
16738        auto_scroll: bool,
16739        cx: &mut Context<Self>,
16740    ) {
16741        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16742            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16743        });
16744        self.folds_did_change(cx);
16745    }
16746
16747    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16748        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16749            return;
16750        }
16751        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16752        self.display_map.update(cx, |display_map, cx| {
16753            display_map.fold_buffers([buffer_id], cx)
16754        });
16755        cx.emit(EditorEvent::BufferFoldToggled {
16756            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16757            folded: true,
16758        });
16759        cx.notify();
16760    }
16761
16762    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16763        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16764            return;
16765        }
16766        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16767        self.display_map.update(cx, |display_map, cx| {
16768            display_map.unfold_buffers([buffer_id], cx);
16769        });
16770        cx.emit(EditorEvent::BufferFoldToggled {
16771            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16772            folded: false,
16773        });
16774        cx.notify();
16775    }
16776
16777    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16778        self.display_map.read(cx).is_buffer_folded(buffer)
16779    }
16780
16781    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16782        self.display_map.read(cx).folded_buffers()
16783    }
16784
16785    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16786        self.display_map.update(cx, |display_map, cx| {
16787            display_map.disable_header_for_buffer(buffer_id, cx);
16788        });
16789        cx.notify();
16790    }
16791
16792    /// Removes any folds with the given ranges.
16793    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16794        &mut self,
16795        ranges: &[Range<T>],
16796        type_id: TypeId,
16797        auto_scroll: bool,
16798        cx: &mut Context<Self>,
16799    ) {
16800        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16801            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16802        });
16803        self.folds_did_change(cx);
16804    }
16805
16806    fn remove_folds_with<T: ToOffset + Clone>(
16807        &mut self,
16808        ranges: &[Range<T>],
16809        auto_scroll: bool,
16810        cx: &mut Context<Self>,
16811        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16812    ) {
16813        if ranges.is_empty() {
16814            return;
16815        }
16816
16817        let mut buffers_affected = HashSet::default();
16818        let multi_buffer = self.buffer().read(cx);
16819        for range in ranges {
16820            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16821                buffers_affected.insert(buffer.read(cx).remote_id());
16822            };
16823        }
16824
16825        self.display_map.update(cx, update);
16826
16827        if auto_scroll {
16828            self.request_autoscroll(Autoscroll::fit(), cx);
16829        }
16830
16831        cx.notify();
16832        self.scrollbar_marker_state.dirty = true;
16833        self.active_indent_guides_state.dirty = true;
16834    }
16835
16836    pub fn update_fold_widths(
16837        &mut self,
16838        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16839        cx: &mut Context<Self>,
16840    ) -> bool {
16841        self.display_map
16842            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16843    }
16844
16845    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16846        self.display_map.read(cx).fold_placeholder.clone()
16847    }
16848
16849    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16850        self.buffer.update(cx, |buffer, cx| {
16851            buffer.set_all_diff_hunks_expanded(cx);
16852        });
16853    }
16854
16855    pub fn expand_all_diff_hunks(
16856        &mut self,
16857        _: &ExpandAllDiffHunks,
16858        _window: &mut Window,
16859        cx: &mut Context<Self>,
16860    ) {
16861        self.buffer.update(cx, |buffer, cx| {
16862            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16863        });
16864    }
16865
16866    pub fn toggle_selected_diff_hunks(
16867        &mut self,
16868        _: &ToggleSelectedDiffHunks,
16869        _window: &mut Window,
16870        cx: &mut Context<Self>,
16871    ) {
16872        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16873        self.toggle_diff_hunks_in_ranges(ranges, cx);
16874    }
16875
16876    pub fn diff_hunks_in_ranges<'a>(
16877        &'a self,
16878        ranges: &'a [Range<Anchor>],
16879        buffer: &'a MultiBufferSnapshot,
16880    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16881        ranges.iter().flat_map(move |range| {
16882            let end_excerpt_id = range.end.excerpt_id;
16883            let range = range.to_point(buffer);
16884            let mut peek_end = range.end;
16885            if range.end.row < buffer.max_row().0 {
16886                peek_end = Point::new(range.end.row + 1, 0);
16887            }
16888            buffer
16889                .diff_hunks_in_range(range.start..peek_end)
16890                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16891        })
16892    }
16893
16894    pub fn has_stageable_diff_hunks_in_ranges(
16895        &self,
16896        ranges: &[Range<Anchor>],
16897        snapshot: &MultiBufferSnapshot,
16898    ) -> bool {
16899        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16900        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16901    }
16902
16903    pub fn toggle_staged_selected_diff_hunks(
16904        &mut self,
16905        _: &::git::ToggleStaged,
16906        _: &mut Window,
16907        cx: &mut Context<Self>,
16908    ) {
16909        let snapshot = self.buffer.read(cx).snapshot(cx);
16910        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16911        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16912        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16913    }
16914
16915    pub fn set_render_diff_hunk_controls(
16916        &mut self,
16917        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16918        cx: &mut Context<Self>,
16919    ) {
16920        self.render_diff_hunk_controls = render_diff_hunk_controls;
16921        cx.notify();
16922    }
16923
16924    pub fn stage_and_next(
16925        &mut self,
16926        _: &::git::StageAndNext,
16927        window: &mut Window,
16928        cx: &mut Context<Self>,
16929    ) {
16930        self.do_stage_or_unstage_and_next(true, window, cx);
16931    }
16932
16933    pub fn unstage_and_next(
16934        &mut self,
16935        _: &::git::UnstageAndNext,
16936        window: &mut Window,
16937        cx: &mut Context<Self>,
16938    ) {
16939        self.do_stage_or_unstage_and_next(false, window, cx);
16940    }
16941
16942    pub fn stage_or_unstage_diff_hunks(
16943        &mut self,
16944        stage: bool,
16945        ranges: Vec<Range<Anchor>>,
16946        cx: &mut Context<Self>,
16947    ) {
16948        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16949        cx.spawn(async move |this, cx| {
16950            task.await?;
16951            this.update(cx, |this, cx| {
16952                let snapshot = this.buffer.read(cx).snapshot(cx);
16953                let chunk_by = this
16954                    .diff_hunks_in_ranges(&ranges, &snapshot)
16955                    .chunk_by(|hunk| hunk.buffer_id);
16956                for (buffer_id, hunks) in &chunk_by {
16957                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16958                }
16959            })
16960        })
16961        .detach_and_log_err(cx);
16962    }
16963
16964    fn save_buffers_for_ranges_if_needed(
16965        &mut self,
16966        ranges: &[Range<Anchor>],
16967        cx: &mut Context<Editor>,
16968    ) -> Task<Result<()>> {
16969        let multibuffer = self.buffer.read(cx);
16970        let snapshot = multibuffer.read(cx);
16971        let buffer_ids: HashSet<_> = ranges
16972            .iter()
16973            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16974            .collect();
16975        drop(snapshot);
16976
16977        let mut buffers = HashSet::default();
16978        for buffer_id in buffer_ids {
16979            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16980                let buffer = buffer_entity.read(cx);
16981                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16982                {
16983                    buffers.insert(buffer_entity);
16984                }
16985            }
16986        }
16987
16988        if let Some(project) = &self.project {
16989            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16990        } else {
16991            Task::ready(Ok(()))
16992        }
16993    }
16994
16995    fn do_stage_or_unstage_and_next(
16996        &mut self,
16997        stage: bool,
16998        window: &mut Window,
16999        cx: &mut Context<Self>,
17000    ) {
17001        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17002
17003        if ranges.iter().any(|range| range.start != range.end) {
17004            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17005            return;
17006        }
17007
17008        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17009        let snapshot = self.snapshot(window, cx);
17010        let position = self.selections.newest::<Point>(cx).head();
17011        let mut row = snapshot
17012            .buffer_snapshot
17013            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17014            .find(|hunk| hunk.row_range.start.0 > position.row)
17015            .map(|hunk| hunk.row_range.start);
17016
17017        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17018        // Outside of the project diff editor, wrap around to the beginning.
17019        if !all_diff_hunks_expanded {
17020            row = row.or_else(|| {
17021                snapshot
17022                    .buffer_snapshot
17023                    .diff_hunks_in_range(Point::zero()..position)
17024                    .find(|hunk| hunk.row_range.end.0 < position.row)
17025                    .map(|hunk| hunk.row_range.start)
17026            });
17027        }
17028
17029        if let Some(row) = row {
17030            let destination = Point::new(row.0, 0);
17031            let autoscroll = Autoscroll::center();
17032
17033            self.unfold_ranges(&[destination..destination], false, false, cx);
17034            self.change_selections(Some(autoscroll), window, cx, |s| {
17035                s.select_ranges([destination..destination]);
17036            });
17037        }
17038    }
17039
17040    fn do_stage_or_unstage(
17041        &self,
17042        stage: bool,
17043        buffer_id: BufferId,
17044        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17045        cx: &mut App,
17046    ) -> Option<()> {
17047        let project = self.project.as_ref()?;
17048        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17049        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17050        let buffer_snapshot = buffer.read(cx).snapshot();
17051        let file_exists = buffer_snapshot
17052            .file()
17053            .is_some_and(|file| file.disk_state().exists());
17054        diff.update(cx, |diff, cx| {
17055            diff.stage_or_unstage_hunks(
17056                stage,
17057                &hunks
17058                    .map(|hunk| buffer_diff::DiffHunk {
17059                        buffer_range: hunk.buffer_range,
17060                        diff_base_byte_range: hunk.diff_base_byte_range,
17061                        secondary_status: hunk.secondary_status,
17062                        range: Point::zero()..Point::zero(), // unused
17063                    })
17064                    .collect::<Vec<_>>(),
17065                &buffer_snapshot,
17066                file_exists,
17067                cx,
17068            )
17069        });
17070        None
17071    }
17072
17073    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17074        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17075        self.buffer
17076            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17077    }
17078
17079    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17080        self.buffer.update(cx, |buffer, cx| {
17081            let ranges = vec![Anchor::min()..Anchor::max()];
17082            if !buffer.all_diff_hunks_expanded()
17083                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17084            {
17085                buffer.collapse_diff_hunks(ranges, cx);
17086                true
17087            } else {
17088                false
17089            }
17090        })
17091    }
17092
17093    fn toggle_diff_hunks_in_ranges(
17094        &mut self,
17095        ranges: Vec<Range<Anchor>>,
17096        cx: &mut Context<Editor>,
17097    ) {
17098        self.buffer.update(cx, |buffer, cx| {
17099            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17100            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17101        })
17102    }
17103
17104    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17105        self.buffer.update(cx, |buffer, cx| {
17106            let snapshot = buffer.snapshot(cx);
17107            let excerpt_id = range.end.excerpt_id;
17108            let point_range = range.to_point(&snapshot);
17109            let expand = !buffer.single_hunk_is_expanded(range, cx);
17110            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17111        })
17112    }
17113
17114    pub(crate) fn apply_all_diff_hunks(
17115        &mut self,
17116        _: &ApplyAllDiffHunks,
17117        window: &mut Window,
17118        cx: &mut Context<Self>,
17119    ) {
17120        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17121
17122        let buffers = self.buffer.read(cx).all_buffers();
17123        for branch_buffer in buffers {
17124            branch_buffer.update(cx, |branch_buffer, cx| {
17125                branch_buffer.merge_into_base(Vec::new(), cx);
17126            });
17127        }
17128
17129        if let Some(project) = self.project.clone() {
17130            self.save(
17131                SaveOptions {
17132                    format: true,
17133                    autosave: false,
17134                },
17135                project,
17136                window,
17137                cx,
17138            )
17139            .detach_and_log_err(cx);
17140        }
17141    }
17142
17143    pub(crate) fn apply_selected_diff_hunks(
17144        &mut self,
17145        _: &ApplyDiffHunk,
17146        window: &mut Window,
17147        cx: &mut Context<Self>,
17148    ) {
17149        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17150        let snapshot = self.snapshot(window, cx);
17151        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17152        let mut ranges_by_buffer = HashMap::default();
17153        self.transact(window, cx, |editor, _window, cx| {
17154            for hunk in hunks {
17155                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17156                    ranges_by_buffer
17157                        .entry(buffer.clone())
17158                        .or_insert_with(Vec::new)
17159                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17160                }
17161            }
17162
17163            for (buffer, ranges) in ranges_by_buffer {
17164                buffer.update(cx, |buffer, cx| {
17165                    buffer.merge_into_base(ranges, cx);
17166                });
17167            }
17168        });
17169
17170        if let Some(project) = self.project.clone() {
17171            self.save(
17172                SaveOptions {
17173                    format: true,
17174                    autosave: false,
17175                },
17176                project,
17177                window,
17178                cx,
17179            )
17180            .detach_and_log_err(cx);
17181        }
17182    }
17183
17184    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17185        if hovered != self.gutter_hovered {
17186            self.gutter_hovered = hovered;
17187            cx.notify();
17188        }
17189    }
17190
17191    pub fn insert_blocks(
17192        &mut self,
17193        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17194        autoscroll: Option<Autoscroll>,
17195        cx: &mut Context<Self>,
17196    ) -> Vec<CustomBlockId> {
17197        let blocks = self
17198            .display_map
17199            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17200        if let Some(autoscroll) = autoscroll {
17201            self.request_autoscroll(autoscroll, cx);
17202        }
17203        cx.notify();
17204        blocks
17205    }
17206
17207    pub fn resize_blocks(
17208        &mut self,
17209        heights: HashMap<CustomBlockId, u32>,
17210        autoscroll: Option<Autoscroll>,
17211        cx: &mut Context<Self>,
17212    ) {
17213        self.display_map
17214            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17215        if let Some(autoscroll) = autoscroll {
17216            self.request_autoscroll(autoscroll, cx);
17217        }
17218        cx.notify();
17219    }
17220
17221    pub fn replace_blocks(
17222        &mut self,
17223        renderers: HashMap<CustomBlockId, RenderBlock>,
17224        autoscroll: Option<Autoscroll>,
17225        cx: &mut Context<Self>,
17226    ) {
17227        self.display_map
17228            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17229        if let Some(autoscroll) = autoscroll {
17230            self.request_autoscroll(autoscroll, cx);
17231        }
17232        cx.notify();
17233    }
17234
17235    pub fn remove_blocks(
17236        &mut self,
17237        block_ids: HashSet<CustomBlockId>,
17238        autoscroll: Option<Autoscroll>,
17239        cx: &mut Context<Self>,
17240    ) {
17241        self.display_map.update(cx, |display_map, cx| {
17242            display_map.remove_blocks(block_ids, cx)
17243        });
17244        if let Some(autoscroll) = autoscroll {
17245            self.request_autoscroll(autoscroll, cx);
17246        }
17247        cx.notify();
17248    }
17249
17250    pub fn row_for_block(
17251        &self,
17252        block_id: CustomBlockId,
17253        cx: &mut Context<Self>,
17254    ) -> Option<DisplayRow> {
17255        self.display_map
17256            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17257    }
17258
17259    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17260        self.focused_block = Some(focused_block);
17261    }
17262
17263    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17264        self.focused_block.take()
17265    }
17266
17267    pub fn insert_creases(
17268        &mut self,
17269        creases: impl IntoIterator<Item = Crease<Anchor>>,
17270        cx: &mut Context<Self>,
17271    ) -> Vec<CreaseId> {
17272        self.display_map
17273            .update(cx, |map, cx| map.insert_creases(creases, cx))
17274    }
17275
17276    pub fn remove_creases(
17277        &mut self,
17278        ids: impl IntoIterator<Item = CreaseId>,
17279        cx: &mut Context<Self>,
17280    ) -> Vec<(CreaseId, Range<Anchor>)> {
17281        self.display_map
17282            .update(cx, |map, cx| map.remove_creases(ids, cx))
17283    }
17284
17285    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17286        self.display_map
17287            .update(cx, |map, cx| map.snapshot(cx))
17288            .longest_row()
17289    }
17290
17291    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17292        self.display_map
17293            .update(cx, |map, cx| map.snapshot(cx))
17294            .max_point()
17295    }
17296
17297    pub fn text(&self, cx: &App) -> String {
17298        self.buffer.read(cx).read(cx).text()
17299    }
17300
17301    pub fn is_empty(&self, cx: &App) -> bool {
17302        self.buffer.read(cx).read(cx).is_empty()
17303    }
17304
17305    pub fn text_option(&self, cx: &App) -> Option<String> {
17306        let text = self.text(cx);
17307        let text = text.trim();
17308
17309        if text.is_empty() {
17310            return None;
17311        }
17312
17313        Some(text.to_string())
17314    }
17315
17316    pub fn set_text(
17317        &mut self,
17318        text: impl Into<Arc<str>>,
17319        window: &mut Window,
17320        cx: &mut Context<Self>,
17321    ) {
17322        self.transact(window, cx, |this, _, cx| {
17323            this.buffer
17324                .read(cx)
17325                .as_singleton()
17326                .expect("you can only call set_text on editors for singleton buffers")
17327                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17328        });
17329    }
17330
17331    pub fn display_text(&self, cx: &mut App) -> String {
17332        self.display_map
17333            .update(cx, |map, cx| map.snapshot(cx))
17334            .text()
17335    }
17336
17337    fn create_minimap(
17338        &self,
17339        minimap_settings: MinimapSettings,
17340        window: &mut Window,
17341        cx: &mut Context<Self>,
17342    ) -> Option<Entity<Self>> {
17343        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17344            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17345    }
17346
17347    fn initialize_new_minimap(
17348        &self,
17349        minimap_settings: MinimapSettings,
17350        window: &mut Window,
17351        cx: &mut Context<Self>,
17352    ) -> Entity<Self> {
17353        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17354
17355        let mut minimap = Editor::new_internal(
17356            EditorMode::Minimap {
17357                parent: cx.weak_entity(),
17358            },
17359            self.buffer.clone(),
17360            self.project.clone(),
17361            Some(self.display_map.clone()),
17362            window,
17363            cx,
17364        );
17365        minimap.scroll_manager.clone_state(&self.scroll_manager);
17366        minimap.set_text_style_refinement(TextStyleRefinement {
17367            font_size: Some(MINIMAP_FONT_SIZE),
17368            font_weight: Some(MINIMAP_FONT_WEIGHT),
17369            ..Default::default()
17370        });
17371        minimap.update_minimap_configuration(minimap_settings, cx);
17372        cx.new(|_| minimap)
17373    }
17374
17375    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17376        let current_line_highlight = minimap_settings
17377            .current_line_highlight
17378            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17379        self.set_current_line_highlight(Some(current_line_highlight));
17380    }
17381
17382    pub fn minimap(&self) -> Option<&Entity<Self>> {
17383        self.minimap
17384            .as_ref()
17385            .filter(|_| self.minimap_visibility.visible())
17386    }
17387
17388    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17389        let mut wrap_guides = smallvec![];
17390
17391        if self.show_wrap_guides == Some(false) {
17392            return wrap_guides;
17393        }
17394
17395        let settings = self.buffer.read(cx).language_settings(cx);
17396        if settings.show_wrap_guides {
17397            match self.soft_wrap_mode(cx) {
17398                SoftWrap::Column(soft_wrap) => {
17399                    wrap_guides.push((soft_wrap as usize, true));
17400                }
17401                SoftWrap::Bounded(soft_wrap) => {
17402                    wrap_guides.push((soft_wrap as usize, true));
17403                }
17404                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17405            }
17406            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17407        }
17408
17409        wrap_guides
17410    }
17411
17412    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17413        let settings = self.buffer.read(cx).language_settings(cx);
17414        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17415        match mode {
17416            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17417                SoftWrap::None
17418            }
17419            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17420            language_settings::SoftWrap::PreferredLineLength => {
17421                SoftWrap::Column(settings.preferred_line_length)
17422            }
17423            language_settings::SoftWrap::Bounded => {
17424                SoftWrap::Bounded(settings.preferred_line_length)
17425            }
17426        }
17427    }
17428
17429    pub fn set_soft_wrap_mode(
17430        &mut self,
17431        mode: language_settings::SoftWrap,
17432
17433        cx: &mut Context<Self>,
17434    ) {
17435        self.soft_wrap_mode_override = Some(mode);
17436        cx.notify();
17437    }
17438
17439    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17440        self.hard_wrap = hard_wrap;
17441        cx.notify();
17442    }
17443
17444    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17445        self.text_style_refinement = Some(style);
17446    }
17447
17448    /// called by the Element so we know what style we were most recently rendered with.
17449    pub(crate) fn set_style(
17450        &mut self,
17451        style: EditorStyle,
17452        window: &mut Window,
17453        cx: &mut Context<Self>,
17454    ) {
17455        // We intentionally do not inform the display map about the minimap style
17456        // so that wrapping is not recalculated and stays consistent for the editor
17457        // and its linked minimap.
17458        if !self.mode.is_minimap() {
17459            let rem_size = window.rem_size();
17460            self.display_map.update(cx, |map, cx| {
17461                map.set_font(
17462                    style.text.font(),
17463                    style.text.font_size.to_pixels(rem_size),
17464                    cx,
17465                )
17466            });
17467        }
17468        self.style = Some(style);
17469    }
17470
17471    pub fn style(&self) -> Option<&EditorStyle> {
17472        self.style.as_ref()
17473    }
17474
17475    // Called by the element. This method is not designed to be called outside of the editor
17476    // element's layout code because it does not notify when rewrapping is computed synchronously.
17477    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17478        self.display_map
17479            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17480    }
17481
17482    pub fn set_soft_wrap(&mut self) {
17483        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17484    }
17485
17486    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17487        if self.soft_wrap_mode_override.is_some() {
17488            self.soft_wrap_mode_override.take();
17489        } else {
17490            let soft_wrap = match self.soft_wrap_mode(cx) {
17491                SoftWrap::GitDiff => return,
17492                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17493                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17494                    language_settings::SoftWrap::None
17495                }
17496            };
17497            self.soft_wrap_mode_override = Some(soft_wrap);
17498        }
17499        cx.notify();
17500    }
17501
17502    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17503        let Some(workspace) = self.workspace() else {
17504            return;
17505        };
17506        let fs = workspace.read(cx).app_state().fs.clone();
17507        let current_show = TabBarSettings::get_global(cx).show;
17508        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17509            setting.show = Some(!current_show);
17510        });
17511    }
17512
17513    pub fn toggle_indent_guides(
17514        &mut self,
17515        _: &ToggleIndentGuides,
17516        _: &mut Window,
17517        cx: &mut Context<Self>,
17518    ) {
17519        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17520            self.buffer
17521                .read(cx)
17522                .language_settings(cx)
17523                .indent_guides
17524                .enabled
17525        });
17526        self.show_indent_guides = Some(!currently_enabled);
17527        cx.notify();
17528    }
17529
17530    fn should_show_indent_guides(&self) -> Option<bool> {
17531        self.show_indent_guides
17532    }
17533
17534    pub fn toggle_line_numbers(
17535        &mut self,
17536        _: &ToggleLineNumbers,
17537        _: &mut Window,
17538        cx: &mut Context<Self>,
17539    ) {
17540        let mut editor_settings = EditorSettings::get_global(cx).clone();
17541        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17542        EditorSettings::override_global(editor_settings, cx);
17543    }
17544
17545    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17546        if let Some(show_line_numbers) = self.show_line_numbers {
17547            return show_line_numbers;
17548        }
17549        EditorSettings::get_global(cx).gutter.line_numbers
17550    }
17551
17552    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17553        self.use_relative_line_numbers
17554            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17555    }
17556
17557    pub fn toggle_relative_line_numbers(
17558        &mut self,
17559        _: &ToggleRelativeLineNumbers,
17560        _: &mut Window,
17561        cx: &mut Context<Self>,
17562    ) {
17563        let is_relative = self.should_use_relative_line_numbers(cx);
17564        self.set_relative_line_number(Some(!is_relative), cx)
17565    }
17566
17567    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17568        self.use_relative_line_numbers = is_relative;
17569        cx.notify();
17570    }
17571
17572    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17573        self.show_gutter = show_gutter;
17574        cx.notify();
17575    }
17576
17577    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17578        self.show_scrollbars = ScrollbarAxes {
17579            horizontal: show,
17580            vertical: show,
17581        };
17582        cx.notify();
17583    }
17584
17585    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17586        self.show_scrollbars.vertical = show;
17587        cx.notify();
17588    }
17589
17590    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17591        self.show_scrollbars.horizontal = show;
17592        cx.notify();
17593    }
17594
17595    pub fn set_minimap_visibility(
17596        &mut self,
17597        minimap_visibility: MinimapVisibility,
17598        window: &mut Window,
17599        cx: &mut Context<Self>,
17600    ) {
17601        if self.minimap_visibility != minimap_visibility {
17602            if minimap_visibility.visible() && self.minimap.is_none() {
17603                let minimap_settings = EditorSettings::get_global(cx).minimap;
17604                self.minimap =
17605                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17606            }
17607            self.minimap_visibility = minimap_visibility;
17608            cx.notify();
17609        }
17610    }
17611
17612    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17613        self.set_show_scrollbars(false, cx);
17614        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17615    }
17616
17617    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17618        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17619    }
17620
17621    /// Normally the text in full mode and auto height editors is padded on the
17622    /// left side by roughly half a character width for improved hit testing.
17623    ///
17624    /// Use this method to disable this for cases where this is not wanted (e.g.
17625    /// if you want to align the editor text with some other text above or below)
17626    /// or if you want to add this padding to single-line editors.
17627    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17628        self.offset_content = offset_content;
17629        cx.notify();
17630    }
17631
17632    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17633        self.show_line_numbers = Some(show_line_numbers);
17634        cx.notify();
17635    }
17636
17637    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17638        self.disable_expand_excerpt_buttons = true;
17639        cx.notify();
17640    }
17641
17642    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17643        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17644        cx.notify();
17645    }
17646
17647    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17648        self.show_code_actions = Some(show_code_actions);
17649        cx.notify();
17650    }
17651
17652    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17653        self.show_runnables = Some(show_runnables);
17654        cx.notify();
17655    }
17656
17657    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17658        self.show_breakpoints = Some(show_breakpoints);
17659        cx.notify();
17660    }
17661
17662    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17663        if self.display_map.read(cx).masked != masked {
17664            self.display_map.update(cx, |map, _| map.masked = masked);
17665        }
17666        cx.notify()
17667    }
17668
17669    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17670        self.show_wrap_guides = Some(show_wrap_guides);
17671        cx.notify();
17672    }
17673
17674    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17675        self.show_indent_guides = Some(show_indent_guides);
17676        cx.notify();
17677    }
17678
17679    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17680        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17681            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17682                if let Some(dir) = file.abs_path(cx).parent() {
17683                    return Some(dir.to_owned());
17684                }
17685            }
17686
17687            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17688                return Some(project_path.path.to_path_buf());
17689            }
17690        }
17691
17692        None
17693    }
17694
17695    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17696        self.active_excerpt(cx)?
17697            .1
17698            .read(cx)
17699            .file()
17700            .and_then(|f| f.as_local())
17701    }
17702
17703    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17704        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17705            let buffer = buffer.read(cx);
17706            if let Some(project_path) = buffer.project_path(cx) {
17707                let project = self.project.as_ref()?.read(cx);
17708                project.absolute_path(&project_path, cx)
17709            } else {
17710                buffer
17711                    .file()
17712                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17713            }
17714        })
17715    }
17716
17717    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17718        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17719            let project_path = buffer.read(cx).project_path(cx)?;
17720            let project = self.project.as_ref()?.read(cx);
17721            let entry = project.entry_for_path(&project_path, cx)?;
17722            let path = entry.path.to_path_buf();
17723            Some(path)
17724        })
17725    }
17726
17727    pub fn reveal_in_finder(
17728        &mut self,
17729        _: &RevealInFileManager,
17730        _window: &mut Window,
17731        cx: &mut Context<Self>,
17732    ) {
17733        if let Some(target) = self.target_file(cx) {
17734            cx.reveal_path(&target.abs_path(cx));
17735        }
17736    }
17737
17738    pub fn copy_path(
17739        &mut self,
17740        _: &zed_actions::workspace::CopyPath,
17741        _window: &mut Window,
17742        cx: &mut Context<Self>,
17743    ) {
17744        if let Some(path) = self.target_file_abs_path(cx) {
17745            if let Some(path) = path.to_str() {
17746                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17747            }
17748        }
17749    }
17750
17751    pub fn copy_relative_path(
17752        &mut self,
17753        _: &zed_actions::workspace::CopyRelativePath,
17754        _window: &mut Window,
17755        cx: &mut Context<Self>,
17756    ) {
17757        if let Some(path) = self.target_file_path(cx) {
17758            if let Some(path) = path.to_str() {
17759                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17760            }
17761        }
17762    }
17763
17764    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17765        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17766            buffer.read(cx).project_path(cx)
17767        } else {
17768            None
17769        }
17770    }
17771
17772    // Returns true if the editor handled a go-to-line request
17773    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17774        maybe!({
17775            let breakpoint_store = self.breakpoint_store.as_ref()?;
17776
17777            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17778            else {
17779                self.clear_row_highlights::<ActiveDebugLine>();
17780                return None;
17781            };
17782
17783            let position = active_stack_frame.position;
17784            let buffer_id = position.buffer_id?;
17785            let snapshot = self
17786                .project
17787                .as_ref()?
17788                .read(cx)
17789                .buffer_for_id(buffer_id, cx)?
17790                .read(cx)
17791                .snapshot();
17792
17793            let mut handled = false;
17794            for (id, ExcerptRange { context, .. }) in
17795                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17796            {
17797                if context.start.cmp(&position, &snapshot).is_ge()
17798                    || context.end.cmp(&position, &snapshot).is_lt()
17799                {
17800                    continue;
17801                }
17802                let snapshot = self.buffer.read(cx).snapshot(cx);
17803                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17804
17805                handled = true;
17806                self.clear_row_highlights::<ActiveDebugLine>();
17807
17808                self.go_to_line::<ActiveDebugLine>(
17809                    multibuffer_anchor,
17810                    Some(cx.theme().colors().editor_debugger_active_line_background),
17811                    window,
17812                    cx,
17813                );
17814
17815                cx.notify();
17816            }
17817
17818            handled.then_some(())
17819        })
17820        .is_some()
17821    }
17822
17823    pub fn copy_file_name_without_extension(
17824        &mut self,
17825        _: &CopyFileNameWithoutExtension,
17826        _: &mut Window,
17827        cx: &mut Context<Self>,
17828    ) {
17829        if let Some(file) = self.target_file(cx) {
17830            if let Some(file_stem) = file.path().file_stem() {
17831                if let Some(name) = file_stem.to_str() {
17832                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17833                }
17834            }
17835        }
17836    }
17837
17838    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17839        if let Some(file) = self.target_file(cx) {
17840            if let Some(file_name) = file.path().file_name() {
17841                if let Some(name) = file_name.to_str() {
17842                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17843                }
17844            }
17845        }
17846    }
17847
17848    pub fn toggle_git_blame(
17849        &mut self,
17850        _: &::git::Blame,
17851        window: &mut Window,
17852        cx: &mut Context<Self>,
17853    ) {
17854        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17855
17856        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17857            self.start_git_blame(true, window, cx);
17858        }
17859
17860        cx.notify();
17861    }
17862
17863    pub fn toggle_git_blame_inline(
17864        &mut self,
17865        _: &ToggleGitBlameInline,
17866        window: &mut Window,
17867        cx: &mut Context<Self>,
17868    ) {
17869        self.toggle_git_blame_inline_internal(true, window, cx);
17870        cx.notify();
17871    }
17872
17873    pub fn open_git_blame_commit(
17874        &mut self,
17875        _: &OpenGitBlameCommit,
17876        window: &mut Window,
17877        cx: &mut Context<Self>,
17878    ) {
17879        self.open_git_blame_commit_internal(window, cx);
17880    }
17881
17882    fn open_git_blame_commit_internal(
17883        &mut self,
17884        window: &mut Window,
17885        cx: &mut Context<Self>,
17886    ) -> Option<()> {
17887        let blame = self.blame.as_ref()?;
17888        let snapshot = self.snapshot(window, cx);
17889        let cursor = self.selections.newest::<Point>(cx).head();
17890        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17891        let blame_entry = blame
17892            .update(cx, |blame, cx| {
17893                blame
17894                    .blame_for_rows(
17895                        &[RowInfo {
17896                            buffer_id: Some(buffer.remote_id()),
17897                            buffer_row: Some(point.row),
17898                            ..Default::default()
17899                        }],
17900                        cx,
17901                    )
17902                    .next()
17903            })
17904            .flatten()?;
17905        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17906        let repo = blame.read(cx).repository(cx)?;
17907        let workspace = self.workspace()?.downgrade();
17908        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17909        None
17910    }
17911
17912    pub fn git_blame_inline_enabled(&self) -> bool {
17913        self.git_blame_inline_enabled
17914    }
17915
17916    pub fn toggle_selection_menu(
17917        &mut self,
17918        _: &ToggleSelectionMenu,
17919        _: &mut Window,
17920        cx: &mut Context<Self>,
17921    ) {
17922        self.show_selection_menu = self
17923            .show_selection_menu
17924            .map(|show_selections_menu| !show_selections_menu)
17925            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17926
17927        cx.notify();
17928    }
17929
17930    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17931        self.show_selection_menu
17932            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17933    }
17934
17935    fn start_git_blame(
17936        &mut self,
17937        user_triggered: bool,
17938        window: &mut Window,
17939        cx: &mut Context<Self>,
17940    ) {
17941        if let Some(project) = self.project.as_ref() {
17942            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17943                return;
17944            };
17945
17946            if buffer.read(cx).file().is_none() {
17947                return;
17948            }
17949
17950            let focused = self.focus_handle(cx).contains_focused(window, cx);
17951
17952            let project = project.clone();
17953            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17954            self.blame_subscription =
17955                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17956            self.blame = Some(blame);
17957        }
17958    }
17959
17960    fn toggle_git_blame_inline_internal(
17961        &mut self,
17962        user_triggered: bool,
17963        window: &mut Window,
17964        cx: &mut Context<Self>,
17965    ) {
17966        if self.git_blame_inline_enabled {
17967            self.git_blame_inline_enabled = false;
17968            self.show_git_blame_inline = false;
17969            self.show_git_blame_inline_delay_task.take();
17970        } else {
17971            self.git_blame_inline_enabled = true;
17972            self.start_git_blame_inline(user_triggered, window, cx);
17973        }
17974
17975        cx.notify();
17976    }
17977
17978    fn start_git_blame_inline(
17979        &mut self,
17980        user_triggered: bool,
17981        window: &mut Window,
17982        cx: &mut Context<Self>,
17983    ) {
17984        self.start_git_blame(user_triggered, window, cx);
17985
17986        if ProjectSettings::get_global(cx)
17987            .git
17988            .inline_blame_delay()
17989            .is_some()
17990        {
17991            self.start_inline_blame_timer(window, cx);
17992        } else {
17993            self.show_git_blame_inline = true
17994        }
17995    }
17996
17997    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17998        self.blame.as_ref()
17999    }
18000
18001    pub fn show_git_blame_gutter(&self) -> bool {
18002        self.show_git_blame_gutter
18003    }
18004
18005    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18006        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18007    }
18008
18009    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18010        self.show_git_blame_inline
18011            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18012            && !self.newest_selection_head_on_empty_line(cx)
18013            && self.has_blame_entries(cx)
18014    }
18015
18016    fn has_blame_entries(&self, cx: &App) -> bool {
18017        self.blame()
18018            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18019    }
18020
18021    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18022        let cursor_anchor = self.selections.newest_anchor().head();
18023
18024        let snapshot = self.buffer.read(cx).snapshot(cx);
18025        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18026
18027        snapshot.line_len(buffer_row) == 0
18028    }
18029
18030    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18031        let buffer_and_selection = maybe!({
18032            let selection = self.selections.newest::<Point>(cx);
18033            let selection_range = selection.range();
18034
18035            let multi_buffer = self.buffer().read(cx);
18036            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18037            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18038
18039            let (buffer, range, _) = if selection.reversed {
18040                buffer_ranges.first()
18041            } else {
18042                buffer_ranges.last()
18043            }?;
18044
18045            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18046                ..text::ToPoint::to_point(&range.end, &buffer).row;
18047            Some((
18048                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18049                selection,
18050            ))
18051        });
18052
18053        let Some((buffer, selection)) = buffer_and_selection else {
18054            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18055        };
18056
18057        let Some(project) = self.project.as_ref() else {
18058            return Task::ready(Err(anyhow!("editor does not have project")));
18059        };
18060
18061        project.update(cx, |project, cx| {
18062            project.get_permalink_to_line(&buffer, selection, cx)
18063        })
18064    }
18065
18066    pub fn copy_permalink_to_line(
18067        &mut self,
18068        _: &CopyPermalinkToLine,
18069        window: &mut Window,
18070        cx: &mut Context<Self>,
18071    ) {
18072        let permalink_task = self.get_permalink_to_line(cx);
18073        let workspace = self.workspace();
18074
18075        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18076            Ok(permalink) => {
18077                cx.update(|_, cx| {
18078                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18079                })
18080                .ok();
18081            }
18082            Err(err) => {
18083                let message = format!("Failed to copy permalink: {err}");
18084
18085                anyhow::Result::<()>::Err(err).log_err();
18086
18087                if let Some(workspace) = workspace {
18088                    workspace
18089                        .update_in(cx, |workspace, _, cx| {
18090                            struct CopyPermalinkToLine;
18091
18092                            workspace.show_toast(
18093                                Toast::new(
18094                                    NotificationId::unique::<CopyPermalinkToLine>(),
18095                                    message,
18096                                ),
18097                                cx,
18098                            )
18099                        })
18100                        .ok();
18101                }
18102            }
18103        })
18104        .detach();
18105    }
18106
18107    pub fn copy_file_location(
18108        &mut self,
18109        _: &CopyFileLocation,
18110        _: &mut Window,
18111        cx: &mut Context<Self>,
18112    ) {
18113        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18114        if let Some(file) = self.target_file(cx) {
18115            if let Some(path) = file.path().to_str() {
18116                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18117            }
18118        }
18119    }
18120
18121    pub fn open_permalink_to_line(
18122        &mut self,
18123        _: &OpenPermalinkToLine,
18124        window: &mut Window,
18125        cx: &mut Context<Self>,
18126    ) {
18127        let permalink_task = self.get_permalink_to_line(cx);
18128        let workspace = self.workspace();
18129
18130        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18131            Ok(permalink) => {
18132                cx.update(|_, cx| {
18133                    cx.open_url(permalink.as_ref());
18134                })
18135                .ok();
18136            }
18137            Err(err) => {
18138                let message = format!("Failed to open permalink: {err}");
18139
18140                anyhow::Result::<()>::Err(err).log_err();
18141
18142                if let Some(workspace) = workspace {
18143                    workspace
18144                        .update(cx, |workspace, cx| {
18145                            struct OpenPermalinkToLine;
18146
18147                            workspace.show_toast(
18148                                Toast::new(
18149                                    NotificationId::unique::<OpenPermalinkToLine>(),
18150                                    message,
18151                                ),
18152                                cx,
18153                            )
18154                        })
18155                        .ok();
18156                }
18157            }
18158        })
18159        .detach();
18160    }
18161
18162    pub fn insert_uuid_v4(
18163        &mut self,
18164        _: &InsertUuidV4,
18165        window: &mut Window,
18166        cx: &mut Context<Self>,
18167    ) {
18168        self.insert_uuid(UuidVersion::V4, window, cx);
18169    }
18170
18171    pub fn insert_uuid_v7(
18172        &mut self,
18173        _: &InsertUuidV7,
18174        window: &mut Window,
18175        cx: &mut Context<Self>,
18176    ) {
18177        self.insert_uuid(UuidVersion::V7, window, cx);
18178    }
18179
18180    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18181        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18182        self.transact(window, cx, |this, window, cx| {
18183            let edits = this
18184                .selections
18185                .all::<Point>(cx)
18186                .into_iter()
18187                .map(|selection| {
18188                    let uuid = match version {
18189                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18190                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18191                    };
18192
18193                    (selection.range(), uuid.to_string())
18194                });
18195            this.edit(edits, cx);
18196            this.refresh_inline_completion(true, false, window, cx);
18197        });
18198    }
18199
18200    pub fn open_selections_in_multibuffer(
18201        &mut self,
18202        _: &OpenSelectionsInMultibuffer,
18203        window: &mut Window,
18204        cx: &mut Context<Self>,
18205    ) {
18206        let multibuffer = self.buffer.read(cx);
18207
18208        let Some(buffer) = multibuffer.as_singleton() else {
18209            return;
18210        };
18211
18212        let Some(workspace) = self.workspace() else {
18213            return;
18214        };
18215
18216        let locations = self
18217            .selections
18218            .disjoint_anchors()
18219            .iter()
18220            .map(|range| Location {
18221                buffer: buffer.clone(),
18222                range: range.start.text_anchor..range.end.text_anchor,
18223            })
18224            .collect::<Vec<_>>();
18225
18226        let title = multibuffer.title(cx).to_string();
18227
18228        cx.spawn_in(window, async move |_, cx| {
18229            workspace.update_in(cx, |workspace, window, cx| {
18230                Self::open_locations_in_multibuffer(
18231                    workspace,
18232                    locations,
18233                    format!("Selections for '{title}'"),
18234                    false,
18235                    MultibufferSelectionMode::All,
18236                    window,
18237                    cx,
18238                );
18239            })
18240        })
18241        .detach();
18242    }
18243
18244    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18245    /// last highlight added will be used.
18246    ///
18247    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18248    pub fn highlight_rows<T: 'static>(
18249        &mut self,
18250        range: Range<Anchor>,
18251        color: Hsla,
18252        options: RowHighlightOptions,
18253        cx: &mut Context<Self>,
18254    ) {
18255        let snapshot = self.buffer().read(cx).snapshot(cx);
18256        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18257        let ix = row_highlights.binary_search_by(|highlight| {
18258            Ordering::Equal
18259                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18260                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18261        });
18262
18263        if let Err(mut ix) = ix {
18264            let index = post_inc(&mut self.highlight_order);
18265
18266            // If this range intersects with the preceding highlight, then merge it with
18267            // the preceding highlight. Otherwise insert a new highlight.
18268            let mut merged = false;
18269            if ix > 0 {
18270                let prev_highlight = &mut row_highlights[ix - 1];
18271                if prev_highlight
18272                    .range
18273                    .end
18274                    .cmp(&range.start, &snapshot)
18275                    .is_ge()
18276                {
18277                    ix -= 1;
18278                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18279                        prev_highlight.range.end = range.end;
18280                    }
18281                    merged = true;
18282                    prev_highlight.index = index;
18283                    prev_highlight.color = color;
18284                    prev_highlight.options = options;
18285                }
18286            }
18287
18288            if !merged {
18289                row_highlights.insert(
18290                    ix,
18291                    RowHighlight {
18292                        range: range.clone(),
18293                        index,
18294                        color,
18295                        options,
18296                        type_id: TypeId::of::<T>(),
18297                    },
18298                );
18299            }
18300
18301            // If any of the following highlights intersect with this one, merge them.
18302            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18303                let highlight = &row_highlights[ix];
18304                if next_highlight
18305                    .range
18306                    .start
18307                    .cmp(&highlight.range.end, &snapshot)
18308                    .is_le()
18309                {
18310                    if next_highlight
18311                        .range
18312                        .end
18313                        .cmp(&highlight.range.end, &snapshot)
18314                        .is_gt()
18315                    {
18316                        row_highlights[ix].range.end = next_highlight.range.end;
18317                    }
18318                    row_highlights.remove(ix + 1);
18319                } else {
18320                    break;
18321                }
18322            }
18323        }
18324    }
18325
18326    /// Remove any highlighted row ranges of the given type that intersect the
18327    /// given ranges.
18328    pub fn remove_highlighted_rows<T: 'static>(
18329        &mut self,
18330        ranges_to_remove: Vec<Range<Anchor>>,
18331        cx: &mut Context<Self>,
18332    ) {
18333        let snapshot = self.buffer().read(cx).snapshot(cx);
18334        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18335        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18336        row_highlights.retain(|highlight| {
18337            while let Some(range_to_remove) = ranges_to_remove.peek() {
18338                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18339                    Ordering::Less | Ordering::Equal => {
18340                        ranges_to_remove.next();
18341                    }
18342                    Ordering::Greater => {
18343                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18344                            Ordering::Less | Ordering::Equal => {
18345                                return false;
18346                            }
18347                            Ordering::Greater => break,
18348                        }
18349                    }
18350                }
18351            }
18352
18353            true
18354        })
18355    }
18356
18357    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18358    pub fn clear_row_highlights<T: 'static>(&mut self) {
18359        self.highlighted_rows.remove(&TypeId::of::<T>());
18360    }
18361
18362    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18363    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18364        self.highlighted_rows
18365            .get(&TypeId::of::<T>())
18366            .map_or(&[] as &[_], |vec| vec.as_slice())
18367            .iter()
18368            .map(|highlight| (highlight.range.clone(), highlight.color))
18369    }
18370
18371    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18372    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18373    /// Allows to ignore certain kinds of highlights.
18374    pub fn highlighted_display_rows(
18375        &self,
18376        window: &mut Window,
18377        cx: &mut App,
18378    ) -> BTreeMap<DisplayRow, LineHighlight> {
18379        let snapshot = self.snapshot(window, cx);
18380        let mut used_highlight_orders = HashMap::default();
18381        self.highlighted_rows
18382            .iter()
18383            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18384            .fold(
18385                BTreeMap::<DisplayRow, LineHighlight>::new(),
18386                |mut unique_rows, highlight| {
18387                    let start = highlight.range.start.to_display_point(&snapshot);
18388                    let end = highlight.range.end.to_display_point(&snapshot);
18389                    let start_row = start.row().0;
18390                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18391                        && end.column() == 0
18392                    {
18393                        end.row().0.saturating_sub(1)
18394                    } else {
18395                        end.row().0
18396                    };
18397                    for row in start_row..=end_row {
18398                        let used_index =
18399                            used_highlight_orders.entry(row).or_insert(highlight.index);
18400                        if highlight.index >= *used_index {
18401                            *used_index = highlight.index;
18402                            unique_rows.insert(
18403                                DisplayRow(row),
18404                                LineHighlight {
18405                                    include_gutter: highlight.options.include_gutter,
18406                                    border: None,
18407                                    background: highlight.color.into(),
18408                                    type_id: Some(highlight.type_id),
18409                                },
18410                            );
18411                        }
18412                    }
18413                    unique_rows
18414                },
18415            )
18416    }
18417
18418    pub fn highlighted_display_row_for_autoscroll(
18419        &self,
18420        snapshot: &DisplaySnapshot,
18421    ) -> Option<DisplayRow> {
18422        self.highlighted_rows
18423            .values()
18424            .flat_map(|highlighted_rows| highlighted_rows.iter())
18425            .filter_map(|highlight| {
18426                if highlight.options.autoscroll {
18427                    Some(highlight.range.start.to_display_point(snapshot).row())
18428                } else {
18429                    None
18430                }
18431            })
18432            .min()
18433    }
18434
18435    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18436        self.highlight_background::<SearchWithinRange>(
18437            ranges,
18438            |colors| colors.editor_document_highlight_read_background,
18439            cx,
18440        )
18441    }
18442
18443    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18444        self.breadcrumb_header = Some(new_header);
18445    }
18446
18447    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18448        self.clear_background_highlights::<SearchWithinRange>(cx);
18449    }
18450
18451    pub fn highlight_background<T: 'static>(
18452        &mut self,
18453        ranges: &[Range<Anchor>],
18454        color_fetcher: fn(&ThemeColors) -> Hsla,
18455        cx: &mut Context<Self>,
18456    ) {
18457        self.background_highlights
18458            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18459        self.scrollbar_marker_state.dirty = true;
18460        cx.notify();
18461    }
18462
18463    pub fn clear_background_highlights<T: 'static>(
18464        &mut self,
18465        cx: &mut Context<Self>,
18466    ) -> Option<BackgroundHighlight> {
18467        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18468        if !text_highlights.1.is_empty() {
18469            self.scrollbar_marker_state.dirty = true;
18470            cx.notify();
18471        }
18472        Some(text_highlights)
18473    }
18474
18475    pub fn highlight_gutter<T: 'static>(
18476        &mut self,
18477        ranges: impl Into<Vec<Range<Anchor>>>,
18478        color_fetcher: fn(&App) -> Hsla,
18479        cx: &mut Context<Self>,
18480    ) {
18481        self.gutter_highlights
18482            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18483        cx.notify();
18484    }
18485
18486    pub fn clear_gutter_highlights<T: 'static>(
18487        &mut self,
18488        cx: &mut Context<Self>,
18489    ) -> Option<GutterHighlight> {
18490        cx.notify();
18491        self.gutter_highlights.remove(&TypeId::of::<T>())
18492    }
18493
18494    pub fn insert_gutter_highlight<T: 'static>(
18495        &mut self,
18496        range: Range<Anchor>,
18497        color_fetcher: fn(&App) -> Hsla,
18498        cx: &mut Context<Self>,
18499    ) {
18500        let snapshot = self.buffer().read(cx).snapshot(cx);
18501        let mut highlights = self
18502            .gutter_highlights
18503            .remove(&TypeId::of::<T>())
18504            .map(|(_, highlights)| highlights)
18505            .unwrap_or_default();
18506        let ix = highlights.binary_search_by(|highlight| {
18507            Ordering::Equal
18508                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18509                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18510        });
18511        if let Err(ix) = ix {
18512            highlights.insert(ix, range);
18513        }
18514        self.gutter_highlights
18515            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18516    }
18517
18518    pub fn remove_gutter_highlights<T: 'static>(
18519        &mut self,
18520        ranges_to_remove: Vec<Range<Anchor>>,
18521        cx: &mut Context<Self>,
18522    ) {
18523        let snapshot = self.buffer().read(cx).snapshot(cx);
18524        let Some((color_fetcher, mut gutter_highlights)) =
18525            self.gutter_highlights.remove(&TypeId::of::<T>())
18526        else {
18527            return;
18528        };
18529        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18530        gutter_highlights.retain(|highlight| {
18531            while let Some(range_to_remove) = ranges_to_remove.peek() {
18532                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18533                    Ordering::Less | Ordering::Equal => {
18534                        ranges_to_remove.next();
18535                    }
18536                    Ordering::Greater => {
18537                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18538                            Ordering::Less | Ordering::Equal => {
18539                                return false;
18540                            }
18541                            Ordering::Greater => break,
18542                        }
18543                    }
18544                }
18545            }
18546
18547            true
18548        });
18549        self.gutter_highlights
18550            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18551    }
18552
18553    #[cfg(feature = "test-support")]
18554    pub fn all_text_background_highlights(
18555        &self,
18556        window: &mut Window,
18557        cx: &mut Context<Self>,
18558    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18559        let snapshot = self.snapshot(window, cx);
18560        let buffer = &snapshot.buffer_snapshot;
18561        let start = buffer.anchor_before(0);
18562        let end = buffer.anchor_after(buffer.len());
18563        let theme = cx.theme().colors();
18564        self.background_highlights_in_range(start..end, &snapshot, theme)
18565    }
18566
18567    #[cfg(feature = "test-support")]
18568    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18569        let snapshot = self.buffer().read(cx).snapshot(cx);
18570
18571        let highlights = self
18572            .background_highlights
18573            .get(&TypeId::of::<items::BufferSearchHighlights>());
18574
18575        if let Some((_color, ranges)) = highlights {
18576            ranges
18577                .iter()
18578                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18579                .collect_vec()
18580        } else {
18581            vec![]
18582        }
18583    }
18584
18585    fn document_highlights_for_position<'a>(
18586        &'a self,
18587        position: Anchor,
18588        buffer: &'a MultiBufferSnapshot,
18589    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18590        let read_highlights = self
18591            .background_highlights
18592            .get(&TypeId::of::<DocumentHighlightRead>())
18593            .map(|h| &h.1);
18594        let write_highlights = self
18595            .background_highlights
18596            .get(&TypeId::of::<DocumentHighlightWrite>())
18597            .map(|h| &h.1);
18598        let left_position = position.bias_left(buffer);
18599        let right_position = position.bias_right(buffer);
18600        read_highlights
18601            .into_iter()
18602            .chain(write_highlights)
18603            .flat_map(move |ranges| {
18604                let start_ix = match ranges.binary_search_by(|probe| {
18605                    let cmp = probe.end.cmp(&left_position, buffer);
18606                    if cmp.is_ge() {
18607                        Ordering::Greater
18608                    } else {
18609                        Ordering::Less
18610                    }
18611                }) {
18612                    Ok(i) | Err(i) => i,
18613                };
18614
18615                ranges[start_ix..]
18616                    .iter()
18617                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18618            })
18619    }
18620
18621    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18622        self.background_highlights
18623            .get(&TypeId::of::<T>())
18624            .map_or(false, |(_, highlights)| !highlights.is_empty())
18625    }
18626
18627    pub fn background_highlights_in_range(
18628        &self,
18629        search_range: Range<Anchor>,
18630        display_snapshot: &DisplaySnapshot,
18631        theme: &ThemeColors,
18632    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18633        let mut results = Vec::new();
18634        for (color_fetcher, ranges) in self.background_highlights.values() {
18635            let color = color_fetcher(theme);
18636            let start_ix = match ranges.binary_search_by(|probe| {
18637                let cmp = probe
18638                    .end
18639                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18640                if cmp.is_gt() {
18641                    Ordering::Greater
18642                } else {
18643                    Ordering::Less
18644                }
18645            }) {
18646                Ok(i) | Err(i) => i,
18647            };
18648            for range in &ranges[start_ix..] {
18649                if range
18650                    .start
18651                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18652                    .is_ge()
18653                {
18654                    break;
18655                }
18656
18657                let start = range.start.to_display_point(display_snapshot);
18658                let end = range.end.to_display_point(display_snapshot);
18659                results.push((start..end, color))
18660            }
18661        }
18662        results
18663    }
18664
18665    pub fn background_highlight_row_ranges<T: 'static>(
18666        &self,
18667        search_range: Range<Anchor>,
18668        display_snapshot: &DisplaySnapshot,
18669        count: usize,
18670    ) -> Vec<RangeInclusive<DisplayPoint>> {
18671        let mut results = Vec::new();
18672        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18673            return vec![];
18674        };
18675
18676        let start_ix = match ranges.binary_search_by(|probe| {
18677            let cmp = probe
18678                .end
18679                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18680            if cmp.is_gt() {
18681                Ordering::Greater
18682            } else {
18683                Ordering::Less
18684            }
18685        }) {
18686            Ok(i) | Err(i) => i,
18687        };
18688        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18689            if let (Some(start_display), Some(end_display)) = (start, end) {
18690                results.push(
18691                    start_display.to_display_point(display_snapshot)
18692                        ..=end_display.to_display_point(display_snapshot),
18693                );
18694            }
18695        };
18696        let mut start_row: Option<Point> = None;
18697        let mut end_row: Option<Point> = None;
18698        if ranges.len() > count {
18699            return Vec::new();
18700        }
18701        for range in &ranges[start_ix..] {
18702            if range
18703                .start
18704                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18705                .is_ge()
18706            {
18707                break;
18708            }
18709            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18710            if let Some(current_row) = &end_row {
18711                if end.row == current_row.row {
18712                    continue;
18713                }
18714            }
18715            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18716            if start_row.is_none() {
18717                assert_eq!(end_row, None);
18718                start_row = Some(start);
18719                end_row = Some(end);
18720                continue;
18721            }
18722            if let Some(current_end) = end_row.as_mut() {
18723                if start.row > current_end.row + 1 {
18724                    push_region(start_row, end_row);
18725                    start_row = Some(start);
18726                    end_row = Some(end);
18727                } else {
18728                    // Merge two hunks.
18729                    *current_end = end;
18730                }
18731            } else {
18732                unreachable!();
18733            }
18734        }
18735        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18736        push_region(start_row, end_row);
18737        results
18738    }
18739
18740    pub fn gutter_highlights_in_range(
18741        &self,
18742        search_range: Range<Anchor>,
18743        display_snapshot: &DisplaySnapshot,
18744        cx: &App,
18745    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18746        let mut results = Vec::new();
18747        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18748            let color = color_fetcher(cx);
18749            let start_ix = match ranges.binary_search_by(|probe| {
18750                let cmp = probe
18751                    .end
18752                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18753                if cmp.is_gt() {
18754                    Ordering::Greater
18755                } else {
18756                    Ordering::Less
18757                }
18758            }) {
18759                Ok(i) | Err(i) => i,
18760            };
18761            for range in &ranges[start_ix..] {
18762                if range
18763                    .start
18764                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18765                    .is_ge()
18766                {
18767                    break;
18768                }
18769
18770                let start = range.start.to_display_point(display_snapshot);
18771                let end = range.end.to_display_point(display_snapshot);
18772                results.push((start..end, color))
18773            }
18774        }
18775        results
18776    }
18777
18778    /// Get the text ranges corresponding to the redaction query
18779    pub fn redacted_ranges(
18780        &self,
18781        search_range: Range<Anchor>,
18782        display_snapshot: &DisplaySnapshot,
18783        cx: &App,
18784    ) -> Vec<Range<DisplayPoint>> {
18785        display_snapshot
18786            .buffer_snapshot
18787            .redacted_ranges(search_range, |file| {
18788                if let Some(file) = file {
18789                    file.is_private()
18790                        && EditorSettings::get(
18791                            Some(SettingsLocation {
18792                                worktree_id: file.worktree_id(cx),
18793                                path: file.path().as_ref(),
18794                            }),
18795                            cx,
18796                        )
18797                        .redact_private_values
18798                } else {
18799                    false
18800                }
18801            })
18802            .map(|range| {
18803                range.start.to_display_point(display_snapshot)
18804                    ..range.end.to_display_point(display_snapshot)
18805            })
18806            .collect()
18807    }
18808
18809    pub fn highlight_text<T: 'static>(
18810        &mut self,
18811        ranges: Vec<Range<Anchor>>,
18812        style: HighlightStyle,
18813        cx: &mut Context<Self>,
18814    ) {
18815        self.display_map.update(cx, |map, _| {
18816            map.highlight_text(TypeId::of::<T>(), ranges, style)
18817        });
18818        cx.notify();
18819    }
18820
18821    pub(crate) fn highlight_inlays<T: 'static>(
18822        &mut self,
18823        highlights: Vec<InlayHighlight>,
18824        style: HighlightStyle,
18825        cx: &mut Context<Self>,
18826    ) {
18827        self.display_map.update(cx, |map, _| {
18828            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18829        });
18830        cx.notify();
18831    }
18832
18833    pub fn text_highlights<'a, T: 'static>(
18834        &'a self,
18835        cx: &'a App,
18836    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18837        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18838    }
18839
18840    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18841        let cleared = self
18842            .display_map
18843            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18844        if cleared {
18845            cx.notify();
18846        }
18847    }
18848
18849    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18850        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18851            && self.focus_handle.is_focused(window)
18852    }
18853
18854    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18855        self.show_cursor_when_unfocused = is_enabled;
18856        cx.notify();
18857    }
18858
18859    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18860        cx.notify();
18861    }
18862
18863    fn on_debug_session_event(
18864        &mut self,
18865        _session: Entity<Session>,
18866        event: &SessionEvent,
18867        cx: &mut Context<Self>,
18868    ) {
18869        match event {
18870            SessionEvent::InvalidateInlineValue => {
18871                self.refresh_inline_values(cx);
18872            }
18873            _ => {}
18874        }
18875    }
18876
18877    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18878        let Some(project) = self.project.clone() else {
18879            return;
18880        };
18881
18882        if !self.inline_value_cache.enabled {
18883            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18884            self.splice_inlays(&inlays, Vec::new(), cx);
18885            return;
18886        }
18887
18888        let current_execution_position = self
18889            .highlighted_rows
18890            .get(&TypeId::of::<ActiveDebugLine>())
18891            .and_then(|lines| lines.last().map(|line| line.range.start));
18892
18893        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18894            let inline_values = editor
18895                .update(cx, |editor, cx| {
18896                    let Some(current_execution_position) = current_execution_position else {
18897                        return Some(Task::ready(Ok(Vec::new())));
18898                    };
18899
18900                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18901                        let snapshot = buffer.snapshot(cx);
18902
18903                        let excerpt = snapshot.excerpt_containing(
18904                            current_execution_position..current_execution_position,
18905                        )?;
18906
18907                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18908                    })?;
18909
18910                    let range =
18911                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18912
18913                    project.inline_values(buffer, range, cx)
18914                })
18915                .ok()
18916                .flatten()?
18917                .await
18918                .context("refreshing debugger inlays")
18919                .log_err()?;
18920
18921            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18922
18923            for (buffer_id, inline_value) in inline_values
18924                .into_iter()
18925                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18926            {
18927                buffer_inline_values
18928                    .entry(buffer_id)
18929                    .or_default()
18930                    .push(inline_value);
18931            }
18932
18933            editor
18934                .update(cx, |editor, cx| {
18935                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18936                    let mut new_inlays = Vec::default();
18937
18938                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18939                        let buffer_id = buffer_snapshot.remote_id();
18940                        buffer_inline_values
18941                            .get(&buffer_id)
18942                            .into_iter()
18943                            .flatten()
18944                            .for_each(|hint| {
18945                                let inlay = Inlay::debugger_hint(
18946                                    post_inc(&mut editor.next_inlay_id),
18947                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18948                                    hint.text(),
18949                                );
18950
18951                                new_inlays.push(inlay);
18952                            });
18953                    }
18954
18955                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18956                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18957
18958                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18959                })
18960                .ok()?;
18961            Some(())
18962        });
18963    }
18964
18965    fn on_buffer_event(
18966        &mut self,
18967        multibuffer: &Entity<MultiBuffer>,
18968        event: &multi_buffer::Event,
18969        window: &mut Window,
18970        cx: &mut Context<Self>,
18971    ) {
18972        match event {
18973            multi_buffer::Event::Edited {
18974                singleton_buffer_edited,
18975                edited_buffer,
18976            } => {
18977                self.scrollbar_marker_state.dirty = true;
18978                self.active_indent_guides_state.dirty = true;
18979                self.refresh_active_diagnostics(cx);
18980                self.refresh_code_actions(window, cx);
18981                self.refresh_selected_text_highlights(true, window, cx);
18982                refresh_matching_bracket_highlights(self, window, cx);
18983                if self.has_active_inline_completion() {
18984                    self.update_visible_inline_completion(window, cx);
18985                }
18986                if let Some(project) = self.project.as_ref() {
18987                    if let Some(edited_buffer) = edited_buffer {
18988                        project.update(cx, |project, cx| {
18989                            self.registered_buffers
18990                                .entry(edited_buffer.read(cx).remote_id())
18991                                .or_insert_with(|| {
18992                                    project
18993                                        .register_buffer_with_language_servers(&edited_buffer, cx)
18994                                });
18995                        });
18996                        if edited_buffer.read(cx).file().is_some() {
18997                            self.pull_diagnostics(
18998                                Some(edited_buffer.read(cx).remote_id()),
18999                                window,
19000                                cx,
19001                            );
19002                        }
19003                    }
19004                }
19005                cx.emit(EditorEvent::BufferEdited);
19006                cx.emit(SearchEvent::MatchesInvalidated);
19007                if *singleton_buffer_edited {
19008                    if let Some(buffer) = edited_buffer {
19009                        if buffer.read(cx).file().is_none() {
19010                            cx.emit(EditorEvent::TitleChanged);
19011                        }
19012                    }
19013                    if let Some(project) = &self.project {
19014                        #[allow(clippy::mutable_key_type)]
19015                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19016                            multibuffer
19017                                .all_buffers()
19018                                .into_iter()
19019                                .filter_map(|buffer| {
19020                                    buffer.update(cx, |buffer, cx| {
19021                                        let language = buffer.language()?;
19022                                        let should_discard = project.update(cx, |project, cx| {
19023                                            project.is_local()
19024                                                && !project.has_language_servers_for(buffer, cx)
19025                                        });
19026                                        should_discard.not().then_some(language.clone())
19027                                    })
19028                                })
19029                                .collect::<HashSet<_>>()
19030                        });
19031                        if !languages_affected.is_empty() {
19032                            self.refresh_inlay_hints(
19033                                InlayHintRefreshReason::BufferEdited(languages_affected),
19034                                cx,
19035                            );
19036                        }
19037                    }
19038                }
19039
19040                let Some(project) = &self.project else { return };
19041                let (telemetry, is_via_ssh) = {
19042                    let project = project.read(cx);
19043                    let telemetry = project.client().telemetry().clone();
19044                    let is_via_ssh = project.is_via_ssh();
19045                    (telemetry, is_via_ssh)
19046                };
19047                refresh_linked_ranges(self, window, cx);
19048                telemetry.log_edit_event("editor", is_via_ssh);
19049            }
19050            multi_buffer::Event::ExcerptsAdded {
19051                buffer,
19052                predecessor,
19053                excerpts,
19054            } => {
19055                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19056                let buffer_id = buffer.read(cx).remote_id();
19057                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19058                    if let Some(project) = &self.project {
19059                        update_uncommitted_diff_for_buffer(
19060                            cx.entity(),
19061                            project,
19062                            [buffer.clone()],
19063                            self.buffer.clone(),
19064                            cx,
19065                        )
19066                        .detach();
19067                    }
19068                }
19069                cx.emit(EditorEvent::ExcerptsAdded {
19070                    buffer: buffer.clone(),
19071                    predecessor: *predecessor,
19072                    excerpts: excerpts.clone(),
19073                });
19074                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19075            }
19076            multi_buffer::Event::ExcerptsRemoved {
19077                ids,
19078                removed_buffer_ids,
19079            } => {
19080                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19081                let buffer = self.buffer.read(cx);
19082                self.registered_buffers
19083                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19084                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19085                cx.emit(EditorEvent::ExcerptsRemoved {
19086                    ids: ids.clone(),
19087                    removed_buffer_ids: removed_buffer_ids.clone(),
19088                })
19089            }
19090            multi_buffer::Event::ExcerptsEdited {
19091                excerpt_ids,
19092                buffer_ids,
19093            } => {
19094                self.display_map.update(cx, |map, cx| {
19095                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19096                });
19097                cx.emit(EditorEvent::ExcerptsEdited {
19098                    ids: excerpt_ids.clone(),
19099                })
19100            }
19101            multi_buffer::Event::ExcerptsExpanded { ids } => {
19102                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19103                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19104            }
19105            multi_buffer::Event::Reparsed(buffer_id) => {
19106                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19107                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19108
19109                cx.emit(EditorEvent::Reparsed(*buffer_id));
19110            }
19111            multi_buffer::Event::DiffHunksToggled => {
19112                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19113            }
19114            multi_buffer::Event::LanguageChanged(buffer_id) => {
19115                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19116                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19117                cx.emit(EditorEvent::Reparsed(*buffer_id));
19118                cx.notify();
19119            }
19120            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19121            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19122            multi_buffer::Event::FileHandleChanged
19123            | multi_buffer::Event::Reloaded
19124            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19125            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19126            multi_buffer::Event::DiagnosticsUpdated => {
19127                self.update_diagnostics_state(window, cx);
19128            }
19129            _ => {}
19130        };
19131    }
19132
19133    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19134        self.refresh_active_diagnostics(cx);
19135        self.refresh_inline_diagnostics(true, window, cx);
19136        self.scrollbar_marker_state.dirty = true;
19137        cx.notify();
19138    }
19139
19140    pub fn start_temporary_diff_override(&mut self) {
19141        self.load_diff_task.take();
19142        self.temporary_diff_override = true;
19143    }
19144
19145    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19146        self.temporary_diff_override = false;
19147        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19148        self.buffer.update(cx, |buffer, cx| {
19149            buffer.set_all_diff_hunks_collapsed(cx);
19150        });
19151
19152        if let Some(project) = self.project.clone() {
19153            self.load_diff_task = Some(
19154                update_uncommitted_diff_for_buffer(
19155                    cx.entity(),
19156                    &project,
19157                    self.buffer.read(cx).all_buffers(),
19158                    self.buffer.clone(),
19159                    cx,
19160                )
19161                .shared(),
19162            );
19163        }
19164    }
19165
19166    fn on_display_map_changed(
19167        &mut self,
19168        _: Entity<DisplayMap>,
19169        _: &mut Window,
19170        cx: &mut Context<Self>,
19171    ) {
19172        cx.notify();
19173    }
19174
19175    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19176        let new_severity = if self.diagnostics_enabled() {
19177            EditorSettings::get_global(cx)
19178                .diagnostics_max_severity
19179                .unwrap_or(DiagnosticSeverity::Hint)
19180        } else {
19181            DiagnosticSeverity::Off
19182        };
19183        self.set_max_diagnostics_severity(new_severity, cx);
19184        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19185        self.update_edit_prediction_settings(cx);
19186        self.refresh_inline_completion(true, false, window, cx);
19187        self.refresh_inlay_hints(
19188            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19189                self.selections.newest_anchor().head(),
19190                &self.buffer.read(cx).snapshot(cx),
19191                cx,
19192            )),
19193            cx,
19194        );
19195
19196        let old_cursor_shape = self.cursor_shape;
19197
19198        {
19199            let editor_settings = EditorSettings::get_global(cx);
19200            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19201            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19202            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19203            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19204            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19205        }
19206
19207        if old_cursor_shape != self.cursor_shape {
19208            cx.emit(EditorEvent::CursorShapeChanged);
19209        }
19210
19211        let project_settings = ProjectSettings::get_global(cx);
19212        self.serialize_dirty_buffers =
19213            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19214
19215        if self.mode.is_full() {
19216            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19217            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19218            if self.show_inline_diagnostics != show_inline_diagnostics {
19219                self.show_inline_diagnostics = show_inline_diagnostics;
19220                self.refresh_inline_diagnostics(false, window, cx);
19221            }
19222
19223            if self.git_blame_inline_enabled != inline_blame_enabled {
19224                self.toggle_git_blame_inline_internal(false, window, cx);
19225            }
19226
19227            let minimap_settings = EditorSettings::get_global(cx).minimap;
19228            if self.minimap_visibility != MinimapVisibility::Disabled {
19229                if self.minimap_visibility.settings_visibility()
19230                    != minimap_settings.minimap_enabled()
19231                {
19232                    self.set_minimap_visibility(
19233                        MinimapVisibility::for_mode(self.mode(), cx),
19234                        window,
19235                        cx,
19236                    );
19237                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19238                    minimap_entity.update(cx, |minimap_editor, cx| {
19239                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19240                    })
19241                }
19242            }
19243        }
19244
19245        cx.notify();
19246    }
19247
19248    pub fn set_searchable(&mut self, searchable: bool) {
19249        self.searchable = searchable;
19250    }
19251
19252    pub fn searchable(&self) -> bool {
19253        self.searchable
19254    }
19255
19256    fn open_proposed_changes_editor(
19257        &mut self,
19258        _: &OpenProposedChangesEditor,
19259        window: &mut Window,
19260        cx: &mut Context<Self>,
19261    ) {
19262        let Some(workspace) = self.workspace() else {
19263            cx.propagate();
19264            return;
19265        };
19266
19267        let selections = self.selections.all::<usize>(cx);
19268        let multi_buffer = self.buffer.read(cx);
19269        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19270        let mut new_selections_by_buffer = HashMap::default();
19271        for selection in selections {
19272            for (buffer, range, _) in
19273                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19274            {
19275                let mut range = range.to_point(buffer);
19276                range.start.column = 0;
19277                range.end.column = buffer.line_len(range.end.row);
19278                new_selections_by_buffer
19279                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19280                    .or_insert(Vec::new())
19281                    .push(range)
19282            }
19283        }
19284
19285        let proposed_changes_buffers = new_selections_by_buffer
19286            .into_iter()
19287            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19288            .collect::<Vec<_>>();
19289        let proposed_changes_editor = cx.new(|cx| {
19290            ProposedChangesEditor::new(
19291                "Proposed changes",
19292                proposed_changes_buffers,
19293                self.project.clone(),
19294                window,
19295                cx,
19296            )
19297        });
19298
19299        window.defer(cx, move |window, cx| {
19300            workspace.update(cx, |workspace, cx| {
19301                workspace.active_pane().update(cx, |pane, cx| {
19302                    pane.add_item(
19303                        Box::new(proposed_changes_editor),
19304                        true,
19305                        true,
19306                        None,
19307                        window,
19308                        cx,
19309                    );
19310                });
19311            });
19312        });
19313    }
19314
19315    pub fn open_excerpts_in_split(
19316        &mut self,
19317        _: &OpenExcerptsSplit,
19318        window: &mut Window,
19319        cx: &mut Context<Self>,
19320    ) {
19321        self.open_excerpts_common(None, true, window, cx)
19322    }
19323
19324    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19325        self.open_excerpts_common(None, false, window, cx)
19326    }
19327
19328    fn open_excerpts_common(
19329        &mut self,
19330        jump_data: Option<JumpData>,
19331        split: bool,
19332        window: &mut Window,
19333        cx: &mut Context<Self>,
19334    ) {
19335        let Some(workspace) = self.workspace() else {
19336            cx.propagate();
19337            return;
19338        };
19339
19340        if self.buffer.read(cx).is_singleton() {
19341            cx.propagate();
19342            return;
19343        }
19344
19345        let mut new_selections_by_buffer = HashMap::default();
19346        match &jump_data {
19347            Some(JumpData::MultiBufferPoint {
19348                excerpt_id,
19349                position,
19350                anchor,
19351                line_offset_from_top,
19352            }) => {
19353                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19354                if let Some(buffer) = multi_buffer_snapshot
19355                    .buffer_id_for_excerpt(*excerpt_id)
19356                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19357                {
19358                    let buffer_snapshot = buffer.read(cx).snapshot();
19359                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19360                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19361                    } else {
19362                        buffer_snapshot.clip_point(*position, Bias::Left)
19363                    };
19364                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19365                    new_selections_by_buffer.insert(
19366                        buffer,
19367                        (
19368                            vec![jump_to_offset..jump_to_offset],
19369                            Some(*line_offset_from_top),
19370                        ),
19371                    );
19372                }
19373            }
19374            Some(JumpData::MultiBufferRow {
19375                row,
19376                line_offset_from_top,
19377            }) => {
19378                let point = MultiBufferPoint::new(row.0, 0);
19379                if let Some((buffer, buffer_point, _)) =
19380                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19381                {
19382                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19383                    new_selections_by_buffer
19384                        .entry(buffer)
19385                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19386                        .0
19387                        .push(buffer_offset..buffer_offset)
19388                }
19389            }
19390            None => {
19391                let selections = self.selections.all::<usize>(cx);
19392                let multi_buffer = self.buffer.read(cx);
19393                for selection in selections {
19394                    for (snapshot, range, _, anchor) in multi_buffer
19395                        .snapshot(cx)
19396                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19397                    {
19398                        if let Some(anchor) = anchor {
19399                            // selection is in a deleted hunk
19400                            let Some(buffer_id) = anchor.buffer_id else {
19401                                continue;
19402                            };
19403                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19404                                continue;
19405                            };
19406                            let offset = text::ToOffset::to_offset(
19407                                &anchor.text_anchor,
19408                                &buffer_handle.read(cx).snapshot(),
19409                            );
19410                            let range = offset..offset;
19411                            new_selections_by_buffer
19412                                .entry(buffer_handle)
19413                                .or_insert((Vec::new(), None))
19414                                .0
19415                                .push(range)
19416                        } else {
19417                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19418                            else {
19419                                continue;
19420                            };
19421                            new_selections_by_buffer
19422                                .entry(buffer_handle)
19423                                .or_insert((Vec::new(), None))
19424                                .0
19425                                .push(range)
19426                        }
19427                    }
19428                }
19429            }
19430        }
19431
19432        new_selections_by_buffer
19433            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19434
19435        if new_selections_by_buffer.is_empty() {
19436            return;
19437        }
19438
19439        // We defer the pane interaction because we ourselves are a workspace item
19440        // and activating a new item causes the pane to call a method on us reentrantly,
19441        // which panics if we're on the stack.
19442        window.defer(cx, move |window, cx| {
19443            workspace.update(cx, |workspace, cx| {
19444                let pane = if split {
19445                    workspace.adjacent_pane(window, cx)
19446                } else {
19447                    workspace.active_pane().clone()
19448                };
19449
19450                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19451                    let editor = buffer
19452                        .read(cx)
19453                        .file()
19454                        .is_none()
19455                        .then(|| {
19456                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19457                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19458                            // Instead, we try to activate the existing editor in the pane first.
19459                            let (editor, pane_item_index) =
19460                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19461                                    let editor = item.downcast::<Editor>()?;
19462                                    let singleton_buffer =
19463                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19464                                    if singleton_buffer == buffer {
19465                                        Some((editor, i))
19466                                    } else {
19467                                        None
19468                                    }
19469                                })?;
19470                            pane.update(cx, |pane, cx| {
19471                                pane.activate_item(pane_item_index, true, true, window, cx)
19472                            });
19473                            Some(editor)
19474                        })
19475                        .flatten()
19476                        .unwrap_or_else(|| {
19477                            workspace.open_project_item::<Self>(
19478                                pane.clone(),
19479                                buffer,
19480                                true,
19481                                true,
19482                                window,
19483                                cx,
19484                            )
19485                        });
19486
19487                    editor.update(cx, |editor, cx| {
19488                        let autoscroll = match scroll_offset {
19489                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19490                            None => Autoscroll::newest(),
19491                        };
19492                        let nav_history = editor.nav_history.take();
19493                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19494                            s.select_ranges(ranges);
19495                        });
19496                        editor.nav_history = nav_history;
19497                    });
19498                }
19499            })
19500        });
19501    }
19502
19503    // For now, don't allow opening excerpts in buffers that aren't backed by
19504    // regular project files.
19505    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19506        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19507    }
19508
19509    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19510        let snapshot = self.buffer.read(cx).read(cx);
19511        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19512        Some(
19513            ranges
19514                .iter()
19515                .map(move |range| {
19516                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19517                })
19518                .collect(),
19519        )
19520    }
19521
19522    fn selection_replacement_ranges(
19523        &self,
19524        range: Range<OffsetUtf16>,
19525        cx: &mut App,
19526    ) -> Vec<Range<OffsetUtf16>> {
19527        let selections = self.selections.all::<OffsetUtf16>(cx);
19528        let newest_selection = selections
19529            .iter()
19530            .max_by_key(|selection| selection.id)
19531            .unwrap();
19532        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19533        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19534        let snapshot = self.buffer.read(cx).read(cx);
19535        selections
19536            .into_iter()
19537            .map(|mut selection| {
19538                selection.start.0 =
19539                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19540                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19541                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19542                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19543            })
19544            .collect()
19545    }
19546
19547    fn report_editor_event(
19548        &self,
19549        event_type: &'static str,
19550        file_extension: Option<String>,
19551        cx: &App,
19552    ) {
19553        if cfg!(any(test, feature = "test-support")) {
19554            return;
19555        }
19556
19557        let Some(project) = &self.project else { return };
19558
19559        // If None, we are in a file without an extension
19560        let file = self
19561            .buffer
19562            .read(cx)
19563            .as_singleton()
19564            .and_then(|b| b.read(cx).file());
19565        let file_extension = file_extension.or(file
19566            .as_ref()
19567            .and_then(|file| Path::new(file.file_name(cx)).extension())
19568            .and_then(|e| e.to_str())
19569            .map(|a| a.to_string()));
19570
19571        let vim_mode = vim_enabled(cx);
19572
19573        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19574        let copilot_enabled = edit_predictions_provider
19575            == language::language_settings::EditPredictionProvider::Copilot;
19576        let copilot_enabled_for_language = self
19577            .buffer
19578            .read(cx)
19579            .language_settings(cx)
19580            .show_edit_predictions;
19581
19582        let project = project.read(cx);
19583        telemetry::event!(
19584            event_type,
19585            file_extension,
19586            vim_mode,
19587            copilot_enabled,
19588            copilot_enabled_for_language,
19589            edit_predictions_provider,
19590            is_via_ssh = project.is_via_ssh(),
19591        );
19592    }
19593
19594    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19595    /// with each line being an array of {text, highlight} objects.
19596    fn copy_highlight_json(
19597        &mut self,
19598        _: &CopyHighlightJson,
19599        window: &mut Window,
19600        cx: &mut Context<Self>,
19601    ) {
19602        #[derive(Serialize)]
19603        struct Chunk<'a> {
19604            text: String,
19605            highlight: Option<&'a str>,
19606        }
19607
19608        let snapshot = self.buffer.read(cx).snapshot(cx);
19609        let range = self
19610            .selected_text_range(false, window, cx)
19611            .and_then(|selection| {
19612                if selection.range.is_empty() {
19613                    None
19614                } else {
19615                    Some(selection.range)
19616                }
19617            })
19618            .unwrap_or_else(|| 0..snapshot.len());
19619
19620        let chunks = snapshot.chunks(range, true);
19621        let mut lines = Vec::new();
19622        let mut line: VecDeque<Chunk> = VecDeque::new();
19623
19624        let Some(style) = self.style.as_ref() else {
19625            return;
19626        };
19627
19628        for chunk in chunks {
19629            let highlight = chunk
19630                .syntax_highlight_id
19631                .and_then(|id| id.name(&style.syntax));
19632            let mut chunk_lines = chunk.text.split('\n').peekable();
19633            while let Some(text) = chunk_lines.next() {
19634                let mut merged_with_last_token = false;
19635                if let Some(last_token) = line.back_mut() {
19636                    if last_token.highlight == highlight {
19637                        last_token.text.push_str(text);
19638                        merged_with_last_token = true;
19639                    }
19640                }
19641
19642                if !merged_with_last_token {
19643                    line.push_back(Chunk {
19644                        text: text.into(),
19645                        highlight,
19646                    });
19647                }
19648
19649                if chunk_lines.peek().is_some() {
19650                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19651                        line.pop_front();
19652                    }
19653                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19654                        line.pop_back();
19655                    }
19656
19657                    lines.push(mem::take(&mut line));
19658                }
19659            }
19660        }
19661
19662        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19663            return;
19664        };
19665        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19666    }
19667
19668    pub fn open_context_menu(
19669        &mut self,
19670        _: &OpenContextMenu,
19671        window: &mut Window,
19672        cx: &mut Context<Self>,
19673    ) {
19674        self.request_autoscroll(Autoscroll::newest(), cx);
19675        let position = self.selections.newest_display(cx).start;
19676        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19677    }
19678
19679    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19680        &self.inlay_hint_cache
19681    }
19682
19683    pub fn replay_insert_event(
19684        &mut self,
19685        text: &str,
19686        relative_utf16_range: Option<Range<isize>>,
19687        window: &mut Window,
19688        cx: &mut Context<Self>,
19689    ) {
19690        if !self.input_enabled {
19691            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19692            return;
19693        }
19694        if let Some(relative_utf16_range) = relative_utf16_range {
19695            let selections = self.selections.all::<OffsetUtf16>(cx);
19696            self.change_selections(None, window, cx, |s| {
19697                let new_ranges = selections.into_iter().map(|range| {
19698                    let start = OffsetUtf16(
19699                        range
19700                            .head()
19701                            .0
19702                            .saturating_add_signed(relative_utf16_range.start),
19703                    );
19704                    let end = OffsetUtf16(
19705                        range
19706                            .head()
19707                            .0
19708                            .saturating_add_signed(relative_utf16_range.end),
19709                    );
19710                    start..end
19711                });
19712                s.select_ranges(new_ranges);
19713            });
19714        }
19715
19716        self.handle_input(text, window, cx);
19717    }
19718
19719    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19720        let Some(provider) = self.semantics_provider.as_ref() else {
19721            return false;
19722        };
19723
19724        let mut supports = false;
19725        self.buffer().update(cx, |this, cx| {
19726            this.for_each_buffer(|buffer| {
19727                supports |= provider.supports_inlay_hints(buffer, cx);
19728            });
19729        });
19730
19731        supports
19732    }
19733
19734    pub fn is_focused(&self, window: &Window) -> bool {
19735        self.focus_handle.is_focused(window)
19736    }
19737
19738    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19739        cx.emit(EditorEvent::Focused);
19740
19741        if let Some(descendant) = self
19742            .last_focused_descendant
19743            .take()
19744            .and_then(|descendant| descendant.upgrade())
19745        {
19746            window.focus(&descendant);
19747        } else {
19748            if let Some(blame) = self.blame.as_ref() {
19749                blame.update(cx, GitBlame::focus)
19750            }
19751
19752            self.blink_manager.update(cx, BlinkManager::enable);
19753            self.show_cursor_names(window, cx);
19754            self.buffer.update(cx, |buffer, cx| {
19755                buffer.finalize_last_transaction(cx);
19756                if self.leader_id.is_none() {
19757                    buffer.set_active_selections(
19758                        &self.selections.disjoint_anchors(),
19759                        self.selections.line_mode,
19760                        self.cursor_shape,
19761                        cx,
19762                    );
19763                }
19764            });
19765        }
19766    }
19767
19768    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19769        cx.emit(EditorEvent::FocusedIn)
19770    }
19771
19772    fn handle_focus_out(
19773        &mut self,
19774        event: FocusOutEvent,
19775        _window: &mut Window,
19776        cx: &mut Context<Self>,
19777    ) {
19778        if event.blurred != self.focus_handle {
19779            self.last_focused_descendant = Some(event.blurred);
19780        }
19781        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19782    }
19783
19784    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19785        self.blink_manager.update(cx, BlinkManager::disable);
19786        self.buffer
19787            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19788
19789        if let Some(blame) = self.blame.as_ref() {
19790            blame.update(cx, GitBlame::blur)
19791        }
19792        if !self.hover_state.focused(window, cx) {
19793            hide_hover(self, cx);
19794        }
19795        if !self
19796            .context_menu
19797            .borrow()
19798            .as_ref()
19799            .is_some_and(|context_menu| context_menu.focused(window, cx))
19800        {
19801            self.hide_context_menu(window, cx);
19802        }
19803        self.discard_inline_completion(false, cx);
19804        cx.emit(EditorEvent::Blurred);
19805        cx.notify();
19806    }
19807
19808    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19809        let mut pending: String = window
19810            .pending_input_keystrokes()
19811            .into_iter()
19812            .flatten()
19813            .filter_map(|keystroke| {
19814                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19815                    keystroke.key_char.clone()
19816                } else {
19817                    None
19818                }
19819            })
19820            .collect();
19821
19822        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19823            pending = "".to_string();
19824        }
19825
19826        let existing_pending = self
19827            .text_highlights::<PendingInput>(cx)
19828            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19829        if existing_pending.is_none() && pending.is_empty() {
19830            return;
19831        }
19832        let transaction =
19833            self.transact(window, cx, |this, window, cx| {
19834                let selections = this.selections.all::<usize>(cx);
19835                let edits = selections
19836                    .iter()
19837                    .map(|selection| (selection.end..selection.end, pending.clone()));
19838                this.edit(edits, cx);
19839                this.change_selections(None, window, cx, |s| {
19840                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19841                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19842                    }));
19843                });
19844                if let Some(existing_ranges) = existing_pending {
19845                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19846                    this.edit(edits, cx);
19847                }
19848            });
19849
19850        let snapshot = self.snapshot(window, cx);
19851        let ranges = self
19852            .selections
19853            .all::<usize>(cx)
19854            .into_iter()
19855            .map(|selection| {
19856                snapshot.buffer_snapshot.anchor_after(selection.end)
19857                    ..snapshot
19858                        .buffer_snapshot
19859                        .anchor_before(selection.end + pending.len())
19860            })
19861            .collect();
19862
19863        if pending.is_empty() {
19864            self.clear_highlights::<PendingInput>(cx);
19865        } else {
19866            self.highlight_text::<PendingInput>(
19867                ranges,
19868                HighlightStyle {
19869                    underline: Some(UnderlineStyle {
19870                        thickness: px(1.),
19871                        color: None,
19872                        wavy: false,
19873                    }),
19874                    ..Default::default()
19875                },
19876                cx,
19877            );
19878        }
19879
19880        self.ime_transaction = self.ime_transaction.or(transaction);
19881        if let Some(transaction) = self.ime_transaction {
19882            self.buffer.update(cx, |buffer, cx| {
19883                buffer.group_until_transaction(transaction, cx);
19884            });
19885        }
19886
19887        if self.text_highlights::<PendingInput>(cx).is_none() {
19888            self.ime_transaction.take();
19889        }
19890    }
19891
19892    pub fn register_action_renderer(
19893        &mut self,
19894        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
19895    ) -> Subscription {
19896        let id = self.next_editor_action_id.post_inc();
19897        self.editor_actions
19898            .borrow_mut()
19899            .insert(id, Box::new(listener));
19900
19901        let editor_actions = self.editor_actions.clone();
19902        Subscription::new(move || {
19903            editor_actions.borrow_mut().remove(&id);
19904        })
19905    }
19906
19907    pub fn register_action<A: Action>(
19908        &mut self,
19909        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19910    ) -> Subscription {
19911        let id = self.next_editor_action_id.post_inc();
19912        let listener = Arc::new(listener);
19913        self.editor_actions.borrow_mut().insert(
19914            id,
19915            Box::new(move |_, window, _| {
19916                let listener = listener.clone();
19917                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19918                    let action = action.downcast_ref().unwrap();
19919                    if phase == DispatchPhase::Bubble {
19920                        listener(action, window, cx)
19921                    }
19922                })
19923            }),
19924        );
19925
19926        let editor_actions = self.editor_actions.clone();
19927        Subscription::new(move || {
19928            editor_actions.borrow_mut().remove(&id);
19929        })
19930    }
19931
19932    pub fn file_header_size(&self) -> u32 {
19933        FILE_HEADER_HEIGHT
19934    }
19935
19936    pub fn restore(
19937        &mut self,
19938        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19939        window: &mut Window,
19940        cx: &mut Context<Self>,
19941    ) {
19942        let workspace = self.workspace();
19943        let project = self.project.as_ref();
19944        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19945            let mut tasks = Vec::new();
19946            for (buffer_id, changes) in revert_changes {
19947                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19948                    buffer.update(cx, |buffer, cx| {
19949                        buffer.edit(
19950                            changes
19951                                .into_iter()
19952                                .map(|(range, text)| (range, text.to_string())),
19953                            None,
19954                            cx,
19955                        );
19956                    });
19957
19958                    if let Some(project) =
19959                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19960                    {
19961                        project.update(cx, |project, cx| {
19962                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19963                        })
19964                    }
19965                }
19966            }
19967            tasks
19968        });
19969        cx.spawn_in(window, async move |_, cx| {
19970            for (buffer, task) in save_tasks {
19971                let result = task.await;
19972                if result.is_err() {
19973                    let Some(path) = buffer
19974                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19975                        .ok()
19976                    else {
19977                        continue;
19978                    };
19979                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19980                        let Some(task) = cx
19981                            .update_window_entity(&workspace, |workspace, window, cx| {
19982                                workspace
19983                                    .open_path_preview(path, None, false, false, false, window, cx)
19984                            })
19985                            .ok()
19986                        else {
19987                            continue;
19988                        };
19989                        task.await.log_err();
19990                    }
19991                }
19992            }
19993        })
19994        .detach();
19995        self.change_selections(None, window, cx, |selections| selections.refresh());
19996    }
19997
19998    pub fn to_pixel_point(
19999        &self,
20000        source: multi_buffer::Anchor,
20001        editor_snapshot: &EditorSnapshot,
20002        window: &mut Window,
20003    ) -> Option<gpui::Point<Pixels>> {
20004        let source_point = source.to_display_point(editor_snapshot);
20005        self.display_to_pixel_point(source_point, editor_snapshot, window)
20006    }
20007
20008    pub fn display_to_pixel_point(
20009        &self,
20010        source: DisplayPoint,
20011        editor_snapshot: &EditorSnapshot,
20012        window: &mut Window,
20013    ) -> Option<gpui::Point<Pixels>> {
20014        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20015        let text_layout_details = self.text_layout_details(window);
20016        let scroll_top = text_layout_details
20017            .scroll_anchor
20018            .scroll_position(editor_snapshot)
20019            .y;
20020
20021        if source.row().as_f32() < scroll_top.floor() {
20022            return None;
20023        }
20024        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20025        let source_y = line_height * (source.row().as_f32() - scroll_top);
20026        Some(gpui::Point::new(source_x, source_y))
20027    }
20028
20029    pub fn has_visible_completions_menu(&self) -> bool {
20030        !self.edit_prediction_preview_is_active()
20031            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20032                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20033            })
20034    }
20035
20036    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20037        if self.mode.is_minimap() {
20038            return;
20039        }
20040        self.addons
20041            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20042    }
20043
20044    pub fn unregister_addon<T: Addon>(&mut self) {
20045        self.addons.remove(&std::any::TypeId::of::<T>());
20046    }
20047
20048    pub fn addon<T: Addon>(&self) -> Option<&T> {
20049        let type_id = std::any::TypeId::of::<T>();
20050        self.addons
20051            .get(&type_id)
20052            .and_then(|item| item.to_any().downcast_ref::<T>())
20053    }
20054
20055    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20056        let type_id = std::any::TypeId::of::<T>();
20057        self.addons
20058            .get_mut(&type_id)
20059            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20060    }
20061
20062    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20063        let text_layout_details = self.text_layout_details(window);
20064        let style = &text_layout_details.editor_style;
20065        let font_id = window.text_system().resolve_font(&style.text.font());
20066        let font_size = style.text.font_size.to_pixels(window.rem_size());
20067        let line_height = style.text.line_height_in_pixels(window.rem_size());
20068        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20069
20070        gpui::Size::new(em_width, line_height)
20071    }
20072
20073    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20074        self.load_diff_task.clone()
20075    }
20076
20077    fn read_metadata_from_db(
20078        &mut self,
20079        item_id: u64,
20080        workspace_id: WorkspaceId,
20081        window: &mut Window,
20082        cx: &mut Context<Editor>,
20083    ) {
20084        if self.is_singleton(cx)
20085            && !self.mode.is_minimap()
20086            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20087        {
20088            let buffer_snapshot = OnceCell::new();
20089
20090            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20091                if !folds.is_empty() {
20092                    let snapshot =
20093                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20094                    self.fold_ranges(
20095                        folds
20096                            .into_iter()
20097                            .map(|(start, end)| {
20098                                snapshot.clip_offset(start, Bias::Left)
20099                                    ..snapshot.clip_offset(end, Bias::Right)
20100                            })
20101                            .collect(),
20102                        false,
20103                        window,
20104                        cx,
20105                    );
20106                }
20107            }
20108
20109            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20110                if !selections.is_empty() {
20111                    let snapshot =
20112                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20113                    // skip adding the initial selection to selection history
20114                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20115                    self.change_selections(None, window, cx, |s| {
20116                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20117                            snapshot.clip_offset(start, Bias::Left)
20118                                ..snapshot.clip_offset(end, Bias::Right)
20119                        }));
20120                    });
20121                    self.selection_history.mode = SelectionHistoryMode::Normal;
20122                }
20123            };
20124        }
20125
20126        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20127    }
20128}
20129
20130fn vim_enabled(cx: &App) -> bool {
20131    cx.global::<SettingsStore>()
20132        .raw_user_settings()
20133        .get("vim_mode")
20134        == Some(&serde_json::Value::Bool(true))
20135}
20136
20137fn process_completion_for_edit(
20138    completion: &Completion,
20139    intent: CompletionIntent,
20140    buffer: &Entity<Buffer>,
20141    cursor_position: &text::Anchor,
20142    cx: &mut Context<Editor>,
20143) -> CompletionEdit {
20144    let buffer = buffer.read(cx);
20145    let buffer_snapshot = buffer.snapshot();
20146    let (snippet, new_text) = if completion.is_snippet() {
20147        // Workaround for typescript language server issues so that methods don't expand within
20148        // strings and functions with type expressions. The previous point is used because the query
20149        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20150        let mut snippet_source = completion.new_text.clone();
20151        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20152        previous_point.column = previous_point.column.saturating_sub(1);
20153        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20154            if scope.prefers_label_for_snippet_in_completion() {
20155                if let Some(label) = completion.label() {
20156                    if matches!(
20157                        completion.kind(),
20158                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20159                    ) {
20160                        snippet_source = label;
20161                    }
20162                }
20163            }
20164        }
20165        match Snippet::parse(&snippet_source).log_err() {
20166            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20167            None => (None, completion.new_text.clone()),
20168        }
20169    } else {
20170        (None, completion.new_text.clone())
20171    };
20172
20173    let mut range_to_replace = {
20174        let replace_range = &completion.replace_range;
20175        if let CompletionSource::Lsp {
20176            insert_range: Some(insert_range),
20177            ..
20178        } = &completion.source
20179        {
20180            debug_assert_eq!(
20181                insert_range.start, replace_range.start,
20182                "insert_range and replace_range should start at the same position"
20183            );
20184            debug_assert!(
20185                insert_range
20186                    .start
20187                    .cmp(&cursor_position, &buffer_snapshot)
20188                    .is_le(),
20189                "insert_range should start before or at cursor position"
20190            );
20191            debug_assert!(
20192                replace_range
20193                    .start
20194                    .cmp(&cursor_position, &buffer_snapshot)
20195                    .is_le(),
20196                "replace_range should start before or at cursor position"
20197            );
20198            debug_assert!(
20199                insert_range
20200                    .end
20201                    .cmp(&cursor_position, &buffer_snapshot)
20202                    .is_le(),
20203                "insert_range should end before or at cursor position"
20204            );
20205
20206            let should_replace = match intent {
20207                CompletionIntent::CompleteWithInsert => false,
20208                CompletionIntent::CompleteWithReplace => true,
20209                CompletionIntent::Complete | CompletionIntent::Compose => {
20210                    let insert_mode =
20211                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20212                            .completions
20213                            .lsp_insert_mode;
20214                    match insert_mode {
20215                        LspInsertMode::Insert => false,
20216                        LspInsertMode::Replace => true,
20217                        LspInsertMode::ReplaceSubsequence => {
20218                            let mut text_to_replace = buffer.chars_for_range(
20219                                buffer.anchor_before(replace_range.start)
20220                                    ..buffer.anchor_after(replace_range.end),
20221                            );
20222                            let mut current_needle = text_to_replace.next();
20223                            for haystack_ch in completion.label.text.chars() {
20224                                if let Some(needle_ch) = current_needle {
20225                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20226                                        current_needle = text_to_replace.next();
20227                                    }
20228                                }
20229                            }
20230                            current_needle.is_none()
20231                        }
20232                        LspInsertMode::ReplaceSuffix => {
20233                            if replace_range
20234                                .end
20235                                .cmp(&cursor_position, &buffer_snapshot)
20236                                .is_gt()
20237                            {
20238                                let range_after_cursor = *cursor_position..replace_range.end;
20239                                let text_after_cursor = buffer
20240                                    .text_for_range(
20241                                        buffer.anchor_before(range_after_cursor.start)
20242                                            ..buffer.anchor_after(range_after_cursor.end),
20243                                    )
20244                                    .collect::<String>()
20245                                    .to_ascii_lowercase();
20246                                completion
20247                                    .label
20248                                    .text
20249                                    .to_ascii_lowercase()
20250                                    .ends_with(&text_after_cursor)
20251                            } else {
20252                                true
20253                            }
20254                        }
20255                    }
20256                }
20257            };
20258
20259            if should_replace {
20260                replace_range.clone()
20261            } else {
20262                insert_range.clone()
20263            }
20264        } else {
20265            replace_range.clone()
20266        }
20267    };
20268
20269    if range_to_replace
20270        .end
20271        .cmp(&cursor_position, &buffer_snapshot)
20272        .is_lt()
20273    {
20274        range_to_replace.end = *cursor_position;
20275    }
20276
20277    CompletionEdit {
20278        new_text,
20279        replace_range: range_to_replace.to_offset(&buffer),
20280        snippet,
20281    }
20282}
20283
20284struct CompletionEdit {
20285    new_text: String,
20286    replace_range: Range<usize>,
20287    snippet: Option<Snippet>,
20288}
20289
20290fn insert_extra_newline_brackets(
20291    buffer: &MultiBufferSnapshot,
20292    range: Range<usize>,
20293    language: &language::LanguageScope,
20294) -> bool {
20295    let leading_whitespace_len = buffer
20296        .reversed_chars_at(range.start)
20297        .take_while(|c| c.is_whitespace() && *c != '\n')
20298        .map(|c| c.len_utf8())
20299        .sum::<usize>();
20300    let trailing_whitespace_len = buffer
20301        .chars_at(range.end)
20302        .take_while(|c| c.is_whitespace() && *c != '\n')
20303        .map(|c| c.len_utf8())
20304        .sum::<usize>();
20305    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20306
20307    language.brackets().any(|(pair, enabled)| {
20308        let pair_start = pair.start.trim_end();
20309        let pair_end = pair.end.trim_start();
20310
20311        enabled
20312            && pair.newline
20313            && buffer.contains_str_at(range.end, pair_end)
20314            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20315    })
20316}
20317
20318fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20319    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20320        [(buffer, range, _)] => (*buffer, range.clone()),
20321        _ => return false,
20322    };
20323    let pair = {
20324        let mut result: Option<BracketMatch> = None;
20325
20326        for pair in buffer
20327            .all_bracket_ranges(range.clone())
20328            .filter(move |pair| {
20329                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20330            })
20331        {
20332            let len = pair.close_range.end - pair.open_range.start;
20333
20334            if let Some(existing) = &result {
20335                let existing_len = existing.close_range.end - existing.open_range.start;
20336                if len > existing_len {
20337                    continue;
20338                }
20339            }
20340
20341            result = Some(pair);
20342        }
20343
20344        result
20345    };
20346    let Some(pair) = pair else {
20347        return false;
20348    };
20349    pair.newline_only
20350        && buffer
20351            .chars_for_range(pair.open_range.end..range.start)
20352            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20353            .all(|c| c.is_whitespace() && c != '\n')
20354}
20355
20356fn update_uncommitted_diff_for_buffer(
20357    editor: Entity<Editor>,
20358    project: &Entity<Project>,
20359    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20360    buffer: Entity<MultiBuffer>,
20361    cx: &mut App,
20362) -> Task<()> {
20363    let mut tasks = Vec::new();
20364    project.update(cx, |project, cx| {
20365        for buffer in buffers {
20366            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20367                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20368            }
20369        }
20370    });
20371    cx.spawn(async move |cx| {
20372        let diffs = future::join_all(tasks).await;
20373        if editor
20374            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20375            .unwrap_or(false)
20376        {
20377            return;
20378        }
20379
20380        buffer
20381            .update(cx, |buffer, cx| {
20382                for diff in diffs.into_iter().flatten() {
20383                    buffer.add_diff(diff, cx);
20384                }
20385            })
20386            .ok();
20387    })
20388}
20389
20390fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20391    let tab_size = tab_size.get() as usize;
20392    let mut width = offset;
20393
20394    for ch in text.chars() {
20395        width += if ch == '\t' {
20396            tab_size - (width % tab_size)
20397        } else {
20398            1
20399        };
20400    }
20401
20402    width - offset
20403}
20404
20405#[cfg(test)]
20406mod tests {
20407    use super::*;
20408
20409    #[test]
20410    fn test_string_size_with_expanded_tabs() {
20411        let nz = |val| NonZeroU32::new(val).unwrap();
20412        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20413        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20414        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20415        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20416        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20417        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20418        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20419        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20420    }
20421}
20422
20423/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20424struct WordBreakingTokenizer<'a> {
20425    input: &'a str,
20426}
20427
20428impl<'a> WordBreakingTokenizer<'a> {
20429    fn new(input: &'a str) -> Self {
20430        Self { input }
20431    }
20432}
20433
20434fn is_char_ideographic(ch: char) -> bool {
20435    use unicode_script::Script::*;
20436    use unicode_script::UnicodeScript;
20437    matches!(ch.script(), Han | Tangut | Yi)
20438}
20439
20440fn is_grapheme_ideographic(text: &str) -> bool {
20441    text.chars().any(is_char_ideographic)
20442}
20443
20444fn is_grapheme_whitespace(text: &str) -> bool {
20445    text.chars().any(|x| x.is_whitespace())
20446}
20447
20448fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20449    text.chars().next().map_or(false, |ch| {
20450        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20451    })
20452}
20453
20454#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20455enum WordBreakToken<'a> {
20456    Word { token: &'a str, grapheme_len: usize },
20457    InlineWhitespace { token: &'a str, grapheme_len: usize },
20458    Newline,
20459}
20460
20461impl<'a> Iterator for WordBreakingTokenizer<'a> {
20462    /// Yields a span, the count of graphemes in the token, and whether it was
20463    /// whitespace. Note that it also breaks at word boundaries.
20464    type Item = WordBreakToken<'a>;
20465
20466    fn next(&mut self) -> Option<Self::Item> {
20467        use unicode_segmentation::UnicodeSegmentation;
20468        if self.input.is_empty() {
20469            return None;
20470        }
20471
20472        let mut iter = self.input.graphemes(true).peekable();
20473        let mut offset = 0;
20474        let mut grapheme_len = 0;
20475        if let Some(first_grapheme) = iter.next() {
20476            let is_newline = first_grapheme == "\n";
20477            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20478            offset += first_grapheme.len();
20479            grapheme_len += 1;
20480            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20481                if let Some(grapheme) = iter.peek().copied() {
20482                    if should_stay_with_preceding_ideograph(grapheme) {
20483                        offset += grapheme.len();
20484                        grapheme_len += 1;
20485                    }
20486                }
20487            } else {
20488                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20489                let mut next_word_bound = words.peek().copied();
20490                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20491                    next_word_bound = words.next();
20492                }
20493                while let Some(grapheme) = iter.peek().copied() {
20494                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20495                        break;
20496                    };
20497                    if is_grapheme_whitespace(grapheme) != is_whitespace
20498                        || (grapheme == "\n") != is_newline
20499                    {
20500                        break;
20501                    };
20502                    offset += grapheme.len();
20503                    grapheme_len += 1;
20504                    iter.next();
20505                }
20506            }
20507            let token = &self.input[..offset];
20508            self.input = &self.input[offset..];
20509            if token == "\n" {
20510                Some(WordBreakToken::Newline)
20511            } else if is_whitespace {
20512                Some(WordBreakToken::InlineWhitespace {
20513                    token,
20514                    grapheme_len,
20515                })
20516            } else {
20517                Some(WordBreakToken::Word {
20518                    token,
20519                    grapheme_len,
20520                })
20521            }
20522        } else {
20523            None
20524        }
20525    }
20526}
20527
20528#[test]
20529fn test_word_breaking_tokenizer() {
20530    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20531        ("", &[]),
20532        ("  ", &[whitespace("  ", 2)]),
20533        ("Ʒ", &[word("Ʒ", 1)]),
20534        ("Ǽ", &[word("Ǽ", 1)]),
20535        ("", &[word("", 1)]),
20536        ("⋑⋑", &[word("⋑⋑", 2)]),
20537        (
20538            "原理,进而",
20539            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20540        ),
20541        (
20542            "hello world",
20543            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20544        ),
20545        (
20546            "hello, world",
20547            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20548        ),
20549        (
20550            "  hello world",
20551            &[
20552                whitespace("  ", 2),
20553                word("hello", 5),
20554                whitespace(" ", 1),
20555                word("world", 5),
20556            ],
20557        ),
20558        (
20559            "这是什么 \n 钢笔",
20560            &[
20561                word("", 1),
20562                word("", 1),
20563                word("", 1),
20564                word("", 1),
20565                whitespace(" ", 1),
20566                newline(),
20567                whitespace(" ", 1),
20568                word("", 1),
20569                word("", 1),
20570            ],
20571        ),
20572        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20573    ];
20574
20575    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20576        WordBreakToken::Word {
20577            token,
20578            grapheme_len,
20579        }
20580    }
20581
20582    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20583        WordBreakToken::InlineWhitespace {
20584            token,
20585            grapheme_len,
20586        }
20587    }
20588
20589    fn newline() -> WordBreakToken<'static> {
20590        WordBreakToken::Newline
20591    }
20592
20593    for (input, result) in tests {
20594        assert_eq!(
20595            WordBreakingTokenizer::new(input)
20596                .collect::<Vec<_>>()
20597                .as_slice(),
20598            *result,
20599        );
20600    }
20601}
20602
20603fn wrap_with_prefix(
20604    line_prefix: String,
20605    unwrapped_text: String,
20606    wrap_column: usize,
20607    tab_size: NonZeroU32,
20608    preserve_existing_whitespace: bool,
20609) -> String {
20610    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20611    let mut wrapped_text = String::new();
20612    let mut current_line = line_prefix.clone();
20613
20614    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20615    let mut current_line_len = line_prefix_len;
20616    let mut in_whitespace = false;
20617    for token in tokenizer {
20618        let have_preceding_whitespace = in_whitespace;
20619        match token {
20620            WordBreakToken::Word {
20621                token,
20622                grapheme_len,
20623            } => {
20624                in_whitespace = false;
20625                if current_line_len + grapheme_len > wrap_column
20626                    && current_line_len != line_prefix_len
20627                {
20628                    wrapped_text.push_str(current_line.trim_end());
20629                    wrapped_text.push('\n');
20630                    current_line.truncate(line_prefix.len());
20631                    current_line_len = line_prefix_len;
20632                }
20633                current_line.push_str(token);
20634                current_line_len += grapheme_len;
20635            }
20636            WordBreakToken::InlineWhitespace {
20637                mut token,
20638                mut grapheme_len,
20639            } => {
20640                in_whitespace = true;
20641                if have_preceding_whitespace && !preserve_existing_whitespace {
20642                    continue;
20643                }
20644                if !preserve_existing_whitespace {
20645                    token = " ";
20646                    grapheme_len = 1;
20647                }
20648                if current_line_len + grapheme_len > wrap_column {
20649                    wrapped_text.push_str(current_line.trim_end());
20650                    wrapped_text.push('\n');
20651                    current_line.truncate(line_prefix.len());
20652                    current_line_len = line_prefix_len;
20653                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20654                    current_line.push_str(token);
20655                    current_line_len += grapheme_len;
20656                }
20657            }
20658            WordBreakToken::Newline => {
20659                in_whitespace = true;
20660                if preserve_existing_whitespace {
20661                    wrapped_text.push_str(current_line.trim_end());
20662                    wrapped_text.push('\n');
20663                    current_line.truncate(line_prefix.len());
20664                    current_line_len = line_prefix_len;
20665                } else if have_preceding_whitespace {
20666                    continue;
20667                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20668                {
20669                    wrapped_text.push_str(current_line.trim_end());
20670                    wrapped_text.push('\n');
20671                    current_line.truncate(line_prefix.len());
20672                    current_line_len = line_prefix_len;
20673                } else if current_line_len != line_prefix_len {
20674                    current_line.push(' ');
20675                    current_line_len += 1;
20676                }
20677            }
20678        }
20679    }
20680
20681    if !current_line.is_empty() {
20682        wrapped_text.push_str(&current_line);
20683    }
20684    wrapped_text
20685}
20686
20687#[test]
20688fn test_wrap_with_prefix() {
20689    assert_eq!(
20690        wrap_with_prefix(
20691            "# ".to_string(),
20692            "abcdefg".to_string(),
20693            4,
20694            NonZeroU32::new(4).unwrap(),
20695            false,
20696        ),
20697        "# abcdefg"
20698    );
20699    assert_eq!(
20700        wrap_with_prefix(
20701            "".to_string(),
20702            "\thello world".to_string(),
20703            8,
20704            NonZeroU32::new(4).unwrap(),
20705            false,
20706        ),
20707        "hello\nworld"
20708    );
20709    assert_eq!(
20710        wrap_with_prefix(
20711            "// ".to_string(),
20712            "xx \nyy zz aa bb cc".to_string(),
20713            12,
20714            NonZeroU32::new(4).unwrap(),
20715            false,
20716        ),
20717        "// xx yy zz\n// aa bb cc"
20718    );
20719    assert_eq!(
20720        wrap_with_prefix(
20721            String::new(),
20722            "这是什么 \n 钢笔".to_string(),
20723            3,
20724            NonZeroU32::new(4).unwrap(),
20725            false,
20726        ),
20727        "这是什\n么 钢\n"
20728    );
20729}
20730
20731pub trait CollaborationHub {
20732    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20733    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20734    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20735}
20736
20737impl CollaborationHub for Entity<Project> {
20738    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20739        self.read(cx).collaborators()
20740    }
20741
20742    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20743        self.read(cx).user_store().read(cx).participant_indices()
20744    }
20745
20746    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20747        let this = self.read(cx);
20748        let user_ids = this.collaborators().values().map(|c| c.user_id);
20749        this.user_store().read(cx).participant_names(user_ids, cx)
20750    }
20751}
20752
20753pub trait SemanticsProvider {
20754    fn hover(
20755        &self,
20756        buffer: &Entity<Buffer>,
20757        position: text::Anchor,
20758        cx: &mut App,
20759    ) -> Option<Task<Vec<project::Hover>>>;
20760
20761    fn inline_values(
20762        &self,
20763        buffer_handle: Entity<Buffer>,
20764        range: Range<text::Anchor>,
20765        cx: &mut App,
20766    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20767
20768    fn inlay_hints(
20769        &self,
20770        buffer_handle: Entity<Buffer>,
20771        range: Range<text::Anchor>,
20772        cx: &mut App,
20773    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20774
20775    fn resolve_inlay_hint(
20776        &self,
20777        hint: InlayHint,
20778        buffer_handle: Entity<Buffer>,
20779        server_id: LanguageServerId,
20780        cx: &mut App,
20781    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20782
20783    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20784
20785    fn document_highlights(
20786        &self,
20787        buffer: &Entity<Buffer>,
20788        position: text::Anchor,
20789        cx: &mut App,
20790    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20791
20792    fn definitions(
20793        &self,
20794        buffer: &Entity<Buffer>,
20795        position: text::Anchor,
20796        kind: GotoDefinitionKind,
20797        cx: &mut App,
20798    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20799
20800    fn range_for_rename(
20801        &self,
20802        buffer: &Entity<Buffer>,
20803        position: text::Anchor,
20804        cx: &mut App,
20805    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20806
20807    fn perform_rename(
20808        &self,
20809        buffer: &Entity<Buffer>,
20810        position: text::Anchor,
20811        new_name: String,
20812        cx: &mut App,
20813    ) -> Option<Task<Result<ProjectTransaction>>>;
20814
20815    fn pull_diagnostics_for_buffer(
20816        &self,
20817        buffer: Entity<Buffer>,
20818        cx: &mut App,
20819    ) -> Task<anyhow::Result<()>>;
20820}
20821
20822pub trait CompletionProvider {
20823    fn completions(
20824        &self,
20825        excerpt_id: ExcerptId,
20826        buffer: &Entity<Buffer>,
20827        buffer_position: text::Anchor,
20828        trigger: CompletionContext,
20829        window: &mut Window,
20830        cx: &mut Context<Editor>,
20831    ) -> Task<Result<Vec<CompletionResponse>>>;
20832
20833    fn resolve_completions(
20834        &self,
20835        _buffer: Entity<Buffer>,
20836        _completion_indices: Vec<usize>,
20837        _completions: Rc<RefCell<Box<[Completion]>>>,
20838        _cx: &mut Context<Editor>,
20839    ) -> Task<Result<bool>> {
20840        Task::ready(Ok(false))
20841    }
20842
20843    fn apply_additional_edits_for_completion(
20844        &self,
20845        _buffer: Entity<Buffer>,
20846        _completions: Rc<RefCell<Box<[Completion]>>>,
20847        _completion_index: usize,
20848        _push_to_history: bool,
20849        _cx: &mut Context<Editor>,
20850    ) -> Task<Result<Option<language::Transaction>>> {
20851        Task::ready(Ok(None))
20852    }
20853
20854    fn is_completion_trigger(
20855        &self,
20856        buffer: &Entity<Buffer>,
20857        position: language::Anchor,
20858        text: &str,
20859        trigger_in_words: bool,
20860        menu_is_open: bool,
20861        cx: &mut Context<Editor>,
20862    ) -> bool;
20863
20864    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20865
20866    fn sort_completions(&self) -> bool {
20867        true
20868    }
20869
20870    fn filter_completions(&self) -> bool {
20871        true
20872    }
20873}
20874
20875pub trait CodeActionProvider {
20876    fn id(&self) -> Arc<str>;
20877
20878    fn code_actions(
20879        &self,
20880        buffer: &Entity<Buffer>,
20881        range: Range<text::Anchor>,
20882        window: &mut Window,
20883        cx: &mut App,
20884    ) -> Task<Result<Vec<CodeAction>>>;
20885
20886    fn apply_code_action(
20887        &self,
20888        buffer_handle: Entity<Buffer>,
20889        action: CodeAction,
20890        excerpt_id: ExcerptId,
20891        push_to_history: bool,
20892        window: &mut Window,
20893        cx: &mut App,
20894    ) -> Task<Result<ProjectTransaction>>;
20895}
20896
20897impl CodeActionProvider for Entity<Project> {
20898    fn id(&self) -> Arc<str> {
20899        "project".into()
20900    }
20901
20902    fn code_actions(
20903        &self,
20904        buffer: &Entity<Buffer>,
20905        range: Range<text::Anchor>,
20906        _window: &mut Window,
20907        cx: &mut App,
20908    ) -> Task<Result<Vec<CodeAction>>> {
20909        self.update(cx, |project, cx| {
20910            let code_lens = project.code_lens(buffer, range.clone(), cx);
20911            let code_actions = project.code_actions(buffer, range, None, cx);
20912            cx.background_spawn(async move {
20913                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20914                Ok(code_lens
20915                    .context("code lens fetch")?
20916                    .into_iter()
20917                    .chain(code_actions.context("code action fetch")?)
20918                    .collect())
20919            })
20920        })
20921    }
20922
20923    fn apply_code_action(
20924        &self,
20925        buffer_handle: Entity<Buffer>,
20926        action: CodeAction,
20927        _excerpt_id: ExcerptId,
20928        push_to_history: bool,
20929        _window: &mut Window,
20930        cx: &mut App,
20931    ) -> Task<Result<ProjectTransaction>> {
20932        self.update(cx, |project, cx| {
20933            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20934        })
20935    }
20936}
20937
20938fn snippet_completions(
20939    project: &Project,
20940    buffer: &Entity<Buffer>,
20941    buffer_position: text::Anchor,
20942    cx: &mut App,
20943) -> Task<Result<CompletionResponse>> {
20944    let languages = buffer.read(cx).languages_at(buffer_position);
20945    let snippet_store = project.snippets().read(cx);
20946
20947    let scopes: Vec<_> = languages
20948        .iter()
20949        .filter_map(|language| {
20950            let language_name = language.lsp_id();
20951            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20952
20953            if snippets.is_empty() {
20954                None
20955            } else {
20956                Some((language.default_scope(), snippets))
20957            }
20958        })
20959        .collect();
20960
20961    if scopes.is_empty() {
20962        return Task::ready(Ok(CompletionResponse {
20963            completions: vec![],
20964            is_incomplete: false,
20965        }));
20966    }
20967
20968    let snapshot = buffer.read(cx).text_snapshot();
20969    let chars: String = snapshot
20970        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20971        .collect();
20972    let executor = cx.background_executor().clone();
20973
20974    cx.background_spawn(async move {
20975        let mut is_incomplete = false;
20976        let mut completions: Vec<Completion> = Vec::new();
20977        for (scope, snippets) in scopes.into_iter() {
20978            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20979            let mut last_word = chars
20980                .chars()
20981                .take_while(|c| classifier.is_word(*c))
20982                .collect::<String>();
20983            last_word = last_word.chars().rev().collect();
20984
20985            if last_word.is_empty() {
20986                return Ok(CompletionResponse {
20987                    completions: vec![],
20988                    is_incomplete: true,
20989                });
20990            }
20991
20992            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20993            let to_lsp = |point: &text::Anchor| {
20994                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20995                point_to_lsp(end)
20996            };
20997            let lsp_end = to_lsp(&buffer_position);
20998
20999            let candidates = snippets
21000                .iter()
21001                .enumerate()
21002                .flat_map(|(ix, snippet)| {
21003                    snippet
21004                        .prefix
21005                        .iter()
21006                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21007                })
21008                .collect::<Vec<StringMatchCandidate>>();
21009
21010            const MAX_RESULTS: usize = 100;
21011            let mut matches = fuzzy::match_strings(
21012                &candidates,
21013                &last_word,
21014                last_word.chars().any(|c| c.is_uppercase()),
21015                MAX_RESULTS,
21016                &Default::default(),
21017                executor.clone(),
21018            )
21019            .await;
21020
21021            if matches.len() >= MAX_RESULTS {
21022                is_incomplete = true;
21023            }
21024
21025            // Remove all candidates where the query's start does not match the start of any word in the candidate
21026            if let Some(query_start) = last_word.chars().next() {
21027                matches.retain(|string_match| {
21028                    split_words(&string_match.string).any(|word| {
21029                        // Check that the first codepoint of the word as lowercase matches the first
21030                        // codepoint of the query as lowercase
21031                        word.chars()
21032                            .flat_map(|codepoint| codepoint.to_lowercase())
21033                            .zip(query_start.to_lowercase())
21034                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21035                    })
21036                });
21037            }
21038
21039            let matched_strings = matches
21040                .into_iter()
21041                .map(|m| m.string)
21042                .collect::<HashSet<_>>();
21043
21044            completions.extend(snippets.iter().filter_map(|snippet| {
21045                let matching_prefix = snippet
21046                    .prefix
21047                    .iter()
21048                    .find(|prefix| matched_strings.contains(*prefix))?;
21049                let start = as_offset - last_word.len();
21050                let start = snapshot.anchor_before(start);
21051                let range = start..buffer_position;
21052                let lsp_start = to_lsp(&start);
21053                let lsp_range = lsp::Range {
21054                    start: lsp_start,
21055                    end: lsp_end,
21056                };
21057                Some(Completion {
21058                    replace_range: range,
21059                    new_text: snippet.body.clone(),
21060                    source: CompletionSource::Lsp {
21061                        insert_range: None,
21062                        server_id: LanguageServerId(usize::MAX),
21063                        resolved: true,
21064                        lsp_completion: Box::new(lsp::CompletionItem {
21065                            label: snippet.prefix.first().unwrap().clone(),
21066                            kind: Some(CompletionItemKind::SNIPPET),
21067                            label_details: snippet.description.as_ref().map(|description| {
21068                                lsp::CompletionItemLabelDetails {
21069                                    detail: Some(description.clone()),
21070                                    description: None,
21071                                }
21072                            }),
21073                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21074                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21075                                lsp::InsertReplaceEdit {
21076                                    new_text: snippet.body.clone(),
21077                                    insert: lsp_range,
21078                                    replace: lsp_range,
21079                                },
21080                            )),
21081                            filter_text: Some(snippet.body.clone()),
21082                            sort_text: Some(char::MAX.to_string()),
21083                            ..lsp::CompletionItem::default()
21084                        }),
21085                        lsp_defaults: None,
21086                    },
21087                    label: CodeLabel {
21088                        text: matching_prefix.clone(),
21089                        runs: Vec::new(),
21090                        filter_range: 0..matching_prefix.len(),
21091                    },
21092                    icon_path: None,
21093                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21094                        single_line: snippet.name.clone().into(),
21095                        plain_text: snippet
21096                            .description
21097                            .clone()
21098                            .map(|description| description.into()),
21099                    }),
21100                    insert_text_mode: None,
21101                    confirm: None,
21102                })
21103            }))
21104        }
21105
21106        Ok(CompletionResponse {
21107            completions,
21108            is_incomplete,
21109        })
21110    })
21111}
21112
21113impl CompletionProvider for Entity<Project> {
21114    fn completions(
21115        &self,
21116        _excerpt_id: ExcerptId,
21117        buffer: &Entity<Buffer>,
21118        buffer_position: text::Anchor,
21119        options: CompletionContext,
21120        _window: &mut Window,
21121        cx: &mut Context<Editor>,
21122    ) -> Task<Result<Vec<CompletionResponse>>> {
21123        self.update(cx, |project, cx| {
21124            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21125            let project_completions = project.completions(buffer, buffer_position, options, cx);
21126            cx.background_spawn(async move {
21127                let mut responses = project_completions.await?;
21128                let snippets = snippets.await?;
21129                if !snippets.completions.is_empty() {
21130                    responses.push(snippets);
21131                }
21132                Ok(responses)
21133            })
21134        })
21135    }
21136
21137    fn resolve_completions(
21138        &self,
21139        buffer: Entity<Buffer>,
21140        completion_indices: Vec<usize>,
21141        completions: Rc<RefCell<Box<[Completion]>>>,
21142        cx: &mut Context<Editor>,
21143    ) -> Task<Result<bool>> {
21144        self.update(cx, |project, cx| {
21145            project.lsp_store().update(cx, |lsp_store, cx| {
21146                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21147            })
21148        })
21149    }
21150
21151    fn apply_additional_edits_for_completion(
21152        &self,
21153        buffer: Entity<Buffer>,
21154        completions: Rc<RefCell<Box<[Completion]>>>,
21155        completion_index: usize,
21156        push_to_history: bool,
21157        cx: &mut Context<Editor>,
21158    ) -> Task<Result<Option<language::Transaction>>> {
21159        self.update(cx, |project, cx| {
21160            project.lsp_store().update(cx, |lsp_store, cx| {
21161                lsp_store.apply_additional_edits_for_completion(
21162                    buffer,
21163                    completions,
21164                    completion_index,
21165                    push_to_history,
21166                    cx,
21167                )
21168            })
21169        })
21170    }
21171
21172    fn is_completion_trigger(
21173        &self,
21174        buffer: &Entity<Buffer>,
21175        position: language::Anchor,
21176        text: &str,
21177        trigger_in_words: bool,
21178        menu_is_open: bool,
21179        cx: &mut Context<Editor>,
21180    ) -> bool {
21181        let mut chars = text.chars();
21182        let char = if let Some(char) = chars.next() {
21183            char
21184        } else {
21185            return false;
21186        };
21187        if chars.next().is_some() {
21188            return false;
21189        }
21190
21191        let buffer = buffer.read(cx);
21192        let snapshot = buffer.snapshot();
21193        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21194            return false;
21195        }
21196        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21197        if trigger_in_words && classifier.is_word(char) {
21198            return true;
21199        }
21200
21201        buffer.completion_triggers().contains(text)
21202    }
21203}
21204
21205impl SemanticsProvider for Entity<Project> {
21206    fn hover(
21207        &self,
21208        buffer: &Entity<Buffer>,
21209        position: text::Anchor,
21210        cx: &mut App,
21211    ) -> Option<Task<Vec<project::Hover>>> {
21212        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21213    }
21214
21215    fn document_highlights(
21216        &self,
21217        buffer: &Entity<Buffer>,
21218        position: text::Anchor,
21219        cx: &mut App,
21220    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21221        Some(self.update(cx, |project, cx| {
21222            project.document_highlights(buffer, position, cx)
21223        }))
21224    }
21225
21226    fn definitions(
21227        &self,
21228        buffer: &Entity<Buffer>,
21229        position: text::Anchor,
21230        kind: GotoDefinitionKind,
21231        cx: &mut App,
21232    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21233        Some(self.update(cx, |project, cx| match kind {
21234            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21235            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21236            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21237            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21238        }))
21239    }
21240
21241    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21242        // TODO: make this work for remote projects
21243        self.update(cx, |project, cx| {
21244            if project
21245                .active_debug_session(cx)
21246                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21247            {
21248                return true;
21249            }
21250
21251            buffer.update(cx, |buffer, cx| {
21252                project.any_language_server_supports_inlay_hints(buffer, cx)
21253            })
21254        })
21255    }
21256
21257    fn inline_values(
21258        &self,
21259        buffer_handle: Entity<Buffer>,
21260
21261        range: Range<text::Anchor>,
21262        cx: &mut App,
21263    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21264        self.update(cx, |project, cx| {
21265            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21266
21267            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21268        })
21269    }
21270
21271    fn inlay_hints(
21272        &self,
21273        buffer_handle: Entity<Buffer>,
21274        range: Range<text::Anchor>,
21275        cx: &mut App,
21276    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21277        Some(self.update(cx, |project, cx| {
21278            project.inlay_hints(buffer_handle, range, cx)
21279        }))
21280    }
21281
21282    fn resolve_inlay_hint(
21283        &self,
21284        hint: InlayHint,
21285        buffer_handle: Entity<Buffer>,
21286        server_id: LanguageServerId,
21287        cx: &mut App,
21288    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21289        Some(self.update(cx, |project, cx| {
21290            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21291        }))
21292    }
21293
21294    fn range_for_rename(
21295        &self,
21296        buffer: &Entity<Buffer>,
21297        position: text::Anchor,
21298        cx: &mut App,
21299    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21300        Some(self.update(cx, |project, cx| {
21301            let buffer = buffer.clone();
21302            let task = project.prepare_rename(buffer.clone(), position, cx);
21303            cx.spawn(async move |_, cx| {
21304                Ok(match task.await? {
21305                    PrepareRenameResponse::Success(range) => Some(range),
21306                    PrepareRenameResponse::InvalidPosition => None,
21307                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21308                        // Fallback on using TreeSitter info to determine identifier range
21309                        buffer.read_with(cx, |buffer, _| {
21310                            let snapshot = buffer.snapshot();
21311                            let (range, kind) = snapshot.surrounding_word(position);
21312                            if kind != Some(CharKind::Word) {
21313                                return None;
21314                            }
21315                            Some(
21316                                snapshot.anchor_before(range.start)
21317                                    ..snapshot.anchor_after(range.end),
21318                            )
21319                        })?
21320                    }
21321                })
21322            })
21323        }))
21324    }
21325
21326    fn perform_rename(
21327        &self,
21328        buffer: &Entity<Buffer>,
21329        position: text::Anchor,
21330        new_name: String,
21331        cx: &mut App,
21332    ) -> Option<Task<Result<ProjectTransaction>>> {
21333        Some(self.update(cx, |project, cx| {
21334            project.perform_rename(buffer.clone(), position, new_name, cx)
21335        }))
21336    }
21337
21338    fn pull_diagnostics_for_buffer(
21339        &self,
21340        buffer: Entity<Buffer>,
21341        cx: &mut App,
21342    ) -> Task<anyhow::Result<()>> {
21343        let diagnostics = self.update(cx, |project, cx| {
21344            project
21345                .lsp_store()
21346                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21347        });
21348        let project = self.clone();
21349        cx.spawn(async move |cx| {
21350            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21351            project.update(cx, |project, cx| {
21352                project.lsp_store().update(cx, |lsp_store, cx| {
21353                    for diagnostics_set in diagnostics {
21354                        let LspPullDiagnostics::Response {
21355                            server_id,
21356                            uri,
21357                            diagnostics,
21358                        } = diagnostics_set
21359                        else {
21360                            continue;
21361                        };
21362
21363                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21364                        let disk_based_sources = adapter
21365                            .as_ref()
21366                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21367                            .unwrap_or(&[]);
21368                        match diagnostics {
21369                            PulledDiagnostics::Unchanged { result_id } => {
21370                                lsp_store
21371                                    .merge_diagnostics(
21372                                        server_id,
21373                                        lsp::PublishDiagnosticsParams {
21374                                            uri: uri.clone(),
21375                                            diagnostics: Vec::new(),
21376                                            version: None,
21377                                        },
21378                                        Some(result_id),
21379                                        DiagnosticSourceKind::Pulled,
21380                                        disk_based_sources,
21381                                        |_, _| true,
21382                                        cx,
21383                                    )
21384                                    .log_err();
21385                            }
21386                            PulledDiagnostics::Changed {
21387                                diagnostics,
21388                                result_id,
21389                            } => {
21390                                lsp_store
21391                                    .merge_diagnostics(
21392                                        server_id,
21393                                        lsp::PublishDiagnosticsParams {
21394                                            uri: uri.clone(),
21395                                            diagnostics,
21396                                            version: None,
21397                                        },
21398                                        result_id,
21399                                        DiagnosticSourceKind::Pulled,
21400                                        disk_based_sources,
21401                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21402                                            DiagnosticSourceKind::Pulled => false,
21403                                            DiagnosticSourceKind::Other
21404                                            | DiagnosticSourceKind::Pushed => true,
21405                                        },
21406                                        cx,
21407                                    )
21408                                    .log_err();
21409                            }
21410                        }
21411                    }
21412                })
21413            })
21414        })
21415    }
21416}
21417
21418fn inlay_hint_settings(
21419    location: Anchor,
21420    snapshot: &MultiBufferSnapshot,
21421    cx: &mut Context<Editor>,
21422) -> InlayHintSettings {
21423    let file = snapshot.file_at(location);
21424    let language = snapshot.language_at(location).map(|l| l.name());
21425    language_settings(language, file, cx).inlay_hints
21426}
21427
21428fn consume_contiguous_rows(
21429    contiguous_row_selections: &mut Vec<Selection<Point>>,
21430    selection: &Selection<Point>,
21431    display_map: &DisplaySnapshot,
21432    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21433) -> (MultiBufferRow, MultiBufferRow) {
21434    contiguous_row_selections.push(selection.clone());
21435    let start_row = MultiBufferRow(selection.start.row);
21436    let mut end_row = ending_row(selection, display_map);
21437
21438    while let Some(next_selection) = selections.peek() {
21439        if next_selection.start.row <= end_row.0 {
21440            end_row = ending_row(next_selection, display_map);
21441            contiguous_row_selections.push(selections.next().unwrap().clone());
21442        } else {
21443            break;
21444        }
21445    }
21446    (start_row, end_row)
21447}
21448
21449fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21450    if next_selection.end.column > 0 || next_selection.is_empty() {
21451        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21452    } else {
21453        MultiBufferRow(next_selection.end.row)
21454    }
21455}
21456
21457impl EditorSnapshot {
21458    pub fn remote_selections_in_range<'a>(
21459        &'a self,
21460        range: &'a Range<Anchor>,
21461        collaboration_hub: &dyn CollaborationHub,
21462        cx: &'a App,
21463    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21464        let participant_names = collaboration_hub.user_names(cx);
21465        let participant_indices = collaboration_hub.user_participant_indices(cx);
21466        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21467        let collaborators_by_replica_id = collaborators_by_peer_id
21468            .values()
21469            .map(|collaborator| (collaborator.replica_id, collaborator))
21470            .collect::<HashMap<_, _>>();
21471        self.buffer_snapshot
21472            .selections_in_range(range, false)
21473            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21474                if replica_id == AGENT_REPLICA_ID {
21475                    Some(RemoteSelection {
21476                        replica_id,
21477                        selection,
21478                        cursor_shape,
21479                        line_mode,
21480                        collaborator_id: CollaboratorId::Agent,
21481                        user_name: Some("Agent".into()),
21482                        color: cx.theme().players().agent(),
21483                    })
21484                } else {
21485                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21486                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21487                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21488                    Some(RemoteSelection {
21489                        replica_id,
21490                        selection,
21491                        cursor_shape,
21492                        line_mode,
21493                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21494                        user_name,
21495                        color: if let Some(index) = participant_index {
21496                            cx.theme().players().color_for_participant(index.0)
21497                        } else {
21498                            cx.theme().players().absent()
21499                        },
21500                    })
21501                }
21502            })
21503    }
21504
21505    pub fn hunks_for_ranges(
21506        &self,
21507        ranges: impl IntoIterator<Item = Range<Point>>,
21508    ) -> Vec<MultiBufferDiffHunk> {
21509        let mut hunks = Vec::new();
21510        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21511            HashMap::default();
21512        for query_range in ranges {
21513            let query_rows =
21514                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21515            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21516                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21517            ) {
21518                // Include deleted hunks that are adjacent to the query range, because
21519                // otherwise they would be missed.
21520                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21521                if hunk.status().is_deleted() {
21522                    intersects_range |= hunk.row_range.start == query_rows.end;
21523                    intersects_range |= hunk.row_range.end == query_rows.start;
21524                }
21525                if intersects_range {
21526                    if !processed_buffer_rows
21527                        .entry(hunk.buffer_id)
21528                        .or_default()
21529                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21530                    {
21531                        continue;
21532                    }
21533                    hunks.push(hunk);
21534                }
21535            }
21536        }
21537
21538        hunks
21539    }
21540
21541    fn display_diff_hunks_for_rows<'a>(
21542        &'a self,
21543        display_rows: Range<DisplayRow>,
21544        folded_buffers: &'a HashSet<BufferId>,
21545    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21546        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21547        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21548
21549        self.buffer_snapshot
21550            .diff_hunks_in_range(buffer_start..buffer_end)
21551            .filter_map(|hunk| {
21552                if folded_buffers.contains(&hunk.buffer_id) {
21553                    return None;
21554                }
21555
21556                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21557                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21558
21559                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21560                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21561
21562                let display_hunk = if hunk_display_start.column() != 0 {
21563                    DisplayDiffHunk::Folded {
21564                        display_row: hunk_display_start.row(),
21565                    }
21566                } else {
21567                    let mut end_row = hunk_display_end.row();
21568                    if hunk_display_end.column() > 0 {
21569                        end_row.0 += 1;
21570                    }
21571                    let is_created_file = hunk.is_created_file();
21572                    DisplayDiffHunk::Unfolded {
21573                        status: hunk.status(),
21574                        diff_base_byte_range: hunk.diff_base_byte_range,
21575                        display_row_range: hunk_display_start.row()..end_row,
21576                        multi_buffer_range: Anchor::range_in_buffer(
21577                            hunk.excerpt_id,
21578                            hunk.buffer_id,
21579                            hunk.buffer_range,
21580                        ),
21581                        is_created_file,
21582                    }
21583                };
21584
21585                Some(display_hunk)
21586            })
21587    }
21588
21589    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21590        self.display_snapshot.buffer_snapshot.language_at(position)
21591    }
21592
21593    pub fn is_focused(&self) -> bool {
21594        self.is_focused
21595    }
21596
21597    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21598        self.placeholder_text.as_ref()
21599    }
21600
21601    pub fn scroll_position(&self) -> gpui::Point<f32> {
21602        self.scroll_anchor.scroll_position(&self.display_snapshot)
21603    }
21604
21605    fn gutter_dimensions(
21606        &self,
21607        font_id: FontId,
21608        font_size: Pixels,
21609        max_line_number_width: Pixels,
21610        cx: &App,
21611    ) -> Option<GutterDimensions> {
21612        if !self.show_gutter {
21613            return None;
21614        }
21615
21616        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21617        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21618
21619        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21620            matches!(
21621                ProjectSettings::get_global(cx).git.git_gutter,
21622                Some(GitGutterSetting::TrackedFiles)
21623            )
21624        });
21625        let gutter_settings = EditorSettings::get_global(cx).gutter;
21626        let show_line_numbers = self
21627            .show_line_numbers
21628            .unwrap_or(gutter_settings.line_numbers);
21629        let line_gutter_width = if show_line_numbers {
21630            // Avoid flicker-like gutter resizes when the line number gains another digit by
21631            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21632            let min_width_for_number_on_gutter =
21633                ch_advance * gutter_settings.min_line_number_digits as f32;
21634            max_line_number_width.max(min_width_for_number_on_gutter)
21635        } else {
21636            0.0.into()
21637        };
21638
21639        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21640        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21641
21642        let git_blame_entries_width =
21643            self.git_blame_gutter_max_author_length
21644                .map(|max_author_length| {
21645                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21646                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21647
21648                    /// The number of characters to dedicate to gaps and margins.
21649                    const SPACING_WIDTH: usize = 4;
21650
21651                    let max_char_count = max_author_length.min(renderer.max_author_length())
21652                        + ::git::SHORT_SHA_LENGTH
21653                        + MAX_RELATIVE_TIMESTAMP.len()
21654                        + SPACING_WIDTH;
21655
21656                    ch_advance * max_char_count
21657                });
21658
21659        let is_singleton = self.buffer_snapshot.is_singleton();
21660
21661        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21662        left_padding += if !is_singleton {
21663            ch_width * 4.0
21664        } else if show_runnables || show_breakpoints {
21665            ch_width * 3.0
21666        } else if show_git_gutter && show_line_numbers {
21667            ch_width * 2.0
21668        } else if show_git_gutter || show_line_numbers {
21669            ch_width
21670        } else {
21671            px(0.)
21672        };
21673
21674        let shows_folds = is_singleton && gutter_settings.folds;
21675
21676        let right_padding = if shows_folds && show_line_numbers {
21677            ch_width * 4.0
21678        } else if shows_folds || (!is_singleton && show_line_numbers) {
21679            ch_width * 3.0
21680        } else if show_line_numbers {
21681            ch_width
21682        } else {
21683            px(0.)
21684        };
21685
21686        Some(GutterDimensions {
21687            left_padding,
21688            right_padding,
21689            width: line_gutter_width + left_padding + right_padding,
21690            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21691            git_blame_entries_width,
21692        })
21693    }
21694
21695    pub fn render_crease_toggle(
21696        &self,
21697        buffer_row: MultiBufferRow,
21698        row_contains_cursor: bool,
21699        editor: Entity<Editor>,
21700        window: &mut Window,
21701        cx: &mut App,
21702    ) -> Option<AnyElement> {
21703        let folded = self.is_line_folded(buffer_row);
21704        let mut is_foldable = false;
21705
21706        if let Some(crease) = self
21707            .crease_snapshot
21708            .query_row(buffer_row, &self.buffer_snapshot)
21709        {
21710            is_foldable = true;
21711            match crease {
21712                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21713                    if let Some(render_toggle) = render_toggle {
21714                        let toggle_callback =
21715                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21716                                if folded {
21717                                    editor.update(cx, |editor, cx| {
21718                                        editor.fold_at(buffer_row, window, cx)
21719                                    });
21720                                } else {
21721                                    editor.update(cx, |editor, cx| {
21722                                        editor.unfold_at(buffer_row, window, cx)
21723                                    });
21724                                }
21725                            });
21726                        return Some((render_toggle)(
21727                            buffer_row,
21728                            folded,
21729                            toggle_callback,
21730                            window,
21731                            cx,
21732                        ));
21733                    }
21734                }
21735            }
21736        }
21737
21738        is_foldable |= self.starts_indent(buffer_row);
21739
21740        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21741            Some(
21742                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21743                    .toggle_state(folded)
21744                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21745                        if folded {
21746                            this.unfold_at(buffer_row, window, cx);
21747                        } else {
21748                            this.fold_at(buffer_row, window, cx);
21749                        }
21750                    }))
21751                    .into_any_element(),
21752            )
21753        } else {
21754            None
21755        }
21756    }
21757
21758    pub fn render_crease_trailer(
21759        &self,
21760        buffer_row: MultiBufferRow,
21761        window: &mut Window,
21762        cx: &mut App,
21763    ) -> Option<AnyElement> {
21764        let folded = self.is_line_folded(buffer_row);
21765        if let Crease::Inline { render_trailer, .. } = self
21766            .crease_snapshot
21767            .query_row(buffer_row, &self.buffer_snapshot)?
21768        {
21769            let render_trailer = render_trailer.as_ref()?;
21770            Some(render_trailer(buffer_row, folded, window, cx))
21771        } else {
21772            None
21773        }
21774    }
21775}
21776
21777impl Deref for EditorSnapshot {
21778    type Target = DisplaySnapshot;
21779
21780    fn deref(&self) -> &Self::Target {
21781        &self.display_snapshot
21782    }
21783}
21784
21785#[derive(Clone, Debug, PartialEq, Eq)]
21786pub enum EditorEvent {
21787    InputIgnored {
21788        text: Arc<str>,
21789    },
21790    InputHandled {
21791        utf16_range_to_replace: Option<Range<isize>>,
21792        text: Arc<str>,
21793    },
21794    ExcerptsAdded {
21795        buffer: Entity<Buffer>,
21796        predecessor: ExcerptId,
21797        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21798    },
21799    ExcerptsRemoved {
21800        ids: Vec<ExcerptId>,
21801        removed_buffer_ids: Vec<BufferId>,
21802    },
21803    BufferFoldToggled {
21804        ids: Vec<ExcerptId>,
21805        folded: bool,
21806    },
21807    ExcerptsEdited {
21808        ids: Vec<ExcerptId>,
21809    },
21810    ExcerptsExpanded {
21811        ids: Vec<ExcerptId>,
21812    },
21813    BufferEdited,
21814    Edited {
21815        transaction_id: clock::Lamport,
21816    },
21817    Reparsed(BufferId),
21818    Focused,
21819    FocusedIn,
21820    Blurred,
21821    DirtyChanged,
21822    Saved,
21823    TitleChanged,
21824    DiffBaseChanged,
21825    SelectionsChanged {
21826        local: bool,
21827    },
21828    ScrollPositionChanged {
21829        local: bool,
21830        autoscroll: bool,
21831    },
21832    Closed,
21833    TransactionUndone {
21834        transaction_id: clock::Lamport,
21835    },
21836    TransactionBegun {
21837        transaction_id: clock::Lamport,
21838    },
21839    Reloaded,
21840    CursorShapeChanged,
21841    PushedToNavHistory {
21842        anchor: Anchor,
21843        is_deactivate: bool,
21844    },
21845}
21846
21847impl EventEmitter<EditorEvent> for Editor {}
21848
21849impl Focusable for Editor {
21850    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21851        self.focus_handle.clone()
21852    }
21853}
21854
21855impl Render for Editor {
21856    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21857        let settings = ThemeSettings::get_global(cx);
21858
21859        let mut text_style = match self.mode {
21860            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21861                color: cx.theme().colors().editor_foreground,
21862                font_family: settings.ui_font.family.clone(),
21863                font_features: settings.ui_font.features.clone(),
21864                font_fallbacks: settings.ui_font.fallbacks.clone(),
21865                font_size: rems(0.875).into(),
21866                font_weight: settings.ui_font.weight,
21867                line_height: relative(settings.buffer_line_height.value()),
21868                ..Default::default()
21869            },
21870            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21871                color: cx.theme().colors().editor_foreground,
21872                font_family: settings.buffer_font.family.clone(),
21873                font_features: settings.buffer_font.features.clone(),
21874                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21875                font_size: settings.buffer_font_size(cx).into(),
21876                font_weight: settings.buffer_font.weight,
21877                line_height: relative(settings.buffer_line_height.value()),
21878                ..Default::default()
21879            },
21880        };
21881        if let Some(text_style_refinement) = &self.text_style_refinement {
21882            text_style.refine(text_style_refinement)
21883        }
21884
21885        let background = match self.mode {
21886            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21887            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21888            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21889            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21890        };
21891
21892        EditorElement::new(
21893            &cx.entity(),
21894            EditorStyle {
21895                background,
21896                local_player: cx.theme().players().local(),
21897                text: text_style,
21898                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21899                syntax: cx.theme().syntax().clone(),
21900                status: cx.theme().status().clone(),
21901                inlay_hints_style: make_inlay_hints_style(cx),
21902                inline_completion_styles: make_suggestion_styles(cx),
21903                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21904                show_underlines: !self.mode.is_minimap(),
21905            },
21906        )
21907    }
21908}
21909
21910impl EntityInputHandler for Editor {
21911    fn text_for_range(
21912        &mut self,
21913        range_utf16: Range<usize>,
21914        adjusted_range: &mut Option<Range<usize>>,
21915        _: &mut Window,
21916        cx: &mut Context<Self>,
21917    ) -> Option<String> {
21918        let snapshot = self.buffer.read(cx).read(cx);
21919        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21920        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21921        if (start.0..end.0) != range_utf16 {
21922            adjusted_range.replace(start.0..end.0);
21923        }
21924        Some(snapshot.text_for_range(start..end).collect())
21925    }
21926
21927    fn selected_text_range(
21928        &mut self,
21929        ignore_disabled_input: bool,
21930        _: &mut Window,
21931        cx: &mut Context<Self>,
21932    ) -> Option<UTF16Selection> {
21933        // Prevent the IME menu from appearing when holding down an alphabetic key
21934        // while input is disabled.
21935        if !ignore_disabled_input && !self.input_enabled {
21936            return None;
21937        }
21938
21939        let selection = self.selections.newest::<OffsetUtf16>(cx);
21940        let range = selection.range();
21941
21942        Some(UTF16Selection {
21943            range: range.start.0..range.end.0,
21944            reversed: selection.reversed,
21945        })
21946    }
21947
21948    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21949        let snapshot = self.buffer.read(cx).read(cx);
21950        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21951        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21952    }
21953
21954    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21955        self.clear_highlights::<InputComposition>(cx);
21956        self.ime_transaction.take();
21957    }
21958
21959    fn replace_text_in_range(
21960        &mut self,
21961        range_utf16: Option<Range<usize>>,
21962        text: &str,
21963        window: &mut Window,
21964        cx: &mut Context<Self>,
21965    ) {
21966        if !self.input_enabled {
21967            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21968            return;
21969        }
21970
21971        self.transact(window, cx, |this, window, cx| {
21972            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21973                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21974                Some(this.selection_replacement_ranges(range_utf16, cx))
21975            } else {
21976                this.marked_text_ranges(cx)
21977            };
21978
21979            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21980                let newest_selection_id = this.selections.newest_anchor().id;
21981                this.selections
21982                    .all::<OffsetUtf16>(cx)
21983                    .iter()
21984                    .zip(ranges_to_replace.iter())
21985                    .find_map(|(selection, range)| {
21986                        if selection.id == newest_selection_id {
21987                            Some(
21988                                (range.start.0 as isize - selection.head().0 as isize)
21989                                    ..(range.end.0 as isize - selection.head().0 as isize),
21990                            )
21991                        } else {
21992                            None
21993                        }
21994                    })
21995            });
21996
21997            cx.emit(EditorEvent::InputHandled {
21998                utf16_range_to_replace: range_to_replace,
21999                text: text.into(),
22000            });
22001
22002            if let Some(new_selected_ranges) = new_selected_ranges {
22003                this.change_selections(None, window, cx, |selections| {
22004                    selections.select_ranges(new_selected_ranges)
22005                });
22006                this.backspace(&Default::default(), window, cx);
22007            }
22008
22009            this.handle_input(text, window, cx);
22010        });
22011
22012        if let Some(transaction) = self.ime_transaction {
22013            self.buffer.update(cx, |buffer, cx| {
22014                buffer.group_until_transaction(transaction, cx);
22015            });
22016        }
22017
22018        self.unmark_text(window, cx);
22019    }
22020
22021    fn replace_and_mark_text_in_range(
22022        &mut self,
22023        range_utf16: Option<Range<usize>>,
22024        text: &str,
22025        new_selected_range_utf16: Option<Range<usize>>,
22026        window: &mut Window,
22027        cx: &mut Context<Self>,
22028    ) {
22029        if !self.input_enabled {
22030            return;
22031        }
22032
22033        let transaction = self.transact(window, cx, |this, window, cx| {
22034            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22035                let snapshot = this.buffer.read(cx).read(cx);
22036                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22037                    for marked_range in &mut marked_ranges {
22038                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22039                        marked_range.start.0 += relative_range_utf16.start;
22040                        marked_range.start =
22041                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22042                        marked_range.end =
22043                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22044                    }
22045                }
22046                Some(marked_ranges)
22047            } else if let Some(range_utf16) = range_utf16 {
22048                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22049                Some(this.selection_replacement_ranges(range_utf16, cx))
22050            } else {
22051                None
22052            };
22053
22054            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22055                let newest_selection_id = this.selections.newest_anchor().id;
22056                this.selections
22057                    .all::<OffsetUtf16>(cx)
22058                    .iter()
22059                    .zip(ranges_to_replace.iter())
22060                    .find_map(|(selection, range)| {
22061                        if selection.id == newest_selection_id {
22062                            Some(
22063                                (range.start.0 as isize - selection.head().0 as isize)
22064                                    ..(range.end.0 as isize - selection.head().0 as isize),
22065                            )
22066                        } else {
22067                            None
22068                        }
22069                    })
22070            });
22071
22072            cx.emit(EditorEvent::InputHandled {
22073                utf16_range_to_replace: range_to_replace,
22074                text: text.into(),
22075            });
22076
22077            if let Some(ranges) = ranges_to_replace {
22078                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22079            }
22080
22081            let marked_ranges = {
22082                let snapshot = this.buffer.read(cx).read(cx);
22083                this.selections
22084                    .disjoint_anchors()
22085                    .iter()
22086                    .map(|selection| {
22087                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22088                    })
22089                    .collect::<Vec<_>>()
22090            };
22091
22092            if text.is_empty() {
22093                this.unmark_text(window, cx);
22094            } else {
22095                this.highlight_text::<InputComposition>(
22096                    marked_ranges.clone(),
22097                    HighlightStyle {
22098                        underline: Some(UnderlineStyle {
22099                            thickness: px(1.),
22100                            color: None,
22101                            wavy: false,
22102                        }),
22103                        ..Default::default()
22104                    },
22105                    cx,
22106                );
22107            }
22108
22109            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22110            let use_autoclose = this.use_autoclose;
22111            let use_auto_surround = this.use_auto_surround;
22112            this.set_use_autoclose(false);
22113            this.set_use_auto_surround(false);
22114            this.handle_input(text, window, cx);
22115            this.set_use_autoclose(use_autoclose);
22116            this.set_use_auto_surround(use_auto_surround);
22117
22118            if let Some(new_selected_range) = new_selected_range_utf16 {
22119                let snapshot = this.buffer.read(cx).read(cx);
22120                let new_selected_ranges = marked_ranges
22121                    .into_iter()
22122                    .map(|marked_range| {
22123                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22124                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22125                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22126                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22127                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22128                    })
22129                    .collect::<Vec<_>>();
22130
22131                drop(snapshot);
22132                this.change_selections(None, window, cx, |selections| {
22133                    selections.select_ranges(new_selected_ranges)
22134                });
22135            }
22136        });
22137
22138        self.ime_transaction = self.ime_transaction.or(transaction);
22139        if let Some(transaction) = self.ime_transaction {
22140            self.buffer.update(cx, |buffer, cx| {
22141                buffer.group_until_transaction(transaction, cx);
22142            });
22143        }
22144
22145        if self.text_highlights::<InputComposition>(cx).is_none() {
22146            self.ime_transaction.take();
22147        }
22148    }
22149
22150    fn bounds_for_range(
22151        &mut self,
22152        range_utf16: Range<usize>,
22153        element_bounds: gpui::Bounds<Pixels>,
22154        window: &mut Window,
22155        cx: &mut Context<Self>,
22156    ) -> Option<gpui::Bounds<Pixels>> {
22157        let text_layout_details = self.text_layout_details(window);
22158        let gpui::Size {
22159            width: em_width,
22160            height: line_height,
22161        } = self.character_size(window);
22162
22163        let snapshot = self.snapshot(window, cx);
22164        let scroll_position = snapshot.scroll_position();
22165        let scroll_left = scroll_position.x * em_width;
22166
22167        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22168        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22169            + self.gutter_dimensions.width
22170            + self.gutter_dimensions.margin;
22171        let y = line_height * (start.row().as_f32() - scroll_position.y);
22172
22173        Some(Bounds {
22174            origin: element_bounds.origin + point(x, y),
22175            size: size(em_width, line_height),
22176        })
22177    }
22178
22179    fn character_index_for_point(
22180        &mut self,
22181        point: gpui::Point<Pixels>,
22182        _window: &mut Window,
22183        _cx: &mut Context<Self>,
22184    ) -> Option<usize> {
22185        let position_map = self.last_position_map.as_ref()?;
22186        if !position_map.text_hitbox.contains(&point) {
22187            return None;
22188        }
22189        let display_point = position_map.point_for_position(point).previous_valid;
22190        let anchor = position_map
22191            .snapshot
22192            .display_point_to_anchor(display_point, Bias::Left);
22193        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22194        Some(utf16_offset.0)
22195    }
22196}
22197
22198trait SelectionExt {
22199    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22200    fn spanned_rows(
22201        &self,
22202        include_end_if_at_line_start: bool,
22203        map: &DisplaySnapshot,
22204    ) -> Range<MultiBufferRow>;
22205}
22206
22207impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22208    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22209        let start = self
22210            .start
22211            .to_point(&map.buffer_snapshot)
22212            .to_display_point(map);
22213        let end = self
22214            .end
22215            .to_point(&map.buffer_snapshot)
22216            .to_display_point(map);
22217        if self.reversed {
22218            end..start
22219        } else {
22220            start..end
22221        }
22222    }
22223
22224    fn spanned_rows(
22225        &self,
22226        include_end_if_at_line_start: bool,
22227        map: &DisplaySnapshot,
22228    ) -> Range<MultiBufferRow> {
22229        let start = self.start.to_point(&map.buffer_snapshot);
22230        let mut end = self.end.to_point(&map.buffer_snapshot);
22231        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22232            end.row -= 1;
22233        }
22234
22235        let buffer_start = map.prev_line_boundary(start).0;
22236        let buffer_end = map.next_line_boundary(end).0;
22237        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22238    }
22239}
22240
22241impl<T: InvalidationRegion> InvalidationStack<T> {
22242    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22243    where
22244        S: Clone + ToOffset,
22245    {
22246        while let Some(region) = self.last() {
22247            let all_selections_inside_invalidation_ranges =
22248                if selections.len() == region.ranges().len() {
22249                    selections
22250                        .iter()
22251                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22252                        .all(|(selection, invalidation_range)| {
22253                            let head = selection.head().to_offset(buffer);
22254                            invalidation_range.start <= head && invalidation_range.end >= head
22255                        })
22256                } else {
22257                    false
22258                };
22259
22260            if all_selections_inside_invalidation_ranges {
22261                break;
22262            } else {
22263                self.pop();
22264            }
22265        }
22266    }
22267}
22268
22269impl<T> Default for InvalidationStack<T> {
22270    fn default() -> Self {
22271        Self(Default::default())
22272    }
22273}
22274
22275impl<T> Deref for InvalidationStack<T> {
22276    type Target = Vec<T>;
22277
22278    fn deref(&self) -> &Self::Target {
22279        &self.0
22280    }
22281}
22282
22283impl<T> DerefMut for InvalidationStack<T> {
22284    fn deref_mut(&mut self) -> &mut Self::Target {
22285        &mut self.0
22286    }
22287}
22288
22289impl InvalidationRegion for SnippetState {
22290    fn ranges(&self) -> &[Range<Anchor>] {
22291        &self.ranges[self.active_index]
22292    }
22293}
22294
22295fn inline_completion_edit_text(
22296    current_snapshot: &BufferSnapshot,
22297    edits: &[(Range<Anchor>, String)],
22298    edit_preview: &EditPreview,
22299    include_deletions: bool,
22300    cx: &App,
22301) -> HighlightedText {
22302    let edits = edits
22303        .iter()
22304        .map(|(anchor, text)| {
22305            (
22306                anchor.start.text_anchor..anchor.end.text_anchor,
22307                text.clone(),
22308            )
22309        })
22310        .collect::<Vec<_>>();
22311
22312    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22313}
22314
22315pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22316    match severity {
22317        lsp::DiagnosticSeverity::ERROR => colors.error,
22318        lsp::DiagnosticSeverity::WARNING => colors.warning,
22319        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22320        lsp::DiagnosticSeverity::HINT => colors.info,
22321        _ => colors.ignored,
22322    }
22323}
22324
22325pub fn styled_runs_for_code_label<'a>(
22326    label: &'a CodeLabel,
22327    syntax_theme: &'a theme::SyntaxTheme,
22328) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22329    let fade_out = HighlightStyle {
22330        fade_out: Some(0.35),
22331        ..Default::default()
22332    };
22333
22334    let mut prev_end = label.filter_range.end;
22335    label
22336        .runs
22337        .iter()
22338        .enumerate()
22339        .flat_map(move |(ix, (range, highlight_id))| {
22340            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22341                style
22342            } else {
22343                return Default::default();
22344            };
22345            let mut muted_style = style;
22346            muted_style.highlight(fade_out);
22347
22348            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22349            if range.start >= label.filter_range.end {
22350                if range.start > prev_end {
22351                    runs.push((prev_end..range.start, fade_out));
22352                }
22353                runs.push((range.clone(), muted_style));
22354            } else if range.end <= label.filter_range.end {
22355                runs.push((range.clone(), style));
22356            } else {
22357                runs.push((range.start..label.filter_range.end, style));
22358                runs.push((label.filter_range.end..range.end, muted_style));
22359            }
22360            prev_end = cmp::max(prev_end, range.end);
22361
22362            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22363                runs.push((prev_end..label.text.len(), fade_out));
22364            }
22365
22366            runs
22367        })
22368}
22369
22370pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22371    let mut prev_index = 0;
22372    let mut prev_codepoint: Option<char> = None;
22373    text.char_indices()
22374        .chain([(text.len(), '\0')])
22375        .filter_map(move |(index, codepoint)| {
22376            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22377            let is_boundary = index == text.len()
22378                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22379                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22380            if is_boundary {
22381                let chunk = &text[prev_index..index];
22382                prev_index = index;
22383                Some(chunk)
22384            } else {
22385                None
22386            }
22387        })
22388}
22389
22390pub trait RangeToAnchorExt: Sized {
22391    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22392
22393    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22394        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22395        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22396    }
22397}
22398
22399impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22400    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22401        let start_offset = self.start.to_offset(snapshot);
22402        let end_offset = self.end.to_offset(snapshot);
22403        if start_offset == end_offset {
22404            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22405        } else {
22406            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22407        }
22408    }
22409}
22410
22411pub trait RowExt {
22412    fn as_f32(&self) -> f32;
22413
22414    fn next_row(&self) -> Self;
22415
22416    fn previous_row(&self) -> Self;
22417
22418    fn minus(&self, other: Self) -> u32;
22419}
22420
22421impl RowExt for DisplayRow {
22422    fn as_f32(&self) -> f32 {
22423        self.0 as f32
22424    }
22425
22426    fn next_row(&self) -> Self {
22427        Self(self.0 + 1)
22428    }
22429
22430    fn previous_row(&self) -> Self {
22431        Self(self.0.saturating_sub(1))
22432    }
22433
22434    fn minus(&self, other: Self) -> u32 {
22435        self.0 - other.0
22436    }
22437}
22438
22439impl RowExt for MultiBufferRow {
22440    fn as_f32(&self) -> f32 {
22441        self.0 as f32
22442    }
22443
22444    fn next_row(&self) -> Self {
22445        Self(self.0 + 1)
22446    }
22447
22448    fn previous_row(&self) -> Self {
22449        Self(self.0.saturating_sub(1))
22450    }
22451
22452    fn minus(&self, other: Self) -> u32 {
22453        self.0 - other.0
22454    }
22455}
22456
22457trait RowRangeExt {
22458    type Row;
22459
22460    fn len(&self) -> usize;
22461
22462    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22463}
22464
22465impl RowRangeExt for Range<MultiBufferRow> {
22466    type Row = MultiBufferRow;
22467
22468    fn len(&self) -> usize {
22469        (self.end.0 - self.start.0) as usize
22470    }
22471
22472    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22473        (self.start.0..self.end.0).map(MultiBufferRow)
22474    }
22475}
22476
22477impl RowRangeExt for Range<DisplayRow> {
22478    type Row = DisplayRow;
22479
22480    fn len(&self) -> usize {
22481        (self.end.0 - self.start.0) as usize
22482    }
22483
22484    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22485        (self.start.0..self.end.0).map(DisplayRow)
22486    }
22487}
22488
22489/// If select range has more than one line, we
22490/// just point the cursor to range.start.
22491fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22492    if range.start.row == range.end.row {
22493        range
22494    } else {
22495        range.start..range.start
22496    }
22497}
22498pub struct KillRing(ClipboardItem);
22499impl Global for KillRing {}
22500
22501const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22502
22503enum BreakpointPromptEditAction {
22504    Log,
22505    Condition,
22506    HitCondition,
22507}
22508
22509struct BreakpointPromptEditor {
22510    pub(crate) prompt: Entity<Editor>,
22511    editor: WeakEntity<Editor>,
22512    breakpoint_anchor: Anchor,
22513    breakpoint: Breakpoint,
22514    edit_action: BreakpointPromptEditAction,
22515    block_ids: HashSet<CustomBlockId>,
22516    editor_margins: Arc<Mutex<EditorMargins>>,
22517    _subscriptions: Vec<Subscription>,
22518}
22519
22520impl BreakpointPromptEditor {
22521    const MAX_LINES: u8 = 4;
22522
22523    fn new(
22524        editor: WeakEntity<Editor>,
22525        breakpoint_anchor: Anchor,
22526        breakpoint: Breakpoint,
22527        edit_action: BreakpointPromptEditAction,
22528        window: &mut Window,
22529        cx: &mut Context<Self>,
22530    ) -> Self {
22531        let base_text = match edit_action {
22532            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22533            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22534            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22535        }
22536        .map(|msg| msg.to_string())
22537        .unwrap_or_default();
22538
22539        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22540        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22541
22542        let prompt = cx.new(|cx| {
22543            let mut prompt = Editor::new(
22544                EditorMode::AutoHeight {
22545                    max_lines: Self::MAX_LINES as usize,
22546                },
22547                buffer,
22548                None,
22549                window,
22550                cx,
22551            );
22552            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22553            prompt.set_show_cursor_when_unfocused(false, cx);
22554            prompt.set_placeholder_text(
22555                match edit_action {
22556                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22557                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22558                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22559                },
22560                cx,
22561            );
22562
22563            prompt
22564        });
22565
22566        Self {
22567            prompt,
22568            editor,
22569            breakpoint_anchor,
22570            breakpoint,
22571            edit_action,
22572            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22573            block_ids: Default::default(),
22574            _subscriptions: vec![],
22575        }
22576    }
22577
22578    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22579        self.block_ids.extend(block_ids)
22580    }
22581
22582    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22583        if let Some(editor) = self.editor.upgrade() {
22584            let message = self
22585                .prompt
22586                .read(cx)
22587                .buffer
22588                .read(cx)
22589                .as_singleton()
22590                .expect("A multi buffer in breakpoint prompt isn't possible")
22591                .read(cx)
22592                .as_rope()
22593                .to_string();
22594
22595            editor.update(cx, |editor, cx| {
22596                editor.edit_breakpoint_at_anchor(
22597                    self.breakpoint_anchor,
22598                    self.breakpoint.clone(),
22599                    match self.edit_action {
22600                        BreakpointPromptEditAction::Log => {
22601                            BreakpointEditAction::EditLogMessage(message.into())
22602                        }
22603                        BreakpointPromptEditAction::Condition => {
22604                            BreakpointEditAction::EditCondition(message.into())
22605                        }
22606                        BreakpointPromptEditAction::HitCondition => {
22607                            BreakpointEditAction::EditHitCondition(message.into())
22608                        }
22609                    },
22610                    cx,
22611                );
22612
22613                editor.remove_blocks(self.block_ids.clone(), None, cx);
22614                cx.focus_self(window);
22615            });
22616        }
22617    }
22618
22619    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22620        self.editor
22621            .update(cx, |editor, cx| {
22622                editor.remove_blocks(self.block_ids.clone(), None, cx);
22623                window.focus(&editor.focus_handle);
22624            })
22625            .log_err();
22626    }
22627
22628    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22629        let settings = ThemeSettings::get_global(cx);
22630        let text_style = TextStyle {
22631            color: if self.prompt.read(cx).read_only(cx) {
22632                cx.theme().colors().text_disabled
22633            } else {
22634                cx.theme().colors().text
22635            },
22636            font_family: settings.buffer_font.family.clone(),
22637            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22638            font_size: settings.buffer_font_size(cx).into(),
22639            font_weight: settings.buffer_font.weight,
22640            line_height: relative(settings.buffer_line_height.value()),
22641            ..Default::default()
22642        };
22643        EditorElement::new(
22644            &self.prompt,
22645            EditorStyle {
22646                background: cx.theme().colors().editor_background,
22647                local_player: cx.theme().players().local(),
22648                text: text_style,
22649                ..Default::default()
22650            },
22651        )
22652    }
22653}
22654
22655impl Render for BreakpointPromptEditor {
22656    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22657        let editor_margins = *self.editor_margins.lock();
22658        let gutter_dimensions = editor_margins.gutter;
22659        h_flex()
22660            .key_context("Editor")
22661            .bg(cx.theme().colors().editor_background)
22662            .border_y_1()
22663            .border_color(cx.theme().status().info_border)
22664            .size_full()
22665            .py(window.line_height() / 2.5)
22666            .on_action(cx.listener(Self::confirm))
22667            .on_action(cx.listener(Self::cancel))
22668            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22669            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22670    }
22671}
22672
22673impl Focusable for BreakpointPromptEditor {
22674    fn focus_handle(&self, cx: &App) -> FocusHandle {
22675        self.prompt.focus_handle(cx)
22676    }
22677}
22678
22679fn all_edits_insertions_or_deletions(
22680    edits: &Vec<(Range<Anchor>, String)>,
22681    snapshot: &MultiBufferSnapshot,
22682) -> bool {
22683    let mut all_insertions = true;
22684    let mut all_deletions = true;
22685
22686    for (range, new_text) in edits.iter() {
22687        let range_is_empty = range.to_offset(&snapshot).is_empty();
22688        let text_is_empty = new_text.is_empty();
22689
22690        if range_is_empty != text_is_empty {
22691            if range_is_empty {
22692                all_deletions = false;
22693            } else {
22694                all_insertions = false;
22695            }
22696        } else {
22697            return false;
22698        }
22699
22700        if !all_insertions && !all_deletions {
22701            return false;
22702        }
22703    }
22704    all_insertions || all_deletions
22705}
22706
22707struct MissingEditPredictionKeybindingTooltip;
22708
22709impl Render for MissingEditPredictionKeybindingTooltip {
22710    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22711        ui::tooltip_container(window, cx, |container, _, cx| {
22712            container
22713                .flex_shrink_0()
22714                .max_w_80()
22715                .min_h(rems_from_px(124.))
22716                .justify_between()
22717                .child(
22718                    v_flex()
22719                        .flex_1()
22720                        .text_ui_sm(cx)
22721                        .child(Label::new("Conflict with Accept Keybinding"))
22722                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22723                )
22724                .child(
22725                    h_flex()
22726                        .pb_1()
22727                        .gap_1()
22728                        .items_end()
22729                        .w_full()
22730                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22731                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22732                        }))
22733                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22734                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22735                        })),
22736                )
22737        })
22738    }
22739}
22740
22741#[derive(Debug, Clone, Copy, PartialEq)]
22742pub struct LineHighlight {
22743    pub background: Background,
22744    pub border: Option<gpui::Hsla>,
22745    pub include_gutter: bool,
22746    pub type_id: Option<TypeId>,
22747}
22748
22749fn render_diff_hunk_controls(
22750    row: u32,
22751    status: &DiffHunkStatus,
22752    hunk_range: Range<Anchor>,
22753    is_created_file: bool,
22754    line_height: Pixels,
22755    editor: &Entity<Editor>,
22756    _window: &mut Window,
22757    cx: &mut App,
22758) -> AnyElement {
22759    h_flex()
22760        .h(line_height)
22761        .mr_1()
22762        .gap_1()
22763        .px_0p5()
22764        .pb_1()
22765        .border_x_1()
22766        .border_b_1()
22767        .border_color(cx.theme().colors().border_variant)
22768        .rounded_b_lg()
22769        .bg(cx.theme().colors().editor_background)
22770        .gap_1()
22771        .block_mouse_except_scroll()
22772        .shadow_md()
22773        .child(if status.has_secondary_hunk() {
22774            Button::new(("stage", row as u64), "Stage")
22775                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22776                .tooltip({
22777                    let focus_handle = editor.focus_handle(cx);
22778                    move |window, cx| {
22779                        Tooltip::for_action_in(
22780                            "Stage Hunk",
22781                            &::git::ToggleStaged,
22782                            &focus_handle,
22783                            window,
22784                            cx,
22785                        )
22786                    }
22787                })
22788                .on_click({
22789                    let editor = editor.clone();
22790                    move |_event, _window, cx| {
22791                        editor.update(cx, |editor, cx| {
22792                            editor.stage_or_unstage_diff_hunks(
22793                                true,
22794                                vec![hunk_range.start..hunk_range.start],
22795                                cx,
22796                            );
22797                        });
22798                    }
22799                })
22800        } else {
22801            Button::new(("unstage", row as u64), "Unstage")
22802                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22803                .tooltip({
22804                    let focus_handle = editor.focus_handle(cx);
22805                    move |window, cx| {
22806                        Tooltip::for_action_in(
22807                            "Unstage Hunk",
22808                            &::git::ToggleStaged,
22809                            &focus_handle,
22810                            window,
22811                            cx,
22812                        )
22813                    }
22814                })
22815                .on_click({
22816                    let editor = editor.clone();
22817                    move |_event, _window, cx| {
22818                        editor.update(cx, |editor, cx| {
22819                            editor.stage_or_unstage_diff_hunks(
22820                                false,
22821                                vec![hunk_range.start..hunk_range.start],
22822                                cx,
22823                            );
22824                        });
22825                    }
22826                })
22827        })
22828        .child(
22829            Button::new(("restore", row as u64), "Restore")
22830                .tooltip({
22831                    let focus_handle = editor.focus_handle(cx);
22832                    move |window, cx| {
22833                        Tooltip::for_action_in(
22834                            "Restore Hunk",
22835                            &::git::Restore,
22836                            &focus_handle,
22837                            window,
22838                            cx,
22839                        )
22840                    }
22841                })
22842                .on_click({
22843                    let editor = editor.clone();
22844                    move |_event, window, cx| {
22845                        editor.update(cx, |editor, cx| {
22846                            let snapshot = editor.snapshot(window, cx);
22847                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22848                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22849                        });
22850                    }
22851                })
22852                .disabled(is_created_file),
22853        )
22854        .when(
22855            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22856            |el| {
22857                el.child(
22858                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22859                        .shape(IconButtonShape::Square)
22860                        .icon_size(IconSize::Small)
22861                        // .disabled(!has_multiple_hunks)
22862                        .tooltip({
22863                            let focus_handle = editor.focus_handle(cx);
22864                            move |window, cx| {
22865                                Tooltip::for_action_in(
22866                                    "Next Hunk",
22867                                    &GoToHunk,
22868                                    &focus_handle,
22869                                    window,
22870                                    cx,
22871                                )
22872                            }
22873                        })
22874                        .on_click({
22875                            let editor = editor.clone();
22876                            move |_event, window, cx| {
22877                                editor.update(cx, |editor, cx| {
22878                                    let snapshot = editor.snapshot(window, cx);
22879                                    let position =
22880                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22881                                    editor.go_to_hunk_before_or_after_position(
22882                                        &snapshot,
22883                                        position,
22884                                        Direction::Next,
22885                                        window,
22886                                        cx,
22887                                    );
22888                                    editor.expand_selected_diff_hunks(cx);
22889                                });
22890                            }
22891                        }),
22892                )
22893                .child(
22894                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22895                        .shape(IconButtonShape::Square)
22896                        .icon_size(IconSize::Small)
22897                        // .disabled(!has_multiple_hunks)
22898                        .tooltip({
22899                            let focus_handle = editor.focus_handle(cx);
22900                            move |window, cx| {
22901                                Tooltip::for_action_in(
22902                                    "Previous Hunk",
22903                                    &GoToPreviousHunk,
22904                                    &focus_handle,
22905                                    window,
22906                                    cx,
22907                                )
22908                            }
22909                        })
22910                        .on_click({
22911                            let editor = editor.clone();
22912                            move |_event, window, cx| {
22913                                editor.update(cx, |editor, cx| {
22914                                    let snapshot = editor.snapshot(window, cx);
22915                                    let point =
22916                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22917                                    editor.go_to_hunk_before_or_after_position(
22918                                        &snapshot,
22919                                        point,
22920                                        Direction::Prev,
22921                                        window,
22922                                        cx,
22923                                    );
22924                                    editor.expand_selected_diff_hunks(cx);
22925                                });
22926                            }
22927                        }),
22928                )
22929            },
22930        )
22931        .into_any_element()
22932}