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_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  125    DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  126    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  127    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{
  169    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  170};
  171use serde::{Deserialize, Serialize};
  172use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  173use smallvec::{SmallVec, smallvec};
  174use snippet::Snippet;
  175use std::{
  176    any::{Any, TypeId},
  177    borrow::Cow,
  178    cell::{OnceCell, RefCell},
  179    cmp::{self, Ordering, Reverse},
  180    iter::{self, Peekable},
  181    mem,
  182    num::NonZeroU32,
  183    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  184    path::{Path, PathBuf},
  185    rc::Rc,
  186    sync::Arc,
  187    time::{Duration, Instant},
  188};
  189use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  190use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  191use theme::{
  192    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  193    observe_buffer_font_size_adjustment,
  194};
  195use ui::{
  196    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  197    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  198};
  199use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  200use workspace::{
  201    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  202    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  203    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  204    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  205    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  206    searchable::SearchEvent,
  207};
  208
  209use crate::{
  210    code_context_menus::CompletionsMenuSource,
  211    editor_settings::MultiCursorModifier,
  212    hover_links::{find_url, find_url_from_range},
  213    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  214};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248enum ReportEditorEvent {
  249    Saved { auto_saved: bool },
  250    EditorOpened,
  251    Closed,
  252}
  253
  254impl ReportEditorEvent {
  255    pub fn event_type(&self) -> &'static str {
  256        match self {
  257            Self::Saved { .. } => "Editor Saved",
  258            Self::EditorOpened => "Editor Opened",
  259            Self::Closed => "Editor Closed",
  260        }
  261    }
  262}
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    EditPrediction(usize),
  283    DebuggerValue(usize),
  284    // LSP
  285    Hint(usize),
  286    Color(usize),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> usize {
  291        match self {
  292            Self::EditPrediction(id) => *id,
  293            Self::DebuggerValue(id) => *id,
  294            Self::Hint(id) => *id,
  295            Self::Color(id) => *id,
  296        }
  297    }
  298}
  299
  300pub enum ActiveDebugLine {}
  301pub enum DebugStackFrameLine {}
  302enum DocumentHighlightRead {}
  303enum DocumentHighlightWrite {}
  304enum InputComposition {}
  305pub enum PendingInput {}
  306enum SelectedTextHighlight {}
  307
  308pub enum ConflictsOuter {}
  309pub enum ConflictsOurs {}
  310pub enum ConflictsTheirs {}
  311pub enum ConflictsOursMarker {}
  312pub enum ConflictsTheirsMarker {}
  313
  314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  315pub enum Navigated {
  316    Yes,
  317    No,
  318}
  319
  320impl Navigated {
  321    pub fn from_bool(yes: bool) -> Navigated {
  322        if yes { Navigated::Yes } else { Navigated::No }
  323    }
  324}
  325
  326#[derive(Debug, Clone, PartialEq, Eq)]
  327enum DisplayDiffHunk {
  328    Folded {
  329        display_row: DisplayRow,
  330    },
  331    Unfolded {
  332        is_created_file: bool,
  333        diff_base_byte_range: Range<usize>,
  334        display_row_range: Range<DisplayRow>,
  335        multi_buffer_range: Range<Anchor>,
  336        status: DiffHunkStatus,
  337    },
  338}
  339
  340pub enum HideMouseCursorOrigin {
  341    TypingAction,
  342    MovementAction,
  343}
  344
  345pub fn init_settings(cx: &mut App) {
  346    EditorSettings::register(cx);
  347}
  348
  349pub fn init(cx: &mut App) {
  350    init_settings(cx);
  351
  352    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  353
  354    workspace::register_project_item::<Editor>(cx);
  355    workspace::FollowableViewRegistry::register::<Editor>(cx);
  356    workspace::register_serializable_item::<Editor>(cx);
  357
  358    cx.observe_new(
  359        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  360            workspace.register_action(Editor::new_file);
  361            workspace.register_action(Editor::new_file_vertical);
  362            workspace.register_action(Editor::new_file_horizontal);
  363            workspace.register_action(Editor::cancel_language_server_work);
  364            workspace.register_action(Editor::toggle_focus);
  365        },
  366    )
  367    .detach();
  368
  369    cx.on_action(move |_: &workspace::NewFile, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    Editor::new_file(workspace, &Default::default(), window, cx)
  378                },
  379            )
  380            .detach();
  381        }
  382    });
  383    cx.on_action(move |_: &workspace::NewWindow, cx| {
  384        let app_state = workspace::AppState::global(cx);
  385        if let Some(app_state) = app_state.upgrade() {
  386            workspace::open_new(
  387                Default::default(),
  388                app_state,
  389                cx,
  390                |workspace, window, cx| {
  391                    cx.activate(true);
  392                    Editor::new_file(workspace, &Default::default(), window, cx)
  393                },
  394            )
  395            .detach();
  396        }
  397    });
  398}
  399
  400pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  401    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  402}
  403
  404pub trait DiagnosticRenderer {
  405    fn render_group(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  408        buffer_id: BufferId,
  409        snapshot: EditorSnapshot,
  410        editor: WeakEntity<Editor>,
  411        cx: &mut App,
  412    ) -> Vec<BlockProperties<Anchor>>;
  413
  414    fn render_hover(
  415        &self,
  416        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  417        range: Range<Point>,
  418        buffer_id: BufferId,
  419        cx: &mut App,
  420    ) -> Option<Entity<markdown::Markdown>>;
  421
  422    fn open_link(
  423        &self,
  424        editor: &mut Editor,
  425        link: SharedString,
  426        window: &mut Window,
  427        cx: &mut Context<Editor>,
  428    );
  429}
  430
  431pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  432
  433impl GlobalDiagnosticRenderer {
  434    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  435        cx.try_global::<Self>().map(|g| g.0.clone())
  436    }
  437}
  438
  439impl gpui::Global for GlobalDiagnosticRenderer {}
  440pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  441    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  442}
  443
  444pub struct SearchWithinRange;
  445
  446trait InvalidationRegion {
  447    fn ranges(&self) -> &[Range<Anchor>];
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum SelectPhase {
  452    Begin {
  453        position: DisplayPoint,
  454        add: bool,
  455        click_count: usize,
  456    },
  457    BeginColumnar {
  458        position: DisplayPoint,
  459        reset: bool,
  460        mode: ColumnarMode,
  461        goal_column: u32,
  462    },
  463    Extend {
  464        position: DisplayPoint,
  465        click_count: usize,
  466    },
  467    Update {
  468        position: DisplayPoint,
  469        goal_column: u32,
  470        scroll_delta: gpui::Point<f32>,
  471    },
  472    End,
  473}
  474
  475#[derive(Clone, Debug, PartialEq)]
  476pub enum ColumnarMode {
  477    FromMouse,
  478    FromSelection,
  479}
  480
  481#[derive(Clone, Debug)]
  482pub enum SelectMode {
  483    Character,
  484    Word(Range<Anchor>),
  485    Line(Range<Anchor>),
  486    All,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// When set to `true`, the editor's height will be determined by its content.
  502        sized_by_content: bool,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sized_by_content: false,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    HighlightStyle {
  596        color: Some(cx.theme().status().hint),
  597        background_color: show_background.then(|| cx.theme().status().hint_background),
  598        ..HighlightStyle::default()
  599    }
  600}
  601
  602pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  603    EditPredictionStyles {
  604        insertion: HighlightStyle {
  605            color: Some(cx.theme().status().predictive),
  606            ..HighlightStyle::default()
  607        },
  608        whitespace: HighlightStyle {
  609            background_color: Some(cx.theme().status().created_background),
  610            ..HighlightStyle::default()
  611        },
  612    }
  613}
  614
  615type CompletionId = usize;
  616
  617pub(crate) enum EditDisplayMode {
  618    TabAccept,
  619    DiffPopover,
  620    Inline,
  621}
  622
  623enum EditPrediction {
  624    Edit {
  625        edits: Vec<(Range<Anchor>, String)>,
  626        edit_preview: Option<EditPreview>,
  627        display_mode: EditDisplayMode,
  628        snapshot: BufferSnapshot,
  629    },
  630    Move {
  631        target: Anchor,
  632        snapshot: BufferSnapshot,
  633    },
  634}
  635
  636struct EditPredictionState {
  637    inlay_ids: Vec<InlayId>,
  638    completion: EditPrediction,
  639    completion_id: Option<SharedString>,
  640    invalidation_range: Range<Anchor>,
  641}
  642
  643enum EditPredictionSettings {
  644    Disabled,
  645    Enabled {
  646        show_in_menu: bool,
  647        preview_requires_modifier: bool,
  648    },
  649}
  650
  651enum EditPredictionHighlight {}
  652
  653#[derive(Debug, Clone)]
  654struct InlineDiagnostic {
  655    message: SharedString,
  656    group_id: usize,
  657    is_primary: bool,
  658    start: Point,
  659    severity: lsp::DiagnosticSeverity,
  660}
  661
  662pub enum MenuEditPredictionsPolicy {
  663    Never,
  664    ByProvider,
  665}
  666
  667pub enum EditPredictionPreview {
  668    /// Modifier is not pressed
  669    Inactive { released_too_fast: bool },
  670    /// Modifier pressed
  671    Active {
  672        since: Instant,
  673        previous_scroll_position: Option<ScrollAnchor>,
  674    },
  675}
  676
  677impl EditPredictionPreview {
  678    pub fn released_too_fast(&self) -> bool {
  679        match self {
  680            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  681            EditPredictionPreview::Active { .. } => false,
  682        }
  683    }
  684
  685    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  686        if let EditPredictionPreview::Active {
  687            previous_scroll_position,
  688            ..
  689        } = self
  690        {
  691            *previous_scroll_position = scroll_position;
  692        }
  693    }
  694}
  695
  696pub struct ContextMenuOptions {
  697    pub min_entries_visible: usize,
  698    pub max_entries_visible: usize,
  699    pub placement: Option<ContextMenuPlacement>,
  700}
  701
  702#[derive(Debug, Clone, PartialEq, Eq)]
  703pub enum ContextMenuPlacement {
  704    Above,
  705    Below,
  706}
  707
  708#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  709struct EditorActionId(usize);
  710
  711impl EditorActionId {
  712    pub fn post_inc(&mut self) -> Self {
  713        let answer = self.0;
  714
  715        *self = Self(answer + 1);
  716
  717        Self(answer)
  718    }
  719}
  720
  721// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  722// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  723
  724type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  725type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  726
  727#[derive(Default)]
  728struct ScrollbarMarkerState {
  729    scrollbar_size: Size<Pixels>,
  730    dirty: bool,
  731    markers: Arc<[PaintQuad]>,
  732    pending_refresh: Option<Task<Result<()>>>,
  733}
  734
  735impl ScrollbarMarkerState {
  736    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  737        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  738    }
  739}
  740
  741#[derive(Clone, Copy, PartialEq, Eq)]
  742pub enum MinimapVisibility {
  743    Disabled,
  744    Enabled {
  745        /// The configuration currently present in the users settings.
  746        setting_configuration: bool,
  747        /// Whether to override the currently set visibility from the users setting.
  748        toggle_override: bool,
  749    },
  750}
  751
  752impl MinimapVisibility {
  753    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  754        if mode.is_full() {
  755            Self::Enabled {
  756                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  757                toggle_override: false,
  758            }
  759        } else {
  760            Self::Disabled
  761        }
  762    }
  763
  764    fn hidden(&self) -> Self {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => Self::Enabled {
  770                setting_configuration,
  771                toggle_override: setting_configuration,
  772            },
  773            Self::Disabled => Self::Disabled,
  774        }
  775    }
  776
  777    fn disabled(&self) -> bool {
  778        matches!(*self, Self::Disabled)
  779    }
  780
  781    fn settings_visibility(&self) -> bool {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => setting_configuration,
  787            _ => false,
  788        }
  789    }
  790
  791    fn visible(&self) -> bool {
  792        match *self {
  793            Self::Enabled {
  794                setting_configuration,
  795                toggle_override,
  796            } => setting_configuration ^ toggle_override,
  797            _ => false,
  798        }
  799    }
  800
  801    fn toggle_visibility(&self) -> Self {
  802        match *self {
  803            Self::Enabled {
  804                toggle_override,
  805                setting_configuration,
  806            } => Self::Enabled {
  807                setting_configuration,
  808                toggle_override: !toggle_override,
  809            },
  810            Self::Disabled => Self::Disabled,
  811        }
  812    }
  813}
  814
  815#[derive(Clone, Debug)]
  816struct RunnableTasks {
  817    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  818    offset: multi_buffer::Anchor,
  819    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  820    column: u32,
  821    // Values of all named captures, including those starting with '_'
  822    extra_variables: HashMap<String, String>,
  823    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  824    context_range: Range<BufferOffset>,
  825}
  826
  827impl RunnableTasks {
  828    fn resolve<'a>(
  829        &'a self,
  830        cx: &'a task::TaskContext,
  831    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  832        self.templates.iter().filter_map(|(kind, template)| {
  833            template
  834                .resolve_task(&kind.to_id_base(), cx)
  835                .map(|task| (kind.clone(), task))
  836        })
  837    }
  838}
  839
  840#[derive(Clone)]
  841pub struct ResolvedTasks {
  842    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  843    position: Anchor,
  844}
  845
  846#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  847struct BufferOffset(usize);
  848
  849/// Addons allow storing per-editor state in other crates (e.g. Vim)
  850pub trait Addon: 'static {
  851    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  852
  853    fn render_buffer_header_controls(
  854        &self,
  855        _: &ExcerptInfo,
  856        _: &Window,
  857        _: &App,
  858    ) -> Option<AnyElement> {
  859        None
  860    }
  861
  862    fn to_any(&self) -> &dyn std::any::Any;
  863
  864    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  865        None
  866    }
  867}
  868
  869struct ChangeLocation {
  870    current: Option<Vec<Anchor>>,
  871    original: Vec<Anchor>,
  872}
  873impl ChangeLocation {
  874    fn locations(&self) -> &[Anchor] {
  875        self.current.as_ref().unwrap_or(&self.original)
  876    }
  877}
  878
  879/// A set of caret positions, registered when the editor was edited.
  880pub struct ChangeList {
  881    changes: Vec<ChangeLocation>,
  882    /// Currently "selected" change.
  883    position: Option<usize>,
  884}
  885
  886impl ChangeList {
  887    pub fn new() -> Self {
  888        Self {
  889            changes: Vec::new(),
  890            position: None,
  891        }
  892    }
  893
  894    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  895    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  896    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  897        if self.changes.is_empty() {
  898            return None;
  899        }
  900
  901        let prev = self.position.unwrap_or(self.changes.len());
  902        let next = if direction == Direction::Prev {
  903            prev.saturating_sub(count)
  904        } else {
  905            (prev + count).min(self.changes.len() - 1)
  906        };
  907        self.position = Some(next);
  908        self.changes.get(next).map(|change| change.locations())
  909    }
  910
  911    /// Adds a new change to the list, resetting the change list position.
  912    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  913        self.position.take();
  914        if let Some(last) = self.changes.last_mut()
  915            && group
  916        {
  917            last.current = Some(new_positions)
  918        } else {
  919            self.changes.push(ChangeLocation {
  920                original: new_positions,
  921                current: None,
  922            });
  923        }
  924    }
  925
  926    pub fn last(&self) -> Option<&[Anchor]> {
  927        self.changes.last().map(|change| change.locations())
  928    }
  929
  930    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  931        self.changes.last().map(|change| change.original.as_slice())
  932    }
  933
  934    pub fn invert_last_group(&mut self) {
  935        if let Some(last) = self.changes.last_mut()
  936            && let Some(current) = last.current.as_mut()
  937        {
  938            mem::swap(&mut last.original, current);
  939        }
  940    }
  941}
  942
  943#[derive(Clone)]
  944struct InlineBlamePopoverState {
  945    scroll_handle: ScrollHandle,
  946    commit_message: Option<ParsedCommitMessage>,
  947    markdown: Entity<Markdown>,
  948}
  949
  950struct InlineBlamePopover {
  951    position: gpui::Point<Pixels>,
  952    hide_task: Option<Task<()>>,
  953    popover_bounds: Option<Bounds<Pixels>>,
  954    popover_state: InlineBlamePopoverState,
  955    keyboard_grace: bool,
  956}
  957
  958enum SelectionDragState {
  959    /// State when no drag related activity is detected.
  960    None,
  961    /// State when the mouse is down on a selection that is about to be dragged.
  962    ReadyToDrag {
  963        selection: Selection<Anchor>,
  964        click_position: gpui::Point<Pixels>,
  965        mouse_down_time: Instant,
  966    },
  967    /// State when the mouse is dragging the selection in the editor.
  968    Dragging {
  969        selection: Selection<Anchor>,
  970        drop_cursor: Selection<Anchor>,
  971        hide_drop_cursor: bool,
  972    },
  973}
  974
  975enum ColumnarSelectionState {
  976    FromMouse {
  977        selection_tail: Anchor,
  978        display_point: Option<DisplayPoint>,
  979    },
  980    FromSelection {
  981        selection_tail: Anchor,
  982    },
  983}
  984
  985/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  986/// a breakpoint on them.
  987#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  988struct PhantomBreakpointIndicator {
  989    display_row: DisplayRow,
  990    /// There's a small debounce between hovering over the line and showing the indicator.
  991    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  992    is_active: bool,
  993    collides_with_existing_breakpoint: bool,
  994}
  995
  996/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  997///
  998/// See the [module level documentation](self) for more information.
  999pub struct Editor {
 1000    focus_handle: FocusHandle,
 1001    last_focused_descendant: Option<WeakFocusHandle>,
 1002    /// The text buffer being edited
 1003    buffer: Entity<MultiBuffer>,
 1004    /// Map of how text in the buffer should be displayed.
 1005    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1006    pub display_map: Entity<DisplayMap>,
 1007    placeholder_display_map: Option<Entity<DisplayMap>>,
 1008    pub selections: SelectionsCollection,
 1009    pub scroll_manager: ScrollManager,
 1010    /// When inline assist editors are linked, they all render cursors because
 1011    /// typing enters text into each of them, even the ones that aren't focused.
 1012    pub(crate) show_cursor_when_unfocused: bool,
 1013    columnar_selection_state: Option<ColumnarSelectionState>,
 1014    add_selections_state: Option<AddSelectionsState>,
 1015    select_next_state: Option<SelectNextState>,
 1016    select_prev_state: Option<SelectNextState>,
 1017    selection_history: SelectionHistory,
 1018    defer_selection_effects: bool,
 1019    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1020    autoclose_regions: Vec<AutocloseRegion>,
 1021    snippet_stack: InvalidationStack<SnippetState>,
 1022    select_syntax_node_history: SelectSyntaxNodeHistory,
 1023    ime_transaction: Option<TransactionId>,
 1024    pub diagnostics_max_severity: DiagnosticSeverity,
 1025    active_diagnostics: ActiveDiagnostic,
 1026    show_inline_diagnostics: bool,
 1027    inline_diagnostics_update: Task<()>,
 1028    inline_diagnostics_enabled: bool,
 1029    diagnostics_enabled: bool,
 1030    word_completions_enabled: bool,
 1031    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1032    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1033    hard_wrap: Option<usize>,
 1034    project: Option<Entity<Project>>,
 1035    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1036    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1037    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1038    blink_manager: Entity<BlinkManager>,
 1039    show_cursor_names: bool,
 1040    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1041    pub show_local_selections: bool,
 1042    mode: EditorMode,
 1043    show_breadcrumbs: bool,
 1044    show_gutter: bool,
 1045    show_scrollbars: ScrollbarAxes,
 1046    minimap_visibility: MinimapVisibility,
 1047    offset_content: bool,
 1048    disable_expand_excerpt_buttons: bool,
 1049    show_line_numbers: Option<bool>,
 1050    use_relative_line_numbers: Option<bool>,
 1051    show_git_diff_gutter: Option<bool>,
 1052    show_code_actions: Option<bool>,
 1053    show_runnables: Option<bool>,
 1054    show_breakpoints: Option<bool>,
 1055    show_wrap_guides: Option<bool>,
 1056    show_indent_guides: Option<bool>,
 1057    highlight_order: usize,
 1058    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1059    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1060    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1061    scrollbar_marker_state: ScrollbarMarkerState,
 1062    active_indent_guides_state: ActiveIndentGuidesState,
 1063    nav_history: Option<ItemNavHistory>,
 1064    context_menu: RefCell<Option<CodeContextMenu>>,
 1065    context_menu_options: Option<ContextMenuOptions>,
 1066    mouse_context_menu: Option<MouseContextMenu>,
 1067    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1068    inline_blame_popover: Option<InlineBlamePopover>,
 1069    inline_blame_popover_show_task: Option<Task<()>>,
 1070    signature_help_state: SignatureHelpState,
 1071    auto_signature_help: Option<bool>,
 1072    find_all_references_task_sources: Vec<Anchor>,
 1073    next_completion_id: CompletionId,
 1074    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1075    code_actions_task: Option<Task<Result<()>>>,
 1076    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1078    document_highlights_task: Option<Task<()>>,
 1079    linked_editing_range_task: Option<Task<Option<()>>>,
 1080    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1081    pending_rename: Option<RenameState>,
 1082    searchable: bool,
 1083    cursor_shape: CursorShape,
 1084    current_line_highlight: Option<CurrentLineHighlight>,
 1085    collapse_matches: bool,
 1086    autoindent_mode: Option<AutoindentMode>,
 1087    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1088    input_enabled: bool,
 1089    use_modal_editing: bool,
 1090    read_only: bool,
 1091    leader_id: Option<CollaboratorId>,
 1092    remote_id: Option<ViewId>,
 1093    pub hover_state: HoverState,
 1094    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1095    gutter_hovered: bool,
 1096    hovered_link_state: Option<HoveredLinkState>,
 1097    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1098    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1099    active_edit_prediction: Option<EditPredictionState>,
 1100    /// Used to prevent flickering as the user types while the menu is open
 1101    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1102    edit_prediction_settings: EditPredictionSettings,
 1103    edit_predictions_hidden_for_vim_mode: bool,
 1104    show_edit_predictions_override: Option<bool>,
 1105    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1106    edit_prediction_preview: EditPredictionPreview,
 1107    edit_prediction_indent_conflict: bool,
 1108    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1109    inlay_hint_cache: InlayHintCache,
 1110    next_inlay_id: usize,
 1111    _subscriptions: Vec<Subscription>,
 1112    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1113    gutter_dimensions: GutterDimensions,
 1114    style: Option<EditorStyle>,
 1115    text_style_refinement: Option<TextStyleRefinement>,
 1116    next_editor_action_id: EditorActionId,
 1117    editor_actions: Rc<
 1118        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1119    >,
 1120    use_autoclose: bool,
 1121    use_auto_surround: bool,
 1122    auto_replace_emoji_shortcode: bool,
 1123    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1124    show_git_blame_gutter: bool,
 1125    show_git_blame_inline: bool,
 1126    show_git_blame_inline_delay_task: Option<Task<()>>,
 1127    git_blame_inline_enabled: bool,
 1128    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1129    serialize_dirty_buffers: bool,
 1130    show_selection_menu: Option<bool>,
 1131    blame: Option<Entity<GitBlame>>,
 1132    blame_subscription: Option<Subscription>,
 1133    custom_context_menu: Option<
 1134        Box<
 1135            dyn 'static
 1136                + Fn(
 1137                    &mut Self,
 1138                    DisplayPoint,
 1139                    &mut Window,
 1140                    &mut Context<Self>,
 1141                ) -> Option<Entity<ui::ContextMenu>>,
 1142        >,
 1143    >,
 1144    last_bounds: Option<Bounds<Pixels>>,
 1145    last_position_map: Option<Rc<PositionMap>>,
 1146    expect_bounds_change: Option<Bounds<Pixels>>,
 1147    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1148    tasks_update_task: Option<Task<()>>,
 1149    breakpoint_store: Option<Entity<BreakpointStore>>,
 1150    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1151    hovered_diff_hunk_row: Option<DisplayRow>,
 1152    pull_diagnostics_task: Task<()>,
 1153    in_project_search: bool,
 1154    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1155    breadcrumb_header: Option<String>,
 1156    focused_block: Option<FocusedBlock>,
 1157    next_scroll_position: NextScrollCursorCenterTopBottom,
 1158    addons: HashMap<TypeId, Box<dyn Addon>>,
 1159    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1160    load_diff_task: Option<Shared<Task<()>>>,
 1161    /// Whether we are temporarily displaying a diff other than git's
 1162    temporary_diff_override: bool,
 1163    selection_mark_mode: bool,
 1164    toggle_fold_multiple_buffers: Task<()>,
 1165    _scroll_cursor_center_top_bottom_task: Task<()>,
 1166    serialize_selections: Task<()>,
 1167    serialize_folds: Task<()>,
 1168    mouse_cursor_hidden: bool,
 1169    minimap: Option<Entity<Self>>,
 1170    hide_mouse_mode: HideMouseMode,
 1171    pub change_list: ChangeList,
 1172    inline_value_cache: InlineValueCache,
 1173    selection_drag_state: SelectionDragState,
 1174    next_color_inlay_id: usize,
 1175    colors: Option<LspColorData>,
 1176    folding_newlines: Task<()>,
 1177    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1178}
 1179
 1180#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1181enum NextScrollCursorCenterTopBottom {
 1182    #[default]
 1183    Center,
 1184    Top,
 1185    Bottom,
 1186}
 1187
 1188impl NextScrollCursorCenterTopBottom {
 1189    fn next(&self) -> Self {
 1190        match self {
 1191            Self::Center => Self::Top,
 1192            Self::Top => Self::Bottom,
 1193            Self::Bottom => Self::Center,
 1194        }
 1195    }
 1196}
 1197
 1198#[derive(Clone)]
 1199pub struct EditorSnapshot {
 1200    pub mode: EditorMode,
 1201    show_gutter: bool,
 1202    show_line_numbers: Option<bool>,
 1203    show_git_diff_gutter: Option<bool>,
 1204    show_code_actions: Option<bool>,
 1205    show_runnables: Option<bool>,
 1206    show_breakpoints: Option<bool>,
 1207    git_blame_gutter_max_author_length: Option<usize>,
 1208    pub display_snapshot: DisplaySnapshot,
 1209    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1210    is_focused: bool,
 1211    scroll_anchor: ScrollAnchor,
 1212    ongoing_scroll: OngoingScroll,
 1213    current_line_highlight: CurrentLineHighlight,
 1214    gutter_hovered: bool,
 1215}
 1216
 1217#[derive(Default, Debug, Clone, Copy)]
 1218pub struct GutterDimensions {
 1219    pub left_padding: Pixels,
 1220    pub right_padding: Pixels,
 1221    pub width: Pixels,
 1222    pub margin: Pixels,
 1223    pub git_blame_entries_width: Option<Pixels>,
 1224}
 1225
 1226impl GutterDimensions {
 1227    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1228        Self {
 1229            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1230            ..Default::default()
 1231        }
 1232    }
 1233
 1234    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1235        -cx.text_system().descent(font_id, font_size)
 1236    }
 1237    /// The full width of the space taken up by the gutter.
 1238    pub fn full_width(&self) -> Pixels {
 1239        self.margin + self.width
 1240    }
 1241
 1242    /// The width of the space reserved for the fold indicators,
 1243    /// use alongside 'justify_end' and `gutter_width` to
 1244    /// right align content with the line numbers
 1245    pub fn fold_area_width(&self) -> Pixels {
 1246        self.margin + self.right_padding
 1247    }
 1248}
 1249
 1250struct CharacterDimensions {
 1251    em_width: Pixels,
 1252    em_advance: Pixels,
 1253    line_height: Pixels,
 1254}
 1255
 1256#[derive(Debug)]
 1257pub struct RemoteSelection {
 1258    pub replica_id: ReplicaId,
 1259    pub selection: Selection<Anchor>,
 1260    pub cursor_shape: CursorShape,
 1261    pub collaborator_id: CollaboratorId,
 1262    pub line_mode: bool,
 1263    pub user_name: Option<SharedString>,
 1264    pub color: PlayerColor,
 1265}
 1266
 1267#[derive(Clone, Debug)]
 1268struct SelectionHistoryEntry {
 1269    selections: Arc<[Selection<Anchor>]>,
 1270    select_next_state: Option<SelectNextState>,
 1271    select_prev_state: Option<SelectNextState>,
 1272    add_selections_state: Option<AddSelectionsState>,
 1273}
 1274
 1275#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1276enum SelectionHistoryMode {
 1277    Normal,
 1278    Undoing,
 1279    Redoing,
 1280    Skipping,
 1281}
 1282
 1283#[derive(Clone, PartialEq, Eq, Hash)]
 1284struct HoveredCursor {
 1285    replica_id: u16,
 1286    selection_id: usize,
 1287}
 1288
 1289impl Default for SelectionHistoryMode {
 1290    fn default() -> Self {
 1291        Self::Normal
 1292    }
 1293}
 1294
 1295#[derive(Debug)]
 1296/// SelectionEffects controls the side-effects of updating the selection.
 1297///
 1298/// The default behaviour does "what you mostly want":
 1299/// - it pushes to the nav history if the cursor moved by >10 lines
 1300/// - it re-triggers completion requests
 1301/// - it scrolls to fit
 1302///
 1303/// You might want to modify these behaviours. For example when doing a "jump"
 1304/// like go to definition, we always want to add to nav history; but when scrolling
 1305/// in vim mode we never do.
 1306///
 1307/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1308/// move.
 1309#[derive(Clone)]
 1310pub struct SelectionEffects {
 1311    nav_history: Option<bool>,
 1312    completions: bool,
 1313    scroll: Option<Autoscroll>,
 1314}
 1315
 1316impl Default for SelectionEffects {
 1317    fn default() -> Self {
 1318        Self {
 1319            nav_history: None,
 1320            completions: true,
 1321            scroll: Some(Autoscroll::fit()),
 1322        }
 1323    }
 1324}
 1325impl SelectionEffects {
 1326    pub fn scroll(scroll: Autoscroll) -> Self {
 1327        Self {
 1328            scroll: Some(scroll),
 1329            ..Default::default()
 1330        }
 1331    }
 1332
 1333    pub fn no_scroll() -> Self {
 1334        Self {
 1335            scroll: None,
 1336            ..Default::default()
 1337        }
 1338    }
 1339
 1340    pub fn completions(self, completions: bool) -> Self {
 1341        Self {
 1342            completions,
 1343            ..self
 1344        }
 1345    }
 1346
 1347    pub fn nav_history(self, nav_history: bool) -> Self {
 1348        Self {
 1349            nav_history: Some(nav_history),
 1350            ..self
 1351        }
 1352    }
 1353}
 1354
 1355struct DeferredSelectionEffectsState {
 1356    changed: bool,
 1357    effects: SelectionEffects,
 1358    old_cursor_position: Anchor,
 1359    history_entry: SelectionHistoryEntry,
 1360}
 1361
 1362#[derive(Default)]
 1363struct SelectionHistory {
 1364    #[allow(clippy::type_complexity)]
 1365    selections_by_transaction:
 1366        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1367    mode: SelectionHistoryMode,
 1368    undo_stack: VecDeque<SelectionHistoryEntry>,
 1369    redo_stack: VecDeque<SelectionHistoryEntry>,
 1370}
 1371
 1372impl SelectionHistory {
 1373    #[track_caller]
 1374    fn insert_transaction(
 1375        &mut self,
 1376        transaction_id: TransactionId,
 1377        selections: Arc<[Selection<Anchor>]>,
 1378    ) {
 1379        if selections.is_empty() {
 1380            log::error!(
 1381                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1382                std::panic::Location::caller()
 1383            );
 1384            return;
 1385        }
 1386        self.selections_by_transaction
 1387            .insert(transaction_id, (selections, None));
 1388    }
 1389
 1390    #[allow(clippy::type_complexity)]
 1391    fn transaction(
 1392        &self,
 1393        transaction_id: TransactionId,
 1394    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1395        self.selections_by_transaction.get(&transaction_id)
 1396    }
 1397
 1398    #[allow(clippy::type_complexity)]
 1399    fn transaction_mut(
 1400        &mut self,
 1401        transaction_id: TransactionId,
 1402    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1403        self.selections_by_transaction.get_mut(&transaction_id)
 1404    }
 1405
 1406    fn push(&mut self, entry: SelectionHistoryEntry) {
 1407        if !entry.selections.is_empty() {
 1408            match self.mode {
 1409                SelectionHistoryMode::Normal => {
 1410                    self.push_undo(entry);
 1411                    self.redo_stack.clear();
 1412                }
 1413                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1414                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1415                SelectionHistoryMode::Skipping => {}
 1416            }
 1417        }
 1418    }
 1419
 1420    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1421        if self
 1422            .undo_stack
 1423            .back()
 1424            .is_none_or(|e| e.selections != entry.selections)
 1425        {
 1426            self.undo_stack.push_back(entry);
 1427            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1428                self.undo_stack.pop_front();
 1429            }
 1430        }
 1431    }
 1432
 1433    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1434        if self
 1435            .redo_stack
 1436            .back()
 1437            .is_none_or(|e| e.selections != entry.selections)
 1438        {
 1439            self.redo_stack.push_back(entry);
 1440            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1441                self.redo_stack.pop_front();
 1442            }
 1443        }
 1444    }
 1445}
 1446
 1447#[derive(Clone, Copy)]
 1448pub struct RowHighlightOptions {
 1449    pub autoscroll: bool,
 1450    pub include_gutter: bool,
 1451}
 1452
 1453impl Default for RowHighlightOptions {
 1454    fn default() -> Self {
 1455        Self {
 1456            autoscroll: Default::default(),
 1457            include_gutter: true,
 1458        }
 1459    }
 1460}
 1461
 1462struct RowHighlight {
 1463    index: usize,
 1464    range: Range<Anchor>,
 1465    color: Hsla,
 1466    options: RowHighlightOptions,
 1467    type_id: TypeId,
 1468}
 1469
 1470#[derive(Clone, Debug)]
 1471struct AddSelectionsState {
 1472    groups: Vec<AddSelectionsGroup>,
 1473}
 1474
 1475#[derive(Clone, Debug)]
 1476struct AddSelectionsGroup {
 1477    above: bool,
 1478    stack: Vec<usize>,
 1479}
 1480
 1481#[derive(Clone)]
 1482struct SelectNextState {
 1483    query: AhoCorasick,
 1484    wordwise: bool,
 1485    done: bool,
 1486}
 1487
 1488impl std::fmt::Debug for SelectNextState {
 1489    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1490        f.debug_struct(std::any::type_name::<Self>())
 1491            .field("wordwise", &self.wordwise)
 1492            .field("done", &self.done)
 1493            .finish()
 1494    }
 1495}
 1496
 1497#[derive(Debug)]
 1498struct AutocloseRegion {
 1499    selection_id: usize,
 1500    range: Range<Anchor>,
 1501    pair: BracketPair,
 1502}
 1503
 1504#[derive(Debug)]
 1505struct SnippetState {
 1506    ranges: Vec<Vec<Range<Anchor>>>,
 1507    active_index: usize,
 1508    choices: Vec<Option<Vec<String>>>,
 1509}
 1510
 1511#[doc(hidden)]
 1512pub struct RenameState {
 1513    pub range: Range<Anchor>,
 1514    pub old_name: Arc<str>,
 1515    pub editor: Entity<Editor>,
 1516    block_id: CustomBlockId,
 1517}
 1518
 1519struct InvalidationStack<T>(Vec<T>);
 1520
 1521struct RegisteredEditPredictionProvider {
 1522    provider: Arc<dyn EditPredictionProviderHandle>,
 1523    _subscription: Subscription,
 1524}
 1525
 1526#[derive(Debug, PartialEq, Eq)]
 1527pub struct ActiveDiagnosticGroup {
 1528    pub active_range: Range<Anchor>,
 1529    pub active_message: String,
 1530    pub group_id: usize,
 1531    pub blocks: HashSet<CustomBlockId>,
 1532}
 1533
 1534#[derive(Debug, PartialEq, Eq)]
 1535
 1536pub(crate) enum ActiveDiagnostic {
 1537    None,
 1538    All,
 1539    Group(ActiveDiagnosticGroup),
 1540}
 1541
 1542#[derive(Serialize, Deserialize, Clone, Debug)]
 1543pub struct ClipboardSelection {
 1544    /// The number of bytes in this selection.
 1545    pub len: usize,
 1546    /// Whether this was a full-line selection.
 1547    pub is_entire_line: bool,
 1548    /// The indentation of the first line when this content was originally copied.
 1549    pub first_line_indent: u32,
 1550}
 1551
 1552// selections, scroll behavior, was newest selection reversed
 1553type SelectSyntaxNodeHistoryState = (
 1554    Box<[Selection<usize>]>,
 1555    SelectSyntaxNodeScrollBehavior,
 1556    bool,
 1557);
 1558
 1559#[derive(Default)]
 1560struct SelectSyntaxNodeHistory {
 1561    stack: Vec<SelectSyntaxNodeHistoryState>,
 1562    // disable temporarily to allow changing selections without losing the stack
 1563    pub disable_clearing: bool,
 1564}
 1565
 1566impl SelectSyntaxNodeHistory {
 1567    pub fn try_clear(&mut self) {
 1568        if !self.disable_clearing {
 1569            self.stack.clear();
 1570        }
 1571    }
 1572
 1573    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1574        self.stack.push(selection);
 1575    }
 1576
 1577    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1578        self.stack.pop()
 1579    }
 1580}
 1581
 1582enum SelectSyntaxNodeScrollBehavior {
 1583    CursorTop,
 1584    FitSelection,
 1585    CursorBottom,
 1586}
 1587
 1588#[derive(Debug)]
 1589pub(crate) struct NavigationData {
 1590    cursor_anchor: Anchor,
 1591    cursor_position: Point,
 1592    scroll_anchor: ScrollAnchor,
 1593    scroll_top_row: u32,
 1594}
 1595
 1596#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1597pub enum GotoDefinitionKind {
 1598    Symbol,
 1599    Declaration,
 1600    Type,
 1601    Implementation,
 1602}
 1603
 1604#[derive(Debug, Clone)]
 1605enum InlayHintRefreshReason {
 1606    ModifiersChanged(bool),
 1607    Toggle(bool),
 1608    SettingsChange(InlayHintSettings),
 1609    NewLinesShown,
 1610    BufferEdited(HashSet<Arc<Language>>),
 1611    RefreshRequested,
 1612    ExcerptsRemoved(Vec<ExcerptId>),
 1613}
 1614
 1615impl InlayHintRefreshReason {
 1616    fn description(&self) -> &'static str {
 1617        match self {
 1618            Self::ModifiersChanged(_) => "modifiers changed",
 1619            Self::Toggle(_) => "toggle",
 1620            Self::SettingsChange(_) => "settings change",
 1621            Self::NewLinesShown => "new lines shown",
 1622            Self::BufferEdited(_) => "buffer edited",
 1623            Self::RefreshRequested => "refresh requested",
 1624            Self::ExcerptsRemoved(_) => "excerpts removed",
 1625        }
 1626    }
 1627}
 1628
 1629pub enum FormatTarget {
 1630    Buffers(HashSet<Entity<Buffer>>),
 1631    Ranges(Vec<Range<MultiBufferPoint>>),
 1632}
 1633
 1634pub(crate) struct FocusedBlock {
 1635    id: BlockId,
 1636    focus_handle: WeakFocusHandle,
 1637}
 1638
 1639#[derive(Clone)]
 1640enum JumpData {
 1641    MultiBufferRow {
 1642        row: MultiBufferRow,
 1643        line_offset_from_top: u32,
 1644    },
 1645    MultiBufferPoint {
 1646        excerpt_id: ExcerptId,
 1647        position: Point,
 1648        anchor: text::Anchor,
 1649        line_offset_from_top: u32,
 1650    },
 1651}
 1652
 1653pub enum MultibufferSelectionMode {
 1654    First,
 1655    All,
 1656}
 1657
 1658#[derive(Clone, Copy, Debug, Default)]
 1659pub struct RewrapOptions {
 1660    pub override_language_settings: bool,
 1661    pub preserve_existing_whitespace: bool,
 1662}
 1663
 1664impl Editor {
 1665    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1666        let buffer = cx.new(|cx| Buffer::local("", cx));
 1667        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1668        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1669    }
 1670
 1671    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1672        let buffer = cx.new(|cx| Buffer::local("", cx));
 1673        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1674        Self::new(EditorMode::full(), buffer, None, window, cx)
 1675    }
 1676
 1677    pub fn auto_height(
 1678        min_lines: usize,
 1679        max_lines: usize,
 1680        window: &mut Window,
 1681        cx: &mut Context<Self>,
 1682    ) -> Self {
 1683        let buffer = cx.new(|cx| Buffer::local("", cx));
 1684        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1685        Self::new(
 1686            EditorMode::AutoHeight {
 1687                min_lines,
 1688                max_lines: Some(max_lines),
 1689            },
 1690            buffer,
 1691            None,
 1692            window,
 1693            cx,
 1694        )
 1695    }
 1696
 1697    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1698    /// The editor grows as tall as needed to fit its content.
 1699    pub fn auto_height_unbounded(
 1700        min_lines: usize,
 1701        window: &mut Window,
 1702        cx: &mut Context<Self>,
 1703    ) -> Self {
 1704        let buffer = cx.new(|cx| Buffer::local("", cx));
 1705        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1706        Self::new(
 1707            EditorMode::AutoHeight {
 1708                min_lines,
 1709                max_lines: None,
 1710            },
 1711            buffer,
 1712            None,
 1713            window,
 1714            cx,
 1715        )
 1716    }
 1717
 1718    pub fn for_buffer(
 1719        buffer: Entity<Buffer>,
 1720        project: Option<Entity<Project>>,
 1721        window: &mut Window,
 1722        cx: &mut Context<Self>,
 1723    ) -> Self {
 1724        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1725        Self::new(EditorMode::full(), buffer, project, window, cx)
 1726    }
 1727
 1728    pub fn for_multibuffer(
 1729        buffer: Entity<MultiBuffer>,
 1730        project: Option<Entity<Project>>,
 1731        window: &mut Window,
 1732        cx: &mut Context<Self>,
 1733    ) -> Self {
 1734        Self::new(EditorMode::full(), buffer, project, window, cx)
 1735    }
 1736
 1737    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1738        let mut clone = Self::new(
 1739            self.mode.clone(),
 1740            self.buffer.clone(),
 1741            self.project.clone(),
 1742            window,
 1743            cx,
 1744        );
 1745        self.display_map.update(cx, |display_map, cx| {
 1746            let snapshot = display_map.snapshot(cx);
 1747            clone.display_map.update(cx, |display_map, cx| {
 1748                display_map.set_state(&snapshot, cx);
 1749            });
 1750        });
 1751        clone.folds_did_change(cx);
 1752        clone.selections.clone_state(&self.selections);
 1753        clone.scroll_manager.clone_state(&self.scroll_manager);
 1754        clone.searchable = self.searchable;
 1755        clone.read_only = self.read_only;
 1756        clone
 1757    }
 1758
 1759    pub fn new(
 1760        mode: EditorMode,
 1761        buffer: Entity<MultiBuffer>,
 1762        project: Option<Entity<Project>>,
 1763        window: &mut Window,
 1764        cx: &mut Context<Self>,
 1765    ) -> Self {
 1766        Editor::new_internal(mode, buffer, project, None, window, cx)
 1767    }
 1768
 1769    fn new_internal(
 1770        mode: EditorMode,
 1771        buffer: Entity<MultiBuffer>,
 1772        project: Option<Entity<Project>>,
 1773        display_map: Option<Entity<DisplayMap>>,
 1774        window: &mut Window,
 1775        cx: &mut Context<Self>,
 1776    ) -> Self {
 1777        debug_assert!(
 1778            display_map.is_none() || mode.is_minimap(),
 1779            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1780        );
 1781
 1782        let full_mode = mode.is_full();
 1783        let is_minimap = mode.is_minimap();
 1784        let diagnostics_max_severity = if full_mode {
 1785            EditorSettings::get_global(cx)
 1786                .diagnostics_max_severity
 1787                .unwrap_or(DiagnosticSeverity::Hint)
 1788        } else {
 1789            DiagnosticSeverity::Off
 1790        };
 1791        let style = window.text_style();
 1792        let font_size = style.font_size.to_pixels(window.rem_size());
 1793        let editor = cx.entity().downgrade();
 1794        let fold_placeholder = FoldPlaceholder {
 1795            constrain_width: false,
 1796            render: Arc::new(move |fold_id, fold_range, cx| {
 1797                let editor = editor.clone();
 1798                div()
 1799                    .id(fold_id)
 1800                    .bg(cx.theme().colors().ghost_element_background)
 1801                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1802                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1803                    .rounded_xs()
 1804                    .size_full()
 1805                    .cursor_pointer()
 1806                    .child("")
 1807                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1808                    .on_click(move |_, _window, cx| {
 1809                        editor
 1810                            .update(cx, |editor, cx| {
 1811                                editor.unfold_ranges(
 1812                                    &[fold_range.start..fold_range.end],
 1813                                    true,
 1814                                    false,
 1815                                    cx,
 1816                                );
 1817                                cx.stop_propagation();
 1818                            })
 1819                            .ok();
 1820                    })
 1821                    .into_any()
 1822            }),
 1823            merge_adjacent: true,
 1824            ..FoldPlaceholder::default()
 1825        };
 1826        let display_map = display_map.unwrap_or_else(|| {
 1827            cx.new(|cx| {
 1828                DisplayMap::new(
 1829                    buffer.clone(),
 1830                    style.font(),
 1831                    font_size,
 1832                    None,
 1833                    FILE_HEADER_HEIGHT,
 1834                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1835                    fold_placeholder,
 1836                    diagnostics_max_severity,
 1837                    cx,
 1838                )
 1839            })
 1840        });
 1841
 1842        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1843
 1844        let blink_manager = cx.new(|cx| {
 1845            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1846            if is_minimap {
 1847                blink_manager.disable(cx);
 1848            }
 1849            blink_manager
 1850        });
 1851
 1852        let soft_wrap_mode_override =
 1853            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1854
 1855        let mut project_subscriptions = Vec::new();
 1856        if full_mode && let Some(project) = project.as_ref() {
 1857            project_subscriptions.push(cx.subscribe_in(
 1858                project,
 1859                window,
 1860                |editor, _, event, window, cx| match event {
 1861                    project::Event::RefreshCodeLens => {
 1862                        // we always query lens with actions, without storing them, always refreshing them
 1863                    }
 1864                    project::Event::RefreshInlayHints => {
 1865                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1866                    }
 1867                    project::Event::LanguageServerAdded(..)
 1868                    | project::Event::LanguageServerRemoved(..) => {
 1869                        if editor.tasks_update_task.is_none() {
 1870                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1871                        }
 1872                    }
 1873                    project::Event::SnippetEdit(id, snippet_edits) => {
 1874                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1875                            let focus_handle = editor.focus_handle(cx);
 1876                            if focus_handle.is_focused(window) {
 1877                                let snapshot = buffer.read(cx).snapshot();
 1878                                for (range, snippet) in snippet_edits {
 1879                                    let editor_range =
 1880                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1881                                    editor
 1882                                        .insert_snippet(
 1883                                            &[editor_range],
 1884                                            snippet.clone(),
 1885                                            window,
 1886                                            cx,
 1887                                        )
 1888                                        .ok();
 1889                                }
 1890                            }
 1891                        }
 1892                    }
 1893                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1894                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1895                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1896                        }
 1897                    }
 1898
 1899                    project::Event::EntryRenamed(transaction) => {
 1900                        let Some(workspace) = editor.workspace() else {
 1901                            return;
 1902                        };
 1903                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1904                        else {
 1905                            return;
 1906                        };
 1907                        if active_editor.entity_id() == cx.entity_id() {
 1908                            let edited_buffers_already_open = {
 1909                                let other_editors: Vec<Entity<Editor>> = workspace
 1910                                    .read(cx)
 1911                                    .panes()
 1912                                    .iter()
 1913                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1914                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1915                                    .collect();
 1916
 1917                                transaction.0.keys().all(|buffer| {
 1918                                    other_editors.iter().any(|editor| {
 1919                                        let multi_buffer = editor.read(cx).buffer();
 1920                                        multi_buffer.read(cx).is_singleton()
 1921                                            && multi_buffer.read(cx).as_singleton().map_or(
 1922                                                false,
 1923                                                |singleton| {
 1924                                                    singleton.entity_id() == buffer.entity_id()
 1925                                                },
 1926                                            )
 1927                                    })
 1928                                })
 1929                            };
 1930
 1931                            if !edited_buffers_already_open {
 1932                                let workspace = workspace.downgrade();
 1933                                let transaction = transaction.clone();
 1934                                cx.defer_in(window, move |_, window, cx| {
 1935                                    cx.spawn_in(window, async move |editor, cx| {
 1936                                        Self::open_project_transaction(
 1937                                            &editor,
 1938                                            workspace,
 1939                                            transaction,
 1940                                            "Rename".to_string(),
 1941                                            cx,
 1942                                        )
 1943                                        .await
 1944                                        .ok()
 1945                                    })
 1946                                    .detach();
 1947                                });
 1948                            }
 1949                        }
 1950                    }
 1951
 1952                    _ => {}
 1953                },
 1954            ));
 1955            if let Some(task_inventory) = project
 1956                .read(cx)
 1957                .task_store()
 1958                .read(cx)
 1959                .task_inventory()
 1960                .cloned()
 1961            {
 1962                project_subscriptions.push(cx.observe_in(
 1963                    &task_inventory,
 1964                    window,
 1965                    |editor, _, window, cx| {
 1966                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1967                    },
 1968                ));
 1969            };
 1970
 1971            project_subscriptions.push(cx.subscribe_in(
 1972                &project.read(cx).breakpoint_store(),
 1973                window,
 1974                |editor, _, event, window, cx| match event {
 1975                    BreakpointStoreEvent::ClearDebugLines => {
 1976                        editor.clear_row_highlights::<ActiveDebugLine>();
 1977                        editor.refresh_inline_values(cx);
 1978                    }
 1979                    BreakpointStoreEvent::SetDebugLine => {
 1980                        if editor.go_to_active_debug_line(window, cx) {
 1981                            cx.stop_propagation();
 1982                        }
 1983
 1984                        editor.refresh_inline_values(cx);
 1985                    }
 1986                    _ => {}
 1987                },
 1988            ));
 1989            let git_store = project.read(cx).git_store().clone();
 1990            let project = project.clone();
 1991            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1992                if let GitStoreEvent::RepositoryUpdated(
 1993                    _,
 1994                    RepositoryEvent::Updated {
 1995                        new_instance: true, ..
 1996                    },
 1997                    _,
 1998                ) = event
 1999                {
 2000                    this.load_diff_task = Some(
 2001                        update_uncommitted_diff_for_buffer(
 2002                            cx.entity(),
 2003                            &project,
 2004                            this.buffer.read(cx).all_buffers(),
 2005                            this.buffer.clone(),
 2006                            cx,
 2007                        )
 2008                        .shared(),
 2009                    );
 2010                }
 2011            }));
 2012        }
 2013
 2014        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2015
 2016        let inlay_hint_settings =
 2017            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2018        let focus_handle = cx.focus_handle();
 2019        if !is_minimap {
 2020            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2021                .detach();
 2022            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2023                .detach();
 2024            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2025                .detach();
 2026            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2027                .detach();
 2028            cx.observe_pending_input(window, Self::observe_pending_input)
 2029                .detach();
 2030        }
 2031
 2032        let show_indent_guides =
 2033            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2034                Some(false)
 2035            } else {
 2036                None
 2037            };
 2038
 2039        let breakpoint_store = match (&mode, project.as_ref()) {
 2040            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2041            _ => None,
 2042        };
 2043
 2044        let mut code_action_providers = Vec::new();
 2045        let mut load_uncommitted_diff = None;
 2046        if let Some(project) = project.clone() {
 2047            load_uncommitted_diff = Some(
 2048                update_uncommitted_diff_for_buffer(
 2049                    cx.entity(),
 2050                    &project,
 2051                    buffer.read(cx).all_buffers(),
 2052                    buffer.clone(),
 2053                    cx,
 2054                )
 2055                .shared(),
 2056            );
 2057            code_action_providers.push(Rc::new(project) as Rc<_>);
 2058        }
 2059
 2060        let mut editor = Self {
 2061            focus_handle,
 2062            show_cursor_when_unfocused: false,
 2063            last_focused_descendant: None,
 2064            buffer: buffer.clone(),
 2065            display_map: display_map.clone(),
 2066            placeholder_display_map: None,
 2067            selections,
 2068            scroll_manager: ScrollManager::new(cx),
 2069            columnar_selection_state: None,
 2070            add_selections_state: None,
 2071            select_next_state: None,
 2072            select_prev_state: None,
 2073            selection_history: SelectionHistory::default(),
 2074            defer_selection_effects: false,
 2075            deferred_selection_effects_state: None,
 2076            autoclose_regions: Vec::new(),
 2077            snippet_stack: InvalidationStack::default(),
 2078            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2079            ime_transaction: None,
 2080            active_diagnostics: ActiveDiagnostic::None,
 2081            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2082            inline_diagnostics_update: Task::ready(()),
 2083            inline_diagnostics: Vec::new(),
 2084            soft_wrap_mode_override,
 2085            diagnostics_max_severity,
 2086            hard_wrap: None,
 2087            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2088            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2089            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2090            project,
 2091            blink_manager: blink_manager.clone(),
 2092            show_local_selections: true,
 2093            show_scrollbars: ScrollbarAxes {
 2094                horizontal: full_mode,
 2095                vertical: full_mode,
 2096            },
 2097            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2098            offset_content: !matches!(mode, EditorMode::SingleLine),
 2099            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2100            show_gutter: full_mode,
 2101            show_line_numbers: (!full_mode).then_some(false),
 2102            use_relative_line_numbers: None,
 2103            disable_expand_excerpt_buttons: !full_mode,
 2104            show_git_diff_gutter: None,
 2105            show_code_actions: None,
 2106            show_runnables: None,
 2107            show_breakpoints: None,
 2108            show_wrap_guides: None,
 2109            show_indent_guides,
 2110            highlight_order: 0,
 2111            highlighted_rows: HashMap::default(),
 2112            background_highlights: HashMap::default(),
 2113            gutter_highlights: HashMap::default(),
 2114            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2115            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2116            nav_history: None,
 2117            context_menu: RefCell::new(None),
 2118            context_menu_options: None,
 2119            mouse_context_menu: None,
 2120            completion_tasks: Vec::new(),
 2121            inline_blame_popover: None,
 2122            inline_blame_popover_show_task: None,
 2123            signature_help_state: SignatureHelpState::default(),
 2124            auto_signature_help: None,
 2125            find_all_references_task_sources: Vec::new(),
 2126            next_completion_id: 0,
 2127            next_inlay_id: 0,
 2128            code_action_providers,
 2129            available_code_actions: None,
 2130            code_actions_task: None,
 2131            quick_selection_highlight_task: None,
 2132            debounced_selection_highlight_task: None,
 2133            document_highlights_task: None,
 2134            linked_editing_range_task: None,
 2135            pending_rename: None,
 2136            searchable: !is_minimap,
 2137            cursor_shape: EditorSettings::get_global(cx)
 2138                .cursor_shape
 2139                .unwrap_or_default(),
 2140            current_line_highlight: None,
 2141            autoindent_mode: Some(AutoindentMode::EachLine),
 2142            collapse_matches: false,
 2143            workspace: None,
 2144            input_enabled: !is_minimap,
 2145            use_modal_editing: full_mode,
 2146            read_only: is_minimap,
 2147            use_autoclose: true,
 2148            use_auto_surround: true,
 2149            auto_replace_emoji_shortcode: false,
 2150            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2151            leader_id: None,
 2152            remote_id: None,
 2153            hover_state: HoverState::default(),
 2154            pending_mouse_down: None,
 2155            hovered_link_state: None,
 2156            edit_prediction_provider: None,
 2157            active_edit_prediction: None,
 2158            stale_edit_prediction_in_menu: None,
 2159            edit_prediction_preview: EditPredictionPreview::Inactive {
 2160                released_too_fast: false,
 2161            },
 2162            inline_diagnostics_enabled: full_mode,
 2163            diagnostics_enabled: full_mode,
 2164            word_completions_enabled: full_mode,
 2165            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2166            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2167            gutter_hovered: false,
 2168            pixel_position_of_newest_cursor: None,
 2169            last_bounds: None,
 2170            last_position_map: None,
 2171            expect_bounds_change: None,
 2172            gutter_dimensions: GutterDimensions::default(),
 2173            style: None,
 2174            show_cursor_names: false,
 2175            hovered_cursors: HashMap::default(),
 2176            next_editor_action_id: EditorActionId::default(),
 2177            editor_actions: Rc::default(),
 2178            edit_predictions_hidden_for_vim_mode: false,
 2179            show_edit_predictions_override: None,
 2180            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2181            edit_prediction_settings: EditPredictionSettings::Disabled,
 2182            edit_prediction_indent_conflict: false,
 2183            edit_prediction_requires_modifier_in_indent_conflict: true,
 2184            custom_context_menu: None,
 2185            show_git_blame_gutter: false,
 2186            show_git_blame_inline: false,
 2187            show_selection_menu: None,
 2188            show_git_blame_inline_delay_task: None,
 2189            git_blame_inline_enabled: full_mode
 2190                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2191            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2192            serialize_dirty_buffers: !is_minimap
 2193                && ProjectSettings::get_global(cx)
 2194                    .session
 2195                    .restore_unsaved_buffers,
 2196            blame: None,
 2197            blame_subscription: None,
 2198            tasks: BTreeMap::default(),
 2199
 2200            breakpoint_store,
 2201            gutter_breakpoint_indicator: (None, None),
 2202            hovered_diff_hunk_row: None,
 2203            _subscriptions: (!is_minimap)
 2204                .then(|| {
 2205                    vec![
 2206                        cx.observe(&buffer, Self::on_buffer_changed),
 2207                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2208                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2209                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2210                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2211                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2212                        cx.observe_window_activation(window, |editor, window, cx| {
 2213                            let active = window.is_window_active();
 2214                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2215                                if active {
 2216                                    blink_manager.enable(cx);
 2217                                } else {
 2218                                    blink_manager.disable(cx);
 2219                                }
 2220                            });
 2221                            if active {
 2222                                editor.show_mouse_cursor(cx);
 2223                            }
 2224                        }),
 2225                    ]
 2226                })
 2227                .unwrap_or_default(),
 2228            tasks_update_task: None,
 2229            pull_diagnostics_task: Task::ready(()),
 2230            colors: None,
 2231            next_color_inlay_id: 0,
 2232            linked_edit_ranges: Default::default(),
 2233            in_project_search: false,
 2234            previous_search_ranges: None,
 2235            breadcrumb_header: None,
 2236            focused_block: None,
 2237            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2238            addons: HashMap::default(),
 2239            registered_buffers: HashMap::default(),
 2240            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2241            selection_mark_mode: false,
 2242            toggle_fold_multiple_buffers: Task::ready(()),
 2243            serialize_selections: Task::ready(()),
 2244            serialize_folds: Task::ready(()),
 2245            text_style_refinement: None,
 2246            load_diff_task: load_uncommitted_diff,
 2247            temporary_diff_override: false,
 2248            mouse_cursor_hidden: false,
 2249            minimap: None,
 2250            hide_mouse_mode: EditorSettings::get_global(cx)
 2251                .hide_mouse
 2252                .unwrap_or_default(),
 2253            change_list: ChangeList::new(),
 2254            mode,
 2255            selection_drag_state: SelectionDragState::None,
 2256            folding_newlines: Task::ready(()),
 2257            lookup_key: None,
 2258        };
 2259
 2260        if is_minimap {
 2261            return editor;
 2262        }
 2263
 2264        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2265            editor
 2266                ._subscriptions
 2267                .push(cx.observe(breakpoints, |_, _, cx| {
 2268                    cx.notify();
 2269                }));
 2270        }
 2271        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2272        editor._subscriptions.extend(project_subscriptions);
 2273
 2274        editor._subscriptions.push(cx.subscribe_in(
 2275            &cx.entity(),
 2276            window,
 2277            |editor, _, e: &EditorEvent, window, cx| match e {
 2278                EditorEvent::ScrollPositionChanged { local, .. } => {
 2279                    if *local {
 2280                        let new_anchor = editor.scroll_manager.anchor();
 2281                        let snapshot = editor.snapshot(window, cx);
 2282                        editor.update_restoration_data(cx, move |data| {
 2283                            data.scroll_position = (
 2284                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2285                                new_anchor.offset,
 2286                            );
 2287                        });
 2288                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2289                        editor.inline_blame_popover.take();
 2290                    }
 2291                }
 2292                EditorEvent::Edited { .. } => {
 2293                    if !vim_enabled(cx) {
 2294                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2295                        let pop_state = editor
 2296                            .change_list
 2297                            .last()
 2298                            .map(|previous| {
 2299                                previous.len() == selections.len()
 2300                                    && previous.iter().enumerate().all(|(ix, p)| {
 2301                                        p.to_display_point(&map).row()
 2302                                            == selections[ix].head().row()
 2303                                    })
 2304                            })
 2305                            .unwrap_or(false);
 2306                        let new_positions = selections
 2307                            .into_iter()
 2308                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2309                            .collect();
 2310                        editor
 2311                            .change_list
 2312                            .push_to_change_list(pop_state, new_positions);
 2313                    }
 2314                }
 2315                _ => (),
 2316            },
 2317        ));
 2318
 2319        if let Some(dap_store) = editor
 2320            .project
 2321            .as_ref()
 2322            .map(|project| project.read(cx).dap_store())
 2323        {
 2324            let weak_editor = cx.weak_entity();
 2325
 2326            editor
 2327                ._subscriptions
 2328                .push(
 2329                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2330                        let session_entity = cx.entity();
 2331                        weak_editor
 2332                            .update(cx, |editor, cx| {
 2333                                editor._subscriptions.push(
 2334                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2335                                );
 2336                            })
 2337                            .ok();
 2338                    }),
 2339                );
 2340
 2341            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2342                editor
 2343                    ._subscriptions
 2344                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2345            }
 2346        }
 2347
 2348        // skip adding the initial selection to selection history
 2349        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2350        editor.end_selection(window, cx);
 2351        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2352
 2353        editor.scroll_manager.show_scrollbars(window, cx);
 2354        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2355
 2356        if full_mode {
 2357            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2358            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2359
 2360            if editor.git_blame_inline_enabled {
 2361                editor.start_git_blame_inline(false, window, cx);
 2362            }
 2363
 2364            editor.go_to_active_debug_line(window, cx);
 2365
 2366            if let Some(buffer) = buffer.read(cx).as_singleton()
 2367                && let Some(project) = editor.project()
 2368            {
 2369                let handle = project.update(cx, |project, cx| {
 2370                    project.register_buffer_with_language_servers(&buffer, cx)
 2371                });
 2372                editor
 2373                    .registered_buffers
 2374                    .insert(buffer.read(cx).remote_id(), handle);
 2375            }
 2376
 2377            editor.minimap =
 2378                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2379            editor.colors = Some(LspColorData::new(cx));
 2380            editor.update_lsp_data(false, None, window, cx);
 2381        }
 2382
 2383        if editor.mode.is_full() {
 2384            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2385        }
 2386
 2387        editor
 2388    }
 2389
 2390    pub fn deploy_mouse_context_menu(
 2391        &mut self,
 2392        position: gpui::Point<Pixels>,
 2393        context_menu: Entity<ContextMenu>,
 2394        window: &mut Window,
 2395        cx: &mut Context<Self>,
 2396    ) {
 2397        self.mouse_context_menu = Some(MouseContextMenu::new(
 2398            self,
 2399            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2400            context_menu,
 2401            window,
 2402            cx,
 2403        ));
 2404    }
 2405
 2406    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2407        self.mouse_context_menu
 2408            .as_ref()
 2409            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2410    }
 2411
 2412    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2413        if self
 2414            .selections
 2415            .pending_anchor()
 2416            .is_some_and(|pending_selection| {
 2417                let snapshot = self.buffer().read(cx).snapshot(cx);
 2418                pending_selection.range().includes(range, &snapshot)
 2419            })
 2420        {
 2421            return true;
 2422        }
 2423
 2424        self.selections
 2425            .disjoint_in_range::<usize>(range.clone(), cx)
 2426            .into_iter()
 2427            .any(|selection| {
 2428                // This is needed to cover a corner case, if we just check for an existing
 2429                // selection in the fold range, having a cursor at the start of the fold
 2430                // marks it as selected. Non-empty selections don't cause this.
 2431                let length = selection.end - selection.start;
 2432                length > 0
 2433            })
 2434    }
 2435
 2436    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2437        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2438    }
 2439
 2440    fn key_context_internal(
 2441        &self,
 2442        has_active_edit_prediction: bool,
 2443        window: &Window,
 2444        cx: &App,
 2445    ) -> KeyContext {
 2446        let mut key_context = KeyContext::new_with_defaults();
 2447        key_context.add("Editor");
 2448        let mode = match self.mode {
 2449            EditorMode::SingleLine => "single_line",
 2450            EditorMode::AutoHeight { .. } => "auto_height",
 2451            EditorMode::Minimap { .. } => "minimap",
 2452            EditorMode::Full { .. } => "full",
 2453        };
 2454
 2455        if EditorSettings::jupyter_enabled(cx) {
 2456            key_context.add("jupyter");
 2457        }
 2458
 2459        key_context.set("mode", mode);
 2460        if self.pending_rename.is_some() {
 2461            key_context.add("renaming");
 2462        }
 2463
 2464        match self.context_menu.borrow().as_ref() {
 2465            Some(CodeContextMenu::Completions(menu)) => {
 2466                if menu.visible() {
 2467                    key_context.add("menu");
 2468                    key_context.add("showing_completions");
 2469                }
 2470            }
 2471            Some(CodeContextMenu::CodeActions(menu)) => {
 2472                if menu.visible() {
 2473                    key_context.add("menu");
 2474                    key_context.add("showing_code_actions")
 2475                }
 2476            }
 2477            None => {}
 2478        }
 2479
 2480        if self.signature_help_state.has_multiple_signatures() {
 2481            key_context.add("showing_signature_help");
 2482        }
 2483
 2484        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2485        if !self.focus_handle(cx).contains_focused(window, cx)
 2486            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2487        {
 2488            for addon in self.addons.values() {
 2489                addon.extend_key_context(&mut key_context, cx)
 2490            }
 2491        }
 2492
 2493        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2494            if let Some(extension) = singleton_buffer
 2495                .read(cx)
 2496                .file()
 2497                .and_then(|file| file.path().extension())
 2498            {
 2499                key_context.set("extension", extension.to_string());
 2500            }
 2501        } else {
 2502            key_context.add("multibuffer");
 2503        }
 2504
 2505        if has_active_edit_prediction {
 2506            if self.edit_prediction_in_conflict() {
 2507                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2508            } else {
 2509                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2510                key_context.add("copilot_suggestion");
 2511            }
 2512        }
 2513
 2514        if self.selection_mark_mode {
 2515            key_context.add("selection_mode");
 2516        }
 2517
 2518        key_context
 2519    }
 2520
 2521    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2522        self.last_bounds.as_ref()
 2523    }
 2524
 2525    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2526        if self.mouse_cursor_hidden {
 2527            self.mouse_cursor_hidden = false;
 2528            cx.notify();
 2529        }
 2530    }
 2531
 2532    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2533        let hide_mouse_cursor = match origin {
 2534            HideMouseCursorOrigin::TypingAction => {
 2535                matches!(
 2536                    self.hide_mouse_mode,
 2537                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2538                )
 2539            }
 2540            HideMouseCursorOrigin::MovementAction => {
 2541                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2542            }
 2543        };
 2544        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2545            self.mouse_cursor_hidden = hide_mouse_cursor;
 2546            cx.notify();
 2547        }
 2548    }
 2549
 2550    pub fn edit_prediction_in_conflict(&self) -> bool {
 2551        if !self.show_edit_predictions_in_menu() {
 2552            return false;
 2553        }
 2554
 2555        let showing_completions = self
 2556            .context_menu
 2557            .borrow()
 2558            .as_ref()
 2559            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2560
 2561        showing_completions
 2562            || self.edit_prediction_requires_modifier()
 2563            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2564            // bindings to insert tab characters.
 2565            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2566    }
 2567
 2568    pub fn accept_edit_prediction_keybind(
 2569        &self,
 2570        accept_partial: bool,
 2571        window: &Window,
 2572        cx: &App,
 2573    ) -> AcceptEditPredictionBinding {
 2574        let key_context = self.key_context_internal(true, window, cx);
 2575        let in_conflict = self.edit_prediction_in_conflict();
 2576
 2577        let bindings = if accept_partial {
 2578            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2579        } else {
 2580            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2581        };
 2582
 2583        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2584        // just the first one.
 2585        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2586            !in_conflict
 2587                || binding
 2588                    .keystrokes()
 2589                    .first()
 2590                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2591        }))
 2592    }
 2593
 2594    pub fn new_file(
 2595        workspace: &mut Workspace,
 2596        _: &workspace::NewFile,
 2597        window: &mut Window,
 2598        cx: &mut Context<Workspace>,
 2599    ) {
 2600        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2601            "Failed to create buffer",
 2602            window,
 2603            cx,
 2604            |e, _, _| match e.error_code() {
 2605                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2606                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2607                e.error_tag("required").unwrap_or("the latest version")
 2608            )),
 2609                _ => None,
 2610            },
 2611        );
 2612    }
 2613
 2614    pub fn new_in_workspace(
 2615        workspace: &mut Workspace,
 2616        window: &mut Window,
 2617        cx: &mut Context<Workspace>,
 2618    ) -> Task<Result<Entity<Editor>>> {
 2619        let project = workspace.project().clone();
 2620        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2621
 2622        cx.spawn_in(window, async move |workspace, cx| {
 2623            let buffer = create.await?;
 2624            workspace.update_in(cx, |workspace, window, cx| {
 2625                let editor =
 2626                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2627                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2628                editor
 2629            })
 2630        })
 2631    }
 2632
 2633    fn new_file_vertical(
 2634        workspace: &mut Workspace,
 2635        _: &workspace::NewFileSplitVertical,
 2636        window: &mut Window,
 2637        cx: &mut Context<Workspace>,
 2638    ) {
 2639        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2640    }
 2641
 2642    fn new_file_horizontal(
 2643        workspace: &mut Workspace,
 2644        _: &workspace::NewFileSplitHorizontal,
 2645        window: &mut Window,
 2646        cx: &mut Context<Workspace>,
 2647    ) {
 2648        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2649    }
 2650
 2651    fn new_file_in_direction(
 2652        workspace: &mut Workspace,
 2653        direction: SplitDirection,
 2654        window: &mut Window,
 2655        cx: &mut Context<Workspace>,
 2656    ) {
 2657        let project = workspace.project().clone();
 2658        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2659
 2660        cx.spawn_in(window, async move |workspace, cx| {
 2661            let buffer = create.await?;
 2662            workspace.update_in(cx, move |workspace, window, cx| {
 2663                workspace.split_item(
 2664                    direction,
 2665                    Box::new(
 2666                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2667                    ),
 2668                    window,
 2669                    cx,
 2670                )
 2671            })?;
 2672            anyhow::Ok(())
 2673        })
 2674        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2675            match e.error_code() {
 2676                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2677                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2678                e.error_tag("required").unwrap_or("the latest version")
 2679            )),
 2680                _ => None,
 2681            }
 2682        });
 2683    }
 2684
 2685    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2686        self.leader_id
 2687    }
 2688
 2689    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2690        &self.buffer
 2691    }
 2692
 2693    pub fn project(&self) -> Option<&Entity<Project>> {
 2694        self.project.as_ref()
 2695    }
 2696
 2697    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2698        self.workspace.as_ref()?.0.upgrade()
 2699    }
 2700
 2701    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2702        self.buffer().read(cx).title(cx)
 2703    }
 2704
 2705    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2706        let git_blame_gutter_max_author_length = self
 2707            .render_git_blame_gutter(cx)
 2708            .then(|| {
 2709                if let Some(blame) = self.blame.as_ref() {
 2710                    let max_author_length =
 2711                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2712                    Some(max_author_length)
 2713                } else {
 2714                    None
 2715                }
 2716            })
 2717            .flatten();
 2718
 2719        EditorSnapshot {
 2720            mode: self.mode.clone(),
 2721            show_gutter: self.show_gutter,
 2722            show_line_numbers: self.show_line_numbers,
 2723            show_git_diff_gutter: self.show_git_diff_gutter,
 2724            show_code_actions: self.show_code_actions,
 2725            show_runnables: self.show_runnables,
 2726            show_breakpoints: self.show_breakpoints,
 2727            git_blame_gutter_max_author_length,
 2728            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2729            placeholder_display_snapshot: self
 2730                .placeholder_display_map
 2731                .as_ref()
 2732                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2733            scroll_anchor: self.scroll_manager.anchor(),
 2734            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2735            is_focused: self.focus_handle.is_focused(window),
 2736            current_line_highlight: self
 2737                .current_line_highlight
 2738                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2739            gutter_hovered: self.gutter_hovered,
 2740        }
 2741    }
 2742
 2743    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2744        self.buffer.read(cx).language_at(point, cx)
 2745    }
 2746
 2747    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2748        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2749    }
 2750
 2751    pub fn active_excerpt(
 2752        &self,
 2753        cx: &App,
 2754    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2755        self.buffer
 2756            .read(cx)
 2757            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2758    }
 2759
 2760    pub fn mode(&self) -> &EditorMode {
 2761        &self.mode
 2762    }
 2763
 2764    pub fn set_mode(&mut self, mode: EditorMode) {
 2765        self.mode = mode;
 2766    }
 2767
 2768    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2769        self.collaboration_hub.as_deref()
 2770    }
 2771
 2772    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2773        self.collaboration_hub = Some(hub);
 2774    }
 2775
 2776    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2777        self.in_project_search = in_project_search;
 2778    }
 2779
 2780    pub fn set_custom_context_menu(
 2781        &mut self,
 2782        f: impl 'static
 2783        + Fn(
 2784            &mut Self,
 2785            DisplayPoint,
 2786            &mut Window,
 2787            &mut Context<Self>,
 2788        ) -> Option<Entity<ui::ContextMenu>>,
 2789    ) {
 2790        self.custom_context_menu = Some(Box::new(f))
 2791    }
 2792
 2793    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2794        self.completion_provider = provider;
 2795    }
 2796
 2797    #[cfg(any(test, feature = "test-support"))]
 2798    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2799        self.completion_provider.clone()
 2800    }
 2801
 2802    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2803        self.semantics_provider.clone()
 2804    }
 2805
 2806    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2807        self.semantics_provider = provider;
 2808    }
 2809
 2810    pub fn set_edit_prediction_provider<T>(
 2811        &mut self,
 2812        provider: Option<Entity<T>>,
 2813        window: &mut Window,
 2814        cx: &mut Context<Self>,
 2815    ) where
 2816        T: EditPredictionProvider,
 2817    {
 2818        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2819            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2820                if this.focus_handle.is_focused(window) {
 2821                    this.update_visible_edit_prediction(window, cx);
 2822                }
 2823            }),
 2824            provider: Arc::new(provider),
 2825        });
 2826        self.update_edit_prediction_settings(cx);
 2827        self.refresh_edit_prediction(false, false, window, cx);
 2828    }
 2829
 2830    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2831        self.placeholder_display_map
 2832            .as_ref()
 2833            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2834    }
 2835
 2836    pub fn set_placeholder_text(
 2837        &mut self,
 2838        placeholder_text: &str,
 2839        window: &mut Window,
 2840        cx: &mut Context<Self>,
 2841    ) {
 2842        let multibuffer = cx
 2843            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2844
 2845        let style = window.text_style();
 2846
 2847        self.placeholder_display_map = Some(cx.new(|cx| {
 2848            DisplayMap::new(
 2849                multibuffer,
 2850                style.font(),
 2851                style.font_size.to_pixels(window.rem_size()),
 2852                None,
 2853                FILE_HEADER_HEIGHT,
 2854                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2855                Default::default(),
 2856                DiagnosticSeverity::Off,
 2857                cx,
 2858            )
 2859        }));
 2860        cx.notify();
 2861    }
 2862
 2863    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2864        self.cursor_shape = cursor_shape;
 2865
 2866        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2867        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2868
 2869        cx.notify();
 2870    }
 2871
 2872    pub fn set_current_line_highlight(
 2873        &mut self,
 2874        current_line_highlight: Option<CurrentLineHighlight>,
 2875    ) {
 2876        self.current_line_highlight = current_line_highlight;
 2877    }
 2878
 2879    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2880        self.collapse_matches = collapse_matches;
 2881    }
 2882
 2883    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2884        let buffers = self.buffer.read(cx).all_buffers();
 2885        let Some(project) = self.project.as_ref() else {
 2886            return;
 2887        };
 2888        project.update(cx, |project, cx| {
 2889            for buffer in buffers {
 2890                self.registered_buffers
 2891                    .entry(buffer.read(cx).remote_id())
 2892                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2893            }
 2894        })
 2895    }
 2896
 2897    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2898        if self.collapse_matches {
 2899            return range.start..range.start;
 2900        }
 2901        range.clone()
 2902    }
 2903
 2904    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2905        if self.display_map.read(cx).clip_at_line_ends != clip {
 2906            self.display_map
 2907                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2908        }
 2909    }
 2910
 2911    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2912        self.input_enabled = input_enabled;
 2913    }
 2914
 2915    pub fn set_edit_predictions_hidden_for_vim_mode(
 2916        &mut self,
 2917        hidden: bool,
 2918        window: &mut Window,
 2919        cx: &mut Context<Self>,
 2920    ) {
 2921        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2922            self.edit_predictions_hidden_for_vim_mode = hidden;
 2923            if hidden {
 2924                self.update_visible_edit_prediction(window, cx);
 2925            } else {
 2926                self.refresh_edit_prediction(true, false, window, cx);
 2927            }
 2928        }
 2929    }
 2930
 2931    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2932        self.menu_edit_predictions_policy = value;
 2933    }
 2934
 2935    pub fn set_autoindent(&mut self, autoindent: bool) {
 2936        if autoindent {
 2937            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2938        } else {
 2939            self.autoindent_mode = None;
 2940        }
 2941    }
 2942
 2943    pub fn read_only(&self, cx: &App) -> bool {
 2944        self.read_only || self.buffer.read(cx).read_only()
 2945    }
 2946
 2947    pub fn set_read_only(&mut self, read_only: bool) {
 2948        self.read_only = read_only;
 2949    }
 2950
 2951    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2952        self.use_autoclose = autoclose;
 2953    }
 2954
 2955    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2956        self.use_auto_surround = auto_surround;
 2957    }
 2958
 2959    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2960        self.auto_replace_emoji_shortcode = auto_replace;
 2961    }
 2962
 2963    pub fn toggle_edit_predictions(
 2964        &mut self,
 2965        _: &ToggleEditPrediction,
 2966        window: &mut Window,
 2967        cx: &mut Context<Self>,
 2968    ) {
 2969        if self.show_edit_predictions_override.is_some() {
 2970            self.set_show_edit_predictions(None, window, cx);
 2971        } else {
 2972            let show_edit_predictions = !self.edit_predictions_enabled();
 2973            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2974        }
 2975    }
 2976
 2977    pub fn set_show_edit_predictions(
 2978        &mut self,
 2979        show_edit_predictions: Option<bool>,
 2980        window: &mut Window,
 2981        cx: &mut Context<Self>,
 2982    ) {
 2983        self.show_edit_predictions_override = show_edit_predictions;
 2984        self.update_edit_prediction_settings(cx);
 2985
 2986        if let Some(false) = show_edit_predictions {
 2987            self.discard_edit_prediction(false, cx);
 2988        } else {
 2989            self.refresh_edit_prediction(false, true, window, cx);
 2990        }
 2991    }
 2992
 2993    fn edit_predictions_disabled_in_scope(
 2994        &self,
 2995        buffer: &Entity<Buffer>,
 2996        buffer_position: language::Anchor,
 2997        cx: &App,
 2998    ) -> bool {
 2999        let snapshot = buffer.read(cx).snapshot();
 3000        let settings = snapshot.settings_at(buffer_position, cx);
 3001
 3002        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3003            return false;
 3004        };
 3005
 3006        scope.override_name().is_some_and(|scope_name| {
 3007            settings
 3008                .edit_predictions_disabled_in
 3009                .iter()
 3010                .any(|s| s == scope_name)
 3011        })
 3012    }
 3013
 3014    pub fn set_use_modal_editing(&mut self, to: bool) {
 3015        self.use_modal_editing = to;
 3016    }
 3017
 3018    pub fn use_modal_editing(&self) -> bool {
 3019        self.use_modal_editing
 3020    }
 3021
 3022    fn selections_did_change(
 3023        &mut self,
 3024        local: bool,
 3025        old_cursor_position: &Anchor,
 3026        effects: SelectionEffects,
 3027        window: &mut Window,
 3028        cx: &mut Context<Self>,
 3029    ) {
 3030        window.invalidate_character_coordinates();
 3031
 3032        // Copy selections to primary selection buffer
 3033        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3034        if local {
 3035            let selections = self.selections.all::<usize>(cx);
 3036            let buffer_handle = self.buffer.read(cx).read(cx);
 3037
 3038            let mut text = String::new();
 3039            for (index, selection) in selections.iter().enumerate() {
 3040                let text_for_selection = buffer_handle
 3041                    .text_for_range(selection.start..selection.end)
 3042                    .collect::<String>();
 3043
 3044                text.push_str(&text_for_selection);
 3045                if index != selections.len() - 1 {
 3046                    text.push('\n');
 3047                }
 3048            }
 3049
 3050            if !text.is_empty() {
 3051                cx.write_to_primary(ClipboardItem::new_string(text));
 3052            }
 3053        }
 3054
 3055        let selection_anchors = self.selections.disjoint_anchors_arc();
 3056
 3057        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3058            self.buffer.update(cx, |buffer, cx| {
 3059                buffer.set_active_selections(
 3060                    &selection_anchors,
 3061                    self.selections.line_mode(),
 3062                    self.cursor_shape,
 3063                    cx,
 3064                )
 3065            });
 3066        }
 3067        let display_map = self
 3068            .display_map
 3069            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3070        let buffer = &display_map.buffer_snapshot;
 3071        if self.selections.count() == 1 {
 3072            self.add_selections_state = None;
 3073        }
 3074        self.select_next_state = None;
 3075        self.select_prev_state = None;
 3076        self.select_syntax_node_history.try_clear();
 3077        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3078        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3079        self.take_rename(false, window, cx);
 3080
 3081        let newest_selection = self.selections.newest_anchor();
 3082        let new_cursor_position = newest_selection.head();
 3083        let selection_start = newest_selection.start;
 3084
 3085        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3086            self.push_to_nav_history(
 3087                *old_cursor_position,
 3088                Some(new_cursor_position.to_point(buffer)),
 3089                false,
 3090                effects.nav_history == Some(true),
 3091                cx,
 3092            );
 3093        }
 3094
 3095        if local {
 3096            if let Some(buffer_id) = new_cursor_position.buffer_id
 3097                && !self.registered_buffers.contains_key(&buffer_id)
 3098                && let Some(project) = self.project.as_ref()
 3099            {
 3100                project.update(cx, |project, cx| {
 3101                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3102                        return;
 3103                    };
 3104                    self.registered_buffers.insert(
 3105                        buffer_id,
 3106                        project.register_buffer_with_language_servers(&buffer, cx),
 3107                    );
 3108                })
 3109            }
 3110
 3111            let mut context_menu = self.context_menu.borrow_mut();
 3112            let completion_menu = match context_menu.as_ref() {
 3113                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3114                Some(CodeContextMenu::CodeActions(_)) => {
 3115                    *context_menu = None;
 3116                    None
 3117                }
 3118                None => None,
 3119            };
 3120            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3121            drop(context_menu);
 3122
 3123            if effects.completions
 3124                && let Some(completion_position) = completion_position
 3125            {
 3126                let start_offset = selection_start.to_offset(buffer);
 3127                let position_matches = start_offset == completion_position.to_offset(buffer);
 3128                let continue_showing = if position_matches {
 3129                    if self.snippet_stack.is_empty() {
 3130                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3131                            == Some(CharKind::Word)
 3132                    } else {
 3133                        // Snippet choices can be shown even when the cursor is in whitespace.
 3134                        // Dismissing the menu with actions like backspace is handled by
 3135                        // invalidation regions.
 3136                        true
 3137                    }
 3138                } else {
 3139                    false
 3140                };
 3141
 3142                if continue_showing {
 3143                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3144                } else {
 3145                    self.hide_context_menu(window, cx);
 3146                }
 3147            }
 3148
 3149            hide_hover(self, cx);
 3150
 3151            if old_cursor_position.to_display_point(&display_map).row()
 3152                != new_cursor_position.to_display_point(&display_map).row()
 3153            {
 3154                self.available_code_actions.take();
 3155            }
 3156            self.refresh_code_actions(window, cx);
 3157            self.refresh_document_highlights(cx);
 3158            self.refresh_selected_text_highlights(false, window, cx);
 3159            refresh_matching_bracket_highlights(self, window, cx);
 3160            self.update_visible_edit_prediction(window, cx);
 3161            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3162            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3163            self.inline_blame_popover.take();
 3164            if self.git_blame_inline_enabled {
 3165                self.start_inline_blame_timer(window, cx);
 3166            }
 3167        }
 3168
 3169        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3170        cx.emit(EditorEvent::SelectionsChanged { local });
 3171
 3172        let selections = &self.selections.disjoint_anchors_arc();
 3173        if selections.len() == 1 {
 3174            cx.emit(SearchEvent::ActiveMatchChanged)
 3175        }
 3176        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3177            let inmemory_selections = selections
 3178                .iter()
 3179                .map(|s| {
 3180                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3181                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3182                })
 3183                .collect();
 3184            self.update_restoration_data(cx, |data| {
 3185                data.selections = inmemory_selections;
 3186            });
 3187
 3188            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3189                && let Some(workspace_id) =
 3190                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3191            {
 3192                let snapshot = self.buffer().read(cx).snapshot(cx);
 3193                let selections = selections.clone();
 3194                let background_executor = cx.background_executor().clone();
 3195                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3196                self.serialize_selections = cx.background_spawn(async move {
 3197                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3198                            let db_selections = selections
 3199                                .iter()
 3200                                .map(|selection| {
 3201                                    (
 3202                                        selection.start.to_offset(&snapshot),
 3203                                        selection.end.to_offset(&snapshot),
 3204                                    )
 3205                                })
 3206                                .collect();
 3207
 3208                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3209                                .await
 3210                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3211                                .log_err();
 3212                        });
 3213            }
 3214        }
 3215
 3216        cx.notify();
 3217    }
 3218
 3219    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3220        use text::ToOffset as _;
 3221        use text::ToPoint as _;
 3222
 3223        if self.mode.is_minimap()
 3224            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3225        {
 3226            return;
 3227        }
 3228
 3229        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3230            return;
 3231        };
 3232
 3233        let snapshot = singleton.read(cx).snapshot();
 3234        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3235            let display_snapshot = display_map.snapshot(cx);
 3236
 3237            display_snapshot
 3238                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3239                .map(|fold| {
 3240                    fold.range.start.text_anchor.to_point(&snapshot)
 3241                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3242                })
 3243                .collect()
 3244        });
 3245        self.update_restoration_data(cx, |data| {
 3246            data.folds = inmemory_folds;
 3247        });
 3248
 3249        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3250            return;
 3251        };
 3252        let background_executor = cx.background_executor().clone();
 3253        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3254        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3255            display_map
 3256                .snapshot(cx)
 3257                .folds_in_range(0..snapshot.len())
 3258                .map(|fold| {
 3259                    (
 3260                        fold.range.start.text_anchor.to_offset(&snapshot),
 3261                        fold.range.end.text_anchor.to_offset(&snapshot),
 3262                    )
 3263                })
 3264                .collect()
 3265        });
 3266        self.serialize_folds = cx.background_spawn(async move {
 3267            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3268            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3269                .await
 3270                .with_context(|| {
 3271                    format!(
 3272                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3273                    )
 3274                })
 3275                .log_err();
 3276        });
 3277    }
 3278
 3279    pub fn sync_selections(
 3280        &mut self,
 3281        other: Entity<Editor>,
 3282        cx: &mut Context<Self>,
 3283    ) -> gpui::Subscription {
 3284        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3285        self.selections.change_with(cx, |selections| {
 3286            selections.select_anchors(other_selections);
 3287        });
 3288
 3289        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3290            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3291                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3292                if other_selections.is_empty() {
 3293                    return;
 3294                }
 3295                this.selections.change_with(cx, |selections| {
 3296                    selections.select_anchors(other_selections);
 3297                });
 3298            }
 3299        });
 3300
 3301        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3302            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3303                let these_selections = this.selections.disjoint_anchors().to_vec();
 3304                if these_selections.is_empty() {
 3305                    return;
 3306                }
 3307                other.update(cx, |other_editor, cx| {
 3308                    other_editor.selections.change_with(cx, |selections| {
 3309                        selections.select_anchors(these_selections);
 3310                    })
 3311                });
 3312            }
 3313        });
 3314
 3315        Subscription::join(other_subscription, this_subscription)
 3316    }
 3317
 3318    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3319    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3320    /// effects of selection change occur at the end of the transaction.
 3321    pub fn change_selections<R>(
 3322        &mut self,
 3323        effects: SelectionEffects,
 3324        window: &mut Window,
 3325        cx: &mut Context<Self>,
 3326        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3327    ) -> R {
 3328        if let Some(state) = &mut self.deferred_selection_effects_state {
 3329            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3330            state.effects.completions = effects.completions;
 3331            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3332            let (changed, result) = self.selections.change_with(cx, change);
 3333            state.changed |= changed;
 3334            return result;
 3335        }
 3336        let mut state = DeferredSelectionEffectsState {
 3337            changed: false,
 3338            effects,
 3339            old_cursor_position: self.selections.newest_anchor().head(),
 3340            history_entry: SelectionHistoryEntry {
 3341                selections: self.selections.disjoint_anchors_arc(),
 3342                select_next_state: self.select_next_state.clone(),
 3343                select_prev_state: self.select_prev_state.clone(),
 3344                add_selections_state: self.add_selections_state.clone(),
 3345            },
 3346        };
 3347        let (changed, result) = self.selections.change_with(cx, change);
 3348        state.changed = state.changed || changed;
 3349        if self.defer_selection_effects {
 3350            self.deferred_selection_effects_state = Some(state);
 3351        } else {
 3352            self.apply_selection_effects(state, window, cx);
 3353        }
 3354        result
 3355    }
 3356
 3357    /// Defers the effects of selection change, so that the effects of multiple calls to
 3358    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3359    /// to selection history and the state of popovers based on selection position aren't
 3360    /// erroneously updated.
 3361    pub fn with_selection_effects_deferred<R>(
 3362        &mut self,
 3363        window: &mut Window,
 3364        cx: &mut Context<Self>,
 3365        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3366    ) -> R {
 3367        let already_deferred = self.defer_selection_effects;
 3368        self.defer_selection_effects = true;
 3369        let result = update(self, window, cx);
 3370        if !already_deferred {
 3371            self.defer_selection_effects = false;
 3372            if let Some(state) = self.deferred_selection_effects_state.take() {
 3373                self.apply_selection_effects(state, window, cx);
 3374            }
 3375        }
 3376        result
 3377    }
 3378
 3379    fn apply_selection_effects(
 3380        &mut self,
 3381        state: DeferredSelectionEffectsState,
 3382        window: &mut Window,
 3383        cx: &mut Context<Self>,
 3384    ) {
 3385        if state.changed {
 3386            self.selection_history.push(state.history_entry);
 3387
 3388            if let Some(autoscroll) = state.effects.scroll {
 3389                self.request_autoscroll(autoscroll, cx);
 3390            }
 3391
 3392            let old_cursor_position = &state.old_cursor_position;
 3393
 3394            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3395
 3396            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3397                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3398            }
 3399        }
 3400    }
 3401
 3402    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3403    where
 3404        I: IntoIterator<Item = (Range<S>, T)>,
 3405        S: ToOffset,
 3406        T: Into<Arc<str>>,
 3407    {
 3408        if self.read_only(cx) {
 3409            return;
 3410        }
 3411
 3412        self.buffer
 3413            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3414    }
 3415
 3416    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3417    where
 3418        I: IntoIterator<Item = (Range<S>, T)>,
 3419        S: ToOffset,
 3420        T: Into<Arc<str>>,
 3421    {
 3422        if self.read_only(cx) {
 3423            return;
 3424        }
 3425
 3426        self.buffer.update(cx, |buffer, cx| {
 3427            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3428        });
 3429    }
 3430
 3431    pub fn edit_with_block_indent<I, S, T>(
 3432        &mut self,
 3433        edits: I,
 3434        original_indent_columns: Vec<Option<u32>>,
 3435        cx: &mut Context<Self>,
 3436    ) where
 3437        I: IntoIterator<Item = (Range<S>, T)>,
 3438        S: ToOffset,
 3439        T: Into<Arc<str>>,
 3440    {
 3441        if self.read_only(cx) {
 3442            return;
 3443        }
 3444
 3445        self.buffer.update(cx, |buffer, cx| {
 3446            buffer.edit(
 3447                edits,
 3448                Some(AutoindentMode::Block {
 3449                    original_indent_columns,
 3450                }),
 3451                cx,
 3452            )
 3453        });
 3454    }
 3455
 3456    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3457        self.hide_context_menu(window, cx);
 3458
 3459        match phase {
 3460            SelectPhase::Begin {
 3461                position,
 3462                add,
 3463                click_count,
 3464            } => self.begin_selection(position, add, click_count, window, cx),
 3465            SelectPhase::BeginColumnar {
 3466                position,
 3467                goal_column,
 3468                reset,
 3469                mode,
 3470            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3471            SelectPhase::Extend {
 3472                position,
 3473                click_count,
 3474            } => self.extend_selection(position, click_count, window, cx),
 3475            SelectPhase::Update {
 3476                position,
 3477                goal_column,
 3478                scroll_delta,
 3479            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3480            SelectPhase::End => self.end_selection(window, cx),
 3481        }
 3482    }
 3483
 3484    fn extend_selection(
 3485        &mut self,
 3486        position: DisplayPoint,
 3487        click_count: usize,
 3488        window: &mut Window,
 3489        cx: &mut Context<Self>,
 3490    ) {
 3491        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3492        let tail = self.selections.newest::<usize>(cx).tail();
 3493        self.begin_selection(position, false, click_count, window, cx);
 3494
 3495        let position = position.to_offset(&display_map, Bias::Left);
 3496        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3497
 3498        let mut pending_selection = self
 3499            .selections
 3500            .pending_anchor()
 3501            .cloned()
 3502            .expect("extend_selection not called with pending selection");
 3503        if position >= tail {
 3504            pending_selection.start = tail_anchor;
 3505        } else {
 3506            pending_selection.end = tail_anchor;
 3507            pending_selection.reversed = true;
 3508        }
 3509
 3510        let mut pending_mode = self.selections.pending_mode().unwrap();
 3511        match &mut pending_mode {
 3512            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3513            _ => {}
 3514        }
 3515
 3516        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3517            SelectionEffects::scroll(Autoscroll::fit())
 3518        } else {
 3519            SelectionEffects::no_scroll()
 3520        };
 3521
 3522        self.change_selections(effects, window, cx, |s| {
 3523            s.set_pending(pending_selection.clone(), pending_mode)
 3524        });
 3525    }
 3526
 3527    fn begin_selection(
 3528        &mut self,
 3529        position: DisplayPoint,
 3530        add: bool,
 3531        click_count: usize,
 3532        window: &mut Window,
 3533        cx: &mut Context<Self>,
 3534    ) {
 3535        if !self.focus_handle.is_focused(window) {
 3536            self.last_focused_descendant = None;
 3537            window.focus(&self.focus_handle);
 3538        }
 3539
 3540        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3541        let buffer = &display_map.buffer_snapshot;
 3542        let position = display_map.clip_point(position, Bias::Left);
 3543
 3544        let start;
 3545        let end;
 3546        let mode;
 3547        let mut auto_scroll;
 3548        match click_count {
 3549            1 => {
 3550                start = buffer.anchor_before(position.to_point(&display_map));
 3551                end = start;
 3552                mode = SelectMode::Character;
 3553                auto_scroll = true;
 3554            }
 3555            2 => {
 3556                let position = display_map
 3557                    .clip_point(position, Bias::Left)
 3558                    .to_offset(&display_map, Bias::Left);
 3559                let (range, _) = buffer.surrounding_word(position, None);
 3560                start = buffer.anchor_before(range.start);
 3561                end = buffer.anchor_before(range.end);
 3562                mode = SelectMode::Word(start..end);
 3563                auto_scroll = true;
 3564            }
 3565            3 => {
 3566                let position = display_map
 3567                    .clip_point(position, Bias::Left)
 3568                    .to_point(&display_map);
 3569                let line_start = display_map.prev_line_boundary(position).0;
 3570                let next_line_start = buffer.clip_point(
 3571                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3572                    Bias::Left,
 3573                );
 3574                start = buffer.anchor_before(line_start);
 3575                end = buffer.anchor_before(next_line_start);
 3576                mode = SelectMode::Line(start..end);
 3577                auto_scroll = true;
 3578            }
 3579            _ => {
 3580                start = buffer.anchor_before(0);
 3581                end = buffer.anchor_before(buffer.len());
 3582                mode = SelectMode::All;
 3583                auto_scroll = false;
 3584            }
 3585        }
 3586        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3587
 3588        let point_to_delete: Option<usize> = {
 3589            let selected_points: Vec<Selection<Point>> =
 3590                self.selections.disjoint_in_range(start..end, cx);
 3591
 3592            if !add || click_count > 1 {
 3593                None
 3594            } else if !selected_points.is_empty() {
 3595                Some(selected_points[0].id)
 3596            } else {
 3597                let clicked_point_already_selected =
 3598                    self.selections.disjoint_anchors().iter().find(|selection| {
 3599                        selection.start.to_point(buffer) == start.to_point(buffer)
 3600                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3601                    });
 3602
 3603                clicked_point_already_selected.map(|selection| selection.id)
 3604            }
 3605        };
 3606
 3607        let selections_count = self.selections.count();
 3608        let effects = if auto_scroll {
 3609            SelectionEffects::default()
 3610        } else {
 3611            SelectionEffects::no_scroll()
 3612        };
 3613
 3614        self.change_selections(effects, window, cx, |s| {
 3615            if let Some(point_to_delete) = point_to_delete {
 3616                s.delete(point_to_delete);
 3617
 3618                if selections_count == 1 {
 3619                    s.set_pending_anchor_range(start..end, mode);
 3620                }
 3621            } else {
 3622                if !add {
 3623                    s.clear_disjoint();
 3624                }
 3625
 3626                s.set_pending_anchor_range(start..end, mode);
 3627            }
 3628        });
 3629    }
 3630
 3631    fn begin_columnar_selection(
 3632        &mut self,
 3633        position: DisplayPoint,
 3634        goal_column: u32,
 3635        reset: bool,
 3636        mode: ColumnarMode,
 3637        window: &mut Window,
 3638        cx: &mut Context<Self>,
 3639    ) {
 3640        if !self.focus_handle.is_focused(window) {
 3641            self.last_focused_descendant = None;
 3642            window.focus(&self.focus_handle);
 3643        }
 3644
 3645        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3646
 3647        if reset {
 3648            let pointer_position = display_map
 3649                .buffer_snapshot
 3650                .anchor_before(position.to_point(&display_map));
 3651
 3652            self.change_selections(
 3653                SelectionEffects::scroll(Autoscroll::newest()),
 3654                window,
 3655                cx,
 3656                |s| {
 3657                    s.clear_disjoint();
 3658                    s.set_pending_anchor_range(
 3659                        pointer_position..pointer_position,
 3660                        SelectMode::Character,
 3661                    );
 3662                },
 3663            );
 3664        };
 3665
 3666        let tail = self.selections.newest::<Point>(cx).tail();
 3667        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3668        self.columnar_selection_state = match mode {
 3669            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3670                selection_tail: selection_anchor,
 3671                display_point: if reset {
 3672                    if position.column() != goal_column {
 3673                        Some(DisplayPoint::new(position.row(), goal_column))
 3674                    } else {
 3675                        None
 3676                    }
 3677                } else {
 3678                    None
 3679                },
 3680            }),
 3681            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3682                selection_tail: selection_anchor,
 3683            }),
 3684        };
 3685
 3686        if !reset {
 3687            self.select_columns(position, goal_column, &display_map, window, cx);
 3688        }
 3689    }
 3690
 3691    fn update_selection(
 3692        &mut self,
 3693        position: DisplayPoint,
 3694        goal_column: u32,
 3695        scroll_delta: gpui::Point<f32>,
 3696        window: &mut Window,
 3697        cx: &mut Context<Self>,
 3698    ) {
 3699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3700
 3701        if self.columnar_selection_state.is_some() {
 3702            self.select_columns(position, goal_column, &display_map, window, cx);
 3703        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3704            let buffer = &display_map.buffer_snapshot;
 3705            let head;
 3706            let tail;
 3707            let mode = self.selections.pending_mode().unwrap();
 3708            match &mode {
 3709                SelectMode::Character => {
 3710                    head = position.to_point(&display_map);
 3711                    tail = pending.tail().to_point(buffer);
 3712                }
 3713                SelectMode::Word(original_range) => {
 3714                    let offset = display_map
 3715                        .clip_point(position, Bias::Left)
 3716                        .to_offset(&display_map, Bias::Left);
 3717                    let original_range = original_range.to_offset(buffer);
 3718
 3719                    let head_offset = if buffer.is_inside_word(offset, None)
 3720                        || original_range.contains(&offset)
 3721                    {
 3722                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3723                        if word_range.start < original_range.start {
 3724                            word_range.start
 3725                        } else {
 3726                            word_range.end
 3727                        }
 3728                    } else {
 3729                        offset
 3730                    };
 3731
 3732                    head = head_offset.to_point(buffer);
 3733                    if head_offset <= original_range.start {
 3734                        tail = original_range.end.to_point(buffer);
 3735                    } else {
 3736                        tail = original_range.start.to_point(buffer);
 3737                    }
 3738                }
 3739                SelectMode::Line(original_range) => {
 3740                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3741
 3742                    let position = display_map
 3743                        .clip_point(position, Bias::Left)
 3744                        .to_point(&display_map);
 3745                    let line_start = display_map.prev_line_boundary(position).0;
 3746                    let next_line_start = buffer.clip_point(
 3747                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3748                        Bias::Left,
 3749                    );
 3750
 3751                    if line_start < original_range.start {
 3752                        head = line_start
 3753                    } else {
 3754                        head = next_line_start
 3755                    }
 3756
 3757                    if head <= original_range.start {
 3758                        tail = original_range.end;
 3759                    } else {
 3760                        tail = original_range.start;
 3761                    }
 3762                }
 3763                SelectMode::All => {
 3764                    return;
 3765                }
 3766            };
 3767
 3768            if head < tail {
 3769                pending.start = buffer.anchor_before(head);
 3770                pending.end = buffer.anchor_before(tail);
 3771                pending.reversed = true;
 3772            } else {
 3773                pending.start = buffer.anchor_before(tail);
 3774                pending.end = buffer.anchor_before(head);
 3775                pending.reversed = false;
 3776            }
 3777
 3778            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3779                s.set_pending(pending.clone(), mode);
 3780            });
 3781        } else {
 3782            log::error!("update_selection dispatched with no pending selection");
 3783            return;
 3784        }
 3785
 3786        self.apply_scroll_delta(scroll_delta, window, cx);
 3787        cx.notify();
 3788    }
 3789
 3790    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3791        self.columnar_selection_state.take();
 3792        if self.selections.pending_anchor().is_some() {
 3793            let selections = self.selections.all::<usize>(cx);
 3794            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3795                s.select(selections);
 3796                s.clear_pending();
 3797            });
 3798        }
 3799    }
 3800
 3801    fn select_columns(
 3802        &mut self,
 3803        head: DisplayPoint,
 3804        goal_column: u32,
 3805        display_map: &DisplaySnapshot,
 3806        window: &mut Window,
 3807        cx: &mut Context<Self>,
 3808    ) {
 3809        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3810            return;
 3811        };
 3812
 3813        let tail = match columnar_state {
 3814            ColumnarSelectionState::FromMouse {
 3815                selection_tail,
 3816                display_point,
 3817            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3818            ColumnarSelectionState::FromSelection { selection_tail } => {
 3819                selection_tail.to_display_point(display_map)
 3820            }
 3821        };
 3822
 3823        let start_row = cmp::min(tail.row(), head.row());
 3824        let end_row = cmp::max(tail.row(), head.row());
 3825        let start_column = cmp::min(tail.column(), goal_column);
 3826        let end_column = cmp::max(tail.column(), goal_column);
 3827        let reversed = start_column < tail.column();
 3828
 3829        let selection_ranges = (start_row.0..=end_row.0)
 3830            .map(DisplayRow)
 3831            .filter_map(|row| {
 3832                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3833                    || start_column <= display_map.line_len(row))
 3834                    && !display_map.is_block_line(row)
 3835                {
 3836                    let start = display_map
 3837                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3838                        .to_point(display_map);
 3839                    let end = display_map
 3840                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3841                        .to_point(display_map);
 3842                    if reversed {
 3843                        Some(end..start)
 3844                    } else {
 3845                        Some(start..end)
 3846                    }
 3847                } else {
 3848                    None
 3849                }
 3850            })
 3851            .collect::<Vec<_>>();
 3852
 3853        let ranges = match columnar_state {
 3854            ColumnarSelectionState::FromMouse { .. } => {
 3855                let mut non_empty_ranges = selection_ranges
 3856                    .iter()
 3857                    .filter(|selection_range| selection_range.start != selection_range.end)
 3858                    .peekable();
 3859                if non_empty_ranges.peek().is_some() {
 3860                    non_empty_ranges.cloned().collect()
 3861                } else {
 3862                    selection_ranges
 3863                }
 3864            }
 3865            _ => selection_ranges,
 3866        };
 3867
 3868        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3869            s.select_ranges(ranges);
 3870        });
 3871        cx.notify();
 3872    }
 3873
 3874    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3875        self.selections
 3876            .all_adjusted(cx)
 3877            .iter()
 3878            .any(|selection| !selection.is_empty())
 3879    }
 3880
 3881    pub fn has_pending_nonempty_selection(&self) -> bool {
 3882        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3883            Some(Selection { start, end, .. }) => start != end,
 3884            None => false,
 3885        };
 3886
 3887        pending_nonempty_selection
 3888            || (self.columnar_selection_state.is_some()
 3889                && self.selections.disjoint_anchors().len() > 1)
 3890    }
 3891
 3892    pub fn has_pending_selection(&self) -> bool {
 3893        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3894    }
 3895
 3896    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3897        self.selection_mark_mode = false;
 3898        self.selection_drag_state = SelectionDragState::None;
 3899
 3900        if self.clear_expanded_diff_hunks(cx) {
 3901            cx.notify();
 3902            return;
 3903        }
 3904        if self.dismiss_menus_and_popups(true, window, cx) {
 3905            return;
 3906        }
 3907
 3908        if self.mode.is_full()
 3909            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3910        {
 3911            return;
 3912        }
 3913
 3914        cx.propagate();
 3915    }
 3916
 3917    pub fn dismiss_menus_and_popups(
 3918        &mut self,
 3919        is_user_requested: bool,
 3920        window: &mut Window,
 3921        cx: &mut Context<Self>,
 3922    ) -> bool {
 3923        if self.take_rename(false, window, cx).is_some() {
 3924            return true;
 3925        }
 3926
 3927        if hide_hover(self, cx) {
 3928            return true;
 3929        }
 3930
 3931        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3932            return true;
 3933        }
 3934
 3935        if self.hide_context_menu(window, cx).is_some() {
 3936            return true;
 3937        }
 3938
 3939        if self.mouse_context_menu.take().is_some() {
 3940            return true;
 3941        }
 3942
 3943        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3944            return true;
 3945        }
 3946
 3947        if self.snippet_stack.pop().is_some() {
 3948            return true;
 3949        }
 3950
 3951        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3952            self.dismiss_diagnostics(cx);
 3953            return true;
 3954        }
 3955
 3956        false
 3957    }
 3958
 3959    fn linked_editing_ranges_for(
 3960        &self,
 3961        selection: Range<text::Anchor>,
 3962        cx: &App,
 3963    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3964        if self.linked_edit_ranges.is_empty() {
 3965            return None;
 3966        }
 3967        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3968            selection.end.buffer_id.and_then(|end_buffer_id| {
 3969                if selection.start.buffer_id != Some(end_buffer_id) {
 3970                    return None;
 3971                }
 3972                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3973                let snapshot = buffer.read(cx).snapshot();
 3974                self.linked_edit_ranges
 3975                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3976                    .map(|ranges| (ranges, snapshot, buffer))
 3977            })?;
 3978        use text::ToOffset as TO;
 3979        // find offset from the start of current range to current cursor position
 3980        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3981
 3982        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3983        let start_difference = start_offset - start_byte_offset;
 3984        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3985        let end_difference = end_offset - start_byte_offset;
 3986        // Current range has associated linked ranges.
 3987        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3988        for range in linked_ranges.iter() {
 3989            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3990            let end_offset = start_offset + end_difference;
 3991            let start_offset = start_offset + start_difference;
 3992            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3993                continue;
 3994            }
 3995            if self.selections.disjoint_anchor_ranges().any(|s| {
 3996                if s.start.buffer_id != selection.start.buffer_id
 3997                    || s.end.buffer_id != selection.end.buffer_id
 3998                {
 3999                    return false;
 4000                }
 4001                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4002                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4003            }) {
 4004                continue;
 4005            }
 4006            let start = buffer_snapshot.anchor_after(start_offset);
 4007            let end = buffer_snapshot.anchor_after(end_offset);
 4008            linked_edits
 4009                .entry(buffer.clone())
 4010                .or_default()
 4011                .push(start..end);
 4012        }
 4013        Some(linked_edits)
 4014    }
 4015
 4016    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4017        let text: Arc<str> = text.into();
 4018
 4019        if self.read_only(cx) {
 4020            return;
 4021        }
 4022
 4023        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4024
 4025        let selections = self.selections.all_adjusted(cx);
 4026        let mut bracket_inserted = false;
 4027        let mut edits = Vec::new();
 4028        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4029        let mut new_selections = Vec::with_capacity(selections.len());
 4030        let mut new_autoclose_regions = Vec::new();
 4031        let snapshot = self.buffer.read(cx).read(cx);
 4032        let mut clear_linked_edit_ranges = false;
 4033
 4034        for (selection, autoclose_region) in
 4035            self.selections_with_autoclose_regions(selections, &snapshot)
 4036        {
 4037            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4038                // Determine if the inserted text matches the opening or closing
 4039                // bracket of any of this language's bracket pairs.
 4040                let mut bracket_pair = None;
 4041                let mut is_bracket_pair_start = false;
 4042                let mut is_bracket_pair_end = false;
 4043                if !text.is_empty() {
 4044                    let mut bracket_pair_matching_end = None;
 4045                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4046                    //  and they are removing the character that triggered IME popup.
 4047                    for (pair, enabled) in scope.brackets() {
 4048                        if !pair.close && !pair.surround {
 4049                            continue;
 4050                        }
 4051
 4052                        if enabled && pair.start.ends_with(text.as_ref()) {
 4053                            let prefix_len = pair.start.len() - text.len();
 4054                            let preceding_text_matches_prefix = prefix_len == 0
 4055                                || (selection.start.column >= (prefix_len as u32)
 4056                                    && snapshot.contains_str_at(
 4057                                        Point::new(
 4058                                            selection.start.row,
 4059                                            selection.start.column - (prefix_len as u32),
 4060                                        ),
 4061                                        &pair.start[..prefix_len],
 4062                                    ));
 4063                            if preceding_text_matches_prefix {
 4064                                bracket_pair = Some(pair.clone());
 4065                                is_bracket_pair_start = true;
 4066                                break;
 4067                            }
 4068                        }
 4069                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4070                        {
 4071                            // take first bracket pair matching end, but don't break in case a later bracket
 4072                            // pair matches start
 4073                            bracket_pair_matching_end = Some(pair.clone());
 4074                        }
 4075                    }
 4076                    if let Some(end) = bracket_pair_matching_end
 4077                        && bracket_pair.is_none()
 4078                    {
 4079                        bracket_pair = Some(end);
 4080                        is_bracket_pair_end = true;
 4081                    }
 4082                }
 4083
 4084                if let Some(bracket_pair) = bracket_pair {
 4085                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4086                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4087                    let auto_surround =
 4088                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4089                    if selection.is_empty() {
 4090                        if is_bracket_pair_start {
 4091                            // If the inserted text is a suffix of an opening bracket and the
 4092                            // selection is preceded by the rest of the opening bracket, then
 4093                            // insert the closing bracket.
 4094                            let following_text_allows_autoclose = snapshot
 4095                                .chars_at(selection.start)
 4096                                .next()
 4097                                .is_none_or(|c| scope.should_autoclose_before(c));
 4098
 4099                            let preceding_text_allows_autoclose = selection.start.column == 0
 4100                                || snapshot
 4101                                    .reversed_chars_at(selection.start)
 4102                                    .next()
 4103                                    .is_none_or(|c| {
 4104                                        bracket_pair.start != bracket_pair.end
 4105                                            || !snapshot
 4106                                                .char_classifier_at(selection.start)
 4107                                                .is_word(c)
 4108                                    });
 4109
 4110                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4111                                && bracket_pair.start.len() == 1
 4112                            {
 4113                                let target = bracket_pair.start.chars().next().unwrap();
 4114                                let current_line_count = snapshot
 4115                                    .reversed_chars_at(selection.start)
 4116                                    .take_while(|&c| c != '\n')
 4117                                    .filter(|&c| c == target)
 4118                                    .count();
 4119                                current_line_count % 2 == 1
 4120                            } else {
 4121                                false
 4122                            };
 4123
 4124                            if autoclose
 4125                                && bracket_pair.close
 4126                                && following_text_allows_autoclose
 4127                                && preceding_text_allows_autoclose
 4128                                && !is_closing_quote
 4129                            {
 4130                                let anchor = snapshot.anchor_before(selection.end);
 4131                                new_selections.push((selection.map(|_| anchor), text.len()));
 4132                                new_autoclose_regions.push((
 4133                                    anchor,
 4134                                    text.len(),
 4135                                    selection.id,
 4136                                    bracket_pair.clone(),
 4137                                ));
 4138                                edits.push((
 4139                                    selection.range(),
 4140                                    format!("{}{}", text, bracket_pair.end).into(),
 4141                                ));
 4142                                bracket_inserted = true;
 4143                                continue;
 4144                            }
 4145                        }
 4146
 4147                        if let Some(region) = autoclose_region {
 4148                            // If the selection is followed by an auto-inserted closing bracket,
 4149                            // then don't insert that closing bracket again; just move the selection
 4150                            // past the closing bracket.
 4151                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4152                                && text.as_ref() == region.pair.end.as_str()
 4153                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4154                            if should_skip {
 4155                                let anchor = snapshot.anchor_after(selection.end);
 4156                                new_selections
 4157                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4158                                continue;
 4159                            }
 4160                        }
 4161
 4162                        let always_treat_brackets_as_autoclosed = snapshot
 4163                            .language_settings_at(selection.start, cx)
 4164                            .always_treat_brackets_as_autoclosed;
 4165                        if always_treat_brackets_as_autoclosed
 4166                            && is_bracket_pair_end
 4167                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4168                        {
 4169                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4170                            // and the inserted text is a closing bracket and the selection is followed
 4171                            // by the closing bracket then move the selection past the closing bracket.
 4172                            let anchor = snapshot.anchor_after(selection.end);
 4173                            new_selections.push((selection.map(|_| anchor), text.len()));
 4174                            continue;
 4175                        }
 4176                    }
 4177                    // If an opening bracket is 1 character long and is typed while
 4178                    // text is selected, then surround that text with the bracket pair.
 4179                    else if auto_surround
 4180                        && bracket_pair.surround
 4181                        && is_bracket_pair_start
 4182                        && bracket_pair.start.chars().count() == 1
 4183                    {
 4184                        edits.push((selection.start..selection.start, text.clone()));
 4185                        edits.push((
 4186                            selection.end..selection.end,
 4187                            bracket_pair.end.as_str().into(),
 4188                        ));
 4189                        bracket_inserted = true;
 4190                        new_selections.push((
 4191                            Selection {
 4192                                id: selection.id,
 4193                                start: snapshot.anchor_after(selection.start),
 4194                                end: snapshot.anchor_before(selection.end),
 4195                                reversed: selection.reversed,
 4196                                goal: selection.goal,
 4197                            },
 4198                            0,
 4199                        ));
 4200                        continue;
 4201                    }
 4202                }
 4203            }
 4204
 4205            if self.auto_replace_emoji_shortcode
 4206                && selection.is_empty()
 4207                && text.as_ref().ends_with(':')
 4208                && let Some(possible_emoji_short_code) =
 4209                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4210                && !possible_emoji_short_code.is_empty()
 4211                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4212            {
 4213                let emoji_shortcode_start = Point::new(
 4214                    selection.start.row,
 4215                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4216                );
 4217
 4218                // Remove shortcode from buffer
 4219                edits.push((
 4220                    emoji_shortcode_start..selection.start,
 4221                    "".to_string().into(),
 4222                ));
 4223                new_selections.push((
 4224                    Selection {
 4225                        id: selection.id,
 4226                        start: snapshot.anchor_after(emoji_shortcode_start),
 4227                        end: snapshot.anchor_before(selection.start),
 4228                        reversed: selection.reversed,
 4229                        goal: selection.goal,
 4230                    },
 4231                    0,
 4232                ));
 4233
 4234                // Insert emoji
 4235                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4236                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4237                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4238
 4239                continue;
 4240            }
 4241
 4242            // If not handling any auto-close operation, then just replace the selected
 4243            // text with the given input and move the selection to the end of the
 4244            // newly inserted text.
 4245            let anchor = snapshot.anchor_after(selection.end);
 4246            if !self.linked_edit_ranges.is_empty() {
 4247                let start_anchor = snapshot.anchor_before(selection.start);
 4248
 4249                let is_word_char = text.chars().next().is_none_or(|char| {
 4250                    let classifier = snapshot
 4251                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4252                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4253                    classifier.is_word(char)
 4254                });
 4255
 4256                if is_word_char {
 4257                    if let Some(ranges) = self
 4258                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4259                    {
 4260                        for (buffer, edits) in ranges {
 4261                            linked_edits
 4262                                .entry(buffer.clone())
 4263                                .or_default()
 4264                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4265                        }
 4266                    }
 4267                } else {
 4268                    clear_linked_edit_ranges = true;
 4269                }
 4270            }
 4271
 4272            new_selections.push((selection.map(|_| anchor), 0));
 4273            edits.push((selection.start..selection.end, text.clone()));
 4274        }
 4275
 4276        drop(snapshot);
 4277
 4278        self.transact(window, cx, |this, window, cx| {
 4279            if clear_linked_edit_ranges {
 4280                this.linked_edit_ranges.clear();
 4281            }
 4282            let initial_buffer_versions =
 4283                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4284
 4285            this.buffer.update(cx, |buffer, cx| {
 4286                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4287            });
 4288            for (buffer, edits) in linked_edits {
 4289                buffer.update(cx, |buffer, cx| {
 4290                    let snapshot = buffer.snapshot();
 4291                    let edits = edits
 4292                        .into_iter()
 4293                        .map(|(range, text)| {
 4294                            use text::ToPoint as TP;
 4295                            let end_point = TP::to_point(&range.end, &snapshot);
 4296                            let start_point = TP::to_point(&range.start, &snapshot);
 4297                            (start_point..end_point, text)
 4298                        })
 4299                        .sorted_by_key(|(range, _)| range.start);
 4300                    buffer.edit(edits, None, cx);
 4301                })
 4302            }
 4303            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4304            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4305            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4306            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4307                .zip(new_selection_deltas)
 4308                .map(|(selection, delta)| Selection {
 4309                    id: selection.id,
 4310                    start: selection.start + delta,
 4311                    end: selection.end + delta,
 4312                    reversed: selection.reversed,
 4313                    goal: SelectionGoal::None,
 4314                })
 4315                .collect::<Vec<_>>();
 4316
 4317            let mut i = 0;
 4318            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4319                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4320                let start = map.buffer_snapshot.anchor_before(position);
 4321                let end = map.buffer_snapshot.anchor_after(position);
 4322                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4323                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4324                        Ordering::Less => i += 1,
 4325                        Ordering::Greater => break,
 4326                        Ordering::Equal => {
 4327                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4328                                Ordering::Less => i += 1,
 4329                                Ordering::Equal => break,
 4330                                Ordering::Greater => break,
 4331                            }
 4332                        }
 4333                    }
 4334                }
 4335                this.autoclose_regions.insert(
 4336                    i,
 4337                    AutocloseRegion {
 4338                        selection_id,
 4339                        range: start..end,
 4340                        pair,
 4341                    },
 4342                );
 4343            }
 4344
 4345            let had_active_edit_prediction = this.has_active_edit_prediction();
 4346            this.change_selections(
 4347                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4348                window,
 4349                cx,
 4350                |s| s.select(new_selections),
 4351            );
 4352
 4353            if !bracket_inserted
 4354                && let Some(on_type_format_task) =
 4355                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4356            {
 4357                on_type_format_task.detach_and_log_err(cx);
 4358            }
 4359
 4360            let editor_settings = EditorSettings::get_global(cx);
 4361            if bracket_inserted
 4362                && (editor_settings.auto_signature_help
 4363                    || editor_settings.show_signature_help_after_edits)
 4364            {
 4365                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4366            }
 4367
 4368            let trigger_in_words =
 4369                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4370            if this.hard_wrap.is_some() {
 4371                let latest: Range<Point> = this.selections.newest(cx).range();
 4372                if latest.is_empty()
 4373                    && this
 4374                        .buffer()
 4375                        .read(cx)
 4376                        .snapshot(cx)
 4377                        .line_len(MultiBufferRow(latest.start.row))
 4378                        == latest.start.column
 4379                {
 4380                    this.rewrap_impl(
 4381                        RewrapOptions {
 4382                            override_language_settings: true,
 4383                            preserve_existing_whitespace: true,
 4384                        },
 4385                        cx,
 4386                    )
 4387                }
 4388            }
 4389            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4390            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4391            this.refresh_edit_prediction(true, false, window, cx);
 4392            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4393        });
 4394    }
 4395
 4396    fn find_possible_emoji_shortcode_at_position(
 4397        snapshot: &MultiBufferSnapshot,
 4398        position: Point,
 4399    ) -> Option<String> {
 4400        let mut chars = Vec::new();
 4401        let mut found_colon = false;
 4402        for char in snapshot.reversed_chars_at(position).take(100) {
 4403            // Found a possible emoji shortcode in the middle of the buffer
 4404            if found_colon {
 4405                if char.is_whitespace() {
 4406                    chars.reverse();
 4407                    return Some(chars.iter().collect());
 4408                }
 4409                // If the previous character is not a whitespace, we are in the middle of a word
 4410                // and we only want to complete the shortcode if the word is made up of other emojis
 4411                let mut containing_word = String::new();
 4412                for ch in snapshot
 4413                    .reversed_chars_at(position)
 4414                    .skip(chars.len() + 1)
 4415                    .take(100)
 4416                {
 4417                    if ch.is_whitespace() {
 4418                        break;
 4419                    }
 4420                    containing_word.push(ch);
 4421                }
 4422                let containing_word = containing_word.chars().rev().collect::<String>();
 4423                if util::word_consists_of_emojis(containing_word.as_str()) {
 4424                    chars.reverse();
 4425                    return Some(chars.iter().collect());
 4426                }
 4427            }
 4428
 4429            if char.is_whitespace() || !char.is_ascii() {
 4430                return None;
 4431            }
 4432            if char == ':' {
 4433                found_colon = true;
 4434            } else {
 4435                chars.push(char);
 4436            }
 4437        }
 4438        // Found a possible emoji shortcode at the beginning of the buffer
 4439        chars.reverse();
 4440        Some(chars.iter().collect())
 4441    }
 4442
 4443    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4444        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4445        self.transact(window, cx, |this, window, cx| {
 4446            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4447                let selections = this.selections.all::<usize>(cx);
 4448                let multi_buffer = this.buffer.read(cx);
 4449                let buffer = multi_buffer.snapshot(cx);
 4450                selections
 4451                    .iter()
 4452                    .map(|selection| {
 4453                        let start_point = selection.start.to_point(&buffer);
 4454                        let mut existing_indent =
 4455                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4456                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4457                        let start = selection.start;
 4458                        let end = selection.end;
 4459                        let selection_is_empty = start == end;
 4460                        let language_scope = buffer.language_scope_at(start);
 4461                        let (
 4462                            comment_delimiter,
 4463                            doc_delimiter,
 4464                            insert_extra_newline,
 4465                            indent_on_newline,
 4466                            indent_on_extra_newline,
 4467                        ) = if let Some(language) = &language_scope {
 4468                            let mut insert_extra_newline =
 4469                                insert_extra_newline_brackets(&buffer, start..end, language)
 4470                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4471
 4472                            // Comment extension on newline is allowed only for cursor selections
 4473                            let comment_delimiter = maybe!({
 4474                                if !selection_is_empty {
 4475                                    return None;
 4476                                }
 4477
 4478                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4479                                    return None;
 4480                                }
 4481
 4482                                let delimiters = language.line_comment_prefixes();
 4483                                let max_len_of_delimiter =
 4484                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4485                                let (snapshot, range) =
 4486                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4487
 4488                                let num_of_whitespaces = snapshot
 4489                                    .chars_for_range(range.clone())
 4490                                    .take_while(|c| c.is_whitespace())
 4491                                    .count();
 4492                                let comment_candidate = snapshot
 4493                                    .chars_for_range(range.clone())
 4494                                    .skip(num_of_whitespaces)
 4495                                    .take(max_len_of_delimiter)
 4496                                    .collect::<String>();
 4497                                let (delimiter, trimmed_len) = delimiters
 4498                                    .iter()
 4499                                    .filter_map(|delimiter| {
 4500                                        let prefix = delimiter.trim_end();
 4501                                        if comment_candidate.starts_with(prefix) {
 4502                                            Some((delimiter, prefix.len()))
 4503                                        } else {
 4504                                            None
 4505                                        }
 4506                                    })
 4507                                    .max_by_key(|(_, len)| *len)?;
 4508
 4509                                if let Some(BlockCommentConfig {
 4510                                    start: block_start, ..
 4511                                }) = language.block_comment()
 4512                                {
 4513                                    let block_start_trimmed = block_start.trim_end();
 4514                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4515                                        let line_content = snapshot
 4516                                            .chars_for_range(range)
 4517                                            .skip(num_of_whitespaces)
 4518                                            .take(block_start_trimmed.len())
 4519                                            .collect::<String>();
 4520
 4521                                        if line_content.starts_with(block_start_trimmed) {
 4522                                            return None;
 4523                                        }
 4524                                    }
 4525                                }
 4526
 4527                                let cursor_is_placed_after_comment_marker =
 4528                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4529                                if cursor_is_placed_after_comment_marker {
 4530                                    Some(delimiter.clone())
 4531                                } else {
 4532                                    None
 4533                                }
 4534                            });
 4535
 4536                            let mut indent_on_newline = IndentSize::spaces(0);
 4537                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4538
 4539                            let doc_delimiter = maybe!({
 4540                                if !selection_is_empty {
 4541                                    return None;
 4542                                }
 4543
 4544                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4545                                    return None;
 4546                                }
 4547
 4548                                let BlockCommentConfig {
 4549                                    start: start_tag,
 4550                                    end: end_tag,
 4551                                    prefix: delimiter,
 4552                                    tab_size: len,
 4553                                } = language.documentation_comment()?;
 4554                                let is_within_block_comment = buffer
 4555                                    .language_scope_at(start_point)
 4556                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4557                                if !is_within_block_comment {
 4558                                    return None;
 4559                                }
 4560
 4561                                let (snapshot, range) =
 4562                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4563
 4564                                let num_of_whitespaces = snapshot
 4565                                    .chars_for_range(range.clone())
 4566                                    .take_while(|c| c.is_whitespace())
 4567                                    .count();
 4568
 4569                                // 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.
 4570                                let column = start_point.column;
 4571                                let cursor_is_after_start_tag = {
 4572                                    let start_tag_len = start_tag.len();
 4573                                    let start_tag_line = snapshot
 4574                                        .chars_for_range(range.clone())
 4575                                        .skip(num_of_whitespaces)
 4576                                        .take(start_tag_len)
 4577                                        .collect::<String>();
 4578                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4579                                        num_of_whitespaces + start_tag_len <= column as usize
 4580                                    } else {
 4581                                        false
 4582                                    }
 4583                                };
 4584
 4585                                let cursor_is_after_delimiter = {
 4586                                    let delimiter_trim = delimiter.trim_end();
 4587                                    let delimiter_line = snapshot
 4588                                        .chars_for_range(range.clone())
 4589                                        .skip(num_of_whitespaces)
 4590                                        .take(delimiter_trim.len())
 4591                                        .collect::<String>();
 4592                                    if delimiter_line.starts_with(delimiter_trim) {
 4593                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4594                                    } else {
 4595                                        false
 4596                                    }
 4597                                };
 4598
 4599                                let cursor_is_before_end_tag_if_exists = {
 4600                                    let mut char_position = 0u32;
 4601                                    let mut end_tag_offset = None;
 4602
 4603                                    'outer: for chunk in snapshot.text_for_range(range) {
 4604                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4605                                            let chars_before_match =
 4606                                                chunk[..byte_pos].chars().count() as u32;
 4607                                            end_tag_offset =
 4608                                                Some(char_position + chars_before_match);
 4609                                            break 'outer;
 4610                                        }
 4611                                        char_position += chunk.chars().count() as u32;
 4612                                    }
 4613
 4614                                    if let Some(end_tag_offset) = end_tag_offset {
 4615                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4616                                        if cursor_is_after_start_tag {
 4617                                            if cursor_is_before_end_tag {
 4618                                                insert_extra_newline = true;
 4619                                            }
 4620                                            let cursor_is_at_start_of_end_tag =
 4621                                                column == end_tag_offset;
 4622                                            if cursor_is_at_start_of_end_tag {
 4623                                                indent_on_extra_newline.len = *len;
 4624                                            }
 4625                                        }
 4626                                        cursor_is_before_end_tag
 4627                                    } else {
 4628                                        true
 4629                                    }
 4630                                };
 4631
 4632                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4633                                    && cursor_is_before_end_tag_if_exists
 4634                                {
 4635                                    if cursor_is_after_start_tag {
 4636                                        indent_on_newline.len = *len;
 4637                                    }
 4638                                    Some(delimiter.clone())
 4639                                } else {
 4640                                    None
 4641                                }
 4642                            });
 4643
 4644                            (
 4645                                comment_delimiter,
 4646                                doc_delimiter,
 4647                                insert_extra_newline,
 4648                                indent_on_newline,
 4649                                indent_on_extra_newline,
 4650                            )
 4651                        } else {
 4652                            (
 4653                                None,
 4654                                None,
 4655                                false,
 4656                                IndentSize::default(),
 4657                                IndentSize::default(),
 4658                            )
 4659                        };
 4660
 4661                        let prevent_auto_indent = doc_delimiter.is_some();
 4662                        let delimiter = comment_delimiter.or(doc_delimiter);
 4663
 4664                        let capacity_for_delimiter =
 4665                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4666                        let mut new_text = String::with_capacity(
 4667                            1 + capacity_for_delimiter
 4668                                + existing_indent.len as usize
 4669                                + indent_on_newline.len as usize
 4670                                + indent_on_extra_newline.len as usize,
 4671                        );
 4672                        new_text.push('\n');
 4673                        new_text.extend(existing_indent.chars());
 4674                        new_text.extend(indent_on_newline.chars());
 4675
 4676                        if let Some(delimiter) = &delimiter {
 4677                            new_text.push_str(delimiter);
 4678                        }
 4679
 4680                        if insert_extra_newline {
 4681                            new_text.push('\n');
 4682                            new_text.extend(existing_indent.chars());
 4683                            new_text.extend(indent_on_extra_newline.chars());
 4684                        }
 4685
 4686                        let anchor = buffer.anchor_after(end);
 4687                        let new_selection = selection.map(|_| anchor);
 4688                        (
 4689                            ((start..end, new_text), prevent_auto_indent),
 4690                            (insert_extra_newline, new_selection),
 4691                        )
 4692                    })
 4693                    .unzip()
 4694            };
 4695
 4696            let mut auto_indent_edits = Vec::new();
 4697            let mut edits = Vec::new();
 4698            for (edit, prevent_auto_indent) in edits_with_flags {
 4699                if prevent_auto_indent {
 4700                    edits.push(edit);
 4701                } else {
 4702                    auto_indent_edits.push(edit);
 4703                }
 4704            }
 4705            if !edits.is_empty() {
 4706                this.edit(edits, cx);
 4707            }
 4708            if !auto_indent_edits.is_empty() {
 4709                this.edit_with_autoindent(auto_indent_edits, cx);
 4710            }
 4711
 4712            let buffer = this.buffer.read(cx).snapshot(cx);
 4713            let new_selections = selection_info
 4714                .into_iter()
 4715                .map(|(extra_newline_inserted, new_selection)| {
 4716                    let mut cursor = new_selection.end.to_point(&buffer);
 4717                    if extra_newline_inserted {
 4718                        cursor.row -= 1;
 4719                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4720                    }
 4721                    new_selection.map(|_| cursor)
 4722                })
 4723                .collect();
 4724
 4725            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4726            this.refresh_edit_prediction(true, false, window, cx);
 4727        });
 4728    }
 4729
 4730    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4731        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4732
 4733        let buffer = self.buffer.read(cx);
 4734        let snapshot = buffer.snapshot(cx);
 4735
 4736        let mut edits = Vec::new();
 4737        let mut rows = Vec::new();
 4738
 4739        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4740            let cursor = selection.head();
 4741            let row = cursor.row;
 4742
 4743            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4744
 4745            let newline = "\n".to_string();
 4746            edits.push((start_of_line..start_of_line, newline));
 4747
 4748            rows.push(row + rows_inserted as u32);
 4749        }
 4750
 4751        self.transact(window, cx, |editor, window, cx| {
 4752            editor.edit(edits, cx);
 4753
 4754            editor.change_selections(Default::default(), window, cx, |s| {
 4755                let mut index = 0;
 4756                s.move_cursors_with(|map, _, _| {
 4757                    let row = rows[index];
 4758                    index += 1;
 4759
 4760                    let point = Point::new(row, 0);
 4761                    let boundary = map.next_line_boundary(point).1;
 4762                    let clipped = map.clip_point(boundary, Bias::Left);
 4763
 4764                    (clipped, SelectionGoal::None)
 4765                });
 4766            });
 4767
 4768            let mut indent_edits = Vec::new();
 4769            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4770            for row in rows {
 4771                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4772                for (row, indent) in indents {
 4773                    if indent.len == 0 {
 4774                        continue;
 4775                    }
 4776
 4777                    let text = match indent.kind {
 4778                        IndentKind::Space => " ".repeat(indent.len as usize),
 4779                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4780                    };
 4781                    let point = Point::new(row.0, 0);
 4782                    indent_edits.push((point..point, text));
 4783                }
 4784            }
 4785            editor.edit(indent_edits, cx);
 4786        });
 4787    }
 4788
 4789    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4790        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4791
 4792        let buffer = self.buffer.read(cx);
 4793        let snapshot = buffer.snapshot(cx);
 4794
 4795        let mut edits = Vec::new();
 4796        let mut rows = Vec::new();
 4797        let mut rows_inserted = 0;
 4798
 4799        for selection in self.selections.all_adjusted(cx) {
 4800            let cursor = selection.head();
 4801            let row = cursor.row;
 4802
 4803            let point = Point::new(row + 1, 0);
 4804            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4805
 4806            let newline = "\n".to_string();
 4807            edits.push((start_of_line..start_of_line, newline));
 4808
 4809            rows_inserted += 1;
 4810            rows.push(row + rows_inserted);
 4811        }
 4812
 4813        self.transact(window, cx, |editor, window, cx| {
 4814            editor.edit(edits, cx);
 4815
 4816            editor.change_selections(Default::default(), window, cx, |s| {
 4817                let mut index = 0;
 4818                s.move_cursors_with(|map, _, _| {
 4819                    let row = rows[index];
 4820                    index += 1;
 4821
 4822                    let point = Point::new(row, 0);
 4823                    let boundary = map.next_line_boundary(point).1;
 4824                    let clipped = map.clip_point(boundary, Bias::Left);
 4825
 4826                    (clipped, SelectionGoal::None)
 4827                });
 4828            });
 4829
 4830            let mut indent_edits = Vec::new();
 4831            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4832            for row in rows {
 4833                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4834                for (row, indent) in indents {
 4835                    if indent.len == 0 {
 4836                        continue;
 4837                    }
 4838
 4839                    let text = match indent.kind {
 4840                        IndentKind::Space => " ".repeat(indent.len as usize),
 4841                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4842                    };
 4843                    let point = Point::new(row.0, 0);
 4844                    indent_edits.push((point..point, text));
 4845                }
 4846            }
 4847            editor.edit(indent_edits, cx);
 4848        });
 4849    }
 4850
 4851    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4852        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4853            original_indent_columns: Vec::new(),
 4854        });
 4855        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4856    }
 4857
 4858    fn insert_with_autoindent_mode(
 4859        &mut self,
 4860        text: &str,
 4861        autoindent_mode: Option<AutoindentMode>,
 4862        window: &mut Window,
 4863        cx: &mut Context<Self>,
 4864    ) {
 4865        if self.read_only(cx) {
 4866            return;
 4867        }
 4868
 4869        let text: Arc<str> = text.into();
 4870        self.transact(window, cx, |this, window, cx| {
 4871            let old_selections = this.selections.all_adjusted(cx);
 4872            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4873                let anchors = {
 4874                    let snapshot = buffer.read(cx);
 4875                    old_selections
 4876                        .iter()
 4877                        .map(|s| {
 4878                            let anchor = snapshot.anchor_after(s.head());
 4879                            s.map(|_| anchor)
 4880                        })
 4881                        .collect::<Vec<_>>()
 4882                };
 4883                buffer.edit(
 4884                    old_selections
 4885                        .iter()
 4886                        .map(|s| (s.start..s.end, text.clone())),
 4887                    autoindent_mode,
 4888                    cx,
 4889                );
 4890                anchors
 4891            });
 4892
 4893            this.change_selections(Default::default(), window, cx, |s| {
 4894                s.select_anchors(selection_anchors);
 4895            });
 4896
 4897            cx.notify();
 4898        });
 4899    }
 4900
 4901    fn trigger_completion_on_input(
 4902        &mut self,
 4903        text: &str,
 4904        trigger_in_words: bool,
 4905        window: &mut Window,
 4906        cx: &mut Context<Self>,
 4907    ) {
 4908        let completions_source = self
 4909            .context_menu
 4910            .borrow()
 4911            .as_ref()
 4912            .and_then(|menu| match menu {
 4913                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4914                CodeContextMenu::CodeActions(_) => None,
 4915            });
 4916
 4917        match completions_source {
 4918            Some(CompletionsMenuSource::Words { .. }) => {
 4919                self.open_or_update_completions_menu(
 4920                    Some(CompletionsMenuSource::Words {
 4921                        ignore_threshold: false,
 4922                    }),
 4923                    None,
 4924                    window,
 4925                    cx,
 4926                );
 4927            }
 4928            Some(CompletionsMenuSource::Normal)
 4929            | Some(CompletionsMenuSource::SnippetChoices)
 4930            | None
 4931                if self.is_completion_trigger(
 4932                    text,
 4933                    trigger_in_words,
 4934                    completions_source.is_some(),
 4935                    cx,
 4936                ) =>
 4937            {
 4938                self.show_completions(
 4939                    &ShowCompletions {
 4940                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4941                    },
 4942                    window,
 4943                    cx,
 4944                )
 4945            }
 4946            _ => {
 4947                self.hide_context_menu(window, cx);
 4948            }
 4949        }
 4950    }
 4951
 4952    fn is_completion_trigger(
 4953        &self,
 4954        text: &str,
 4955        trigger_in_words: bool,
 4956        menu_is_open: bool,
 4957        cx: &mut Context<Self>,
 4958    ) -> bool {
 4959        let position = self.selections.newest_anchor().head();
 4960        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4961            return false;
 4962        };
 4963
 4964        if let Some(completion_provider) = &self.completion_provider {
 4965            completion_provider.is_completion_trigger(
 4966                &buffer,
 4967                position.text_anchor,
 4968                text,
 4969                trigger_in_words,
 4970                menu_is_open,
 4971                cx,
 4972            )
 4973        } else {
 4974            false
 4975        }
 4976    }
 4977
 4978    /// If any empty selections is touching the start of its innermost containing autoclose
 4979    /// region, expand it to select the brackets.
 4980    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4981        let selections = self.selections.all::<usize>(cx);
 4982        let buffer = self.buffer.read(cx).read(cx);
 4983        let new_selections = self
 4984            .selections_with_autoclose_regions(selections, &buffer)
 4985            .map(|(mut selection, region)| {
 4986                if !selection.is_empty() {
 4987                    return selection;
 4988                }
 4989
 4990                if let Some(region) = region {
 4991                    let mut range = region.range.to_offset(&buffer);
 4992                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4993                        range.start -= region.pair.start.len();
 4994                        if buffer.contains_str_at(range.start, &region.pair.start)
 4995                            && buffer.contains_str_at(range.end, &region.pair.end)
 4996                        {
 4997                            range.end += region.pair.end.len();
 4998                            selection.start = range.start;
 4999                            selection.end = range.end;
 5000
 5001                            return selection;
 5002                        }
 5003                    }
 5004                }
 5005
 5006                let always_treat_brackets_as_autoclosed = buffer
 5007                    .language_settings_at(selection.start, cx)
 5008                    .always_treat_brackets_as_autoclosed;
 5009
 5010                if !always_treat_brackets_as_autoclosed {
 5011                    return selection;
 5012                }
 5013
 5014                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5015                    for (pair, enabled) in scope.brackets() {
 5016                        if !enabled || !pair.close {
 5017                            continue;
 5018                        }
 5019
 5020                        if buffer.contains_str_at(selection.start, &pair.end) {
 5021                            let pair_start_len = pair.start.len();
 5022                            if buffer.contains_str_at(
 5023                                selection.start.saturating_sub(pair_start_len),
 5024                                &pair.start,
 5025                            ) {
 5026                                selection.start -= pair_start_len;
 5027                                selection.end += pair.end.len();
 5028
 5029                                return selection;
 5030                            }
 5031                        }
 5032                    }
 5033                }
 5034
 5035                selection
 5036            })
 5037            .collect();
 5038
 5039        drop(buffer);
 5040        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5041            selections.select(new_selections)
 5042        });
 5043    }
 5044
 5045    /// Iterate the given selections, and for each one, find the smallest surrounding
 5046    /// autoclose region. This uses the ordering of the selections and the autoclose
 5047    /// regions to avoid repeated comparisons.
 5048    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5049        &'a self,
 5050        selections: impl IntoIterator<Item = Selection<D>>,
 5051        buffer: &'a MultiBufferSnapshot,
 5052    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5053        let mut i = 0;
 5054        let mut regions = self.autoclose_regions.as_slice();
 5055        selections.into_iter().map(move |selection| {
 5056            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5057
 5058            let mut enclosing = None;
 5059            while let Some(pair_state) = regions.get(i) {
 5060                if pair_state.range.end.to_offset(buffer) < range.start {
 5061                    regions = &regions[i + 1..];
 5062                    i = 0;
 5063                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5064                    break;
 5065                } else {
 5066                    if pair_state.selection_id == selection.id {
 5067                        enclosing = Some(pair_state);
 5068                    }
 5069                    i += 1;
 5070                }
 5071            }
 5072
 5073            (selection, enclosing)
 5074        })
 5075    }
 5076
 5077    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5078    fn invalidate_autoclose_regions(
 5079        &mut self,
 5080        mut selections: &[Selection<Anchor>],
 5081        buffer: &MultiBufferSnapshot,
 5082    ) {
 5083        self.autoclose_regions.retain(|state| {
 5084            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5085                return false;
 5086            }
 5087
 5088            let mut i = 0;
 5089            while let Some(selection) = selections.get(i) {
 5090                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5091                    selections = &selections[1..];
 5092                    continue;
 5093                }
 5094                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5095                    break;
 5096                }
 5097                if selection.id == state.selection_id {
 5098                    return true;
 5099                } else {
 5100                    i += 1;
 5101                }
 5102            }
 5103            false
 5104        });
 5105    }
 5106
 5107    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5108        let offset = position.to_offset(buffer);
 5109        let (word_range, kind) =
 5110            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5111        if offset > word_range.start && kind == Some(CharKind::Word) {
 5112            Some(
 5113                buffer
 5114                    .text_for_range(word_range.start..offset)
 5115                    .collect::<String>(),
 5116            )
 5117        } else {
 5118            None
 5119        }
 5120    }
 5121
 5122    pub fn toggle_inline_values(
 5123        &mut self,
 5124        _: &ToggleInlineValues,
 5125        _: &mut Window,
 5126        cx: &mut Context<Self>,
 5127    ) {
 5128        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5129
 5130        self.refresh_inline_values(cx);
 5131    }
 5132
 5133    pub fn toggle_inlay_hints(
 5134        &mut self,
 5135        _: &ToggleInlayHints,
 5136        _: &mut Window,
 5137        cx: &mut Context<Self>,
 5138    ) {
 5139        self.refresh_inlay_hints(
 5140            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5141            cx,
 5142        );
 5143    }
 5144
 5145    pub fn inlay_hints_enabled(&self) -> bool {
 5146        self.inlay_hint_cache.enabled
 5147    }
 5148
 5149    pub fn inline_values_enabled(&self) -> bool {
 5150        self.inline_value_cache.enabled
 5151    }
 5152
 5153    #[cfg(any(test, feature = "test-support"))]
 5154    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5155        self.display_map
 5156            .read(cx)
 5157            .current_inlays()
 5158            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5159            .cloned()
 5160            .collect()
 5161    }
 5162
 5163    #[cfg(any(test, feature = "test-support"))]
 5164    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5165        self.display_map
 5166            .read(cx)
 5167            .current_inlays()
 5168            .cloned()
 5169            .collect()
 5170    }
 5171
 5172    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5173        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5174            return;
 5175        }
 5176
 5177        let reason_description = reason.description();
 5178        let ignore_debounce = matches!(
 5179            reason,
 5180            InlayHintRefreshReason::SettingsChange(_)
 5181                | InlayHintRefreshReason::Toggle(_)
 5182                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5183                | InlayHintRefreshReason::ModifiersChanged(_)
 5184        );
 5185        let (invalidate_cache, required_languages) = match reason {
 5186            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5187                match self.inlay_hint_cache.modifiers_override(enabled) {
 5188                    Some(enabled) => {
 5189                        if enabled {
 5190                            (InvalidationStrategy::RefreshRequested, None)
 5191                        } else {
 5192                            self.splice_inlays(
 5193                                &self
 5194                                    .visible_inlay_hints(cx)
 5195                                    .iter()
 5196                                    .map(|inlay| inlay.id)
 5197                                    .collect::<Vec<InlayId>>(),
 5198                                Vec::new(),
 5199                                cx,
 5200                            );
 5201                            return;
 5202                        }
 5203                    }
 5204                    None => return,
 5205                }
 5206            }
 5207            InlayHintRefreshReason::Toggle(enabled) => {
 5208                if self.inlay_hint_cache.toggle(enabled) {
 5209                    if enabled {
 5210                        (InvalidationStrategy::RefreshRequested, None)
 5211                    } else {
 5212                        self.splice_inlays(
 5213                            &self
 5214                                .visible_inlay_hints(cx)
 5215                                .iter()
 5216                                .map(|inlay| inlay.id)
 5217                                .collect::<Vec<InlayId>>(),
 5218                            Vec::new(),
 5219                            cx,
 5220                        );
 5221                        return;
 5222                    }
 5223                } else {
 5224                    return;
 5225                }
 5226            }
 5227            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5228                match self.inlay_hint_cache.update_settings(
 5229                    &self.buffer,
 5230                    new_settings,
 5231                    self.visible_inlay_hints(cx),
 5232                    cx,
 5233                ) {
 5234                    ControlFlow::Break(Some(InlaySplice {
 5235                        to_remove,
 5236                        to_insert,
 5237                    })) => {
 5238                        self.splice_inlays(&to_remove, to_insert, cx);
 5239                        return;
 5240                    }
 5241                    ControlFlow::Break(None) => return,
 5242                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5243                }
 5244            }
 5245            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5246                if let Some(InlaySplice {
 5247                    to_remove,
 5248                    to_insert,
 5249                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5250                {
 5251                    self.splice_inlays(&to_remove, to_insert, cx);
 5252                }
 5253                self.display_map.update(cx, |display_map, _| {
 5254                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5255                });
 5256                return;
 5257            }
 5258            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5259            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5260                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5261            }
 5262            InlayHintRefreshReason::RefreshRequested => {
 5263                (InvalidationStrategy::RefreshRequested, None)
 5264            }
 5265        };
 5266
 5267        if let Some(InlaySplice {
 5268            to_remove,
 5269            to_insert,
 5270        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5271            reason_description,
 5272            self.visible_excerpts(required_languages.as_ref(), cx),
 5273            invalidate_cache,
 5274            ignore_debounce,
 5275            cx,
 5276        ) {
 5277            self.splice_inlays(&to_remove, to_insert, cx);
 5278        }
 5279    }
 5280
 5281    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5282        self.display_map
 5283            .read(cx)
 5284            .current_inlays()
 5285            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5286            .cloned()
 5287            .collect()
 5288    }
 5289
 5290    pub fn visible_excerpts(
 5291        &self,
 5292        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5293        cx: &mut Context<Editor>,
 5294    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5295        let Some(project) = self.project() else {
 5296            return HashMap::default();
 5297        };
 5298        let project = project.read(cx);
 5299        let multi_buffer = self.buffer().read(cx);
 5300        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5301        let multi_buffer_visible_start = self
 5302            .scroll_manager
 5303            .anchor()
 5304            .anchor
 5305            .to_point(&multi_buffer_snapshot);
 5306        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5307            multi_buffer_visible_start
 5308                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5309            Bias::Left,
 5310        );
 5311        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5312        multi_buffer_snapshot
 5313            .range_to_buffer_ranges(multi_buffer_visible_range)
 5314            .into_iter()
 5315            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5316            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5317                let buffer_file = project::File::from_dyn(buffer.file())?;
 5318                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5319                let worktree_entry = buffer_worktree
 5320                    .read(cx)
 5321                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5322                if worktree_entry.is_ignored {
 5323                    return None;
 5324                }
 5325
 5326                let language = buffer.language()?;
 5327                if let Some(restrict_to_languages) = restrict_to_languages
 5328                    && !restrict_to_languages.contains(language)
 5329                {
 5330                    return None;
 5331                }
 5332                Some((
 5333                    excerpt_id,
 5334                    (
 5335                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5336                        buffer.version().clone(),
 5337                        excerpt_visible_range,
 5338                    ),
 5339                ))
 5340            })
 5341            .collect()
 5342    }
 5343
 5344    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5345        TextLayoutDetails {
 5346            text_system: window.text_system().clone(),
 5347            editor_style: self.style.clone().unwrap(),
 5348            rem_size: window.rem_size(),
 5349            scroll_anchor: self.scroll_manager.anchor(),
 5350            visible_rows: self.visible_line_count(),
 5351            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5352        }
 5353    }
 5354
 5355    pub fn splice_inlays(
 5356        &self,
 5357        to_remove: &[InlayId],
 5358        to_insert: Vec<Inlay>,
 5359        cx: &mut Context<Self>,
 5360    ) {
 5361        self.display_map.update(cx, |display_map, cx| {
 5362            display_map.splice_inlays(to_remove, to_insert, cx)
 5363        });
 5364        cx.notify();
 5365    }
 5366
 5367    fn trigger_on_type_formatting(
 5368        &self,
 5369        input: String,
 5370        window: &mut Window,
 5371        cx: &mut Context<Self>,
 5372    ) -> Option<Task<Result<()>>> {
 5373        if input.len() != 1 {
 5374            return None;
 5375        }
 5376
 5377        let project = self.project()?;
 5378        let position = self.selections.newest_anchor().head();
 5379        let (buffer, buffer_position) = self
 5380            .buffer
 5381            .read(cx)
 5382            .text_anchor_for_position(position, cx)?;
 5383
 5384        let settings = language_settings::language_settings(
 5385            buffer
 5386                .read(cx)
 5387                .language_at(buffer_position)
 5388                .map(|l| l.name()),
 5389            buffer.read(cx).file(),
 5390            cx,
 5391        );
 5392        if !settings.use_on_type_format {
 5393            return None;
 5394        }
 5395
 5396        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5397        // hence we do LSP request & edit on host side only — add formats to host's history.
 5398        let push_to_lsp_host_history = true;
 5399        // If this is not the host, append its history with new edits.
 5400        let push_to_client_history = project.read(cx).is_via_collab();
 5401
 5402        let on_type_formatting = project.update(cx, |project, cx| {
 5403            project.on_type_format(
 5404                buffer.clone(),
 5405                buffer_position,
 5406                input,
 5407                push_to_lsp_host_history,
 5408                cx,
 5409            )
 5410        });
 5411        Some(cx.spawn_in(window, async move |editor, cx| {
 5412            if let Some(transaction) = on_type_formatting.await? {
 5413                if push_to_client_history {
 5414                    buffer
 5415                        .update(cx, |buffer, _| {
 5416                            buffer.push_transaction(transaction, Instant::now());
 5417                            buffer.finalize_last_transaction();
 5418                        })
 5419                        .ok();
 5420                }
 5421                editor.update(cx, |editor, cx| {
 5422                    editor.refresh_document_highlights(cx);
 5423                })?;
 5424            }
 5425            Ok(())
 5426        }))
 5427    }
 5428
 5429    pub fn show_word_completions(
 5430        &mut self,
 5431        _: &ShowWordCompletions,
 5432        window: &mut Window,
 5433        cx: &mut Context<Self>,
 5434    ) {
 5435        self.open_or_update_completions_menu(
 5436            Some(CompletionsMenuSource::Words {
 5437                ignore_threshold: true,
 5438            }),
 5439            None,
 5440            window,
 5441            cx,
 5442        );
 5443    }
 5444
 5445    pub fn show_completions(
 5446        &mut self,
 5447        options: &ShowCompletions,
 5448        window: &mut Window,
 5449        cx: &mut Context<Self>,
 5450    ) {
 5451        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5452    }
 5453
 5454    fn open_or_update_completions_menu(
 5455        &mut self,
 5456        requested_source: Option<CompletionsMenuSource>,
 5457        trigger: Option<&str>,
 5458        window: &mut Window,
 5459        cx: &mut Context<Self>,
 5460    ) {
 5461        if self.pending_rename.is_some() {
 5462            return;
 5463        }
 5464
 5465        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5466
 5467        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5468        // inserted and selected. To handle that case, the start of the selection is used so that
 5469        // the menu starts with all choices.
 5470        let position = self
 5471            .selections
 5472            .newest_anchor()
 5473            .start
 5474            .bias_right(&multibuffer_snapshot);
 5475        if position.diff_base_anchor.is_some() {
 5476            return;
 5477        }
 5478        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5479        let Some(buffer) = buffer_position
 5480            .buffer_id
 5481            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5482        else {
 5483            return;
 5484        };
 5485        let buffer_snapshot = buffer.read(cx).snapshot();
 5486
 5487        let query: Option<Arc<String>> =
 5488            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5489                .map(|query| query.into());
 5490
 5491        drop(multibuffer_snapshot);
 5492
 5493        // Hide the current completions menu when query is empty. Without this, cached
 5494        // completions from before the trigger char may be reused (#32774).
 5495        if query.is_none() {
 5496            let menu_is_open = matches!(
 5497                self.context_menu.borrow().as_ref(),
 5498                Some(CodeContextMenu::Completions(_))
 5499            );
 5500            if menu_is_open {
 5501                self.hide_context_menu(window, cx);
 5502            }
 5503        }
 5504
 5505        let mut ignore_word_threshold = false;
 5506        let provider = match requested_source {
 5507            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5508            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5509                ignore_word_threshold = ignore_threshold;
 5510                None
 5511            }
 5512            Some(CompletionsMenuSource::SnippetChoices) => {
 5513                log::error!("bug: SnippetChoices requested_source is not handled");
 5514                None
 5515            }
 5516        };
 5517
 5518        let sort_completions = provider
 5519            .as_ref()
 5520            .is_some_and(|provider| provider.sort_completions());
 5521
 5522        let filter_completions = provider
 5523            .as_ref()
 5524            .is_none_or(|provider| provider.filter_completions());
 5525
 5526        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5527            if filter_completions {
 5528                menu.filter(query.clone(), provider.clone(), window, cx);
 5529            }
 5530            // When `is_incomplete` is false, no need to re-query completions when the current query
 5531            // is a suffix of the initial query.
 5532            if !menu.is_incomplete {
 5533                // If the new query is a suffix of the old query (typing more characters) and
 5534                // the previous result was complete, the existing completions can be filtered.
 5535                //
 5536                // Note that this is always true for snippet completions.
 5537                let query_matches = match (&menu.initial_query, &query) {
 5538                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5539                    (None, _) => true,
 5540                    _ => false,
 5541                };
 5542                if query_matches {
 5543                    let position_matches = if menu.initial_position == position {
 5544                        true
 5545                    } else {
 5546                        let snapshot = self.buffer.read(cx).read(cx);
 5547                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5548                    };
 5549                    if position_matches {
 5550                        return;
 5551                    }
 5552                }
 5553            }
 5554        };
 5555
 5556        let trigger_kind = match trigger {
 5557            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5558                CompletionTriggerKind::TRIGGER_CHARACTER
 5559            }
 5560            _ => CompletionTriggerKind::INVOKED,
 5561        };
 5562        let completion_context = CompletionContext {
 5563            trigger_character: trigger.and_then(|trigger| {
 5564                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5565                    Some(String::from(trigger))
 5566                } else {
 5567                    None
 5568                }
 5569            }),
 5570            trigger_kind,
 5571        };
 5572
 5573        let Anchor {
 5574            excerpt_id: buffer_excerpt_id,
 5575            text_anchor: buffer_position,
 5576            ..
 5577        } = buffer_position;
 5578
 5579        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5580            buffer_snapshot.surrounding_word(buffer_position, None)
 5581        {
 5582            let word_to_exclude = buffer_snapshot
 5583                .text_for_range(word_range.clone())
 5584                .collect::<String>();
 5585            (
 5586                buffer_snapshot.anchor_before(word_range.start)
 5587                    ..buffer_snapshot.anchor_after(buffer_position),
 5588                Some(word_to_exclude),
 5589            )
 5590        } else {
 5591            (buffer_position..buffer_position, None)
 5592        };
 5593
 5594        let language = buffer_snapshot
 5595            .language_at(buffer_position)
 5596            .map(|language| language.name());
 5597
 5598        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5599            .completions
 5600            .clone();
 5601
 5602        let show_completion_documentation = buffer_snapshot
 5603            .settings_at(buffer_position, cx)
 5604            .show_completion_documentation;
 5605
 5606        // The document can be large, so stay in reasonable bounds when searching for words,
 5607        // otherwise completion pop-up might be slow to appear.
 5608        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5609        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5610        let min_word_search = buffer_snapshot.clip_point(
 5611            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5612            Bias::Left,
 5613        );
 5614        let max_word_search = buffer_snapshot.clip_point(
 5615            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5616            Bias::Right,
 5617        );
 5618        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5619            ..buffer_snapshot.point_to_offset(max_word_search);
 5620
 5621        let skip_digits = query
 5622            .as_ref()
 5623            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5624
 5625        let omit_word_completions = !self.word_completions_enabled
 5626            || (!ignore_word_threshold
 5627                && match &query {
 5628                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5629                    None => completion_settings.words_min_length != 0,
 5630                });
 5631
 5632        let (mut words, provider_responses) = match &provider {
 5633            Some(provider) => {
 5634                let provider_responses = provider.completions(
 5635                    buffer_excerpt_id,
 5636                    &buffer,
 5637                    buffer_position,
 5638                    completion_context,
 5639                    window,
 5640                    cx,
 5641                );
 5642
 5643                let words = match (omit_word_completions, completion_settings.words) {
 5644                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5645                        Task::ready(BTreeMap::default())
 5646                    }
 5647                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5648                        .background_spawn(async move {
 5649                            buffer_snapshot.words_in_range(WordsQuery {
 5650                                fuzzy_contents: None,
 5651                                range: word_search_range,
 5652                                skip_digits,
 5653                            })
 5654                        }),
 5655                };
 5656
 5657                (words, provider_responses)
 5658            }
 5659            None => {
 5660                let words = if omit_word_completions {
 5661                    Task::ready(BTreeMap::default())
 5662                } else {
 5663                    cx.background_spawn(async move {
 5664                        buffer_snapshot.words_in_range(WordsQuery {
 5665                            fuzzy_contents: None,
 5666                            range: word_search_range,
 5667                            skip_digits,
 5668                        })
 5669                    })
 5670                };
 5671                (words, Task::ready(Ok(Vec::new())))
 5672            }
 5673        };
 5674
 5675        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5676
 5677        let id = post_inc(&mut self.next_completion_id);
 5678        let task = cx.spawn_in(window, async move |editor, cx| {
 5679            let Ok(()) = editor.update(cx, |this, _| {
 5680                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5681            }) else {
 5682                return;
 5683            };
 5684
 5685            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5686            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5687            let mut completions = Vec::new();
 5688            let mut is_incomplete = false;
 5689            let mut display_options: Option<CompletionDisplayOptions> = None;
 5690            if let Some(provider_responses) = provider_responses.await.log_err()
 5691                && !provider_responses.is_empty()
 5692            {
 5693                for response in provider_responses {
 5694                    completions.extend(response.completions);
 5695                    is_incomplete = is_incomplete || response.is_incomplete;
 5696                    match display_options.as_mut() {
 5697                        None => {
 5698                            display_options = Some(response.display_options);
 5699                        }
 5700                        Some(options) => options.merge(&response.display_options),
 5701                    }
 5702                }
 5703                if completion_settings.words == WordsCompletionMode::Fallback {
 5704                    words = Task::ready(BTreeMap::default());
 5705                }
 5706            }
 5707            let display_options = display_options.unwrap_or_default();
 5708
 5709            let mut words = words.await;
 5710            if let Some(word_to_exclude) = &word_to_exclude {
 5711                words.remove(word_to_exclude);
 5712            }
 5713            for lsp_completion in &completions {
 5714                words.remove(&lsp_completion.new_text);
 5715            }
 5716            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5717                replace_range: word_replace_range.clone(),
 5718                new_text: word.clone(),
 5719                label: CodeLabel::plain(word, None),
 5720                icon_path: None,
 5721                documentation: None,
 5722                source: CompletionSource::BufferWord {
 5723                    word_range,
 5724                    resolved: false,
 5725                },
 5726                insert_text_mode: Some(InsertTextMode::AS_IS),
 5727                confirm: None,
 5728            }));
 5729
 5730            let menu = if completions.is_empty() {
 5731                None
 5732            } else {
 5733                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5734                    let languages = editor
 5735                        .workspace
 5736                        .as_ref()
 5737                        .and_then(|(workspace, _)| workspace.upgrade())
 5738                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5739                    let menu = CompletionsMenu::new(
 5740                        id,
 5741                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5742                        sort_completions,
 5743                        show_completion_documentation,
 5744                        position,
 5745                        query.clone(),
 5746                        is_incomplete,
 5747                        buffer.clone(),
 5748                        completions.into(),
 5749                        display_options,
 5750                        snippet_sort_order,
 5751                        languages,
 5752                        language,
 5753                        cx,
 5754                    );
 5755
 5756                    let query = if filter_completions { query } else { None };
 5757                    let matches_task = if let Some(query) = query {
 5758                        menu.do_async_filtering(query, cx)
 5759                    } else {
 5760                        Task::ready(menu.unfiltered_matches())
 5761                    };
 5762                    (menu, matches_task)
 5763                }) else {
 5764                    return;
 5765                };
 5766
 5767                let matches = matches_task.await;
 5768
 5769                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5770                    // Newer menu already set, so exit.
 5771                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5772                        editor.context_menu.borrow().as_ref()
 5773                        && prev_menu.id > id
 5774                    {
 5775                        return;
 5776                    };
 5777
 5778                    // Only valid to take prev_menu because it the new menu is immediately set
 5779                    // below, or the menu is hidden.
 5780                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5781                        editor.context_menu.borrow_mut().take()
 5782                    {
 5783                        let position_matches =
 5784                            if prev_menu.initial_position == menu.initial_position {
 5785                                true
 5786                            } else {
 5787                                let snapshot = editor.buffer.read(cx).read(cx);
 5788                                prev_menu.initial_position.to_offset(&snapshot)
 5789                                    == menu.initial_position.to_offset(&snapshot)
 5790                            };
 5791                        if position_matches {
 5792                            // Preserve markdown cache before `set_filter_results` because it will
 5793                            // try to populate the documentation cache.
 5794                            menu.preserve_markdown_cache(prev_menu);
 5795                        }
 5796                    };
 5797
 5798                    menu.set_filter_results(matches, provider, window, cx);
 5799                }) else {
 5800                    return;
 5801                };
 5802
 5803                menu.visible().then_some(menu)
 5804            };
 5805
 5806            editor
 5807                .update_in(cx, |editor, window, cx| {
 5808                    if editor.focus_handle.is_focused(window)
 5809                        && let Some(menu) = menu
 5810                    {
 5811                        *editor.context_menu.borrow_mut() =
 5812                            Some(CodeContextMenu::Completions(menu));
 5813
 5814                        crate::hover_popover::hide_hover(editor, cx);
 5815                        if editor.show_edit_predictions_in_menu() {
 5816                            editor.update_visible_edit_prediction(window, cx);
 5817                        } else {
 5818                            editor.discard_edit_prediction(false, cx);
 5819                        }
 5820
 5821                        cx.notify();
 5822                        return;
 5823                    }
 5824
 5825                    if editor.completion_tasks.len() <= 1 {
 5826                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5827                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5828                        // If it was already hidden and we don't show edit predictions in the menu,
 5829                        // we should also show the edit prediction when available.
 5830                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5831                            editor.update_visible_edit_prediction(window, cx);
 5832                        }
 5833                    }
 5834                })
 5835                .ok();
 5836        });
 5837
 5838        self.completion_tasks.push((id, task));
 5839    }
 5840
 5841    #[cfg(feature = "test-support")]
 5842    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5843        let menu = self.context_menu.borrow();
 5844        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5845            let completions = menu.completions.borrow();
 5846            Some(completions.to_vec())
 5847        } else {
 5848            None
 5849        }
 5850    }
 5851
 5852    pub fn with_completions_menu_matching_id<R>(
 5853        &self,
 5854        id: CompletionId,
 5855        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5856    ) -> R {
 5857        let mut context_menu = self.context_menu.borrow_mut();
 5858        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5859            return f(None);
 5860        };
 5861        if completions_menu.id != id {
 5862            return f(None);
 5863        }
 5864        f(Some(completions_menu))
 5865    }
 5866
 5867    pub fn confirm_completion(
 5868        &mut self,
 5869        action: &ConfirmCompletion,
 5870        window: &mut Window,
 5871        cx: &mut Context<Self>,
 5872    ) -> Option<Task<Result<()>>> {
 5873        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5874        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5875    }
 5876
 5877    pub fn confirm_completion_insert(
 5878        &mut self,
 5879        _: &ConfirmCompletionInsert,
 5880        window: &mut Window,
 5881        cx: &mut Context<Self>,
 5882    ) -> Option<Task<Result<()>>> {
 5883        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5884        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5885    }
 5886
 5887    pub fn confirm_completion_replace(
 5888        &mut self,
 5889        _: &ConfirmCompletionReplace,
 5890        window: &mut Window,
 5891        cx: &mut Context<Self>,
 5892    ) -> Option<Task<Result<()>>> {
 5893        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5894        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5895    }
 5896
 5897    pub fn compose_completion(
 5898        &mut self,
 5899        action: &ComposeCompletion,
 5900        window: &mut Window,
 5901        cx: &mut Context<Self>,
 5902    ) -> Option<Task<Result<()>>> {
 5903        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5904        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5905    }
 5906
 5907    fn do_completion(
 5908        &mut self,
 5909        item_ix: Option<usize>,
 5910        intent: CompletionIntent,
 5911        window: &mut Window,
 5912        cx: &mut Context<Editor>,
 5913    ) -> Option<Task<Result<()>>> {
 5914        use language::ToOffset as _;
 5915
 5916        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5917        else {
 5918            return None;
 5919        };
 5920
 5921        let candidate_id = {
 5922            let entries = completions_menu.entries.borrow();
 5923            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5924            if self.show_edit_predictions_in_menu() {
 5925                self.discard_edit_prediction(true, cx);
 5926            }
 5927            mat.candidate_id
 5928        };
 5929
 5930        let completion = completions_menu
 5931            .completions
 5932            .borrow()
 5933            .get(candidate_id)?
 5934            .clone();
 5935        cx.stop_propagation();
 5936
 5937        let buffer_handle = completions_menu.buffer.clone();
 5938
 5939        let CompletionEdit {
 5940            new_text,
 5941            snippet,
 5942            replace_range,
 5943        } = process_completion_for_edit(
 5944            &completion,
 5945            intent,
 5946            &buffer_handle,
 5947            &completions_menu.initial_position.text_anchor,
 5948            cx,
 5949        );
 5950
 5951        let buffer = buffer_handle.read(cx);
 5952        let snapshot = self.buffer.read(cx).snapshot(cx);
 5953        let newest_anchor = self.selections.newest_anchor();
 5954        let replace_range_multibuffer = {
 5955            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5956            let multibuffer_anchor = snapshot
 5957                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5958                .unwrap()
 5959                ..snapshot
 5960                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5961                    .unwrap();
 5962            multibuffer_anchor.start.to_offset(&snapshot)
 5963                ..multibuffer_anchor.end.to_offset(&snapshot)
 5964        };
 5965        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5966            return None;
 5967        }
 5968
 5969        let old_text = buffer
 5970            .text_for_range(replace_range.clone())
 5971            .collect::<String>();
 5972        let lookbehind = newest_anchor
 5973            .start
 5974            .text_anchor
 5975            .to_offset(buffer)
 5976            .saturating_sub(replace_range.start);
 5977        let lookahead = replace_range
 5978            .end
 5979            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5980        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5981        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5982
 5983        let selections = self.selections.all::<usize>(cx);
 5984        let mut ranges = Vec::new();
 5985        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5986
 5987        for selection in &selections {
 5988            let range = if selection.id == newest_anchor.id {
 5989                replace_range_multibuffer.clone()
 5990            } else {
 5991                let mut range = selection.range();
 5992
 5993                // if prefix is present, don't duplicate it
 5994                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5995                    range.start = range.start.saturating_sub(lookbehind);
 5996
 5997                    // if suffix is also present, mimic the newest cursor and replace it
 5998                    if selection.id != newest_anchor.id
 5999                        && snapshot.contains_str_at(range.end, suffix)
 6000                    {
 6001                        range.end += lookahead;
 6002                    }
 6003                }
 6004                range
 6005            };
 6006
 6007            ranges.push(range.clone());
 6008
 6009            if !self.linked_edit_ranges.is_empty() {
 6010                let start_anchor = snapshot.anchor_before(range.start);
 6011                let end_anchor = snapshot.anchor_after(range.end);
 6012                if let Some(ranges) = self
 6013                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6014                {
 6015                    for (buffer, edits) in ranges {
 6016                        linked_edits
 6017                            .entry(buffer.clone())
 6018                            .or_default()
 6019                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6020                    }
 6021                }
 6022            }
 6023        }
 6024
 6025        let common_prefix_len = old_text
 6026            .chars()
 6027            .zip(new_text.chars())
 6028            .take_while(|(a, b)| a == b)
 6029            .map(|(a, _)| a.len_utf8())
 6030            .sum::<usize>();
 6031
 6032        cx.emit(EditorEvent::InputHandled {
 6033            utf16_range_to_replace: None,
 6034            text: new_text[common_prefix_len..].into(),
 6035        });
 6036
 6037        self.transact(window, cx, |editor, window, cx| {
 6038            if let Some(mut snippet) = snippet {
 6039                snippet.text = new_text.to_string();
 6040                editor
 6041                    .insert_snippet(&ranges, snippet, window, cx)
 6042                    .log_err();
 6043            } else {
 6044                editor.buffer.update(cx, |multi_buffer, cx| {
 6045                    let auto_indent = match completion.insert_text_mode {
 6046                        Some(InsertTextMode::AS_IS) => None,
 6047                        _ => editor.autoindent_mode.clone(),
 6048                    };
 6049                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6050                    multi_buffer.edit(edits, auto_indent, cx);
 6051                });
 6052            }
 6053            for (buffer, edits) in linked_edits {
 6054                buffer.update(cx, |buffer, cx| {
 6055                    let snapshot = buffer.snapshot();
 6056                    let edits = edits
 6057                        .into_iter()
 6058                        .map(|(range, text)| {
 6059                            use text::ToPoint as TP;
 6060                            let end_point = TP::to_point(&range.end, &snapshot);
 6061                            let start_point = TP::to_point(&range.start, &snapshot);
 6062                            (start_point..end_point, text)
 6063                        })
 6064                        .sorted_by_key(|(range, _)| range.start);
 6065                    buffer.edit(edits, None, cx);
 6066                })
 6067            }
 6068
 6069            editor.refresh_edit_prediction(true, false, window, cx);
 6070        });
 6071        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6072
 6073        let show_new_completions_on_confirm = completion
 6074            .confirm
 6075            .as_ref()
 6076            .is_some_and(|confirm| confirm(intent, window, cx));
 6077        if show_new_completions_on_confirm {
 6078            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6079        }
 6080
 6081        let provider = self.completion_provider.as_ref()?;
 6082        drop(completion);
 6083        let apply_edits = provider.apply_additional_edits_for_completion(
 6084            buffer_handle,
 6085            completions_menu.completions.clone(),
 6086            candidate_id,
 6087            true,
 6088            cx,
 6089        );
 6090
 6091        let editor_settings = EditorSettings::get_global(cx);
 6092        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6093            // After the code completion is finished, users often want to know what signatures are needed.
 6094            // so we should automatically call signature_help
 6095            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6096        }
 6097
 6098        Some(cx.foreground_executor().spawn(async move {
 6099            apply_edits.await?;
 6100            Ok(())
 6101        }))
 6102    }
 6103
 6104    pub fn toggle_code_actions(
 6105        &mut self,
 6106        action: &ToggleCodeActions,
 6107        window: &mut Window,
 6108        cx: &mut Context<Self>,
 6109    ) {
 6110        let quick_launch = action.quick_launch;
 6111        let mut context_menu = self.context_menu.borrow_mut();
 6112        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6113            if code_actions.deployed_from == action.deployed_from {
 6114                // Toggle if we're selecting the same one
 6115                *context_menu = None;
 6116                cx.notify();
 6117                return;
 6118            } else {
 6119                // Otherwise, clear it and start a new one
 6120                *context_menu = None;
 6121                cx.notify();
 6122            }
 6123        }
 6124        drop(context_menu);
 6125        let snapshot = self.snapshot(window, cx);
 6126        let deployed_from = action.deployed_from.clone();
 6127        let action = action.clone();
 6128        self.completion_tasks.clear();
 6129        self.discard_edit_prediction(false, cx);
 6130
 6131        let multibuffer_point = match &action.deployed_from {
 6132            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6133                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6134            }
 6135            _ => self.selections.newest::<Point>(cx).head(),
 6136        };
 6137        let Some((buffer, buffer_row)) = snapshot
 6138            .buffer_snapshot
 6139            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6140            .and_then(|(buffer_snapshot, range)| {
 6141                self.buffer()
 6142                    .read(cx)
 6143                    .buffer(buffer_snapshot.remote_id())
 6144                    .map(|buffer| (buffer, range.start.row))
 6145            })
 6146        else {
 6147            return;
 6148        };
 6149        let buffer_id = buffer.read(cx).remote_id();
 6150        let tasks = self
 6151            .tasks
 6152            .get(&(buffer_id, buffer_row))
 6153            .map(|t| Arc::new(t.to_owned()));
 6154
 6155        if !self.focus_handle.is_focused(window) {
 6156            return;
 6157        }
 6158        let project = self.project.clone();
 6159
 6160        let code_actions_task = match deployed_from {
 6161            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6162            _ => self.code_actions(buffer_row, window, cx),
 6163        };
 6164
 6165        let runnable_task = match deployed_from {
 6166            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6167            _ => {
 6168                let mut task_context_task = Task::ready(None);
 6169                if let Some(tasks) = &tasks
 6170                    && let Some(project) = project
 6171                {
 6172                    task_context_task =
 6173                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6174                }
 6175
 6176                cx.spawn_in(window, {
 6177                    let buffer = buffer.clone();
 6178                    async move |editor, cx| {
 6179                        let task_context = task_context_task.await;
 6180
 6181                        let resolved_tasks =
 6182                            tasks
 6183                                .zip(task_context.clone())
 6184                                .map(|(tasks, task_context)| ResolvedTasks {
 6185                                    templates: tasks.resolve(&task_context).collect(),
 6186                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6187                                        multibuffer_point.row,
 6188                                        tasks.column,
 6189                                    )),
 6190                                });
 6191                        let debug_scenarios = editor
 6192                            .update(cx, |editor, cx| {
 6193                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6194                            })?
 6195                            .await;
 6196                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6197                    }
 6198                })
 6199            }
 6200        };
 6201
 6202        cx.spawn_in(window, async move |editor, cx| {
 6203            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6204            let code_actions = code_actions_task.await;
 6205            let spawn_straight_away = quick_launch
 6206                && resolved_tasks
 6207                    .as_ref()
 6208                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6209                && code_actions
 6210                    .as_ref()
 6211                    .is_none_or(|actions| actions.is_empty())
 6212                && debug_scenarios.is_empty();
 6213
 6214            editor.update_in(cx, |editor, window, cx| {
 6215                crate::hover_popover::hide_hover(editor, cx);
 6216                let actions = CodeActionContents::new(
 6217                    resolved_tasks,
 6218                    code_actions,
 6219                    debug_scenarios,
 6220                    task_context.unwrap_or_default(),
 6221                );
 6222
 6223                // Don't show the menu if there are no actions available
 6224                if actions.is_empty() {
 6225                    cx.notify();
 6226                    return Task::ready(Ok(()));
 6227                }
 6228
 6229                *editor.context_menu.borrow_mut() =
 6230                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6231                        buffer,
 6232                        actions,
 6233                        selected_item: Default::default(),
 6234                        scroll_handle: UniformListScrollHandle::default(),
 6235                        deployed_from,
 6236                    }));
 6237                cx.notify();
 6238                if spawn_straight_away
 6239                    && let Some(task) = editor.confirm_code_action(
 6240                        &ConfirmCodeAction { item_ix: Some(0) },
 6241                        window,
 6242                        cx,
 6243                    )
 6244                {
 6245                    return task;
 6246                }
 6247
 6248                Task::ready(Ok(()))
 6249            })
 6250        })
 6251        .detach_and_log_err(cx);
 6252    }
 6253
 6254    fn debug_scenarios(
 6255        &mut self,
 6256        resolved_tasks: &Option<ResolvedTasks>,
 6257        buffer: &Entity<Buffer>,
 6258        cx: &mut App,
 6259    ) -> Task<Vec<task::DebugScenario>> {
 6260        maybe!({
 6261            let project = self.project()?;
 6262            let dap_store = project.read(cx).dap_store();
 6263            let mut scenarios = vec![];
 6264            let resolved_tasks = resolved_tasks.as_ref()?;
 6265            let buffer = buffer.read(cx);
 6266            let language = buffer.language()?;
 6267            let file = buffer.file();
 6268            let debug_adapter = language_settings(language.name().into(), file, cx)
 6269                .debuggers
 6270                .first()
 6271                .map(SharedString::from)
 6272                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6273
 6274            dap_store.update(cx, |dap_store, cx| {
 6275                for (_, task) in &resolved_tasks.templates {
 6276                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6277                        task.original_task().clone(),
 6278                        debug_adapter.clone().into(),
 6279                        task.display_label().to_owned().into(),
 6280                        cx,
 6281                    );
 6282                    scenarios.push(maybe_scenario);
 6283                }
 6284            });
 6285            Some(cx.background_spawn(async move {
 6286                futures::future::join_all(scenarios)
 6287                    .await
 6288                    .into_iter()
 6289                    .flatten()
 6290                    .collect::<Vec<_>>()
 6291            }))
 6292        })
 6293        .unwrap_or_else(|| Task::ready(vec![]))
 6294    }
 6295
 6296    fn code_actions(
 6297        &mut self,
 6298        buffer_row: u32,
 6299        window: &mut Window,
 6300        cx: &mut Context<Self>,
 6301    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6302        let mut task = self.code_actions_task.take();
 6303        cx.spawn_in(window, async move |editor, cx| {
 6304            while let Some(prev_task) = task {
 6305                prev_task.await.log_err();
 6306                task = editor
 6307                    .update(cx, |this, _| this.code_actions_task.take())
 6308                    .ok()?;
 6309            }
 6310
 6311            editor
 6312                .update(cx, |editor, cx| {
 6313                    editor
 6314                        .available_code_actions
 6315                        .clone()
 6316                        .and_then(|(location, code_actions)| {
 6317                            let snapshot = location.buffer.read(cx).snapshot();
 6318                            let point_range = location.range.to_point(&snapshot);
 6319                            let point_range = point_range.start.row..=point_range.end.row;
 6320                            if point_range.contains(&buffer_row) {
 6321                                Some(code_actions)
 6322                            } else {
 6323                                None
 6324                            }
 6325                        })
 6326                })
 6327                .ok()
 6328                .flatten()
 6329        })
 6330    }
 6331
 6332    pub fn confirm_code_action(
 6333        &mut self,
 6334        action: &ConfirmCodeAction,
 6335        window: &mut Window,
 6336        cx: &mut Context<Self>,
 6337    ) -> Option<Task<Result<()>>> {
 6338        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6339
 6340        let actions_menu =
 6341            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6342                menu
 6343            } else {
 6344                return None;
 6345            };
 6346
 6347        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6348        let action = actions_menu.actions.get(action_ix)?;
 6349        let title = action.label();
 6350        let buffer = actions_menu.buffer;
 6351        let workspace = self.workspace()?;
 6352
 6353        match action {
 6354            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6355                workspace.update(cx, |workspace, cx| {
 6356                    workspace.schedule_resolved_task(
 6357                        task_source_kind,
 6358                        resolved_task,
 6359                        false,
 6360                        window,
 6361                        cx,
 6362                    );
 6363
 6364                    Some(Task::ready(Ok(())))
 6365                })
 6366            }
 6367            CodeActionsItem::CodeAction {
 6368                excerpt_id,
 6369                action,
 6370                provider,
 6371            } => {
 6372                let apply_code_action =
 6373                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6374                let workspace = workspace.downgrade();
 6375                Some(cx.spawn_in(window, async move |editor, cx| {
 6376                    let project_transaction = apply_code_action.await?;
 6377                    Self::open_project_transaction(
 6378                        &editor,
 6379                        workspace,
 6380                        project_transaction,
 6381                        title,
 6382                        cx,
 6383                    )
 6384                    .await
 6385                }))
 6386            }
 6387            CodeActionsItem::DebugScenario(scenario) => {
 6388                let context = actions_menu.actions.context;
 6389
 6390                workspace.update(cx, |workspace, cx| {
 6391                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6392                    workspace.start_debug_session(
 6393                        scenario,
 6394                        context,
 6395                        Some(buffer),
 6396                        None,
 6397                        window,
 6398                        cx,
 6399                    );
 6400                });
 6401                Some(Task::ready(Ok(())))
 6402            }
 6403        }
 6404    }
 6405
 6406    pub async fn open_project_transaction(
 6407        editor: &WeakEntity<Editor>,
 6408        workspace: WeakEntity<Workspace>,
 6409        transaction: ProjectTransaction,
 6410        title: String,
 6411        cx: &mut AsyncWindowContext,
 6412    ) -> Result<()> {
 6413        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6414        cx.update(|_, cx| {
 6415            entries.sort_unstable_by_key(|(buffer, _)| {
 6416                buffer.read(cx).file().map(|f| f.path().clone())
 6417            });
 6418        })?;
 6419
 6420        // If the project transaction's edits are all contained within this editor, then
 6421        // avoid opening a new editor to display them.
 6422
 6423        if let Some((buffer, transaction)) = entries.first() {
 6424            if entries.len() == 1 {
 6425                let excerpt = editor.update(cx, |editor, cx| {
 6426                    editor
 6427                        .buffer()
 6428                        .read(cx)
 6429                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6430                })?;
 6431                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6432                    && excerpted_buffer == *buffer
 6433                {
 6434                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6435                        let excerpt_range = excerpt_range.to_offset(buffer);
 6436                        buffer
 6437                            .edited_ranges_for_transaction::<usize>(transaction)
 6438                            .all(|range| {
 6439                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6440                            })
 6441                    })?;
 6442
 6443                    if all_edits_within_excerpt {
 6444                        return Ok(());
 6445                    }
 6446                }
 6447            }
 6448        } else {
 6449            return Ok(());
 6450        }
 6451
 6452        let mut ranges_to_highlight = Vec::new();
 6453        let excerpt_buffer = cx.new(|cx| {
 6454            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6455            for (buffer_handle, transaction) in &entries {
 6456                let edited_ranges = buffer_handle
 6457                    .read(cx)
 6458                    .edited_ranges_for_transaction::<Point>(transaction)
 6459                    .collect::<Vec<_>>();
 6460                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6461                    PathKey::for_buffer(buffer_handle, cx),
 6462                    buffer_handle.clone(),
 6463                    edited_ranges,
 6464                    multibuffer_context_lines(cx),
 6465                    cx,
 6466                );
 6467
 6468                ranges_to_highlight.extend(ranges);
 6469            }
 6470            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6471            multibuffer
 6472        })?;
 6473
 6474        workspace.update_in(cx, |workspace, window, cx| {
 6475            let project = workspace.project().clone();
 6476            let editor =
 6477                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6478            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6479            editor.update(cx, |editor, cx| {
 6480                editor.highlight_background::<Self>(
 6481                    &ranges_to_highlight,
 6482                    |theme| theme.colors().editor_highlighted_line_background,
 6483                    cx,
 6484                );
 6485            });
 6486        })?;
 6487
 6488        Ok(())
 6489    }
 6490
 6491    pub fn clear_code_action_providers(&mut self) {
 6492        self.code_action_providers.clear();
 6493        self.available_code_actions.take();
 6494    }
 6495
 6496    pub fn add_code_action_provider(
 6497        &mut self,
 6498        provider: Rc<dyn CodeActionProvider>,
 6499        window: &mut Window,
 6500        cx: &mut Context<Self>,
 6501    ) {
 6502        if self
 6503            .code_action_providers
 6504            .iter()
 6505            .any(|existing_provider| existing_provider.id() == provider.id())
 6506        {
 6507            return;
 6508        }
 6509
 6510        self.code_action_providers.push(provider);
 6511        self.refresh_code_actions(window, cx);
 6512    }
 6513
 6514    pub fn remove_code_action_provider(
 6515        &mut self,
 6516        id: Arc<str>,
 6517        window: &mut Window,
 6518        cx: &mut Context<Self>,
 6519    ) {
 6520        self.code_action_providers
 6521            .retain(|provider| provider.id() != id);
 6522        self.refresh_code_actions(window, cx);
 6523    }
 6524
 6525    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6526        !self.code_action_providers.is_empty()
 6527            && EditorSettings::get_global(cx).toolbar.code_actions
 6528    }
 6529
 6530    pub fn has_available_code_actions(&self) -> bool {
 6531        self.available_code_actions
 6532            .as_ref()
 6533            .is_some_and(|(_, actions)| !actions.is_empty())
 6534    }
 6535
 6536    fn render_inline_code_actions(
 6537        &self,
 6538        icon_size: ui::IconSize,
 6539        display_row: DisplayRow,
 6540        is_active: bool,
 6541        cx: &mut Context<Self>,
 6542    ) -> AnyElement {
 6543        let show_tooltip = !self.context_menu_visible();
 6544        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6545            .icon_size(icon_size)
 6546            .shape(ui::IconButtonShape::Square)
 6547            .icon_color(ui::Color::Hidden)
 6548            .toggle_state(is_active)
 6549            .when(show_tooltip, |this| {
 6550                this.tooltip({
 6551                    let focus_handle = self.focus_handle.clone();
 6552                    move |window, cx| {
 6553                        Tooltip::for_action_in(
 6554                            "Toggle Code Actions",
 6555                            &ToggleCodeActions {
 6556                                deployed_from: None,
 6557                                quick_launch: false,
 6558                            },
 6559                            &focus_handle,
 6560                            window,
 6561                            cx,
 6562                        )
 6563                    }
 6564                })
 6565            })
 6566            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6567                window.focus(&editor.focus_handle(cx));
 6568                editor.toggle_code_actions(
 6569                    &crate::actions::ToggleCodeActions {
 6570                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6571                            display_row,
 6572                        )),
 6573                        quick_launch: false,
 6574                    },
 6575                    window,
 6576                    cx,
 6577                );
 6578            }))
 6579            .into_any_element()
 6580    }
 6581
 6582    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6583        &self.context_menu
 6584    }
 6585
 6586    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6587        let newest_selection = self.selections.newest_anchor().clone();
 6588        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6589        let buffer = self.buffer.read(cx);
 6590        if newest_selection.head().diff_base_anchor.is_some() {
 6591            return None;
 6592        }
 6593        let (start_buffer, start) =
 6594            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6595        let (end_buffer, end) =
 6596            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6597        if start_buffer != end_buffer {
 6598            return None;
 6599        }
 6600
 6601        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6602            cx.background_executor()
 6603                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6604                .await;
 6605
 6606            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6607                let providers = this.code_action_providers.clone();
 6608                let tasks = this
 6609                    .code_action_providers
 6610                    .iter()
 6611                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6612                    .collect::<Vec<_>>();
 6613                (providers, tasks)
 6614            })?;
 6615
 6616            let mut actions = Vec::new();
 6617            for (provider, provider_actions) in
 6618                providers.into_iter().zip(future::join_all(tasks).await)
 6619            {
 6620                if let Some(provider_actions) = provider_actions.log_err() {
 6621                    actions.extend(provider_actions.into_iter().map(|action| {
 6622                        AvailableCodeAction {
 6623                            excerpt_id: newest_selection.start.excerpt_id,
 6624                            action,
 6625                            provider: provider.clone(),
 6626                        }
 6627                    }));
 6628                }
 6629            }
 6630
 6631            this.update(cx, |this, cx| {
 6632                this.available_code_actions = if actions.is_empty() {
 6633                    None
 6634                } else {
 6635                    Some((
 6636                        Location {
 6637                            buffer: start_buffer,
 6638                            range: start..end,
 6639                        },
 6640                        actions.into(),
 6641                    ))
 6642                };
 6643                cx.notify();
 6644            })
 6645        }));
 6646        None
 6647    }
 6648
 6649    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6650        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6651            self.show_git_blame_inline = false;
 6652
 6653            self.show_git_blame_inline_delay_task =
 6654                Some(cx.spawn_in(window, async move |this, cx| {
 6655                    cx.background_executor().timer(delay).await;
 6656
 6657                    this.update(cx, |this, cx| {
 6658                        this.show_git_blame_inline = true;
 6659                        cx.notify();
 6660                    })
 6661                    .log_err();
 6662                }));
 6663        }
 6664    }
 6665
 6666    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6667        let snapshot = self.snapshot(window, cx);
 6668        let cursor = self.selections.newest::<Point>(cx).head();
 6669        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6670        else {
 6671            return;
 6672        };
 6673
 6674        let Some(blame) = self.blame.as_ref() else {
 6675            return;
 6676        };
 6677
 6678        let row_info = RowInfo {
 6679            buffer_id: Some(buffer.remote_id()),
 6680            buffer_row: Some(point.row),
 6681            ..Default::default()
 6682        };
 6683        let Some((buffer, blame_entry)) = blame
 6684            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6685            .flatten()
 6686        else {
 6687            return;
 6688        };
 6689
 6690        let anchor = self.selections.newest_anchor().head();
 6691        let position = self.to_pixel_point(anchor, &snapshot, window);
 6692        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6693            self.show_blame_popover(
 6694                buffer,
 6695                &blame_entry,
 6696                position + last_bounds.origin,
 6697                true,
 6698                cx,
 6699            );
 6700        };
 6701    }
 6702
 6703    fn show_blame_popover(
 6704        &mut self,
 6705        buffer: BufferId,
 6706        blame_entry: &BlameEntry,
 6707        position: gpui::Point<Pixels>,
 6708        ignore_timeout: bool,
 6709        cx: &mut Context<Self>,
 6710    ) {
 6711        if let Some(state) = &mut self.inline_blame_popover {
 6712            state.hide_task.take();
 6713        } else {
 6714            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6715            let blame_entry = blame_entry.clone();
 6716            let show_task = cx.spawn(async move |editor, cx| {
 6717                if !ignore_timeout {
 6718                    cx.background_executor()
 6719                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6720                        .await;
 6721                }
 6722                editor
 6723                    .update(cx, |editor, cx| {
 6724                        editor.inline_blame_popover_show_task.take();
 6725                        let Some(blame) = editor.blame.as_ref() else {
 6726                            return;
 6727                        };
 6728                        let blame = blame.read(cx);
 6729                        let details = blame.details_for_entry(buffer, &blame_entry);
 6730                        let markdown = cx.new(|cx| {
 6731                            Markdown::new(
 6732                                details
 6733                                    .as_ref()
 6734                                    .map(|message| message.message.clone())
 6735                                    .unwrap_or_default(),
 6736                                None,
 6737                                None,
 6738                                cx,
 6739                            )
 6740                        });
 6741                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6742                            position,
 6743                            hide_task: None,
 6744                            popover_bounds: None,
 6745                            popover_state: InlineBlamePopoverState {
 6746                                scroll_handle: ScrollHandle::new(),
 6747                                commit_message: details,
 6748                                markdown,
 6749                            },
 6750                            keyboard_grace: ignore_timeout,
 6751                        });
 6752                        cx.notify();
 6753                    })
 6754                    .ok();
 6755            });
 6756            self.inline_blame_popover_show_task = Some(show_task);
 6757        }
 6758    }
 6759
 6760    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6761        self.inline_blame_popover_show_task.take();
 6762        if let Some(state) = &mut self.inline_blame_popover {
 6763            let hide_task = cx.spawn(async move |editor, cx| {
 6764                cx.background_executor()
 6765                    .timer(std::time::Duration::from_millis(100))
 6766                    .await;
 6767                editor
 6768                    .update(cx, |editor, cx| {
 6769                        editor.inline_blame_popover.take();
 6770                        cx.notify();
 6771                    })
 6772                    .ok();
 6773            });
 6774            state.hide_task = Some(hide_task);
 6775        }
 6776    }
 6777
 6778    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6779        if self.pending_rename.is_some() {
 6780            return None;
 6781        }
 6782
 6783        let provider = self.semantics_provider.clone()?;
 6784        let buffer = self.buffer.read(cx);
 6785        let newest_selection = self.selections.newest_anchor().clone();
 6786        let cursor_position = newest_selection.head();
 6787        let (cursor_buffer, cursor_buffer_position) =
 6788            buffer.text_anchor_for_position(cursor_position, cx)?;
 6789        let (tail_buffer, tail_buffer_position) =
 6790            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6791        if cursor_buffer != tail_buffer {
 6792            return None;
 6793        }
 6794
 6795        let snapshot = cursor_buffer.read(cx).snapshot();
 6796        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6797        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6798        if start_word_range != end_word_range {
 6799            self.document_highlights_task.take();
 6800            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6801            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6802            return None;
 6803        }
 6804
 6805        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6806        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6807            cx.background_executor()
 6808                .timer(Duration::from_millis(debounce))
 6809                .await;
 6810
 6811            let highlights = if let Some(highlights) = cx
 6812                .update(|cx| {
 6813                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6814                })
 6815                .ok()
 6816                .flatten()
 6817            {
 6818                highlights.await.log_err()
 6819            } else {
 6820                None
 6821            };
 6822
 6823            if let Some(highlights) = highlights {
 6824                this.update(cx, |this, cx| {
 6825                    if this.pending_rename.is_some() {
 6826                        return;
 6827                    }
 6828
 6829                    let buffer = this.buffer.read(cx);
 6830                    if buffer
 6831                        .text_anchor_for_position(cursor_position, cx)
 6832                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6833                    {
 6834                        return;
 6835                    }
 6836
 6837                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6838                    let mut write_ranges = Vec::new();
 6839                    let mut read_ranges = Vec::new();
 6840                    for highlight in highlights {
 6841                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6842                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6843                        {
 6844                            let start = highlight
 6845                                .range
 6846                                .start
 6847                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6848                            let end = highlight
 6849                                .range
 6850                                .end
 6851                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6852                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6853                                continue;
 6854                            }
 6855
 6856                            let range = Anchor {
 6857                                buffer_id: Some(buffer_id),
 6858                                excerpt_id,
 6859                                text_anchor: start,
 6860                                diff_base_anchor: None,
 6861                            }..Anchor {
 6862                                buffer_id: Some(buffer_id),
 6863                                excerpt_id,
 6864                                text_anchor: end,
 6865                                diff_base_anchor: None,
 6866                            };
 6867                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6868                                write_ranges.push(range);
 6869                            } else {
 6870                                read_ranges.push(range);
 6871                            }
 6872                        }
 6873                    }
 6874
 6875                    this.highlight_background::<DocumentHighlightRead>(
 6876                        &read_ranges,
 6877                        |theme| theme.colors().editor_document_highlight_read_background,
 6878                        cx,
 6879                    );
 6880                    this.highlight_background::<DocumentHighlightWrite>(
 6881                        &write_ranges,
 6882                        |theme| theme.colors().editor_document_highlight_write_background,
 6883                        cx,
 6884                    );
 6885                    cx.notify();
 6886                })
 6887                .log_err();
 6888            }
 6889        }));
 6890        None
 6891    }
 6892
 6893    fn prepare_highlight_query_from_selection(
 6894        &mut self,
 6895        cx: &mut Context<Editor>,
 6896    ) -> Option<(String, Range<Anchor>)> {
 6897        if matches!(self.mode, EditorMode::SingleLine) {
 6898            return None;
 6899        }
 6900        if !EditorSettings::get_global(cx).selection_highlight {
 6901            return None;
 6902        }
 6903        if self.selections.count() != 1 || self.selections.line_mode() {
 6904            return None;
 6905        }
 6906        let selection = self.selections.newest::<Point>(cx);
 6907        if selection.is_empty() || selection.start.row != selection.end.row {
 6908            return None;
 6909        }
 6910        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6911        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6912        let query = multi_buffer_snapshot
 6913            .text_for_range(selection_anchor_range.clone())
 6914            .collect::<String>();
 6915        if query.trim().is_empty() {
 6916            return None;
 6917        }
 6918        Some((query, selection_anchor_range))
 6919    }
 6920
 6921    fn update_selection_occurrence_highlights(
 6922        &mut self,
 6923        query_text: String,
 6924        query_range: Range<Anchor>,
 6925        multi_buffer_range_to_query: Range<Point>,
 6926        use_debounce: bool,
 6927        window: &mut Window,
 6928        cx: &mut Context<Editor>,
 6929    ) -> Task<()> {
 6930        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6931        cx.spawn_in(window, async move |editor, cx| {
 6932            if use_debounce {
 6933                cx.background_executor()
 6934                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6935                    .await;
 6936            }
 6937            let match_task = cx.background_spawn(async move {
 6938                let buffer_ranges = multi_buffer_snapshot
 6939                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6940                    .into_iter()
 6941                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6942                let mut match_ranges = Vec::new();
 6943                let Ok(regex) = project::search::SearchQuery::text(
 6944                    query_text.clone(),
 6945                    false,
 6946                    false,
 6947                    false,
 6948                    Default::default(),
 6949                    Default::default(),
 6950                    false,
 6951                    None,
 6952                ) else {
 6953                    return Vec::default();
 6954                };
 6955                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6956                    match_ranges.extend(
 6957                        regex
 6958                            .search(buffer_snapshot, Some(search_range.clone()))
 6959                            .await
 6960                            .into_iter()
 6961                            .filter_map(|match_range| {
 6962                                let match_start = buffer_snapshot
 6963                                    .anchor_after(search_range.start + match_range.start);
 6964                                let match_end = buffer_snapshot
 6965                                    .anchor_before(search_range.start + match_range.end);
 6966                                let match_anchor_range = Anchor::range_in_buffer(
 6967                                    excerpt_id,
 6968                                    buffer_snapshot.remote_id(),
 6969                                    match_start..match_end,
 6970                                );
 6971                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6972                            }),
 6973                    );
 6974                }
 6975                match_ranges
 6976            });
 6977            let match_ranges = match_task.await;
 6978            editor
 6979                .update_in(cx, |editor, _, cx| {
 6980                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6981                    if !match_ranges.is_empty() {
 6982                        editor.highlight_background::<SelectedTextHighlight>(
 6983                            &match_ranges,
 6984                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6985                            cx,
 6986                        )
 6987                    }
 6988                })
 6989                .log_err();
 6990        })
 6991    }
 6992
 6993    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6994        struct NewlineFold;
 6995        let type_id = std::any::TypeId::of::<NewlineFold>();
 6996        if !self.mode.is_single_line() {
 6997            return;
 6998        }
 6999        let snapshot = self.snapshot(window, cx);
 7000        if snapshot.buffer_snapshot.max_point().row == 0 {
 7001            return;
 7002        }
 7003        let task = cx.background_spawn(async move {
 7004            let new_newlines = snapshot
 7005                .buffer_chars_at(0)
 7006                .filter_map(|(c, i)| {
 7007                    if c == '\n' {
 7008                        Some(
 7009                            snapshot.buffer_snapshot.anchor_after(i)
 7010                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7011                        )
 7012                    } else {
 7013                        None
 7014                    }
 7015                })
 7016                .collect::<Vec<_>>();
 7017            let existing_newlines = snapshot
 7018                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7019                .filter_map(|fold| {
 7020                    if fold.placeholder.type_tag == Some(type_id) {
 7021                        Some(fold.range.start..fold.range.end)
 7022                    } else {
 7023                        None
 7024                    }
 7025                })
 7026                .collect::<Vec<_>>();
 7027
 7028            (new_newlines, existing_newlines)
 7029        });
 7030        self.folding_newlines = cx.spawn(async move |this, cx| {
 7031            let (new_newlines, existing_newlines) = task.await;
 7032            if new_newlines == existing_newlines {
 7033                return;
 7034            }
 7035            let placeholder = FoldPlaceholder {
 7036                render: Arc::new(move |_, _, cx| {
 7037                    div()
 7038                        .bg(cx.theme().status().hint_background)
 7039                        .border_b_1()
 7040                        .size_full()
 7041                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7042                        .border_color(cx.theme().status().hint)
 7043                        .child("\\n")
 7044                        .into_any()
 7045                }),
 7046                constrain_width: false,
 7047                merge_adjacent: false,
 7048                type_tag: Some(type_id),
 7049            };
 7050            let creases = new_newlines
 7051                .into_iter()
 7052                .map(|range| Crease::simple(range, placeholder.clone()))
 7053                .collect();
 7054            this.update(cx, |this, cx| {
 7055                this.display_map.update(cx, |display_map, cx| {
 7056                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7057                    display_map.fold(creases, cx);
 7058                });
 7059            })
 7060            .ok();
 7061        });
 7062    }
 7063
 7064    fn refresh_selected_text_highlights(
 7065        &mut self,
 7066        on_buffer_edit: bool,
 7067        window: &mut Window,
 7068        cx: &mut Context<Editor>,
 7069    ) {
 7070        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7071        else {
 7072            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7073            self.quick_selection_highlight_task.take();
 7074            self.debounced_selection_highlight_task.take();
 7075            return;
 7076        };
 7077        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7078        if on_buffer_edit
 7079            || self
 7080                .quick_selection_highlight_task
 7081                .as_ref()
 7082                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7083        {
 7084            let multi_buffer_visible_start = self
 7085                .scroll_manager
 7086                .anchor()
 7087                .anchor
 7088                .to_point(&multi_buffer_snapshot);
 7089            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7090                multi_buffer_visible_start
 7091                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7092                Bias::Left,
 7093            );
 7094            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7095            self.quick_selection_highlight_task = Some((
 7096                query_range.clone(),
 7097                self.update_selection_occurrence_highlights(
 7098                    query_text.clone(),
 7099                    query_range.clone(),
 7100                    multi_buffer_visible_range,
 7101                    false,
 7102                    window,
 7103                    cx,
 7104                ),
 7105            ));
 7106        }
 7107        if on_buffer_edit
 7108            || self
 7109                .debounced_selection_highlight_task
 7110                .as_ref()
 7111                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7112        {
 7113            let multi_buffer_start = multi_buffer_snapshot
 7114                .anchor_before(0)
 7115                .to_point(&multi_buffer_snapshot);
 7116            let multi_buffer_end = multi_buffer_snapshot
 7117                .anchor_after(multi_buffer_snapshot.len())
 7118                .to_point(&multi_buffer_snapshot);
 7119            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7120            self.debounced_selection_highlight_task = Some((
 7121                query_range.clone(),
 7122                self.update_selection_occurrence_highlights(
 7123                    query_text,
 7124                    query_range,
 7125                    multi_buffer_full_range,
 7126                    true,
 7127                    window,
 7128                    cx,
 7129                ),
 7130            ));
 7131        }
 7132    }
 7133
 7134    pub fn refresh_edit_prediction(
 7135        &mut self,
 7136        debounce: bool,
 7137        user_requested: bool,
 7138        window: &mut Window,
 7139        cx: &mut Context<Self>,
 7140    ) -> Option<()> {
 7141        if DisableAiSettings::get_global(cx).disable_ai {
 7142            return None;
 7143        }
 7144
 7145        let provider = self.edit_prediction_provider()?;
 7146        let cursor = self.selections.newest_anchor().head();
 7147        let (buffer, cursor_buffer_position) =
 7148            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7149
 7150        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7151            self.discard_edit_prediction(false, cx);
 7152            return None;
 7153        }
 7154
 7155        self.update_visible_edit_prediction(window, cx);
 7156
 7157        if !user_requested
 7158            && (!self.should_show_edit_predictions()
 7159                || !self.is_focused(window)
 7160                || buffer.read(cx).is_empty())
 7161        {
 7162            self.discard_edit_prediction(false, cx);
 7163            return None;
 7164        }
 7165
 7166        provider.refresh(
 7167            self.project.clone(),
 7168            buffer,
 7169            cursor_buffer_position,
 7170            debounce,
 7171            cx,
 7172        );
 7173        Some(())
 7174    }
 7175
 7176    fn show_edit_predictions_in_menu(&self) -> bool {
 7177        match self.edit_prediction_settings {
 7178            EditPredictionSettings::Disabled => false,
 7179            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7180        }
 7181    }
 7182
 7183    pub fn edit_predictions_enabled(&self) -> bool {
 7184        match self.edit_prediction_settings {
 7185            EditPredictionSettings::Disabled => false,
 7186            EditPredictionSettings::Enabled { .. } => true,
 7187        }
 7188    }
 7189
 7190    fn edit_prediction_requires_modifier(&self) -> bool {
 7191        match self.edit_prediction_settings {
 7192            EditPredictionSettings::Disabled => false,
 7193            EditPredictionSettings::Enabled {
 7194                preview_requires_modifier,
 7195                ..
 7196            } => preview_requires_modifier,
 7197        }
 7198    }
 7199
 7200    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7201        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7202            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7203            self.discard_edit_prediction(false, cx);
 7204        } else {
 7205            let selection = self.selections.newest_anchor();
 7206            let cursor = selection.head();
 7207
 7208            if let Some((buffer, cursor_buffer_position)) =
 7209                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7210            {
 7211                self.edit_prediction_settings =
 7212                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7213            }
 7214        }
 7215    }
 7216
 7217    fn edit_prediction_settings_at_position(
 7218        &self,
 7219        buffer: &Entity<Buffer>,
 7220        buffer_position: language::Anchor,
 7221        cx: &App,
 7222    ) -> EditPredictionSettings {
 7223        if !self.mode.is_full()
 7224            || !self.show_edit_predictions_override.unwrap_or(true)
 7225            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7226        {
 7227            return EditPredictionSettings::Disabled;
 7228        }
 7229
 7230        let buffer = buffer.read(cx);
 7231
 7232        let file = buffer.file();
 7233
 7234        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7235            return EditPredictionSettings::Disabled;
 7236        };
 7237
 7238        let by_provider = matches!(
 7239            self.menu_edit_predictions_policy,
 7240            MenuEditPredictionsPolicy::ByProvider
 7241        );
 7242
 7243        let show_in_menu = by_provider
 7244            && self
 7245                .edit_prediction_provider
 7246                .as_ref()
 7247                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7248
 7249        let preview_requires_modifier =
 7250            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7251
 7252        EditPredictionSettings::Enabled {
 7253            show_in_menu,
 7254            preview_requires_modifier,
 7255        }
 7256    }
 7257
 7258    fn should_show_edit_predictions(&self) -> bool {
 7259        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7260    }
 7261
 7262    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7263        matches!(
 7264            self.edit_prediction_preview,
 7265            EditPredictionPreview::Active { .. }
 7266        )
 7267    }
 7268
 7269    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7270        let cursor = self.selections.newest_anchor().head();
 7271        if let Some((buffer, cursor_position)) =
 7272            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7273        {
 7274            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7275        } else {
 7276            false
 7277        }
 7278    }
 7279
 7280    pub fn supports_minimap(&self, cx: &App) -> bool {
 7281        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7282    }
 7283
 7284    fn edit_predictions_enabled_in_buffer(
 7285        &self,
 7286        buffer: &Entity<Buffer>,
 7287        buffer_position: language::Anchor,
 7288        cx: &App,
 7289    ) -> bool {
 7290        maybe!({
 7291            if self.read_only(cx) {
 7292                return Some(false);
 7293            }
 7294            let provider = self.edit_prediction_provider()?;
 7295            if !provider.is_enabled(buffer, buffer_position, cx) {
 7296                return Some(false);
 7297            }
 7298            let buffer = buffer.read(cx);
 7299            let Some(file) = buffer.file() else {
 7300                return Some(true);
 7301            };
 7302            let settings = all_language_settings(Some(file), cx);
 7303            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7304        })
 7305        .unwrap_or(false)
 7306    }
 7307
 7308    fn cycle_edit_prediction(
 7309        &mut self,
 7310        direction: Direction,
 7311        window: &mut Window,
 7312        cx: &mut Context<Self>,
 7313    ) -> Option<()> {
 7314        let provider = self.edit_prediction_provider()?;
 7315        let cursor = self.selections.newest_anchor().head();
 7316        let (buffer, cursor_buffer_position) =
 7317            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7318        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7319            return None;
 7320        }
 7321
 7322        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7323        self.update_visible_edit_prediction(window, cx);
 7324
 7325        Some(())
 7326    }
 7327
 7328    pub fn show_edit_prediction(
 7329        &mut self,
 7330        _: &ShowEditPrediction,
 7331        window: &mut Window,
 7332        cx: &mut Context<Self>,
 7333    ) {
 7334        if !self.has_active_edit_prediction() {
 7335            self.refresh_edit_prediction(false, true, window, cx);
 7336            return;
 7337        }
 7338
 7339        self.update_visible_edit_prediction(window, cx);
 7340    }
 7341
 7342    pub fn display_cursor_names(
 7343        &mut self,
 7344        _: &DisplayCursorNames,
 7345        window: &mut Window,
 7346        cx: &mut Context<Self>,
 7347    ) {
 7348        self.show_cursor_names(window, cx);
 7349    }
 7350
 7351    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7352        self.show_cursor_names = true;
 7353        cx.notify();
 7354        cx.spawn_in(window, async move |this, cx| {
 7355            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7356            this.update(cx, |this, cx| {
 7357                this.show_cursor_names = false;
 7358                cx.notify()
 7359            })
 7360            .ok()
 7361        })
 7362        .detach();
 7363    }
 7364
 7365    pub fn next_edit_prediction(
 7366        &mut self,
 7367        _: &NextEditPrediction,
 7368        window: &mut Window,
 7369        cx: &mut Context<Self>,
 7370    ) {
 7371        if self.has_active_edit_prediction() {
 7372            self.cycle_edit_prediction(Direction::Next, window, cx);
 7373        } else {
 7374            let is_copilot_disabled = self
 7375                .refresh_edit_prediction(false, true, window, cx)
 7376                .is_none();
 7377            if is_copilot_disabled {
 7378                cx.propagate();
 7379            }
 7380        }
 7381    }
 7382
 7383    pub fn previous_edit_prediction(
 7384        &mut self,
 7385        _: &PreviousEditPrediction,
 7386        window: &mut Window,
 7387        cx: &mut Context<Self>,
 7388    ) {
 7389        if self.has_active_edit_prediction() {
 7390            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7391        } else {
 7392            let is_copilot_disabled = self
 7393                .refresh_edit_prediction(false, true, window, cx)
 7394                .is_none();
 7395            if is_copilot_disabled {
 7396                cx.propagate();
 7397            }
 7398        }
 7399    }
 7400
 7401    pub fn accept_edit_prediction(
 7402        &mut self,
 7403        _: &AcceptEditPrediction,
 7404        window: &mut Window,
 7405        cx: &mut Context<Self>,
 7406    ) {
 7407        if self.show_edit_predictions_in_menu() {
 7408            self.hide_context_menu(window, cx);
 7409        }
 7410
 7411        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7412            return;
 7413        };
 7414
 7415        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7416
 7417        match &active_edit_prediction.completion {
 7418            EditPrediction::Move { target, .. } => {
 7419                let target = *target;
 7420
 7421                if let Some(position_map) = &self.last_position_map {
 7422                    if position_map
 7423                        .visible_row_range
 7424                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7425                        || !self.edit_prediction_requires_modifier()
 7426                    {
 7427                        self.unfold_ranges(&[target..target], true, false, cx);
 7428                        // Note that this is also done in vim's handler of the Tab action.
 7429                        self.change_selections(
 7430                            SelectionEffects::scroll(Autoscroll::newest()),
 7431                            window,
 7432                            cx,
 7433                            |selections| {
 7434                                selections.select_anchor_ranges([target..target]);
 7435                            },
 7436                        );
 7437                        self.clear_row_highlights::<EditPredictionPreview>();
 7438
 7439                        self.edit_prediction_preview
 7440                            .set_previous_scroll_position(None);
 7441                    } else {
 7442                        self.edit_prediction_preview
 7443                            .set_previous_scroll_position(Some(
 7444                                position_map.snapshot.scroll_anchor,
 7445                            ));
 7446
 7447                        self.highlight_rows::<EditPredictionPreview>(
 7448                            target..target,
 7449                            cx.theme().colors().editor_highlighted_line_background,
 7450                            RowHighlightOptions {
 7451                                autoscroll: true,
 7452                                ..Default::default()
 7453                            },
 7454                            cx,
 7455                        );
 7456                        self.request_autoscroll(Autoscroll::fit(), cx);
 7457                    }
 7458                }
 7459            }
 7460            EditPrediction::Edit { edits, .. } => {
 7461                if let Some(provider) = self.edit_prediction_provider() {
 7462                    provider.accept(cx);
 7463                }
 7464
 7465                // Store the transaction ID and selections before applying the edit
 7466                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7467
 7468                let snapshot = self.buffer.read(cx).snapshot(cx);
 7469                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7470
 7471                self.buffer.update(cx, |buffer, cx| {
 7472                    buffer.edit(edits.iter().cloned(), None, cx)
 7473                });
 7474
 7475                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7476                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7477                });
 7478
 7479                let selections = self.selections.disjoint_anchors_arc();
 7480                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7481                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7482                    if has_new_transaction {
 7483                        self.selection_history
 7484                            .insert_transaction(transaction_id_now, selections);
 7485                    }
 7486                }
 7487
 7488                self.update_visible_edit_prediction(window, cx);
 7489                if self.active_edit_prediction.is_none() {
 7490                    self.refresh_edit_prediction(true, true, window, cx);
 7491                }
 7492
 7493                cx.notify();
 7494            }
 7495        }
 7496
 7497        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7498    }
 7499
 7500    pub fn accept_partial_edit_prediction(
 7501        &mut self,
 7502        _: &AcceptPartialEditPrediction,
 7503        window: &mut Window,
 7504        cx: &mut Context<Self>,
 7505    ) {
 7506        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7507            return;
 7508        };
 7509        if self.selections.count() != 1 {
 7510            return;
 7511        }
 7512
 7513        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7514
 7515        match &active_edit_prediction.completion {
 7516            EditPrediction::Move { target, .. } => {
 7517                let target = *target;
 7518                self.change_selections(
 7519                    SelectionEffects::scroll(Autoscroll::newest()),
 7520                    window,
 7521                    cx,
 7522                    |selections| {
 7523                        selections.select_anchor_ranges([target..target]);
 7524                    },
 7525                );
 7526            }
 7527            EditPrediction::Edit { edits, .. } => {
 7528                // Find an insertion that starts at the cursor position.
 7529                let snapshot = self.buffer.read(cx).snapshot(cx);
 7530                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7531                let insertion = edits.iter().find_map(|(range, text)| {
 7532                    let range = range.to_offset(&snapshot);
 7533                    if range.is_empty() && range.start == cursor_offset {
 7534                        Some(text)
 7535                    } else {
 7536                        None
 7537                    }
 7538                });
 7539
 7540                if let Some(text) = insertion {
 7541                    let mut partial_completion = text
 7542                        .chars()
 7543                        .by_ref()
 7544                        .take_while(|c| c.is_alphabetic())
 7545                        .collect::<String>();
 7546                    if partial_completion.is_empty() {
 7547                        partial_completion = text
 7548                            .chars()
 7549                            .by_ref()
 7550                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7551                            .collect::<String>();
 7552                    }
 7553
 7554                    cx.emit(EditorEvent::InputHandled {
 7555                        utf16_range_to_replace: None,
 7556                        text: partial_completion.clone().into(),
 7557                    });
 7558
 7559                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7560
 7561                    self.refresh_edit_prediction(true, true, window, cx);
 7562                    cx.notify();
 7563                } else {
 7564                    self.accept_edit_prediction(&Default::default(), window, cx);
 7565                }
 7566            }
 7567        }
 7568    }
 7569
 7570    fn discard_edit_prediction(
 7571        &mut self,
 7572        should_report_edit_prediction_event: bool,
 7573        cx: &mut Context<Self>,
 7574    ) -> bool {
 7575        if should_report_edit_prediction_event {
 7576            let completion_id = self
 7577                .active_edit_prediction
 7578                .as_ref()
 7579                .and_then(|active_completion| active_completion.completion_id.clone());
 7580
 7581            self.report_edit_prediction_event(completion_id, false, cx);
 7582        }
 7583
 7584        if let Some(provider) = self.edit_prediction_provider() {
 7585            provider.discard(cx);
 7586        }
 7587
 7588        self.take_active_edit_prediction(cx)
 7589    }
 7590
 7591    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7592        let Some(provider) = self.edit_prediction_provider() else {
 7593            return;
 7594        };
 7595
 7596        let Some((_, buffer, _)) = self
 7597            .buffer
 7598            .read(cx)
 7599            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7600        else {
 7601            return;
 7602        };
 7603
 7604        let extension = buffer
 7605            .read(cx)
 7606            .file()
 7607            .and_then(|file| Some(file.path().extension()?.to_string()));
 7608
 7609        let event_type = match accepted {
 7610            true => "Edit Prediction Accepted",
 7611            false => "Edit Prediction Discarded",
 7612        };
 7613        telemetry::event!(
 7614            event_type,
 7615            provider = provider.name(),
 7616            prediction_id = id,
 7617            suggestion_accepted = accepted,
 7618            file_extension = extension,
 7619        );
 7620    }
 7621
 7622    pub fn has_active_edit_prediction(&self) -> bool {
 7623        self.active_edit_prediction.is_some()
 7624    }
 7625
 7626    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7627        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7628            return false;
 7629        };
 7630
 7631        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7632        self.clear_highlights::<EditPredictionHighlight>(cx);
 7633        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7634        true
 7635    }
 7636
 7637    /// Returns true when we're displaying the edit prediction popover below the cursor
 7638    /// like we are not previewing and the LSP autocomplete menu is visible
 7639    /// or we are in `when_holding_modifier` mode.
 7640    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7641        if self.edit_prediction_preview_is_active()
 7642            || !self.show_edit_predictions_in_menu()
 7643            || !self.edit_predictions_enabled()
 7644        {
 7645            return false;
 7646        }
 7647
 7648        if self.has_visible_completions_menu() {
 7649            return true;
 7650        }
 7651
 7652        has_completion && self.edit_prediction_requires_modifier()
 7653    }
 7654
 7655    fn handle_modifiers_changed(
 7656        &mut self,
 7657        modifiers: Modifiers,
 7658        position_map: &PositionMap,
 7659        window: &mut Window,
 7660        cx: &mut Context<Self>,
 7661    ) {
 7662        if self.show_edit_predictions_in_menu() {
 7663            self.update_edit_prediction_preview(&modifiers, window, cx);
 7664        }
 7665
 7666        self.update_selection_mode(&modifiers, position_map, window, cx);
 7667
 7668        let mouse_position = window.mouse_position();
 7669        if !position_map.text_hitbox.is_hovered(window) {
 7670            return;
 7671        }
 7672
 7673        self.update_hovered_link(
 7674            position_map.point_for_position(mouse_position),
 7675            &position_map.snapshot,
 7676            modifiers,
 7677            window,
 7678            cx,
 7679        )
 7680    }
 7681
 7682    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7683        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7684        if invert {
 7685            match multi_cursor_setting {
 7686                MultiCursorModifier::Alt => modifiers.alt,
 7687                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7688            }
 7689        } else {
 7690            match multi_cursor_setting {
 7691                MultiCursorModifier::Alt => modifiers.secondary(),
 7692                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7693            }
 7694        }
 7695    }
 7696
 7697    fn columnar_selection_mode(
 7698        modifiers: &Modifiers,
 7699        cx: &mut Context<Self>,
 7700    ) -> Option<ColumnarMode> {
 7701        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7702            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7703                Some(ColumnarMode::FromMouse)
 7704            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7705                Some(ColumnarMode::FromSelection)
 7706            } else {
 7707                None
 7708            }
 7709        } else {
 7710            None
 7711        }
 7712    }
 7713
 7714    fn update_selection_mode(
 7715        &mut self,
 7716        modifiers: &Modifiers,
 7717        position_map: &PositionMap,
 7718        window: &mut Window,
 7719        cx: &mut Context<Self>,
 7720    ) {
 7721        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7722            return;
 7723        };
 7724        if self.selections.pending_anchor().is_none() {
 7725            return;
 7726        }
 7727
 7728        let mouse_position = window.mouse_position();
 7729        let point_for_position = position_map.point_for_position(mouse_position);
 7730        let position = point_for_position.previous_valid;
 7731
 7732        self.select(
 7733            SelectPhase::BeginColumnar {
 7734                position,
 7735                reset: false,
 7736                mode,
 7737                goal_column: point_for_position.exact_unclipped.column(),
 7738            },
 7739            window,
 7740            cx,
 7741        );
 7742    }
 7743
 7744    fn update_edit_prediction_preview(
 7745        &mut self,
 7746        modifiers: &Modifiers,
 7747        window: &mut Window,
 7748        cx: &mut Context<Self>,
 7749    ) {
 7750        let mut modifiers_held = false;
 7751        if let Some(accept_keystroke) = self
 7752            .accept_edit_prediction_keybind(false, window, cx)
 7753            .keystroke()
 7754        {
 7755            modifiers_held = modifiers_held
 7756                || (accept_keystroke.modifiers() == modifiers
 7757                    && accept_keystroke.modifiers().modified());
 7758        };
 7759        if let Some(accept_partial_keystroke) = self
 7760            .accept_edit_prediction_keybind(true, window, cx)
 7761            .keystroke()
 7762        {
 7763            modifiers_held = modifiers_held
 7764                || (accept_partial_keystroke.modifiers() == modifiers
 7765                    && accept_partial_keystroke.modifiers().modified());
 7766        }
 7767
 7768        if modifiers_held {
 7769            if matches!(
 7770                self.edit_prediction_preview,
 7771                EditPredictionPreview::Inactive { .. }
 7772            ) {
 7773                self.edit_prediction_preview = EditPredictionPreview::Active {
 7774                    previous_scroll_position: None,
 7775                    since: Instant::now(),
 7776                };
 7777
 7778                self.update_visible_edit_prediction(window, cx);
 7779                cx.notify();
 7780            }
 7781        } else if let EditPredictionPreview::Active {
 7782            previous_scroll_position,
 7783            since,
 7784        } = self.edit_prediction_preview
 7785        {
 7786            if let (Some(previous_scroll_position), Some(position_map)) =
 7787                (previous_scroll_position, self.last_position_map.as_ref())
 7788            {
 7789                self.set_scroll_position(
 7790                    previous_scroll_position
 7791                        .scroll_position(&position_map.snapshot.display_snapshot),
 7792                    window,
 7793                    cx,
 7794                );
 7795            }
 7796
 7797            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7798                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7799            };
 7800            self.clear_row_highlights::<EditPredictionPreview>();
 7801            self.update_visible_edit_prediction(window, cx);
 7802            cx.notify();
 7803        }
 7804    }
 7805
 7806    fn update_visible_edit_prediction(
 7807        &mut self,
 7808        _window: &mut Window,
 7809        cx: &mut Context<Self>,
 7810    ) -> Option<()> {
 7811        if DisableAiSettings::get_global(cx).disable_ai {
 7812            return None;
 7813        }
 7814
 7815        if self.ime_transaction.is_some() {
 7816            self.discard_edit_prediction(false, cx);
 7817            return None;
 7818        }
 7819
 7820        let selection = self.selections.newest_anchor();
 7821        let cursor = selection.head();
 7822        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7823        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7824        let excerpt_id = cursor.excerpt_id;
 7825
 7826        let show_in_menu = self.show_edit_predictions_in_menu();
 7827        let completions_menu_has_precedence = !show_in_menu
 7828            && (self.context_menu.borrow().is_some()
 7829                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7830
 7831        if completions_menu_has_precedence
 7832            || !offset_selection.is_empty()
 7833            || self
 7834                .active_edit_prediction
 7835                .as_ref()
 7836                .is_some_and(|completion| {
 7837                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7838                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7839                    !invalidation_range.contains(&offset_selection.head())
 7840                })
 7841        {
 7842            self.discard_edit_prediction(false, cx);
 7843            return None;
 7844        }
 7845
 7846        self.take_active_edit_prediction(cx);
 7847        let Some(provider) = self.edit_prediction_provider() else {
 7848            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7849            return None;
 7850        };
 7851
 7852        let (buffer, cursor_buffer_position) =
 7853            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7854
 7855        self.edit_prediction_settings =
 7856            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7857
 7858        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7859
 7860        if self.edit_prediction_indent_conflict {
 7861            let cursor_point = cursor.to_point(&multibuffer);
 7862
 7863            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7864
 7865            if let Some((_, indent)) = indents.iter().next()
 7866                && indent.len == cursor_point.column
 7867            {
 7868                self.edit_prediction_indent_conflict = false;
 7869            }
 7870        }
 7871
 7872        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7873        let edits = edit_prediction
 7874            .edits
 7875            .into_iter()
 7876            .flat_map(|(range, new_text)| {
 7877                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7878                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7879                Some((start..end, new_text))
 7880            })
 7881            .collect::<Vec<_>>();
 7882        if edits.is_empty() {
 7883            return None;
 7884        }
 7885
 7886        let first_edit_start = edits.first().unwrap().0.start;
 7887        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7888        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7889
 7890        let last_edit_end = edits.last().unwrap().0.end;
 7891        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7892        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7893
 7894        let cursor_row = cursor.to_point(&multibuffer).row;
 7895
 7896        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7897
 7898        let mut inlay_ids = Vec::new();
 7899        let invalidation_row_range;
 7900        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7901            Some(cursor_row..edit_end_row)
 7902        } else if cursor_row > edit_end_row {
 7903            Some(edit_start_row..cursor_row)
 7904        } else {
 7905            None
 7906        };
 7907        let supports_jump = self
 7908            .edit_prediction_provider
 7909            .as_ref()
 7910            .map(|provider| provider.provider.supports_jump_to_edit())
 7911            .unwrap_or(true);
 7912
 7913        let is_move = supports_jump
 7914            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7915        let completion = if is_move {
 7916            invalidation_row_range =
 7917                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7918            let target = first_edit_start;
 7919            EditPrediction::Move { target, snapshot }
 7920        } else {
 7921            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7922                && !self.edit_predictions_hidden_for_vim_mode;
 7923
 7924            if show_completions_in_buffer {
 7925                if edits
 7926                    .iter()
 7927                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7928                {
 7929                    let mut inlays = Vec::new();
 7930                    for (range, new_text) in &edits {
 7931                        let inlay = Inlay::edit_prediction(
 7932                            post_inc(&mut self.next_inlay_id),
 7933                            range.start,
 7934                            new_text.as_str(),
 7935                        );
 7936                        inlay_ids.push(inlay.id);
 7937                        inlays.push(inlay);
 7938                    }
 7939
 7940                    self.splice_inlays(&[], inlays, cx);
 7941                } else {
 7942                    let background_color = cx.theme().status().deleted_background;
 7943                    self.highlight_text::<EditPredictionHighlight>(
 7944                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7945                        HighlightStyle {
 7946                            background_color: Some(background_color),
 7947                            ..Default::default()
 7948                        },
 7949                        cx,
 7950                    );
 7951                }
 7952            }
 7953
 7954            invalidation_row_range = edit_start_row..edit_end_row;
 7955
 7956            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7957                if provider.show_tab_accept_marker() {
 7958                    EditDisplayMode::TabAccept
 7959                } else {
 7960                    EditDisplayMode::Inline
 7961                }
 7962            } else {
 7963                EditDisplayMode::DiffPopover
 7964            };
 7965
 7966            EditPrediction::Edit {
 7967                edits,
 7968                edit_preview: edit_prediction.edit_preview,
 7969                display_mode,
 7970                snapshot,
 7971            }
 7972        };
 7973
 7974        let invalidation_range = multibuffer
 7975            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7976            ..multibuffer.anchor_after(Point::new(
 7977                invalidation_row_range.end,
 7978                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7979            ));
 7980
 7981        self.stale_edit_prediction_in_menu = None;
 7982        self.active_edit_prediction = Some(EditPredictionState {
 7983            inlay_ids,
 7984            completion,
 7985            completion_id: edit_prediction.id,
 7986            invalidation_range,
 7987        });
 7988
 7989        cx.notify();
 7990
 7991        Some(())
 7992    }
 7993
 7994    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7995        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7996    }
 7997
 7998    fn clear_tasks(&mut self) {
 7999        self.tasks.clear()
 8000    }
 8001
 8002    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8003        if self.tasks.insert(key, value).is_some() {
 8004            // This case should hopefully be rare, but just in case...
 8005            log::error!(
 8006                "multiple different run targets found on a single line, only the last target will be rendered"
 8007            )
 8008        }
 8009    }
 8010
 8011    /// Get all display points of breakpoints that will be rendered within editor
 8012    ///
 8013    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8014    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8015    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8016    fn active_breakpoints(
 8017        &self,
 8018        range: Range<DisplayRow>,
 8019        window: &mut Window,
 8020        cx: &mut Context<Self>,
 8021    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8022        let mut breakpoint_display_points = HashMap::default();
 8023
 8024        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8025            return breakpoint_display_points;
 8026        };
 8027
 8028        let snapshot = self.snapshot(window, cx);
 8029
 8030        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8031        let Some(project) = self.project() else {
 8032            return breakpoint_display_points;
 8033        };
 8034
 8035        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8036            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8037
 8038        for (buffer_snapshot, range, excerpt_id) in
 8039            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8040        {
 8041            let Some(buffer) = project
 8042                .read(cx)
 8043                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8044            else {
 8045                continue;
 8046            };
 8047            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8048                &buffer,
 8049                Some(
 8050                    buffer_snapshot.anchor_before(range.start)
 8051                        ..buffer_snapshot.anchor_after(range.end),
 8052                ),
 8053                buffer_snapshot,
 8054                cx,
 8055            );
 8056            for (breakpoint, state) in breakpoints {
 8057                let multi_buffer_anchor =
 8058                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8059                let position = multi_buffer_anchor
 8060                    .to_point(multi_buffer_snapshot)
 8061                    .to_display_point(&snapshot);
 8062
 8063                breakpoint_display_points.insert(
 8064                    position.row(),
 8065                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8066                );
 8067            }
 8068        }
 8069
 8070        breakpoint_display_points
 8071    }
 8072
 8073    fn breakpoint_context_menu(
 8074        &self,
 8075        anchor: Anchor,
 8076        window: &mut Window,
 8077        cx: &mut Context<Self>,
 8078    ) -> Entity<ui::ContextMenu> {
 8079        let weak_editor = cx.weak_entity();
 8080        let focus_handle = self.focus_handle(cx);
 8081
 8082        let row = self
 8083            .buffer
 8084            .read(cx)
 8085            .snapshot(cx)
 8086            .summary_for_anchor::<Point>(&anchor)
 8087            .row;
 8088
 8089        let breakpoint = self
 8090            .breakpoint_at_row(row, window, cx)
 8091            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8092
 8093        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8094            "Edit Log Breakpoint"
 8095        } else {
 8096            "Set Log Breakpoint"
 8097        };
 8098
 8099        let condition_breakpoint_msg = if breakpoint
 8100            .as_ref()
 8101            .is_some_and(|bp| bp.1.condition.is_some())
 8102        {
 8103            "Edit Condition Breakpoint"
 8104        } else {
 8105            "Set Condition Breakpoint"
 8106        };
 8107
 8108        let hit_condition_breakpoint_msg = if breakpoint
 8109            .as_ref()
 8110            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8111        {
 8112            "Edit Hit Condition Breakpoint"
 8113        } else {
 8114            "Set Hit Condition Breakpoint"
 8115        };
 8116
 8117        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8118            "Unset Breakpoint"
 8119        } else {
 8120            "Set Breakpoint"
 8121        };
 8122
 8123        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8124
 8125        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8126            BreakpointState::Enabled => Some("Disable"),
 8127            BreakpointState::Disabled => Some("Enable"),
 8128        });
 8129
 8130        let (anchor, breakpoint) =
 8131            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8132
 8133        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8134            menu.on_blur_subscription(Subscription::new(|| {}))
 8135                .context(focus_handle)
 8136                .when(run_to_cursor, |this| {
 8137                    let weak_editor = weak_editor.clone();
 8138                    this.entry("Run to cursor", None, move |window, cx| {
 8139                        weak_editor
 8140                            .update(cx, |editor, cx| {
 8141                                editor.change_selections(
 8142                                    SelectionEffects::no_scroll(),
 8143                                    window,
 8144                                    cx,
 8145                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8146                                );
 8147                            })
 8148                            .ok();
 8149
 8150                        window.dispatch_action(Box::new(RunToCursor), cx);
 8151                    })
 8152                    .separator()
 8153                })
 8154                .when_some(toggle_state_msg, |this, msg| {
 8155                    this.entry(msg, None, {
 8156                        let weak_editor = weak_editor.clone();
 8157                        let breakpoint = breakpoint.clone();
 8158                        move |_window, cx| {
 8159                            weak_editor
 8160                                .update(cx, |this, cx| {
 8161                                    this.edit_breakpoint_at_anchor(
 8162                                        anchor,
 8163                                        breakpoint.as_ref().clone(),
 8164                                        BreakpointEditAction::InvertState,
 8165                                        cx,
 8166                                    );
 8167                                })
 8168                                .log_err();
 8169                        }
 8170                    })
 8171                })
 8172                .entry(set_breakpoint_msg, None, {
 8173                    let weak_editor = weak_editor.clone();
 8174                    let breakpoint = breakpoint.clone();
 8175                    move |_window, cx| {
 8176                        weak_editor
 8177                            .update(cx, |this, cx| {
 8178                                this.edit_breakpoint_at_anchor(
 8179                                    anchor,
 8180                                    breakpoint.as_ref().clone(),
 8181                                    BreakpointEditAction::Toggle,
 8182                                    cx,
 8183                                );
 8184                            })
 8185                            .log_err();
 8186                    }
 8187                })
 8188                .entry(log_breakpoint_msg, None, {
 8189                    let breakpoint = breakpoint.clone();
 8190                    let weak_editor = weak_editor.clone();
 8191                    move |window, cx| {
 8192                        weak_editor
 8193                            .update(cx, |this, cx| {
 8194                                this.add_edit_breakpoint_block(
 8195                                    anchor,
 8196                                    breakpoint.as_ref(),
 8197                                    BreakpointPromptEditAction::Log,
 8198                                    window,
 8199                                    cx,
 8200                                );
 8201                            })
 8202                            .log_err();
 8203                    }
 8204                })
 8205                .entry(condition_breakpoint_msg, None, {
 8206                    let breakpoint = breakpoint.clone();
 8207                    let weak_editor = weak_editor.clone();
 8208                    move |window, cx| {
 8209                        weak_editor
 8210                            .update(cx, |this, cx| {
 8211                                this.add_edit_breakpoint_block(
 8212                                    anchor,
 8213                                    breakpoint.as_ref(),
 8214                                    BreakpointPromptEditAction::Condition,
 8215                                    window,
 8216                                    cx,
 8217                                );
 8218                            })
 8219                            .log_err();
 8220                    }
 8221                })
 8222                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8223                    weak_editor
 8224                        .update(cx, |this, cx| {
 8225                            this.add_edit_breakpoint_block(
 8226                                anchor,
 8227                                breakpoint.as_ref(),
 8228                                BreakpointPromptEditAction::HitCondition,
 8229                                window,
 8230                                cx,
 8231                            );
 8232                        })
 8233                        .log_err();
 8234                })
 8235        })
 8236    }
 8237
 8238    fn render_breakpoint(
 8239        &self,
 8240        position: Anchor,
 8241        row: DisplayRow,
 8242        breakpoint: &Breakpoint,
 8243        state: Option<BreakpointSessionState>,
 8244        cx: &mut Context<Self>,
 8245    ) -> IconButton {
 8246        let is_rejected = state.is_some_and(|s| !s.verified);
 8247        // Is it a breakpoint that shows up when hovering over gutter?
 8248        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8249            (false, false),
 8250            |PhantomBreakpointIndicator {
 8251                 is_active,
 8252                 display_row,
 8253                 collides_with_existing_breakpoint,
 8254             }| {
 8255                (
 8256                    is_active && display_row == row,
 8257                    collides_with_existing_breakpoint,
 8258                )
 8259            },
 8260        );
 8261
 8262        let (color, icon) = {
 8263            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8264                (false, false) => ui::IconName::DebugBreakpoint,
 8265                (true, false) => ui::IconName::DebugLogBreakpoint,
 8266                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8267                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8268            };
 8269
 8270            let color = if is_phantom {
 8271                Color::Hint
 8272            } else if is_rejected {
 8273                Color::Disabled
 8274            } else {
 8275                Color::Debugger
 8276            };
 8277
 8278            (color, icon)
 8279        };
 8280
 8281        let breakpoint = Arc::from(breakpoint.clone());
 8282
 8283        let alt_as_text = gpui::Keystroke {
 8284            modifiers: Modifiers::secondary_key(),
 8285            ..Default::default()
 8286        };
 8287        let primary_action_text = if breakpoint.is_disabled() {
 8288            "Enable breakpoint"
 8289        } else if is_phantom && !collides_with_existing {
 8290            "Set breakpoint"
 8291        } else {
 8292            "Unset breakpoint"
 8293        };
 8294        let focus_handle = self.focus_handle.clone();
 8295
 8296        let meta = if is_rejected {
 8297            SharedString::from("No executable code is associated with this line.")
 8298        } else if collides_with_existing && !breakpoint.is_disabled() {
 8299            SharedString::from(format!(
 8300                "{alt_as_text}-click to disable,\nright-click for more options."
 8301            ))
 8302        } else {
 8303            SharedString::from("Right-click for more options.")
 8304        };
 8305        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8306            .icon_size(IconSize::XSmall)
 8307            .size(ui::ButtonSize::None)
 8308            .when(is_rejected, |this| {
 8309                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8310            })
 8311            .icon_color(color)
 8312            .style(ButtonStyle::Transparent)
 8313            .on_click(cx.listener({
 8314                move |editor, event: &ClickEvent, window, cx| {
 8315                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8316                        BreakpointEditAction::InvertState
 8317                    } else {
 8318                        BreakpointEditAction::Toggle
 8319                    };
 8320
 8321                    window.focus(&editor.focus_handle(cx));
 8322                    editor.edit_breakpoint_at_anchor(
 8323                        position,
 8324                        breakpoint.as_ref().clone(),
 8325                        edit_action,
 8326                        cx,
 8327                    );
 8328                }
 8329            }))
 8330            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8331                editor.set_breakpoint_context_menu(
 8332                    row,
 8333                    Some(position),
 8334                    event.position(),
 8335                    window,
 8336                    cx,
 8337                );
 8338            }))
 8339            .tooltip(move |window, cx| {
 8340                Tooltip::with_meta_in(
 8341                    primary_action_text,
 8342                    Some(&ToggleBreakpoint),
 8343                    meta.clone(),
 8344                    &focus_handle,
 8345                    window,
 8346                    cx,
 8347                )
 8348            })
 8349    }
 8350
 8351    fn build_tasks_context(
 8352        project: &Entity<Project>,
 8353        buffer: &Entity<Buffer>,
 8354        buffer_row: u32,
 8355        tasks: &Arc<RunnableTasks>,
 8356        cx: &mut Context<Self>,
 8357    ) -> Task<Option<task::TaskContext>> {
 8358        let position = Point::new(buffer_row, tasks.column);
 8359        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8360        let location = Location {
 8361            buffer: buffer.clone(),
 8362            range: range_start..range_start,
 8363        };
 8364        // Fill in the environmental variables from the tree-sitter captures
 8365        let mut captured_task_variables = TaskVariables::default();
 8366        for (capture_name, value) in tasks.extra_variables.clone() {
 8367            captured_task_variables.insert(
 8368                task::VariableName::Custom(capture_name.into()),
 8369                value.clone(),
 8370            );
 8371        }
 8372        project.update(cx, |project, cx| {
 8373            project.task_store().update(cx, |task_store, cx| {
 8374                task_store.task_context_for_location(captured_task_variables, location, cx)
 8375            })
 8376        })
 8377    }
 8378
 8379    pub fn spawn_nearest_task(
 8380        &mut self,
 8381        action: &SpawnNearestTask,
 8382        window: &mut Window,
 8383        cx: &mut Context<Self>,
 8384    ) {
 8385        let Some((workspace, _)) = self.workspace.clone() else {
 8386            return;
 8387        };
 8388        let Some(project) = self.project.clone() else {
 8389            return;
 8390        };
 8391
 8392        // Try to find a closest, enclosing node using tree-sitter that has a task
 8393        let Some((buffer, buffer_row, tasks)) = self
 8394            .find_enclosing_node_task(cx)
 8395            // Or find the task that's closest in row-distance.
 8396            .or_else(|| self.find_closest_task(cx))
 8397        else {
 8398            return;
 8399        };
 8400
 8401        let reveal_strategy = action.reveal;
 8402        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8403        cx.spawn_in(window, async move |_, cx| {
 8404            let context = task_context.await?;
 8405            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8406
 8407            let resolved = &mut resolved_task.resolved;
 8408            resolved.reveal = reveal_strategy;
 8409
 8410            workspace
 8411                .update_in(cx, |workspace, window, cx| {
 8412                    workspace.schedule_resolved_task(
 8413                        task_source_kind,
 8414                        resolved_task,
 8415                        false,
 8416                        window,
 8417                        cx,
 8418                    );
 8419                })
 8420                .ok()
 8421        })
 8422        .detach();
 8423    }
 8424
 8425    fn find_closest_task(
 8426        &mut self,
 8427        cx: &mut Context<Self>,
 8428    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8429        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8430
 8431        let ((buffer_id, row), tasks) = self
 8432            .tasks
 8433            .iter()
 8434            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8435
 8436        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8437        let tasks = Arc::new(tasks.to_owned());
 8438        Some((buffer, *row, tasks))
 8439    }
 8440
 8441    fn find_enclosing_node_task(
 8442        &mut self,
 8443        cx: &mut Context<Self>,
 8444    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8445        let snapshot = self.buffer.read(cx).snapshot(cx);
 8446        let offset = self.selections.newest::<usize>(cx).head();
 8447        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8448        let buffer_id = excerpt.buffer().remote_id();
 8449
 8450        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8451        let mut cursor = layer.node().walk();
 8452
 8453        while cursor.goto_first_child_for_byte(offset).is_some() {
 8454            if cursor.node().end_byte() == offset {
 8455                cursor.goto_next_sibling();
 8456            }
 8457        }
 8458
 8459        // Ascend to the smallest ancestor that contains the range and has a task.
 8460        loop {
 8461            let node = cursor.node();
 8462            let node_range = node.byte_range();
 8463            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8464
 8465            // Check if this node contains our offset
 8466            if node_range.start <= offset && node_range.end >= offset {
 8467                // If it contains offset, check for task
 8468                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8469                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8470                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8471                }
 8472            }
 8473
 8474            if !cursor.goto_parent() {
 8475                break;
 8476            }
 8477        }
 8478        None
 8479    }
 8480
 8481    fn render_run_indicator(
 8482        &self,
 8483        _style: &EditorStyle,
 8484        is_active: bool,
 8485        row: DisplayRow,
 8486        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8487        cx: &mut Context<Self>,
 8488    ) -> IconButton {
 8489        let color = Color::Muted;
 8490        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8491
 8492        IconButton::new(
 8493            ("run_indicator", row.0 as usize),
 8494            ui::IconName::PlayOutlined,
 8495        )
 8496        .shape(ui::IconButtonShape::Square)
 8497        .icon_size(IconSize::XSmall)
 8498        .icon_color(color)
 8499        .toggle_state(is_active)
 8500        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8501            let quick_launch = match e {
 8502                ClickEvent::Keyboard(_) => true,
 8503                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8504            };
 8505
 8506            window.focus(&editor.focus_handle(cx));
 8507            editor.toggle_code_actions(
 8508                &ToggleCodeActions {
 8509                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8510                    quick_launch,
 8511                },
 8512                window,
 8513                cx,
 8514            );
 8515        }))
 8516        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8517            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8518        }))
 8519    }
 8520
 8521    pub fn context_menu_visible(&self) -> bool {
 8522        !self.edit_prediction_preview_is_active()
 8523            && self
 8524                .context_menu
 8525                .borrow()
 8526                .as_ref()
 8527                .is_some_and(|menu| menu.visible())
 8528    }
 8529
 8530    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8531        self.context_menu
 8532            .borrow()
 8533            .as_ref()
 8534            .map(|menu| menu.origin())
 8535    }
 8536
 8537    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8538        self.context_menu_options = Some(options);
 8539    }
 8540
 8541    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8542    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8543
 8544    fn render_edit_prediction_popover(
 8545        &mut self,
 8546        text_bounds: &Bounds<Pixels>,
 8547        content_origin: gpui::Point<Pixels>,
 8548        right_margin: Pixels,
 8549        editor_snapshot: &EditorSnapshot,
 8550        visible_row_range: Range<DisplayRow>,
 8551        scroll_top: f32,
 8552        scroll_bottom: f32,
 8553        line_layouts: &[LineWithInvisibles],
 8554        line_height: Pixels,
 8555        scroll_pixel_position: gpui::Point<Pixels>,
 8556        newest_selection_head: Option<DisplayPoint>,
 8557        editor_width: Pixels,
 8558        style: &EditorStyle,
 8559        window: &mut Window,
 8560        cx: &mut App,
 8561    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8562        if self.mode().is_minimap() {
 8563            return None;
 8564        }
 8565        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8566
 8567        if self.edit_prediction_visible_in_cursor_popover(true) {
 8568            return None;
 8569        }
 8570
 8571        match &active_edit_prediction.completion {
 8572            EditPrediction::Move { target, .. } => {
 8573                let target_display_point = target.to_display_point(editor_snapshot);
 8574
 8575                if self.edit_prediction_requires_modifier() {
 8576                    if !self.edit_prediction_preview_is_active() {
 8577                        return None;
 8578                    }
 8579
 8580                    self.render_edit_prediction_modifier_jump_popover(
 8581                        text_bounds,
 8582                        content_origin,
 8583                        visible_row_range,
 8584                        line_layouts,
 8585                        line_height,
 8586                        scroll_pixel_position,
 8587                        newest_selection_head,
 8588                        target_display_point,
 8589                        window,
 8590                        cx,
 8591                    )
 8592                } else {
 8593                    self.render_edit_prediction_eager_jump_popover(
 8594                        text_bounds,
 8595                        content_origin,
 8596                        editor_snapshot,
 8597                        visible_row_range,
 8598                        scroll_top,
 8599                        scroll_bottom,
 8600                        line_height,
 8601                        scroll_pixel_position,
 8602                        target_display_point,
 8603                        editor_width,
 8604                        window,
 8605                        cx,
 8606                    )
 8607                }
 8608            }
 8609            EditPrediction::Edit {
 8610                display_mode: EditDisplayMode::Inline,
 8611                ..
 8612            } => None,
 8613            EditPrediction::Edit {
 8614                display_mode: EditDisplayMode::TabAccept,
 8615                edits,
 8616                ..
 8617            } => {
 8618                let range = &edits.first()?.0;
 8619                let target_display_point = range.end.to_display_point(editor_snapshot);
 8620
 8621                self.render_edit_prediction_end_of_line_popover(
 8622                    "Accept",
 8623                    editor_snapshot,
 8624                    visible_row_range,
 8625                    target_display_point,
 8626                    line_height,
 8627                    scroll_pixel_position,
 8628                    content_origin,
 8629                    editor_width,
 8630                    window,
 8631                    cx,
 8632                )
 8633            }
 8634            EditPrediction::Edit {
 8635                edits,
 8636                edit_preview,
 8637                display_mode: EditDisplayMode::DiffPopover,
 8638                snapshot,
 8639            } => self.render_edit_prediction_diff_popover(
 8640                text_bounds,
 8641                content_origin,
 8642                right_margin,
 8643                editor_snapshot,
 8644                visible_row_range,
 8645                line_layouts,
 8646                line_height,
 8647                scroll_pixel_position,
 8648                newest_selection_head,
 8649                editor_width,
 8650                style,
 8651                edits,
 8652                edit_preview,
 8653                snapshot,
 8654                window,
 8655                cx,
 8656            ),
 8657        }
 8658    }
 8659
 8660    fn render_edit_prediction_modifier_jump_popover(
 8661        &mut self,
 8662        text_bounds: &Bounds<Pixels>,
 8663        content_origin: gpui::Point<Pixels>,
 8664        visible_row_range: Range<DisplayRow>,
 8665        line_layouts: &[LineWithInvisibles],
 8666        line_height: Pixels,
 8667        scroll_pixel_position: gpui::Point<Pixels>,
 8668        newest_selection_head: Option<DisplayPoint>,
 8669        target_display_point: DisplayPoint,
 8670        window: &mut Window,
 8671        cx: &mut App,
 8672    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8673        let scrolled_content_origin =
 8674            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8675
 8676        const SCROLL_PADDING_Y: Pixels = px(12.);
 8677
 8678        if target_display_point.row() < visible_row_range.start {
 8679            return self.render_edit_prediction_scroll_popover(
 8680                |_| SCROLL_PADDING_Y,
 8681                IconName::ArrowUp,
 8682                visible_row_range,
 8683                line_layouts,
 8684                newest_selection_head,
 8685                scrolled_content_origin,
 8686                window,
 8687                cx,
 8688            );
 8689        } else if target_display_point.row() >= visible_row_range.end {
 8690            return self.render_edit_prediction_scroll_popover(
 8691                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8692                IconName::ArrowDown,
 8693                visible_row_range,
 8694                line_layouts,
 8695                newest_selection_head,
 8696                scrolled_content_origin,
 8697                window,
 8698                cx,
 8699            );
 8700        }
 8701
 8702        const POLE_WIDTH: Pixels = px(2.);
 8703
 8704        let line_layout =
 8705            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8706        let target_column = target_display_point.column() as usize;
 8707
 8708        let target_x = line_layout.x_for_index(target_column);
 8709        let target_y =
 8710            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8711
 8712        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8713
 8714        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8715        border_color.l += 0.001;
 8716
 8717        let mut element = v_flex()
 8718            .items_end()
 8719            .when(flag_on_right, |el| el.items_start())
 8720            .child(if flag_on_right {
 8721                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8722                    .rounded_bl(px(0.))
 8723                    .rounded_tl(px(0.))
 8724                    .border_l_2()
 8725                    .border_color(border_color)
 8726            } else {
 8727                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8728                    .rounded_br(px(0.))
 8729                    .rounded_tr(px(0.))
 8730                    .border_r_2()
 8731                    .border_color(border_color)
 8732            })
 8733            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8734            .into_any();
 8735
 8736        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8737
 8738        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8739            - point(
 8740                if flag_on_right {
 8741                    POLE_WIDTH
 8742                } else {
 8743                    size.width - POLE_WIDTH
 8744                },
 8745                size.height - line_height,
 8746            );
 8747
 8748        origin.x = origin.x.max(content_origin.x);
 8749
 8750        element.prepaint_at(origin, window, cx);
 8751
 8752        Some((element, origin))
 8753    }
 8754
 8755    fn render_edit_prediction_scroll_popover(
 8756        &mut self,
 8757        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8758        scroll_icon: IconName,
 8759        visible_row_range: Range<DisplayRow>,
 8760        line_layouts: &[LineWithInvisibles],
 8761        newest_selection_head: Option<DisplayPoint>,
 8762        scrolled_content_origin: gpui::Point<Pixels>,
 8763        window: &mut Window,
 8764        cx: &mut App,
 8765    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8766        let mut element = self
 8767            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8768            .into_any();
 8769
 8770        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8771
 8772        let cursor = newest_selection_head?;
 8773        let cursor_row_layout =
 8774            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8775        let cursor_column = cursor.column() as usize;
 8776
 8777        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8778
 8779        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8780
 8781        element.prepaint_at(origin, window, cx);
 8782        Some((element, origin))
 8783    }
 8784
 8785    fn render_edit_prediction_eager_jump_popover(
 8786        &mut self,
 8787        text_bounds: &Bounds<Pixels>,
 8788        content_origin: gpui::Point<Pixels>,
 8789        editor_snapshot: &EditorSnapshot,
 8790        visible_row_range: Range<DisplayRow>,
 8791        scroll_top: f32,
 8792        scroll_bottom: f32,
 8793        line_height: Pixels,
 8794        scroll_pixel_position: gpui::Point<Pixels>,
 8795        target_display_point: DisplayPoint,
 8796        editor_width: Pixels,
 8797        window: &mut Window,
 8798        cx: &mut App,
 8799    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8800        if target_display_point.row().as_f32() < scroll_top {
 8801            let mut element = self
 8802                .render_edit_prediction_line_popover(
 8803                    "Jump to Edit",
 8804                    Some(IconName::ArrowUp),
 8805                    window,
 8806                    cx,
 8807                )?
 8808                .into_any();
 8809
 8810            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8811            let offset = point(
 8812                (text_bounds.size.width - size.width) / 2.,
 8813                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8814            );
 8815
 8816            let origin = text_bounds.origin + offset;
 8817            element.prepaint_at(origin, window, cx);
 8818            Some((element, origin))
 8819        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8820            let mut element = self
 8821                .render_edit_prediction_line_popover(
 8822                    "Jump to Edit",
 8823                    Some(IconName::ArrowDown),
 8824                    window,
 8825                    cx,
 8826                )?
 8827                .into_any();
 8828
 8829            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8830            let offset = point(
 8831                (text_bounds.size.width - size.width) / 2.,
 8832                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8833            );
 8834
 8835            let origin = text_bounds.origin + offset;
 8836            element.prepaint_at(origin, window, cx);
 8837            Some((element, origin))
 8838        } else {
 8839            self.render_edit_prediction_end_of_line_popover(
 8840                "Jump to Edit",
 8841                editor_snapshot,
 8842                visible_row_range,
 8843                target_display_point,
 8844                line_height,
 8845                scroll_pixel_position,
 8846                content_origin,
 8847                editor_width,
 8848                window,
 8849                cx,
 8850            )
 8851        }
 8852    }
 8853
 8854    fn render_edit_prediction_end_of_line_popover(
 8855        self: &mut Editor,
 8856        label: &'static str,
 8857        editor_snapshot: &EditorSnapshot,
 8858        visible_row_range: Range<DisplayRow>,
 8859        target_display_point: DisplayPoint,
 8860        line_height: Pixels,
 8861        scroll_pixel_position: gpui::Point<Pixels>,
 8862        content_origin: gpui::Point<Pixels>,
 8863        editor_width: Pixels,
 8864        window: &mut Window,
 8865        cx: &mut App,
 8866    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8867        let target_line_end = DisplayPoint::new(
 8868            target_display_point.row(),
 8869            editor_snapshot.line_len(target_display_point.row()),
 8870        );
 8871
 8872        let mut element = self
 8873            .render_edit_prediction_line_popover(label, None, window, cx)?
 8874            .into_any();
 8875
 8876        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8877
 8878        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8879
 8880        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8881        let mut origin = start_point
 8882            + line_origin
 8883            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8884        origin.x = origin.x.max(content_origin.x);
 8885
 8886        let max_x = content_origin.x + editor_width - size.width;
 8887
 8888        if origin.x > max_x {
 8889            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8890
 8891            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8892                origin.y += offset;
 8893                IconName::ArrowUp
 8894            } else {
 8895                origin.y -= offset;
 8896                IconName::ArrowDown
 8897            };
 8898
 8899            element = self
 8900                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8901                .into_any();
 8902
 8903            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8904
 8905            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8906        }
 8907
 8908        element.prepaint_at(origin, window, cx);
 8909        Some((element, origin))
 8910    }
 8911
 8912    fn render_edit_prediction_diff_popover(
 8913        self: &Editor,
 8914        text_bounds: &Bounds<Pixels>,
 8915        content_origin: gpui::Point<Pixels>,
 8916        right_margin: Pixels,
 8917        editor_snapshot: &EditorSnapshot,
 8918        visible_row_range: Range<DisplayRow>,
 8919        line_layouts: &[LineWithInvisibles],
 8920        line_height: Pixels,
 8921        scroll_pixel_position: gpui::Point<Pixels>,
 8922        newest_selection_head: Option<DisplayPoint>,
 8923        editor_width: Pixels,
 8924        style: &EditorStyle,
 8925        edits: &Vec<(Range<Anchor>, String)>,
 8926        edit_preview: &Option<language::EditPreview>,
 8927        snapshot: &language::BufferSnapshot,
 8928        window: &mut Window,
 8929        cx: &mut App,
 8930    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8931        let edit_start = edits
 8932            .first()
 8933            .unwrap()
 8934            .0
 8935            .start
 8936            .to_display_point(editor_snapshot);
 8937        let edit_end = edits
 8938            .last()
 8939            .unwrap()
 8940            .0
 8941            .end
 8942            .to_display_point(editor_snapshot);
 8943
 8944        let is_visible = visible_row_range.contains(&edit_start.row())
 8945            || visible_row_range.contains(&edit_end.row());
 8946        if !is_visible {
 8947            return None;
 8948        }
 8949
 8950        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8951            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8952        } else {
 8953            // Fallback for providers without edit_preview
 8954            crate::edit_prediction_fallback_text(edits, cx)
 8955        };
 8956
 8957        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8958        let line_count = highlighted_edits.text.lines().count();
 8959
 8960        const BORDER_WIDTH: Pixels = px(1.);
 8961
 8962        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8963        let has_keybind = keybind.is_some();
 8964
 8965        let mut element = h_flex()
 8966            .items_start()
 8967            .child(
 8968                h_flex()
 8969                    .bg(cx.theme().colors().editor_background)
 8970                    .border(BORDER_WIDTH)
 8971                    .shadow_xs()
 8972                    .border_color(cx.theme().colors().border)
 8973                    .rounded_l_lg()
 8974                    .when(line_count > 1, |el| el.rounded_br_lg())
 8975                    .pr_1()
 8976                    .child(styled_text),
 8977            )
 8978            .child(
 8979                h_flex()
 8980                    .h(line_height + BORDER_WIDTH * 2.)
 8981                    .px_1p5()
 8982                    .gap_1()
 8983                    // Workaround: For some reason, there's a gap if we don't do this
 8984                    .ml(-BORDER_WIDTH)
 8985                    .shadow(vec![gpui::BoxShadow {
 8986                        color: gpui::black().opacity(0.05),
 8987                        offset: point(px(1.), px(1.)),
 8988                        blur_radius: px(2.),
 8989                        spread_radius: px(0.),
 8990                    }])
 8991                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8992                    .border(BORDER_WIDTH)
 8993                    .border_color(cx.theme().colors().border)
 8994                    .rounded_r_lg()
 8995                    .id("edit_prediction_diff_popover_keybind")
 8996                    .when(!has_keybind, |el| {
 8997                        let status_colors = cx.theme().status();
 8998
 8999                        el.bg(status_colors.error_background)
 9000                            .border_color(status_colors.error.opacity(0.6))
 9001                            .child(Icon::new(IconName::Info).color(Color::Error))
 9002                            .cursor_default()
 9003                            .hoverable_tooltip(move |_window, cx| {
 9004                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9005                            })
 9006                    })
 9007                    .children(keybind),
 9008            )
 9009            .into_any();
 9010
 9011        let longest_row =
 9012            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9013        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9014            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9015        } else {
 9016            layout_line(
 9017                longest_row,
 9018                editor_snapshot,
 9019                style,
 9020                editor_width,
 9021                |_| false,
 9022                window,
 9023                cx,
 9024            )
 9025            .width
 9026        };
 9027
 9028        let viewport_bounds =
 9029            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9030                right: -right_margin,
 9031                ..Default::default()
 9032            });
 9033
 9034        let x_after_longest =
 9035            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9036                - scroll_pixel_position.x;
 9037
 9038        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9039
 9040        // Fully visible if it can be displayed within the window (allow overlapping other
 9041        // panes). However, this is only allowed if the popover starts within text_bounds.
 9042        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9043            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9044
 9045        let mut origin = if can_position_to_the_right {
 9046            point(
 9047                x_after_longest,
 9048                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9049                    - scroll_pixel_position.y,
 9050            )
 9051        } else {
 9052            let cursor_row = newest_selection_head.map(|head| head.row());
 9053            let above_edit = edit_start
 9054                .row()
 9055                .0
 9056                .checked_sub(line_count as u32)
 9057                .map(DisplayRow);
 9058            let below_edit = Some(edit_end.row() + 1);
 9059            let above_cursor =
 9060                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9061            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9062
 9063            // Place the edit popover adjacent to the edit if there is a location
 9064            // available that is onscreen and does not obscure the cursor. Otherwise,
 9065            // place it adjacent to the cursor.
 9066            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9067                .into_iter()
 9068                .flatten()
 9069                .find(|&start_row| {
 9070                    let end_row = start_row + line_count as u32;
 9071                    visible_row_range.contains(&start_row)
 9072                        && visible_row_range.contains(&end_row)
 9073                        && cursor_row
 9074                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9075                })?;
 9076
 9077            content_origin
 9078                + point(
 9079                    -scroll_pixel_position.x,
 9080                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9081                )
 9082        };
 9083
 9084        origin.x -= BORDER_WIDTH;
 9085
 9086        window.defer_draw(element, origin, 1);
 9087
 9088        // Do not return an element, since it will already be drawn due to defer_draw.
 9089        None
 9090    }
 9091
 9092    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9093        px(30.)
 9094    }
 9095
 9096    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9097        if self.read_only(cx) {
 9098            cx.theme().players().read_only()
 9099        } else {
 9100            self.style.as_ref().unwrap().local_player
 9101        }
 9102    }
 9103
 9104    fn render_edit_prediction_accept_keybind(
 9105        &self,
 9106        window: &mut Window,
 9107        cx: &App,
 9108    ) -> Option<AnyElement> {
 9109        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9110        let accept_keystroke = accept_binding.keystroke()?;
 9111
 9112        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9113
 9114        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9115            Color::Accent
 9116        } else {
 9117            Color::Muted
 9118        };
 9119
 9120        h_flex()
 9121            .px_0p5()
 9122            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9123            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9124            .text_size(TextSize::XSmall.rems(cx))
 9125            .child(h_flex().children(ui::render_modifiers(
 9126                accept_keystroke.modifiers(),
 9127                PlatformStyle::platform(),
 9128                Some(modifiers_color),
 9129                Some(IconSize::XSmall.rems().into()),
 9130                true,
 9131            )))
 9132            .when(is_platform_style_mac, |parent| {
 9133                parent.child(accept_keystroke.key().to_string())
 9134            })
 9135            .when(!is_platform_style_mac, |parent| {
 9136                parent.child(
 9137                    Key::new(
 9138                        util::capitalize(accept_keystroke.key()),
 9139                        Some(Color::Default),
 9140                    )
 9141                    .size(Some(IconSize::XSmall.rems().into())),
 9142                )
 9143            })
 9144            .into_any()
 9145            .into()
 9146    }
 9147
 9148    fn render_edit_prediction_line_popover(
 9149        &self,
 9150        label: impl Into<SharedString>,
 9151        icon: Option<IconName>,
 9152        window: &mut Window,
 9153        cx: &App,
 9154    ) -> Option<Stateful<Div>> {
 9155        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9156
 9157        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9158        let has_keybind = keybind.is_some();
 9159
 9160        let result = h_flex()
 9161            .id("ep-line-popover")
 9162            .py_0p5()
 9163            .pl_1()
 9164            .pr(padding_right)
 9165            .gap_1()
 9166            .rounded_md()
 9167            .border_1()
 9168            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9169            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9170            .shadow_xs()
 9171            .when(!has_keybind, |el| {
 9172                let status_colors = cx.theme().status();
 9173
 9174                el.bg(status_colors.error_background)
 9175                    .border_color(status_colors.error.opacity(0.6))
 9176                    .pl_2()
 9177                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9178                    .cursor_default()
 9179                    .hoverable_tooltip(move |_window, cx| {
 9180                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9181                    })
 9182            })
 9183            .children(keybind)
 9184            .child(
 9185                Label::new(label)
 9186                    .size(LabelSize::Small)
 9187                    .when(!has_keybind, |el| {
 9188                        el.color(cx.theme().status().error.into()).strikethrough()
 9189                    }),
 9190            )
 9191            .when(!has_keybind, |el| {
 9192                el.child(
 9193                    h_flex().ml_1().child(
 9194                        Icon::new(IconName::Info)
 9195                            .size(IconSize::Small)
 9196                            .color(cx.theme().status().error.into()),
 9197                    ),
 9198                )
 9199            })
 9200            .when_some(icon, |element, icon| {
 9201                element.child(
 9202                    div()
 9203                        .mt(px(1.5))
 9204                        .child(Icon::new(icon).size(IconSize::Small)),
 9205                )
 9206            });
 9207
 9208        Some(result)
 9209    }
 9210
 9211    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9212        let accent_color = cx.theme().colors().text_accent;
 9213        let editor_bg_color = cx.theme().colors().editor_background;
 9214        editor_bg_color.blend(accent_color.opacity(0.1))
 9215    }
 9216
 9217    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9218        let accent_color = cx.theme().colors().text_accent;
 9219        let editor_bg_color = cx.theme().colors().editor_background;
 9220        editor_bg_color.blend(accent_color.opacity(0.6))
 9221    }
 9222    fn get_prediction_provider_icon_name(
 9223        provider: &Option<RegisteredEditPredictionProvider>,
 9224    ) -> IconName {
 9225        match provider {
 9226            Some(provider) => match provider.provider.name() {
 9227                "copilot" => IconName::Copilot,
 9228                "supermaven" => IconName::Supermaven,
 9229                _ => IconName::ZedPredict,
 9230            },
 9231            None => IconName::ZedPredict,
 9232        }
 9233    }
 9234
 9235    fn render_edit_prediction_cursor_popover(
 9236        &self,
 9237        min_width: Pixels,
 9238        max_width: Pixels,
 9239        cursor_point: Point,
 9240        style: &EditorStyle,
 9241        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9242        _window: &Window,
 9243        cx: &mut Context<Editor>,
 9244    ) -> Option<AnyElement> {
 9245        let provider = self.edit_prediction_provider.as_ref()?;
 9246        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9247
 9248        let is_refreshing = provider.provider.is_refreshing(cx);
 9249
 9250        fn pending_completion_container(icon: IconName) -> Div {
 9251            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9252        }
 9253
 9254        let completion = match &self.active_edit_prediction {
 9255            Some(prediction) => {
 9256                if !self.has_visible_completions_menu() {
 9257                    const RADIUS: Pixels = px(6.);
 9258                    const BORDER_WIDTH: Pixels = px(1.);
 9259
 9260                    return Some(
 9261                        h_flex()
 9262                            .elevation_2(cx)
 9263                            .border(BORDER_WIDTH)
 9264                            .border_color(cx.theme().colors().border)
 9265                            .when(accept_keystroke.is_none(), |el| {
 9266                                el.border_color(cx.theme().status().error)
 9267                            })
 9268                            .rounded(RADIUS)
 9269                            .rounded_tl(px(0.))
 9270                            .overflow_hidden()
 9271                            .child(div().px_1p5().child(match &prediction.completion {
 9272                                EditPrediction::Move { target, snapshot } => {
 9273                                    use text::ToPoint as _;
 9274                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9275                                    {
 9276                                        Icon::new(IconName::ZedPredictDown)
 9277                                    } else {
 9278                                        Icon::new(IconName::ZedPredictUp)
 9279                                    }
 9280                                }
 9281                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9282                            }))
 9283                            .child(
 9284                                h_flex()
 9285                                    .gap_1()
 9286                                    .py_1()
 9287                                    .px_2()
 9288                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9289                                    .border_l_1()
 9290                                    .border_color(cx.theme().colors().border)
 9291                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9292                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9293                                        el.child(
 9294                                            Label::new("Hold")
 9295                                                .size(LabelSize::Small)
 9296                                                .when(accept_keystroke.is_none(), |el| {
 9297                                                    el.strikethrough()
 9298                                                })
 9299                                                .line_height_style(LineHeightStyle::UiLabel),
 9300                                        )
 9301                                    })
 9302                                    .id("edit_prediction_cursor_popover_keybind")
 9303                                    .when(accept_keystroke.is_none(), |el| {
 9304                                        let status_colors = cx.theme().status();
 9305
 9306                                        el.bg(status_colors.error_background)
 9307                                            .border_color(status_colors.error.opacity(0.6))
 9308                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9309                                            .cursor_default()
 9310                                            .hoverable_tooltip(move |_window, cx| {
 9311                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9312                                                    .into()
 9313                                            })
 9314                                    })
 9315                                    .when_some(
 9316                                        accept_keystroke.as_ref(),
 9317                                        |el, accept_keystroke| {
 9318                                            el.child(h_flex().children(ui::render_modifiers(
 9319                                                accept_keystroke.modifiers(),
 9320                                                PlatformStyle::platform(),
 9321                                                Some(Color::Default),
 9322                                                Some(IconSize::XSmall.rems().into()),
 9323                                                false,
 9324                                            )))
 9325                                        },
 9326                                    ),
 9327                            )
 9328                            .into_any(),
 9329                    );
 9330                }
 9331
 9332                self.render_edit_prediction_cursor_popover_preview(
 9333                    prediction,
 9334                    cursor_point,
 9335                    style,
 9336                    cx,
 9337                )?
 9338            }
 9339
 9340            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9341                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9342                    stale_completion,
 9343                    cursor_point,
 9344                    style,
 9345                    cx,
 9346                )?,
 9347
 9348                None => pending_completion_container(provider_icon)
 9349                    .child(Label::new("...").size(LabelSize::Small)),
 9350            },
 9351
 9352            None => pending_completion_container(provider_icon)
 9353                .child(Label::new("...").size(LabelSize::Small)),
 9354        };
 9355
 9356        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9357            completion
 9358                .with_animation(
 9359                    "loading-completion",
 9360                    Animation::new(Duration::from_secs(2))
 9361                        .repeat()
 9362                        .with_easing(pulsating_between(0.4, 0.8)),
 9363                    |label, delta| label.opacity(delta),
 9364                )
 9365                .into_any_element()
 9366        } else {
 9367            completion.into_any_element()
 9368        };
 9369
 9370        let has_completion = self.active_edit_prediction.is_some();
 9371
 9372        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9373        Some(
 9374            h_flex()
 9375                .min_w(min_width)
 9376                .max_w(max_width)
 9377                .flex_1()
 9378                .elevation_2(cx)
 9379                .border_color(cx.theme().colors().border)
 9380                .child(
 9381                    div()
 9382                        .flex_1()
 9383                        .py_1()
 9384                        .px_2()
 9385                        .overflow_hidden()
 9386                        .child(completion),
 9387                )
 9388                .when_some(accept_keystroke, |el, accept_keystroke| {
 9389                    if !accept_keystroke.modifiers().modified() {
 9390                        return el;
 9391                    }
 9392
 9393                    el.child(
 9394                        h_flex()
 9395                            .h_full()
 9396                            .border_l_1()
 9397                            .rounded_r_lg()
 9398                            .border_color(cx.theme().colors().border)
 9399                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9400                            .gap_1()
 9401                            .py_1()
 9402                            .px_2()
 9403                            .child(
 9404                                h_flex()
 9405                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9406                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9407                                    .child(h_flex().children(ui::render_modifiers(
 9408                                        accept_keystroke.modifiers(),
 9409                                        PlatformStyle::platform(),
 9410                                        Some(if !has_completion {
 9411                                            Color::Muted
 9412                                        } else {
 9413                                            Color::Default
 9414                                        }),
 9415                                        None,
 9416                                        false,
 9417                                    ))),
 9418                            )
 9419                            .child(Label::new("Preview").into_any_element())
 9420                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9421                    )
 9422                })
 9423                .into_any(),
 9424        )
 9425    }
 9426
 9427    fn render_edit_prediction_cursor_popover_preview(
 9428        &self,
 9429        completion: &EditPredictionState,
 9430        cursor_point: Point,
 9431        style: &EditorStyle,
 9432        cx: &mut Context<Editor>,
 9433    ) -> Option<Div> {
 9434        use text::ToPoint as _;
 9435
 9436        fn render_relative_row_jump(
 9437            prefix: impl Into<String>,
 9438            current_row: u32,
 9439            target_row: u32,
 9440        ) -> Div {
 9441            let (row_diff, arrow) = if target_row < current_row {
 9442                (current_row - target_row, IconName::ArrowUp)
 9443            } else {
 9444                (target_row - current_row, IconName::ArrowDown)
 9445            };
 9446
 9447            h_flex()
 9448                .child(
 9449                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9450                        .color(Color::Muted)
 9451                        .size(LabelSize::Small),
 9452                )
 9453                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9454        }
 9455
 9456        let supports_jump = self
 9457            .edit_prediction_provider
 9458            .as_ref()
 9459            .map(|provider| provider.provider.supports_jump_to_edit())
 9460            .unwrap_or(true);
 9461
 9462        match &completion.completion {
 9463            EditPrediction::Move {
 9464                target, snapshot, ..
 9465            } => {
 9466                if !supports_jump {
 9467                    return None;
 9468                }
 9469
 9470                Some(
 9471                    h_flex()
 9472                        .px_2()
 9473                        .gap_2()
 9474                        .flex_1()
 9475                        .child(
 9476                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9477                                Icon::new(IconName::ZedPredictDown)
 9478                            } else {
 9479                                Icon::new(IconName::ZedPredictUp)
 9480                            },
 9481                        )
 9482                        .child(Label::new("Jump to Edit")),
 9483                )
 9484            }
 9485
 9486            EditPrediction::Edit {
 9487                edits,
 9488                edit_preview,
 9489                snapshot,
 9490                display_mode: _,
 9491            } => {
 9492                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9493
 9494                let (highlighted_edits, has_more_lines) =
 9495                    if let Some(edit_preview) = edit_preview.as_ref() {
 9496                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9497                            .first_line_preview()
 9498                    } else {
 9499                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9500                    };
 9501
 9502                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9503                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9504
 9505                let preview = h_flex()
 9506                    .gap_1()
 9507                    .min_w_16()
 9508                    .child(styled_text)
 9509                    .when(has_more_lines, |parent| parent.child(""));
 9510
 9511                let left = if supports_jump && first_edit_row != cursor_point.row {
 9512                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9513                        .into_any_element()
 9514                } else {
 9515                    let icon_name =
 9516                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9517                    Icon::new(icon_name).into_any_element()
 9518                };
 9519
 9520                Some(
 9521                    h_flex()
 9522                        .h_full()
 9523                        .flex_1()
 9524                        .gap_2()
 9525                        .pr_1()
 9526                        .overflow_x_hidden()
 9527                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9528                        .child(left)
 9529                        .child(preview),
 9530                )
 9531            }
 9532        }
 9533    }
 9534
 9535    pub fn render_context_menu(
 9536        &self,
 9537        style: &EditorStyle,
 9538        max_height_in_lines: u32,
 9539        window: &mut Window,
 9540        cx: &mut Context<Editor>,
 9541    ) -> Option<AnyElement> {
 9542        let menu = self.context_menu.borrow();
 9543        let menu = menu.as_ref()?;
 9544        if !menu.visible() {
 9545            return None;
 9546        };
 9547        Some(menu.render(style, max_height_in_lines, window, cx))
 9548    }
 9549
 9550    fn render_context_menu_aside(
 9551        &mut self,
 9552        max_size: Size<Pixels>,
 9553        window: &mut Window,
 9554        cx: &mut Context<Editor>,
 9555    ) -> Option<AnyElement> {
 9556        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9557            if menu.visible() {
 9558                menu.render_aside(max_size, window, cx)
 9559            } else {
 9560                None
 9561            }
 9562        })
 9563    }
 9564
 9565    fn hide_context_menu(
 9566        &mut self,
 9567        window: &mut Window,
 9568        cx: &mut Context<Self>,
 9569    ) -> Option<CodeContextMenu> {
 9570        cx.notify();
 9571        self.completion_tasks.clear();
 9572        let context_menu = self.context_menu.borrow_mut().take();
 9573        self.stale_edit_prediction_in_menu.take();
 9574        self.update_visible_edit_prediction(window, cx);
 9575        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9576            && let Some(completion_provider) = &self.completion_provider
 9577        {
 9578            completion_provider.selection_changed(None, window, cx);
 9579        }
 9580        context_menu
 9581    }
 9582
 9583    fn show_snippet_choices(
 9584        &mut self,
 9585        choices: &Vec<String>,
 9586        selection: Range<Anchor>,
 9587        cx: &mut Context<Self>,
 9588    ) {
 9589        let Some((_, buffer, _)) = self
 9590            .buffer()
 9591            .read(cx)
 9592            .excerpt_containing(selection.start, cx)
 9593        else {
 9594            return;
 9595        };
 9596        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9597        else {
 9598            return;
 9599        };
 9600        if buffer != end_buffer {
 9601            log::error!("expected anchor range to have matching buffer IDs");
 9602            return;
 9603        }
 9604
 9605        let id = post_inc(&mut self.next_completion_id);
 9606        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9607        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9608            CompletionsMenu::new_snippet_choices(
 9609                id,
 9610                true,
 9611                choices,
 9612                selection,
 9613                buffer,
 9614                snippet_sort_order,
 9615            ),
 9616        ));
 9617    }
 9618
 9619    pub fn insert_snippet(
 9620        &mut self,
 9621        insertion_ranges: &[Range<usize>],
 9622        snippet: Snippet,
 9623        window: &mut Window,
 9624        cx: &mut Context<Self>,
 9625    ) -> Result<()> {
 9626        struct Tabstop<T> {
 9627            is_end_tabstop: bool,
 9628            ranges: Vec<Range<T>>,
 9629            choices: Option<Vec<String>>,
 9630        }
 9631
 9632        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9633            let snippet_text: Arc<str> = snippet.text.clone().into();
 9634            let edits = insertion_ranges
 9635                .iter()
 9636                .cloned()
 9637                .map(|range| (range, snippet_text.clone()));
 9638            let autoindent_mode = AutoindentMode::Block {
 9639                original_indent_columns: Vec::new(),
 9640            };
 9641            buffer.edit(edits, Some(autoindent_mode), cx);
 9642
 9643            let snapshot = &*buffer.read(cx);
 9644            let snippet = &snippet;
 9645            snippet
 9646                .tabstops
 9647                .iter()
 9648                .map(|tabstop| {
 9649                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9650                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9651                    });
 9652                    let mut tabstop_ranges = tabstop
 9653                        .ranges
 9654                        .iter()
 9655                        .flat_map(|tabstop_range| {
 9656                            let mut delta = 0_isize;
 9657                            insertion_ranges.iter().map(move |insertion_range| {
 9658                                let insertion_start = insertion_range.start as isize + delta;
 9659                                delta +=
 9660                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9661
 9662                                let start = ((insertion_start + tabstop_range.start) as usize)
 9663                                    .min(snapshot.len());
 9664                                let end = ((insertion_start + tabstop_range.end) as usize)
 9665                                    .min(snapshot.len());
 9666                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9667                            })
 9668                        })
 9669                        .collect::<Vec<_>>();
 9670                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9671
 9672                    Tabstop {
 9673                        is_end_tabstop,
 9674                        ranges: tabstop_ranges,
 9675                        choices: tabstop.choices.clone(),
 9676                    }
 9677                })
 9678                .collect::<Vec<_>>()
 9679        });
 9680        if let Some(tabstop) = tabstops.first() {
 9681            self.change_selections(Default::default(), window, cx, |s| {
 9682                // Reverse order so that the first range is the newest created selection.
 9683                // Completions will use it and autoscroll will prioritize it.
 9684                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9685            });
 9686
 9687            if let Some(choices) = &tabstop.choices
 9688                && let Some(selection) = tabstop.ranges.first()
 9689            {
 9690                self.show_snippet_choices(choices, selection.clone(), cx)
 9691            }
 9692
 9693            // If we're already at the last tabstop and it's at the end of the snippet,
 9694            // we're done, we don't need to keep the state around.
 9695            if !tabstop.is_end_tabstop {
 9696                let choices = tabstops
 9697                    .iter()
 9698                    .map(|tabstop| tabstop.choices.clone())
 9699                    .collect();
 9700
 9701                let ranges = tabstops
 9702                    .into_iter()
 9703                    .map(|tabstop| tabstop.ranges)
 9704                    .collect::<Vec<_>>();
 9705
 9706                self.snippet_stack.push(SnippetState {
 9707                    active_index: 0,
 9708                    ranges,
 9709                    choices,
 9710                });
 9711            }
 9712
 9713            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9714            if self.autoclose_regions.is_empty() {
 9715                let snapshot = self.buffer.read(cx).snapshot(cx);
 9716                let mut all_selections = self.selections.all::<Point>(cx);
 9717                for selection in &mut all_selections {
 9718                    let selection_head = selection.head();
 9719                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9720                        continue;
 9721                    };
 9722
 9723                    let mut bracket_pair = None;
 9724                    let max_lookup_length = scope
 9725                        .brackets()
 9726                        .map(|(pair, _)| {
 9727                            pair.start
 9728                                .as_str()
 9729                                .chars()
 9730                                .count()
 9731                                .max(pair.end.as_str().chars().count())
 9732                        })
 9733                        .max();
 9734                    if let Some(max_lookup_length) = max_lookup_length {
 9735                        let next_text = snapshot
 9736                            .chars_at(selection_head)
 9737                            .take(max_lookup_length)
 9738                            .collect::<String>();
 9739                        let prev_text = snapshot
 9740                            .reversed_chars_at(selection_head)
 9741                            .take(max_lookup_length)
 9742                            .collect::<String>();
 9743
 9744                        for (pair, enabled) in scope.brackets() {
 9745                            if enabled
 9746                                && pair.close
 9747                                && prev_text.starts_with(pair.start.as_str())
 9748                                && next_text.starts_with(pair.end.as_str())
 9749                            {
 9750                                bracket_pair = Some(pair.clone());
 9751                                break;
 9752                            }
 9753                        }
 9754                    }
 9755
 9756                    if let Some(pair) = bracket_pair {
 9757                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9758                        let autoclose_enabled =
 9759                            self.use_autoclose && snapshot_settings.use_autoclose;
 9760                        if autoclose_enabled {
 9761                            let start = snapshot.anchor_after(selection_head);
 9762                            let end = snapshot.anchor_after(selection_head);
 9763                            self.autoclose_regions.push(AutocloseRegion {
 9764                                selection_id: selection.id,
 9765                                range: start..end,
 9766                                pair,
 9767                            });
 9768                        }
 9769                    }
 9770                }
 9771            }
 9772        }
 9773        Ok(())
 9774    }
 9775
 9776    pub fn move_to_next_snippet_tabstop(
 9777        &mut self,
 9778        window: &mut Window,
 9779        cx: &mut Context<Self>,
 9780    ) -> bool {
 9781        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9782    }
 9783
 9784    pub fn move_to_prev_snippet_tabstop(
 9785        &mut self,
 9786        window: &mut Window,
 9787        cx: &mut Context<Self>,
 9788    ) -> bool {
 9789        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9790    }
 9791
 9792    pub fn move_to_snippet_tabstop(
 9793        &mut self,
 9794        bias: Bias,
 9795        window: &mut Window,
 9796        cx: &mut Context<Self>,
 9797    ) -> bool {
 9798        if let Some(mut snippet) = self.snippet_stack.pop() {
 9799            match bias {
 9800                Bias::Left => {
 9801                    if snippet.active_index > 0 {
 9802                        snippet.active_index -= 1;
 9803                    } else {
 9804                        self.snippet_stack.push(snippet);
 9805                        return false;
 9806                    }
 9807                }
 9808                Bias::Right => {
 9809                    if snippet.active_index + 1 < snippet.ranges.len() {
 9810                        snippet.active_index += 1;
 9811                    } else {
 9812                        self.snippet_stack.push(snippet);
 9813                        return false;
 9814                    }
 9815                }
 9816            }
 9817            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9818                self.change_selections(Default::default(), window, cx, |s| {
 9819                    // Reverse order so that the first range is the newest created selection.
 9820                    // Completions will use it and autoscroll will prioritize it.
 9821                    s.select_ranges(current_ranges.iter().rev().cloned())
 9822                });
 9823
 9824                if let Some(choices) = &snippet.choices[snippet.active_index]
 9825                    && let Some(selection) = current_ranges.first()
 9826                {
 9827                    self.show_snippet_choices(choices, selection.clone(), cx);
 9828                }
 9829
 9830                // If snippet state is not at the last tabstop, push it back on the stack
 9831                if snippet.active_index + 1 < snippet.ranges.len() {
 9832                    self.snippet_stack.push(snippet);
 9833                }
 9834                return true;
 9835            }
 9836        }
 9837
 9838        false
 9839    }
 9840
 9841    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9842        self.transact(window, cx, |this, window, cx| {
 9843            this.select_all(&SelectAll, window, cx);
 9844            this.insert("", window, cx);
 9845        });
 9846    }
 9847
 9848    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9849        if self.read_only(cx) {
 9850            return;
 9851        }
 9852        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9853        self.transact(window, cx, |this, window, cx| {
 9854            this.select_autoclose_pair(window, cx);
 9855            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9856            if !this.linked_edit_ranges.is_empty() {
 9857                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9858                let snapshot = this.buffer.read(cx).snapshot(cx);
 9859
 9860                for selection in selections.iter() {
 9861                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9862                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9863                    if selection_start.buffer_id != selection_end.buffer_id {
 9864                        continue;
 9865                    }
 9866                    if let Some(ranges) =
 9867                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9868                    {
 9869                        for (buffer, entries) in ranges {
 9870                            linked_ranges.entry(buffer).or_default().extend(entries);
 9871                        }
 9872                    }
 9873                }
 9874            }
 9875
 9876            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9877            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9878            for selection in &mut selections {
 9879                if selection.is_empty() {
 9880                    let old_head = selection.head();
 9881                    let mut new_head =
 9882                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9883                            .to_point(&display_map);
 9884                    if let Some((buffer, line_buffer_range)) = display_map
 9885                        .buffer_snapshot
 9886                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9887                    {
 9888                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9889                        let indent_len = match indent_size.kind {
 9890                            IndentKind::Space => {
 9891                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9892                            }
 9893                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9894                        };
 9895                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9896                            let indent_len = indent_len.get();
 9897                            new_head = cmp::min(
 9898                                new_head,
 9899                                MultiBufferPoint::new(
 9900                                    old_head.row,
 9901                                    ((old_head.column - 1) / indent_len) * indent_len,
 9902                                ),
 9903                            );
 9904                        }
 9905                    }
 9906
 9907                    selection.set_head(new_head, SelectionGoal::None);
 9908                }
 9909            }
 9910
 9911            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9912            this.insert("", window, cx);
 9913            let empty_str: Arc<str> = Arc::from("");
 9914            for (buffer, edits) in linked_ranges {
 9915                let snapshot = buffer.read(cx).snapshot();
 9916                use text::ToPoint as TP;
 9917
 9918                let edits = edits
 9919                    .into_iter()
 9920                    .map(|range| {
 9921                        let end_point = TP::to_point(&range.end, &snapshot);
 9922                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9923
 9924                        if end_point == start_point {
 9925                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9926                                .saturating_sub(1);
 9927                            start_point =
 9928                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9929                        };
 9930
 9931                        (start_point..end_point, empty_str.clone())
 9932                    })
 9933                    .sorted_by_key(|(range, _)| range.start)
 9934                    .collect::<Vec<_>>();
 9935                buffer.update(cx, |this, cx| {
 9936                    this.edit(edits, None, cx);
 9937                })
 9938            }
 9939            this.refresh_edit_prediction(true, false, window, cx);
 9940            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9941        });
 9942    }
 9943
 9944    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9945        if self.read_only(cx) {
 9946            return;
 9947        }
 9948        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9949        self.transact(window, cx, |this, window, cx| {
 9950            this.change_selections(Default::default(), window, cx, |s| {
 9951                s.move_with(|map, selection| {
 9952                    if selection.is_empty() {
 9953                        let cursor = movement::right(map, selection.head());
 9954                        selection.end = cursor;
 9955                        selection.reversed = true;
 9956                        selection.goal = SelectionGoal::None;
 9957                    }
 9958                })
 9959            });
 9960            this.insert("", window, cx);
 9961            this.refresh_edit_prediction(true, false, window, cx);
 9962        });
 9963    }
 9964
 9965    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9966        if self.mode.is_single_line() {
 9967            cx.propagate();
 9968            return;
 9969        }
 9970
 9971        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9972        if self.move_to_prev_snippet_tabstop(window, cx) {
 9973            return;
 9974        }
 9975        self.outdent(&Outdent, window, cx);
 9976    }
 9977
 9978    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9979        if self.mode.is_single_line() {
 9980            cx.propagate();
 9981            return;
 9982        }
 9983
 9984        if self.move_to_next_snippet_tabstop(window, cx) {
 9985            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9986            return;
 9987        }
 9988        if self.read_only(cx) {
 9989            return;
 9990        }
 9991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9992        let mut selections = self.selections.all_adjusted(cx);
 9993        let buffer = self.buffer.read(cx);
 9994        let snapshot = buffer.snapshot(cx);
 9995        let rows_iter = selections.iter().map(|s| s.head().row);
 9996        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9997
 9998        let has_some_cursor_in_whitespace = selections
 9999            .iter()
10000            .filter(|selection| selection.is_empty())
10001            .any(|selection| {
10002                let cursor = selection.head();
10003                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10004                cursor.column < current_indent.len
10005            });
10006
10007        let mut edits = Vec::new();
10008        let mut prev_edited_row = 0;
10009        let mut row_delta = 0;
10010        for selection in &mut selections {
10011            if selection.start.row != prev_edited_row {
10012                row_delta = 0;
10013            }
10014            prev_edited_row = selection.end.row;
10015
10016            // If the selection is non-empty, then increase the indentation of the selected lines.
10017            if !selection.is_empty() {
10018                row_delta =
10019                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10020                continue;
10021            }
10022
10023            let cursor = selection.head();
10024            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10025            if let Some(suggested_indent) =
10026                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10027            {
10028                // Don't do anything if already at suggested indent
10029                // and there is any other cursor which is not
10030                if has_some_cursor_in_whitespace
10031                    && cursor.column == current_indent.len
10032                    && current_indent.len == suggested_indent.len
10033                {
10034                    continue;
10035                }
10036
10037                // Adjust line and move cursor to suggested indent
10038                // if cursor is not at suggested indent
10039                if cursor.column < suggested_indent.len
10040                    && cursor.column <= current_indent.len
10041                    && current_indent.len <= suggested_indent.len
10042                {
10043                    selection.start = Point::new(cursor.row, suggested_indent.len);
10044                    selection.end = selection.start;
10045                    if row_delta == 0 {
10046                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10047                            cursor.row,
10048                            current_indent,
10049                            suggested_indent,
10050                        ));
10051                        row_delta = suggested_indent.len - current_indent.len;
10052                    }
10053                    continue;
10054                }
10055
10056                // If current indent is more than suggested indent
10057                // only move cursor to current indent and skip indent
10058                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10059                    selection.start = Point::new(cursor.row, current_indent.len);
10060                    selection.end = selection.start;
10061                    continue;
10062                }
10063            }
10064
10065            // Otherwise, insert a hard or soft tab.
10066            let settings = buffer.language_settings_at(cursor, cx);
10067            let tab_size = if settings.hard_tabs {
10068                IndentSize::tab()
10069            } else {
10070                let tab_size = settings.tab_size.get();
10071                let indent_remainder = snapshot
10072                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10073                    .flat_map(str::chars)
10074                    .fold(row_delta % tab_size, |counter: u32, c| {
10075                        if c == '\t' {
10076                            0
10077                        } else {
10078                            (counter + 1) % tab_size
10079                        }
10080                    });
10081
10082                let chars_to_next_tab_stop = tab_size - indent_remainder;
10083                IndentSize::spaces(chars_to_next_tab_stop)
10084            };
10085            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10086            selection.end = selection.start;
10087            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10088            row_delta += tab_size.len;
10089        }
10090
10091        self.transact(window, cx, |this, window, cx| {
10092            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10093            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10094            this.refresh_edit_prediction(true, false, window, cx);
10095        });
10096    }
10097
10098    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10099        if self.read_only(cx) {
10100            return;
10101        }
10102        if self.mode.is_single_line() {
10103            cx.propagate();
10104            return;
10105        }
10106
10107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10108        let mut selections = self.selections.all::<Point>(cx);
10109        let mut prev_edited_row = 0;
10110        let mut row_delta = 0;
10111        let mut edits = Vec::new();
10112        let buffer = self.buffer.read(cx);
10113        let snapshot = buffer.snapshot(cx);
10114        for selection in &mut selections {
10115            if selection.start.row != prev_edited_row {
10116                row_delta = 0;
10117            }
10118            prev_edited_row = selection.end.row;
10119
10120            row_delta =
10121                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10122        }
10123
10124        self.transact(window, cx, |this, window, cx| {
10125            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10126            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10127        });
10128    }
10129
10130    fn indent_selection(
10131        buffer: &MultiBuffer,
10132        snapshot: &MultiBufferSnapshot,
10133        selection: &mut Selection<Point>,
10134        edits: &mut Vec<(Range<Point>, String)>,
10135        delta_for_start_row: u32,
10136        cx: &App,
10137    ) -> u32 {
10138        let settings = buffer.language_settings_at(selection.start, cx);
10139        let tab_size = settings.tab_size.get();
10140        let indent_kind = if settings.hard_tabs {
10141            IndentKind::Tab
10142        } else {
10143            IndentKind::Space
10144        };
10145        let mut start_row = selection.start.row;
10146        let mut end_row = selection.end.row + 1;
10147
10148        // If a selection ends at the beginning of a line, don't indent
10149        // that last line.
10150        if selection.end.column == 0 && selection.end.row > selection.start.row {
10151            end_row -= 1;
10152        }
10153
10154        // Avoid re-indenting a row that has already been indented by a
10155        // previous selection, but still update this selection's column
10156        // to reflect that indentation.
10157        if delta_for_start_row > 0 {
10158            start_row += 1;
10159            selection.start.column += delta_for_start_row;
10160            if selection.end.row == selection.start.row {
10161                selection.end.column += delta_for_start_row;
10162            }
10163        }
10164
10165        let mut delta_for_end_row = 0;
10166        let has_multiple_rows = start_row + 1 != end_row;
10167        for row in start_row..end_row {
10168            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10169            let indent_delta = match (current_indent.kind, indent_kind) {
10170                (IndentKind::Space, IndentKind::Space) => {
10171                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10172                    IndentSize::spaces(columns_to_next_tab_stop)
10173                }
10174                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10175                (_, IndentKind::Tab) => IndentSize::tab(),
10176            };
10177
10178            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10179                0
10180            } else {
10181                selection.start.column
10182            };
10183            let row_start = Point::new(row, start);
10184            edits.push((
10185                row_start..row_start,
10186                indent_delta.chars().collect::<String>(),
10187            ));
10188
10189            // Update this selection's endpoints to reflect the indentation.
10190            if row == selection.start.row {
10191                selection.start.column += indent_delta.len;
10192            }
10193            if row == selection.end.row {
10194                selection.end.column += indent_delta.len;
10195                delta_for_end_row = indent_delta.len;
10196            }
10197        }
10198
10199        if selection.start.row == selection.end.row {
10200            delta_for_start_row + delta_for_end_row
10201        } else {
10202            delta_for_end_row
10203        }
10204    }
10205
10206    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10207        if self.read_only(cx) {
10208            return;
10209        }
10210        if self.mode.is_single_line() {
10211            cx.propagate();
10212            return;
10213        }
10214
10215        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10216        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10217        let selections = self.selections.all::<Point>(cx);
10218        let mut deletion_ranges = Vec::new();
10219        let mut last_outdent = None;
10220        {
10221            let buffer = self.buffer.read(cx);
10222            let snapshot = buffer.snapshot(cx);
10223            for selection in &selections {
10224                let settings = buffer.language_settings_at(selection.start, cx);
10225                let tab_size = settings.tab_size.get();
10226                let mut rows = selection.spanned_rows(false, &display_map);
10227
10228                // Avoid re-outdenting a row that has already been outdented by a
10229                // previous selection.
10230                if let Some(last_row) = last_outdent
10231                    && last_row == rows.start
10232                {
10233                    rows.start = rows.start.next_row();
10234                }
10235                let has_multiple_rows = rows.len() > 1;
10236                for row in rows.iter_rows() {
10237                    let indent_size = snapshot.indent_size_for_line(row);
10238                    if indent_size.len > 0 {
10239                        let deletion_len = match indent_size.kind {
10240                            IndentKind::Space => {
10241                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10242                                if columns_to_prev_tab_stop == 0 {
10243                                    tab_size
10244                                } else {
10245                                    columns_to_prev_tab_stop
10246                                }
10247                            }
10248                            IndentKind::Tab => 1,
10249                        };
10250                        let start = if has_multiple_rows
10251                            || deletion_len > selection.start.column
10252                            || indent_size.len < selection.start.column
10253                        {
10254                            0
10255                        } else {
10256                            selection.start.column - deletion_len
10257                        };
10258                        deletion_ranges.push(
10259                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10260                        );
10261                        last_outdent = Some(row);
10262                    }
10263                }
10264            }
10265        }
10266
10267        self.transact(window, cx, |this, window, cx| {
10268            this.buffer.update(cx, |buffer, cx| {
10269                let empty_str: Arc<str> = Arc::default();
10270                buffer.edit(
10271                    deletion_ranges
10272                        .into_iter()
10273                        .map(|range| (range, empty_str.clone())),
10274                    None,
10275                    cx,
10276                );
10277            });
10278            let selections = this.selections.all::<usize>(cx);
10279            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10280        });
10281    }
10282
10283    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10284        if self.read_only(cx) {
10285            return;
10286        }
10287        if self.mode.is_single_line() {
10288            cx.propagate();
10289            return;
10290        }
10291
10292        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10293        let selections = self
10294            .selections
10295            .all::<usize>(cx)
10296            .into_iter()
10297            .map(|s| s.range());
10298
10299        self.transact(window, cx, |this, window, cx| {
10300            this.buffer.update(cx, |buffer, cx| {
10301                buffer.autoindent_ranges(selections, cx);
10302            });
10303            let selections = this.selections.all::<usize>(cx);
10304            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10305        });
10306    }
10307
10308    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10310        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10311        let selections = self.selections.all::<Point>(cx);
10312
10313        let mut new_cursors = Vec::new();
10314        let mut edit_ranges = Vec::new();
10315        let mut selections = selections.iter().peekable();
10316        while let Some(selection) = selections.next() {
10317            let mut rows = selection.spanned_rows(false, &display_map);
10318            let goal_display_column = selection.head().to_display_point(&display_map).column();
10319
10320            // Accumulate contiguous regions of rows that we want to delete.
10321            while let Some(next_selection) = selections.peek() {
10322                let next_rows = next_selection.spanned_rows(false, &display_map);
10323                if next_rows.start <= rows.end {
10324                    rows.end = next_rows.end;
10325                    selections.next().unwrap();
10326                } else {
10327                    break;
10328                }
10329            }
10330
10331            let buffer = &display_map.buffer_snapshot;
10332            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10333            let edit_end;
10334            let cursor_buffer_row;
10335            if buffer.max_point().row >= rows.end.0 {
10336                // If there's a line after the range, delete the \n from the end of the row range
10337                // and position the cursor on the next line.
10338                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10339                cursor_buffer_row = rows.end;
10340            } else {
10341                // If there isn't a line after the range, delete the \n from the line before the
10342                // start of the row range and position the cursor there.
10343                edit_start = edit_start.saturating_sub(1);
10344                edit_end = buffer.len();
10345                cursor_buffer_row = rows.start.previous_row();
10346            }
10347
10348            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10349            *cursor.column_mut() =
10350                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10351
10352            new_cursors.push((
10353                selection.id,
10354                buffer.anchor_after(cursor.to_point(&display_map)),
10355            ));
10356            edit_ranges.push(edit_start..edit_end);
10357        }
10358
10359        self.transact(window, cx, |this, window, cx| {
10360            let buffer = this.buffer.update(cx, |buffer, cx| {
10361                let empty_str: Arc<str> = Arc::default();
10362                buffer.edit(
10363                    edit_ranges
10364                        .into_iter()
10365                        .map(|range| (range, empty_str.clone())),
10366                    None,
10367                    cx,
10368                );
10369                buffer.snapshot(cx)
10370            });
10371            let new_selections = new_cursors
10372                .into_iter()
10373                .map(|(id, cursor)| {
10374                    let cursor = cursor.to_point(&buffer);
10375                    Selection {
10376                        id,
10377                        start: cursor,
10378                        end: cursor,
10379                        reversed: false,
10380                        goal: SelectionGoal::None,
10381                    }
10382                })
10383                .collect();
10384
10385            this.change_selections(Default::default(), window, cx, |s| {
10386                s.select(new_selections);
10387            });
10388        });
10389    }
10390
10391    pub fn join_lines_impl(
10392        &mut self,
10393        insert_whitespace: bool,
10394        window: &mut Window,
10395        cx: &mut Context<Self>,
10396    ) {
10397        if self.read_only(cx) {
10398            return;
10399        }
10400        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10401        for selection in self.selections.all::<Point>(cx) {
10402            let start = MultiBufferRow(selection.start.row);
10403            // Treat single line selections as if they include the next line. Otherwise this action
10404            // would do nothing for single line selections individual cursors.
10405            let end = if selection.start.row == selection.end.row {
10406                MultiBufferRow(selection.start.row + 1)
10407            } else {
10408                MultiBufferRow(selection.end.row)
10409            };
10410
10411            if let Some(last_row_range) = row_ranges.last_mut()
10412                && start <= last_row_range.end
10413            {
10414                last_row_range.end = end;
10415                continue;
10416            }
10417            row_ranges.push(start..end);
10418        }
10419
10420        let snapshot = self.buffer.read(cx).snapshot(cx);
10421        let mut cursor_positions = Vec::new();
10422        for row_range in &row_ranges {
10423            let anchor = snapshot.anchor_before(Point::new(
10424                row_range.end.previous_row().0,
10425                snapshot.line_len(row_range.end.previous_row()),
10426            ));
10427            cursor_positions.push(anchor..anchor);
10428        }
10429
10430        self.transact(window, cx, |this, window, cx| {
10431            for row_range in row_ranges.into_iter().rev() {
10432                for row in row_range.iter_rows().rev() {
10433                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10434                    let next_line_row = row.next_row();
10435                    let indent = snapshot.indent_size_for_line(next_line_row);
10436                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10437
10438                    let replace =
10439                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10440                            " "
10441                        } else {
10442                            ""
10443                        };
10444
10445                    this.buffer.update(cx, |buffer, cx| {
10446                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10447                    });
10448                }
10449            }
10450
10451            this.change_selections(Default::default(), window, cx, |s| {
10452                s.select_anchor_ranges(cursor_positions)
10453            });
10454        });
10455    }
10456
10457    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10459        self.join_lines_impl(true, window, cx);
10460    }
10461
10462    pub fn sort_lines_case_sensitive(
10463        &mut self,
10464        _: &SortLinesCaseSensitive,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467    ) {
10468        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10469    }
10470
10471    pub fn sort_lines_by_length(
10472        &mut self,
10473        _: &SortLinesByLength,
10474        window: &mut Window,
10475        cx: &mut Context<Self>,
10476    ) {
10477        self.manipulate_immutable_lines(window, cx, |lines| {
10478            lines.sort_by_key(|&line| line.chars().count())
10479        })
10480    }
10481
10482    pub fn sort_lines_case_insensitive(
10483        &mut self,
10484        _: &SortLinesCaseInsensitive,
10485        window: &mut Window,
10486        cx: &mut Context<Self>,
10487    ) {
10488        self.manipulate_immutable_lines(window, cx, |lines| {
10489            lines.sort_by_key(|line| line.to_lowercase())
10490        })
10491    }
10492
10493    pub fn unique_lines_case_insensitive(
10494        &mut self,
10495        _: &UniqueLinesCaseInsensitive,
10496        window: &mut Window,
10497        cx: &mut Context<Self>,
10498    ) {
10499        self.manipulate_immutable_lines(window, cx, |lines| {
10500            let mut seen = HashSet::default();
10501            lines.retain(|line| seen.insert(line.to_lowercase()));
10502        })
10503    }
10504
10505    pub fn unique_lines_case_sensitive(
10506        &mut self,
10507        _: &UniqueLinesCaseSensitive,
10508        window: &mut Window,
10509        cx: &mut Context<Self>,
10510    ) {
10511        self.manipulate_immutable_lines(window, cx, |lines| {
10512            let mut seen = HashSet::default();
10513            lines.retain(|line| seen.insert(*line));
10514        })
10515    }
10516
10517    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10518        let snapshot = self.buffer.read(cx).snapshot(cx);
10519        for selection in self.selections.disjoint_anchors_arc().iter() {
10520            if snapshot
10521                .language_at(selection.start)
10522                .and_then(|lang| lang.config().wrap_characters.as_ref())
10523                .is_some()
10524            {
10525                return true;
10526            }
10527        }
10528        false
10529    }
10530
10531    fn wrap_selections_in_tag(
10532        &mut self,
10533        _: &WrapSelectionsInTag,
10534        window: &mut Window,
10535        cx: &mut Context<Self>,
10536    ) {
10537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10538
10539        let snapshot = self.buffer.read(cx).snapshot(cx);
10540
10541        let mut edits = Vec::new();
10542        let mut boundaries = Vec::new();
10543
10544        for selection in self.selections.all::<Point>(cx).iter() {
10545            let Some(wrap_config) = snapshot
10546                .language_at(selection.start)
10547                .and_then(|lang| lang.config().wrap_characters.clone())
10548            else {
10549                continue;
10550            };
10551
10552            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10553            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10554
10555            let start_before = snapshot.anchor_before(selection.start);
10556            let end_after = snapshot.anchor_after(selection.end);
10557
10558            edits.push((start_before..start_before, open_tag));
10559            edits.push((end_after..end_after, close_tag));
10560
10561            boundaries.push((
10562                start_before,
10563                end_after,
10564                wrap_config.start_prefix.len(),
10565                wrap_config.end_suffix.len(),
10566            ));
10567        }
10568
10569        if edits.is_empty() {
10570            return;
10571        }
10572
10573        self.transact(window, cx, |this, window, cx| {
10574            let buffer = this.buffer.update(cx, |buffer, cx| {
10575                buffer.edit(edits, None, cx);
10576                buffer.snapshot(cx)
10577            });
10578
10579            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10580            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10581                boundaries.into_iter()
10582            {
10583                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10584                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10585                new_selections.push(open_offset..open_offset);
10586                new_selections.push(close_offset..close_offset);
10587            }
10588
10589            this.change_selections(Default::default(), window, cx, |s| {
10590                s.select_ranges(new_selections);
10591            });
10592
10593            this.request_autoscroll(Autoscroll::fit(), cx);
10594        });
10595    }
10596
10597    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10598        let Some(project) = self.project.clone() else {
10599            return;
10600        };
10601        self.reload(project, window, cx)
10602            .detach_and_notify_err(window, cx);
10603    }
10604
10605    pub fn restore_file(
10606        &mut self,
10607        _: &::git::RestoreFile,
10608        window: &mut Window,
10609        cx: &mut Context<Self>,
10610    ) {
10611        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10612        let mut buffer_ids = HashSet::default();
10613        let snapshot = self.buffer().read(cx).snapshot(cx);
10614        for selection in self.selections.all::<usize>(cx) {
10615            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10616        }
10617
10618        let buffer = self.buffer().read(cx);
10619        let ranges = buffer_ids
10620            .into_iter()
10621            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10622            .collect::<Vec<_>>();
10623
10624        self.restore_hunks_in_ranges(ranges, window, cx);
10625    }
10626
10627    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10628        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10629        let selections = self
10630            .selections
10631            .all(cx)
10632            .into_iter()
10633            .map(|s| s.range())
10634            .collect();
10635        self.restore_hunks_in_ranges(selections, window, cx);
10636    }
10637
10638    pub fn restore_hunks_in_ranges(
10639        &mut self,
10640        ranges: Vec<Range<Point>>,
10641        window: &mut Window,
10642        cx: &mut Context<Editor>,
10643    ) {
10644        let mut revert_changes = HashMap::default();
10645        let chunk_by = self
10646            .snapshot(window, cx)
10647            .hunks_for_ranges(ranges)
10648            .into_iter()
10649            .chunk_by(|hunk| hunk.buffer_id);
10650        for (buffer_id, hunks) in &chunk_by {
10651            let hunks = hunks.collect::<Vec<_>>();
10652            for hunk in &hunks {
10653                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10654            }
10655            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10656        }
10657        drop(chunk_by);
10658        if !revert_changes.is_empty() {
10659            self.transact(window, cx, |editor, window, cx| {
10660                editor.restore(revert_changes, window, cx);
10661            });
10662        }
10663    }
10664
10665    pub fn open_active_item_in_terminal(
10666        &mut self,
10667        _: &OpenInTerminal,
10668        window: &mut Window,
10669        cx: &mut Context<Self>,
10670    ) {
10671        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10672            let project_path = buffer.read(cx).project_path(cx)?;
10673            let project = self.project()?.read(cx);
10674            let entry = project.entry_for_path(&project_path, cx)?;
10675            let parent = match &entry.canonical_path {
10676                Some(canonical_path) => canonical_path.to_path_buf(),
10677                None => project.absolute_path(&project_path, cx)?,
10678            }
10679            .parent()?
10680            .to_path_buf();
10681            Some(parent)
10682        }) {
10683            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10684        }
10685    }
10686
10687    fn set_breakpoint_context_menu(
10688        &mut self,
10689        display_row: DisplayRow,
10690        position: Option<Anchor>,
10691        clicked_point: gpui::Point<Pixels>,
10692        window: &mut Window,
10693        cx: &mut Context<Self>,
10694    ) {
10695        let source = self
10696            .buffer
10697            .read(cx)
10698            .snapshot(cx)
10699            .anchor_before(Point::new(display_row.0, 0u32));
10700
10701        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10702
10703        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10704            self,
10705            source,
10706            clicked_point,
10707            context_menu,
10708            window,
10709            cx,
10710        );
10711    }
10712
10713    fn add_edit_breakpoint_block(
10714        &mut self,
10715        anchor: Anchor,
10716        breakpoint: &Breakpoint,
10717        edit_action: BreakpointPromptEditAction,
10718        window: &mut Window,
10719        cx: &mut Context<Self>,
10720    ) {
10721        let weak_editor = cx.weak_entity();
10722        let bp_prompt = cx.new(|cx| {
10723            BreakpointPromptEditor::new(
10724                weak_editor,
10725                anchor,
10726                breakpoint.clone(),
10727                edit_action,
10728                window,
10729                cx,
10730            )
10731        });
10732
10733        let height = bp_prompt.update(cx, |this, cx| {
10734            this.prompt
10735                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10736        });
10737        let cloned_prompt = bp_prompt.clone();
10738        let blocks = vec![BlockProperties {
10739            style: BlockStyle::Sticky,
10740            placement: BlockPlacement::Above(anchor),
10741            height: Some(height),
10742            render: Arc::new(move |cx| {
10743                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10744                cloned_prompt.clone().into_any_element()
10745            }),
10746            priority: 0,
10747        }];
10748
10749        let focus_handle = bp_prompt.focus_handle(cx);
10750        window.focus(&focus_handle);
10751
10752        let block_ids = self.insert_blocks(blocks, None, cx);
10753        bp_prompt.update(cx, |prompt, _| {
10754            prompt.add_block_ids(block_ids);
10755        });
10756    }
10757
10758    pub(crate) fn breakpoint_at_row(
10759        &self,
10760        row: u32,
10761        window: &mut Window,
10762        cx: &mut Context<Self>,
10763    ) -> Option<(Anchor, Breakpoint)> {
10764        let snapshot = self.snapshot(window, cx);
10765        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10766
10767        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10768    }
10769
10770    pub(crate) fn breakpoint_at_anchor(
10771        &self,
10772        breakpoint_position: Anchor,
10773        snapshot: &EditorSnapshot,
10774        cx: &mut Context<Self>,
10775    ) -> Option<(Anchor, Breakpoint)> {
10776        let buffer = self
10777            .buffer
10778            .read(cx)
10779            .buffer_for_anchor(breakpoint_position, cx)?;
10780
10781        let enclosing_excerpt = breakpoint_position.excerpt_id;
10782        let buffer_snapshot = buffer.read(cx).snapshot();
10783
10784        let row = buffer_snapshot
10785            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10786            .row;
10787
10788        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10789        let anchor_end = snapshot
10790            .buffer_snapshot
10791            .anchor_after(Point::new(row, line_len));
10792
10793        self.breakpoint_store
10794            .as_ref()?
10795            .read_with(cx, |breakpoint_store, cx| {
10796                breakpoint_store
10797                    .breakpoints(
10798                        &buffer,
10799                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10800                        &buffer_snapshot,
10801                        cx,
10802                    )
10803                    .next()
10804                    .and_then(|(bp, _)| {
10805                        let breakpoint_row = buffer_snapshot
10806                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10807                            .row;
10808
10809                        if breakpoint_row == row {
10810                            snapshot
10811                                .buffer_snapshot
10812                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10813                                .map(|position| (position, bp.bp.clone()))
10814                        } else {
10815                            None
10816                        }
10817                    })
10818            })
10819    }
10820
10821    pub fn edit_log_breakpoint(
10822        &mut self,
10823        _: &EditLogBreakpoint,
10824        window: &mut Window,
10825        cx: &mut Context<Self>,
10826    ) {
10827        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10828            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10829                message: None,
10830                state: BreakpointState::Enabled,
10831                condition: None,
10832                hit_condition: None,
10833            });
10834
10835            self.add_edit_breakpoint_block(
10836                anchor,
10837                &breakpoint,
10838                BreakpointPromptEditAction::Log,
10839                window,
10840                cx,
10841            );
10842        }
10843    }
10844
10845    fn breakpoints_at_cursors(
10846        &self,
10847        window: &mut Window,
10848        cx: &mut Context<Self>,
10849    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10850        let snapshot = self.snapshot(window, cx);
10851        let cursors = self
10852            .selections
10853            .disjoint_anchors_arc()
10854            .iter()
10855            .map(|selection| {
10856                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10857
10858                let breakpoint_position = self
10859                    .breakpoint_at_row(cursor_position.row, window, cx)
10860                    .map(|bp| bp.0)
10861                    .unwrap_or_else(|| {
10862                        snapshot
10863                            .display_snapshot
10864                            .buffer_snapshot
10865                            .anchor_after(Point::new(cursor_position.row, 0))
10866                    });
10867
10868                let breakpoint = self
10869                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10870                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10871
10872                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10873            })
10874            // 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.
10875            .collect::<HashMap<Anchor, _>>();
10876
10877        cursors.into_iter().collect()
10878    }
10879
10880    pub fn enable_breakpoint(
10881        &mut self,
10882        _: &crate::actions::EnableBreakpoint,
10883        window: &mut Window,
10884        cx: &mut Context<Self>,
10885    ) {
10886        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10887            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10888                continue;
10889            };
10890            self.edit_breakpoint_at_anchor(
10891                anchor,
10892                breakpoint,
10893                BreakpointEditAction::InvertState,
10894                cx,
10895            );
10896        }
10897    }
10898
10899    pub fn disable_breakpoint(
10900        &mut self,
10901        _: &crate::actions::DisableBreakpoint,
10902        window: &mut Window,
10903        cx: &mut Context<Self>,
10904    ) {
10905        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10906            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10907                continue;
10908            };
10909            self.edit_breakpoint_at_anchor(
10910                anchor,
10911                breakpoint,
10912                BreakpointEditAction::InvertState,
10913                cx,
10914            );
10915        }
10916    }
10917
10918    pub fn toggle_breakpoint(
10919        &mut self,
10920        _: &crate::actions::ToggleBreakpoint,
10921        window: &mut Window,
10922        cx: &mut Context<Self>,
10923    ) {
10924        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10925            if let Some(breakpoint) = breakpoint {
10926                self.edit_breakpoint_at_anchor(
10927                    anchor,
10928                    breakpoint,
10929                    BreakpointEditAction::Toggle,
10930                    cx,
10931                );
10932            } else {
10933                self.edit_breakpoint_at_anchor(
10934                    anchor,
10935                    Breakpoint::new_standard(),
10936                    BreakpointEditAction::Toggle,
10937                    cx,
10938                );
10939            }
10940        }
10941    }
10942
10943    pub fn edit_breakpoint_at_anchor(
10944        &mut self,
10945        breakpoint_position: Anchor,
10946        breakpoint: Breakpoint,
10947        edit_action: BreakpointEditAction,
10948        cx: &mut Context<Self>,
10949    ) {
10950        let Some(breakpoint_store) = &self.breakpoint_store else {
10951            return;
10952        };
10953
10954        let Some(buffer) = self
10955            .buffer
10956            .read(cx)
10957            .buffer_for_anchor(breakpoint_position, cx)
10958        else {
10959            return;
10960        };
10961
10962        breakpoint_store.update(cx, |breakpoint_store, cx| {
10963            breakpoint_store.toggle_breakpoint(
10964                buffer,
10965                BreakpointWithPosition {
10966                    position: breakpoint_position.text_anchor,
10967                    bp: breakpoint,
10968                },
10969                edit_action,
10970                cx,
10971            );
10972        });
10973
10974        cx.notify();
10975    }
10976
10977    #[cfg(any(test, feature = "test-support"))]
10978    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10979        self.breakpoint_store.clone()
10980    }
10981
10982    pub fn prepare_restore_change(
10983        &self,
10984        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10985        hunk: &MultiBufferDiffHunk,
10986        cx: &mut App,
10987    ) -> Option<()> {
10988        if hunk.is_created_file() {
10989            return None;
10990        }
10991        let buffer = self.buffer.read(cx);
10992        let diff = buffer.diff_for(hunk.buffer_id)?;
10993        let buffer = buffer.buffer(hunk.buffer_id)?;
10994        let buffer = buffer.read(cx);
10995        let original_text = diff
10996            .read(cx)
10997            .base_text()
10998            .as_rope()
10999            .slice(hunk.diff_base_byte_range.clone());
11000        let buffer_snapshot = buffer.snapshot();
11001        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11002        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11003            probe
11004                .0
11005                .start
11006                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11007                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11008        }) {
11009            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11010            Some(())
11011        } else {
11012            None
11013        }
11014    }
11015
11016    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11017        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11018    }
11019
11020    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11021        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11022    }
11023
11024    fn manipulate_lines<M>(
11025        &mut self,
11026        window: &mut Window,
11027        cx: &mut Context<Self>,
11028        mut manipulate: M,
11029    ) where
11030        M: FnMut(&str) -> LineManipulationResult,
11031    {
11032        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11033
11034        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11035        let buffer = self.buffer.read(cx).snapshot(cx);
11036
11037        let mut edits = Vec::new();
11038
11039        let selections = self.selections.all::<Point>(cx);
11040        let mut selections = selections.iter().peekable();
11041        let mut contiguous_row_selections = Vec::new();
11042        let mut new_selections = Vec::new();
11043        let mut added_lines = 0;
11044        let mut removed_lines = 0;
11045
11046        while let Some(selection) = selections.next() {
11047            let (start_row, end_row) = consume_contiguous_rows(
11048                &mut contiguous_row_selections,
11049                selection,
11050                &display_map,
11051                &mut selections,
11052            );
11053
11054            let start_point = Point::new(start_row.0, 0);
11055            let end_point = Point::new(
11056                end_row.previous_row().0,
11057                buffer.line_len(end_row.previous_row()),
11058            );
11059            let text = buffer
11060                .text_for_range(start_point..end_point)
11061                .collect::<String>();
11062
11063            let LineManipulationResult {
11064                new_text,
11065                line_count_before,
11066                line_count_after,
11067            } = manipulate(&text);
11068
11069            edits.push((start_point..end_point, new_text));
11070
11071            // Selections must change based on added and removed line count
11072            let start_row =
11073                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11074            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11075            new_selections.push(Selection {
11076                id: selection.id,
11077                start: start_row,
11078                end: end_row,
11079                goal: SelectionGoal::None,
11080                reversed: selection.reversed,
11081            });
11082
11083            if line_count_after > line_count_before {
11084                added_lines += line_count_after - line_count_before;
11085            } else if line_count_before > line_count_after {
11086                removed_lines += line_count_before - line_count_after;
11087            }
11088        }
11089
11090        self.transact(window, cx, |this, window, cx| {
11091            let buffer = this.buffer.update(cx, |buffer, cx| {
11092                buffer.edit(edits, None, cx);
11093                buffer.snapshot(cx)
11094            });
11095
11096            // Recalculate offsets on newly edited buffer
11097            let new_selections = new_selections
11098                .iter()
11099                .map(|s| {
11100                    let start_point = Point::new(s.start.0, 0);
11101                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11102                    Selection {
11103                        id: s.id,
11104                        start: buffer.point_to_offset(start_point),
11105                        end: buffer.point_to_offset(end_point),
11106                        goal: s.goal,
11107                        reversed: s.reversed,
11108                    }
11109                })
11110                .collect();
11111
11112            this.change_selections(Default::default(), window, cx, |s| {
11113                s.select(new_selections);
11114            });
11115
11116            this.request_autoscroll(Autoscroll::fit(), cx);
11117        });
11118    }
11119
11120    fn manipulate_immutable_lines<Fn>(
11121        &mut self,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124        mut callback: Fn,
11125    ) where
11126        Fn: FnMut(&mut Vec<&str>),
11127    {
11128        self.manipulate_lines(window, cx, |text| {
11129            let mut lines: Vec<&str> = text.split('\n').collect();
11130            let line_count_before = lines.len();
11131
11132            callback(&mut lines);
11133
11134            LineManipulationResult {
11135                new_text: lines.join("\n"),
11136                line_count_before,
11137                line_count_after: lines.len(),
11138            }
11139        });
11140    }
11141
11142    fn manipulate_mutable_lines<Fn>(
11143        &mut self,
11144        window: &mut Window,
11145        cx: &mut Context<Self>,
11146        mut callback: Fn,
11147    ) where
11148        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11149    {
11150        self.manipulate_lines(window, cx, |text| {
11151            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11152            let line_count_before = lines.len();
11153
11154            callback(&mut lines);
11155
11156            LineManipulationResult {
11157                new_text: lines.join("\n"),
11158                line_count_before,
11159                line_count_after: lines.len(),
11160            }
11161        });
11162    }
11163
11164    pub fn convert_indentation_to_spaces(
11165        &mut self,
11166        _: &ConvertIndentationToSpaces,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169    ) {
11170        let settings = self.buffer.read(cx).language_settings(cx);
11171        let tab_size = settings.tab_size.get() as usize;
11172
11173        self.manipulate_mutable_lines(window, cx, |lines| {
11174            // Allocates a reasonably sized scratch buffer once for the whole loop
11175            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11176            // Avoids recomputing spaces that could be inserted many times
11177            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11178                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11179                .collect();
11180
11181            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11182                let mut chars = line.as_ref().chars();
11183                let mut col = 0;
11184                let mut changed = false;
11185
11186                for ch in chars.by_ref() {
11187                    match ch {
11188                        ' ' => {
11189                            reindented_line.push(' ');
11190                            col += 1;
11191                        }
11192                        '\t' => {
11193                            // \t are converted to spaces depending on the current column
11194                            let spaces_len = tab_size - (col % tab_size);
11195                            reindented_line.extend(&space_cache[spaces_len - 1]);
11196                            col += spaces_len;
11197                            changed = true;
11198                        }
11199                        _ => {
11200                            // If we dont append before break, the character is consumed
11201                            reindented_line.push(ch);
11202                            break;
11203                        }
11204                    }
11205                }
11206
11207                if !changed {
11208                    reindented_line.clear();
11209                    continue;
11210                }
11211                // Append the rest of the line and replace old reference with new one
11212                reindented_line.extend(chars);
11213                *line = Cow::Owned(reindented_line.clone());
11214                reindented_line.clear();
11215            }
11216        });
11217    }
11218
11219    pub fn convert_indentation_to_tabs(
11220        &mut self,
11221        _: &ConvertIndentationToTabs,
11222        window: &mut Window,
11223        cx: &mut Context<Self>,
11224    ) {
11225        let settings = self.buffer.read(cx).language_settings(cx);
11226        let tab_size = settings.tab_size.get() as usize;
11227
11228        self.manipulate_mutable_lines(window, cx, |lines| {
11229            // Allocates a reasonably sized buffer once for the whole loop
11230            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11231            // Avoids recomputing spaces that could be inserted many times
11232            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11233                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11234                .collect();
11235
11236            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11237                let mut chars = line.chars();
11238                let mut spaces_count = 0;
11239                let mut first_non_indent_char = None;
11240                let mut changed = false;
11241
11242                for ch in chars.by_ref() {
11243                    match ch {
11244                        ' ' => {
11245                            // Keep track of spaces. Append \t when we reach tab_size
11246                            spaces_count += 1;
11247                            changed = true;
11248                            if spaces_count == tab_size {
11249                                reindented_line.push('\t');
11250                                spaces_count = 0;
11251                            }
11252                        }
11253                        '\t' => {
11254                            reindented_line.push('\t');
11255                            spaces_count = 0;
11256                        }
11257                        _ => {
11258                            // Dont append it yet, we might have remaining spaces
11259                            first_non_indent_char = Some(ch);
11260                            break;
11261                        }
11262                    }
11263                }
11264
11265                if !changed {
11266                    reindented_line.clear();
11267                    continue;
11268                }
11269                // Remaining spaces that didn't make a full tab stop
11270                if spaces_count > 0 {
11271                    reindented_line.extend(&space_cache[spaces_count - 1]);
11272                }
11273                // If we consume an extra character that was not indentation, add it back
11274                if let Some(extra_char) = first_non_indent_char {
11275                    reindented_line.push(extra_char);
11276                }
11277                // Append the rest of the line and replace old reference with new one
11278                reindented_line.extend(chars);
11279                *line = Cow::Owned(reindented_line.clone());
11280                reindented_line.clear();
11281            }
11282        });
11283    }
11284
11285    pub fn convert_to_upper_case(
11286        &mut self,
11287        _: &ConvertToUpperCase,
11288        window: &mut Window,
11289        cx: &mut Context<Self>,
11290    ) {
11291        self.manipulate_text(window, cx, |text| text.to_uppercase())
11292    }
11293
11294    pub fn convert_to_lower_case(
11295        &mut self,
11296        _: &ConvertToLowerCase,
11297        window: &mut Window,
11298        cx: &mut Context<Self>,
11299    ) {
11300        self.manipulate_text(window, cx, |text| text.to_lowercase())
11301    }
11302
11303    pub fn convert_to_title_case(
11304        &mut self,
11305        _: &ConvertToTitleCase,
11306        window: &mut Window,
11307        cx: &mut Context<Self>,
11308    ) {
11309        self.manipulate_text(window, cx, |text| {
11310            text.split('\n')
11311                .map(|line| line.to_case(Case::Title))
11312                .join("\n")
11313        })
11314    }
11315
11316    pub fn convert_to_snake_case(
11317        &mut self,
11318        _: &ConvertToSnakeCase,
11319        window: &mut Window,
11320        cx: &mut Context<Self>,
11321    ) {
11322        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11323    }
11324
11325    pub fn convert_to_kebab_case(
11326        &mut self,
11327        _: &ConvertToKebabCase,
11328        window: &mut Window,
11329        cx: &mut Context<Self>,
11330    ) {
11331        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11332    }
11333
11334    pub fn convert_to_upper_camel_case(
11335        &mut self,
11336        _: &ConvertToUpperCamelCase,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        self.manipulate_text(window, cx, |text| {
11341            text.split('\n')
11342                .map(|line| line.to_case(Case::UpperCamel))
11343                .join("\n")
11344        })
11345    }
11346
11347    pub fn convert_to_lower_camel_case(
11348        &mut self,
11349        _: &ConvertToLowerCamelCase,
11350        window: &mut Window,
11351        cx: &mut Context<Self>,
11352    ) {
11353        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11354    }
11355
11356    pub fn convert_to_opposite_case(
11357        &mut self,
11358        _: &ConvertToOppositeCase,
11359        window: &mut Window,
11360        cx: &mut Context<Self>,
11361    ) {
11362        self.manipulate_text(window, cx, |text| {
11363            text.chars()
11364                .fold(String::with_capacity(text.len()), |mut t, c| {
11365                    if c.is_uppercase() {
11366                        t.extend(c.to_lowercase());
11367                    } else {
11368                        t.extend(c.to_uppercase());
11369                    }
11370                    t
11371                })
11372        })
11373    }
11374
11375    pub fn convert_to_sentence_case(
11376        &mut self,
11377        _: &ConvertToSentenceCase,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11382    }
11383
11384    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11385        self.manipulate_text(window, cx, |text| {
11386            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11387            if has_upper_case_characters {
11388                text.to_lowercase()
11389            } else {
11390                text.to_uppercase()
11391            }
11392        })
11393    }
11394
11395    pub fn convert_to_rot13(
11396        &mut self,
11397        _: &ConvertToRot13,
11398        window: &mut Window,
11399        cx: &mut Context<Self>,
11400    ) {
11401        self.manipulate_text(window, cx, |text| {
11402            text.chars()
11403                .map(|c| match c {
11404                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11405                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11406                    _ => c,
11407                })
11408                .collect()
11409        })
11410    }
11411
11412    pub fn convert_to_rot47(
11413        &mut self,
11414        _: &ConvertToRot47,
11415        window: &mut Window,
11416        cx: &mut Context<Self>,
11417    ) {
11418        self.manipulate_text(window, cx, |text| {
11419            text.chars()
11420                .map(|c| {
11421                    let code_point = c as u32;
11422                    if code_point >= 33 && code_point <= 126 {
11423                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11424                    }
11425                    c
11426                })
11427                .collect()
11428        })
11429    }
11430
11431    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11432    where
11433        Fn: FnMut(&str) -> String,
11434    {
11435        let buffer = self.buffer.read(cx).snapshot(cx);
11436
11437        let mut new_selections = Vec::new();
11438        let mut edits = Vec::new();
11439        let mut selection_adjustment = 0i32;
11440
11441        for selection in self.selections.all_adjusted(cx) {
11442            let selection_is_empty = selection.is_empty();
11443
11444            let (start, end) = if selection_is_empty {
11445                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11446                (word_range.start, word_range.end)
11447            } else {
11448                (
11449                    buffer.point_to_offset(selection.start),
11450                    buffer.point_to_offset(selection.end),
11451                )
11452            };
11453
11454            let text = buffer.text_for_range(start..end).collect::<String>();
11455            let old_length = text.len() as i32;
11456            let text = callback(&text);
11457
11458            new_selections.push(Selection {
11459                start: (start as i32 - selection_adjustment) as usize,
11460                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11461                goal: SelectionGoal::None,
11462                id: selection.id,
11463                reversed: selection.reversed,
11464            });
11465
11466            selection_adjustment += old_length - text.len() as i32;
11467
11468            edits.push((start..end, text));
11469        }
11470
11471        self.transact(window, cx, |this, window, cx| {
11472            this.buffer.update(cx, |buffer, cx| {
11473                buffer.edit(edits, None, cx);
11474            });
11475
11476            this.change_selections(Default::default(), window, cx, |s| {
11477                s.select(new_selections);
11478            });
11479
11480            this.request_autoscroll(Autoscroll::fit(), cx);
11481        });
11482    }
11483
11484    pub fn move_selection_on_drop(
11485        &mut self,
11486        selection: &Selection<Anchor>,
11487        target: DisplayPoint,
11488        is_cut: bool,
11489        window: &mut Window,
11490        cx: &mut Context<Self>,
11491    ) {
11492        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11493        let buffer = &display_map.buffer_snapshot;
11494        let mut edits = Vec::new();
11495        let insert_point = display_map
11496            .clip_point(target, Bias::Left)
11497            .to_point(&display_map);
11498        let text = buffer
11499            .text_for_range(selection.start..selection.end)
11500            .collect::<String>();
11501        if is_cut {
11502            edits.push(((selection.start..selection.end), String::new()));
11503        }
11504        let insert_anchor = buffer.anchor_before(insert_point);
11505        edits.push(((insert_anchor..insert_anchor), text));
11506        let last_edit_start = insert_anchor.bias_left(buffer);
11507        let last_edit_end = insert_anchor.bias_right(buffer);
11508        self.transact(window, cx, |this, window, cx| {
11509            this.buffer.update(cx, |buffer, cx| {
11510                buffer.edit(edits, None, cx);
11511            });
11512            this.change_selections(Default::default(), window, cx, |s| {
11513                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11514            });
11515        });
11516    }
11517
11518    pub fn clear_selection_drag_state(&mut self) {
11519        self.selection_drag_state = SelectionDragState::None;
11520    }
11521
11522    pub fn duplicate(
11523        &mut self,
11524        upwards: bool,
11525        whole_lines: bool,
11526        window: &mut Window,
11527        cx: &mut Context<Self>,
11528    ) {
11529        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11530
11531        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11532        let buffer = &display_map.buffer_snapshot;
11533        let selections = self.selections.all::<Point>(cx);
11534
11535        let mut edits = Vec::new();
11536        let mut selections_iter = selections.iter().peekable();
11537        while let Some(selection) = selections_iter.next() {
11538            let mut rows = selection.spanned_rows(false, &display_map);
11539            // duplicate line-wise
11540            if whole_lines || selection.start == selection.end {
11541                // Avoid duplicating the same lines twice.
11542                while let Some(next_selection) = selections_iter.peek() {
11543                    let next_rows = next_selection.spanned_rows(false, &display_map);
11544                    if next_rows.start < rows.end {
11545                        rows.end = next_rows.end;
11546                        selections_iter.next().unwrap();
11547                    } else {
11548                        break;
11549                    }
11550                }
11551
11552                // Copy the text from the selected row region and splice it either at the start
11553                // or end of the region.
11554                let start = Point::new(rows.start.0, 0);
11555                let end = Point::new(
11556                    rows.end.previous_row().0,
11557                    buffer.line_len(rows.end.previous_row()),
11558                );
11559                let text = buffer
11560                    .text_for_range(start..end)
11561                    .chain(Some("\n"))
11562                    .collect::<String>();
11563                let insert_location = if upwards {
11564                    Point::new(rows.end.0, 0)
11565                } else {
11566                    start
11567                };
11568                edits.push((insert_location..insert_location, text));
11569            } else {
11570                // duplicate character-wise
11571                let start = selection.start;
11572                let end = selection.end;
11573                let text = buffer.text_for_range(start..end).collect::<String>();
11574                edits.push((selection.end..selection.end, text));
11575            }
11576        }
11577
11578        self.transact(window, cx, |this, _, cx| {
11579            this.buffer.update(cx, |buffer, cx| {
11580                buffer.edit(edits, None, cx);
11581            });
11582
11583            this.request_autoscroll(Autoscroll::fit(), cx);
11584        });
11585    }
11586
11587    pub fn duplicate_line_up(
11588        &mut self,
11589        _: &DuplicateLineUp,
11590        window: &mut Window,
11591        cx: &mut Context<Self>,
11592    ) {
11593        self.duplicate(true, true, window, cx);
11594    }
11595
11596    pub fn duplicate_line_down(
11597        &mut self,
11598        _: &DuplicateLineDown,
11599        window: &mut Window,
11600        cx: &mut Context<Self>,
11601    ) {
11602        self.duplicate(false, true, window, cx);
11603    }
11604
11605    pub fn duplicate_selection(
11606        &mut self,
11607        _: &DuplicateSelection,
11608        window: &mut Window,
11609        cx: &mut Context<Self>,
11610    ) {
11611        self.duplicate(false, false, window, cx);
11612    }
11613
11614    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11616        if self.mode.is_single_line() {
11617            cx.propagate();
11618            return;
11619        }
11620
11621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11622        let buffer = self.buffer.read(cx).snapshot(cx);
11623
11624        let mut edits = Vec::new();
11625        let mut unfold_ranges = Vec::new();
11626        let mut refold_creases = Vec::new();
11627
11628        let selections = self.selections.all::<Point>(cx);
11629        let mut selections = selections.iter().peekable();
11630        let mut contiguous_row_selections = Vec::new();
11631        let mut new_selections = Vec::new();
11632
11633        while let Some(selection) = selections.next() {
11634            // Find all the selections that span a contiguous row range
11635            let (start_row, end_row) = consume_contiguous_rows(
11636                &mut contiguous_row_selections,
11637                selection,
11638                &display_map,
11639                &mut selections,
11640            );
11641
11642            // Move the text spanned by the row range to be before the line preceding the row range
11643            if start_row.0 > 0 {
11644                let range_to_move = Point::new(
11645                    start_row.previous_row().0,
11646                    buffer.line_len(start_row.previous_row()),
11647                )
11648                    ..Point::new(
11649                        end_row.previous_row().0,
11650                        buffer.line_len(end_row.previous_row()),
11651                    );
11652                let insertion_point = display_map
11653                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11654                    .0;
11655
11656                // Don't move lines across excerpts
11657                if buffer
11658                    .excerpt_containing(insertion_point..range_to_move.end)
11659                    .is_some()
11660                {
11661                    let text = buffer
11662                        .text_for_range(range_to_move.clone())
11663                        .flat_map(|s| s.chars())
11664                        .skip(1)
11665                        .chain(['\n'])
11666                        .collect::<String>();
11667
11668                    edits.push((
11669                        buffer.anchor_after(range_to_move.start)
11670                            ..buffer.anchor_before(range_to_move.end),
11671                        String::new(),
11672                    ));
11673                    let insertion_anchor = buffer.anchor_after(insertion_point);
11674                    edits.push((insertion_anchor..insertion_anchor, text));
11675
11676                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11677
11678                    // Move selections up
11679                    new_selections.extend(contiguous_row_selections.drain(..).map(
11680                        |mut selection| {
11681                            selection.start.row -= row_delta;
11682                            selection.end.row -= row_delta;
11683                            selection
11684                        },
11685                    ));
11686
11687                    // Move folds up
11688                    unfold_ranges.push(range_to_move.clone());
11689                    for fold in display_map.folds_in_range(
11690                        buffer.anchor_before(range_to_move.start)
11691                            ..buffer.anchor_after(range_to_move.end),
11692                    ) {
11693                        let mut start = fold.range.start.to_point(&buffer);
11694                        let mut end = fold.range.end.to_point(&buffer);
11695                        start.row -= row_delta;
11696                        end.row -= row_delta;
11697                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11698                    }
11699                }
11700            }
11701
11702            // If we didn't move line(s), preserve the existing selections
11703            new_selections.append(&mut contiguous_row_selections);
11704        }
11705
11706        self.transact(window, cx, |this, window, cx| {
11707            this.unfold_ranges(&unfold_ranges, true, true, cx);
11708            this.buffer.update(cx, |buffer, cx| {
11709                for (range, text) in edits {
11710                    buffer.edit([(range, text)], None, cx);
11711                }
11712            });
11713            this.fold_creases(refold_creases, true, window, cx);
11714            this.change_selections(Default::default(), window, cx, |s| {
11715                s.select(new_selections);
11716            })
11717        });
11718    }
11719
11720    pub fn move_line_down(
11721        &mut self,
11722        _: &MoveLineDown,
11723        window: &mut Window,
11724        cx: &mut Context<Self>,
11725    ) {
11726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11727        if self.mode.is_single_line() {
11728            cx.propagate();
11729            return;
11730        }
11731
11732        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11733        let buffer = self.buffer.read(cx).snapshot(cx);
11734
11735        let mut edits = Vec::new();
11736        let mut unfold_ranges = Vec::new();
11737        let mut refold_creases = Vec::new();
11738
11739        let selections = self.selections.all::<Point>(cx);
11740        let mut selections = selections.iter().peekable();
11741        let mut contiguous_row_selections = Vec::new();
11742        let mut new_selections = Vec::new();
11743
11744        while let Some(selection) = selections.next() {
11745            // Find all the selections that span a contiguous row range
11746            let (start_row, end_row) = consume_contiguous_rows(
11747                &mut contiguous_row_selections,
11748                selection,
11749                &display_map,
11750                &mut selections,
11751            );
11752
11753            // Move the text spanned by the row range to be after the last line of the row range
11754            if end_row.0 <= buffer.max_point().row {
11755                let range_to_move =
11756                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11757                let insertion_point = display_map
11758                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11759                    .0;
11760
11761                // Don't move lines across excerpt boundaries
11762                if buffer
11763                    .excerpt_containing(range_to_move.start..insertion_point)
11764                    .is_some()
11765                {
11766                    let mut text = String::from("\n");
11767                    text.extend(buffer.text_for_range(range_to_move.clone()));
11768                    text.pop(); // Drop trailing newline
11769                    edits.push((
11770                        buffer.anchor_after(range_to_move.start)
11771                            ..buffer.anchor_before(range_to_move.end),
11772                        String::new(),
11773                    ));
11774                    let insertion_anchor = buffer.anchor_after(insertion_point);
11775                    edits.push((insertion_anchor..insertion_anchor, text));
11776
11777                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11778
11779                    // Move selections down
11780                    new_selections.extend(contiguous_row_selections.drain(..).map(
11781                        |mut selection| {
11782                            selection.start.row += row_delta;
11783                            selection.end.row += row_delta;
11784                            selection
11785                        },
11786                    ));
11787
11788                    // Move folds down
11789                    unfold_ranges.push(range_to_move.clone());
11790                    for fold in display_map.folds_in_range(
11791                        buffer.anchor_before(range_to_move.start)
11792                            ..buffer.anchor_after(range_to_move.end),
11793                    ) {
11794                        let mut start = fold.range.start.to_point(&buffer);
11795                        let mut end = fold.range.end.to_point(&buffer);
11796                        start.row += row_delta;
11797                        end.row += row_delta;
11798                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11799                    }
11800                }
11801            }
11802
11803            // If we didn't move line(s), preserve the existing selections
11804            new_selections.append(&mut contiguous_row_selections);
11805        }
11806
11807        self.transact(window, cx, |this, window, cx| {
11808            this.unfold_ranges(&unfold_ranges, true, true, cx);
11809            this.buffer.update(cx, |buffer, cx| {
11810                for (range, text) in edits {
11811                    buffer.edit([(range, text)], None, cx);
11812                }
11813            });
11814            this.fold_creases(refold_creases, true, window, cx);
11815            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11816        });
11817    }
11818
11819    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11821        let text_layout_details = &self.text_layout_details(window);
11822        self.transact(window, cx, |this, window, cx| {
11823            let edits = this.change_selections(Default::default(), window, cx, |s| {
11824                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11825                s.move_with(|display_map, selection| {
11826                    if !selection.is_empty() {
11827                        return;
11828                    }
11829
11830                    let mut head = selection.head();
11831                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11832                    if head.column() == display_map.line_len(head.row()) {
11833                        transpose_offset = display_map
11834                            .buffer_snapshot
11835                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11836                    }
11837
11838                    if transpose_offset == 0 {
11839                        return;
11840                    }
11841
11842                    *head.column_mut() += 1;
11843                    head = display_map.clip_point(head, Bias::Right);
11844                    let goal = SelectionGoal::HorizontalPosition(
11845                        display_map
11846                            .x_for_display_point(head, text_layout_details)
11847                            .into(),
11848                    );
11849                    selection.collapse_to(head, goal);
11850
11851                    let transpose_start = display_map
11852                        .buffer_snapshot
11853                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11854                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11855                        let transpose_end = display_map
11856                            .buffer_snapshot
11857                            .clip_offset(transpose_offset + 1, Bias::Right);
11858                        if let Some(ch) =
11859                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11860                        {
11861                            edits.push((transpose_start..transpose_offset, String::new()));
11862                            edits.push((transpose_end..transpose_end, ch.to_string()));
11863                        }
11864                    }
11865                });
11866                edits
11867            });
11868            this.buffer
11869                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11870            let selections = this.selections.all::<usize>(cx);
11871            this.change_selections(Default::default(), window, cx, |s| {
11872                s.select(selections);
11873            });
11874        });
11875    }
11876
11877    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11879        if self.mode.is_single_line() {
11880            cx.propagate();
11881            return;
11882        }
11883
11884        self.rewrap_impl(RewrapOptions::default(), cx)
11885    }
11886
11887    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11888        let buffer = self.buffer.read(cx).snapshot(cx);
11889        let selections = self.selections.all::<Point>(cx);
11890
11891        #[derive(Clone, Debug, PartialEq)]
11892        enum CommentFormat {
11893            /// single line comment, with prefix for line
11894            Line(String),
11895            /// single line within a block comment, with prefix for line
11896            BlockLine(String),
11897            /// a single line of a block comment that includes the initial delimiter
11898            BlockCommentWithStart(BlockCommentConfig),
11899            /// a single line of a block comment that includes the ending delimiter
11900            BlockCommentWithEnd(BlockCommentConfig),
11901        }
11902
11903        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11904        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11905            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11906                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11907                .peekable();
11908
11909            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11910                row
11911            } else {
11912                return Vec::new();
11913            };
11914
11915            let language_settings = buffer.language_settings_at(selection.head(), cx);
11916            let language_scope = buffer.language_scope_at(selection.head());
11917
11918            let indent_and_prefix_for_row =
11919                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11920                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11921                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11922                        &language_scope
11923                    {
11924                        let indent_end = Point::new(row, indent.len);
11925                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11926                        let line_text_after_indent = buffer
11927                            .text_for_range(indent_end..line_end)
11928                            .collect::<String>();
11929
11930                        let is_within_comment_override = buffer
11931                            .language_scope_at(indent_end)
11932                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11933                        let comment_delimiters = if is_within_comment_override {
11934                            // we are within a comment syntax node, but we don't
11935                            // yet know what kind of comment: block, doc or line
11936                            match (
11937                                language_scope.documentation_comment(),
11938                                language_scope.block_comment(),
11939                            ) {
11940                                (Some(config), _) | (_, Some(config))
11941                                    if buffer.contains_str_at(indent_end, &config.start) =>
11942                                {
11943                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11944                                }
11945                                (Some(config), _) | (_, Some(config))
11946                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11947                                {
11948                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11949                                }
11950                                (Some(config), _) | (_, Some(config))
11951                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11952                                {
11953                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11954                                }
11955                                (_, _) => language_scope
11956                                    .line_comment_prefixes()
11957                                    .iter()
11958                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11959                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11960                            }
11961                        } else {
11962                            // we not in an overridden comment node, but we may
11963                            // be within a non-overridden line comment node
11964                            language_scope
11965                                .line_comment_prefixes()
11966                                .iter()
11967                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11968                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11969                        };
11970
11971                        let rewrap_prefix = language_scope
11972                            .rewrap_prefixes()
11973                            .iter()
11974                            .find_map(|prefix_regex| {
11975                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11976                                    if mat.start() == 0 {
11977                                        Some(mat.as_str().to_string())
11978                                    } else {
11979                                        None
11980                                    }
11981                                })
11982                            })
11983                            .flatten();
11984                        (comment_delimiters, rewrap_prefix)
11985                    } else {
11986                        (None, None)
11987                    };
11988                    (indent, comment_prefix, rewrap_prefix)
11989                };
11990
11991            let mut ranges = Vec::new();
11992            let from_empty_selection = selection.is_empty();
11993
11994            let mut current_range_start = first_row;
11995            let mut prev_row = first_row;
11996            let (
11997                mut current_range_indent,
11998                mut current_range_comment_delimiters,
11999                mut current_range_rewrap_prefix,
12000            ) = indent_and_prefix_for_row(first_row);
12001
12002            for row in non_blank_rows_iter.skip(1) {
12003                let has_paragraph_break = row > prev_row + 1;
12004
12005                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12006                    indent_and_prefix_for_row(row);
12007
12008                let has_indent_change = row_indent != current_range_indent;
12009                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12010
12011                let has_boundary_change = has_comment_change
12012                    || row_rewrap_prefix.is_some()
12013                    || (has_indent_change && current_range_comment_delimiters.is_some());
12014
12015                if has_paragraph_break || has_boundary_change {
12016                    ranges.push((
12017                        language_settings.clone(),
12018                        Point::new(current_range_start, 0)
12019                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12020                        current_range_indent,
12021                        current_range_comment_delimiters.clone(),
12022                        current_range_rewrap_prefix.clone(),
12023                        from_empty_selection,
12024                    ));
12025                    current_range_start = row;
12026                    current_range_indent = row_indent;
12027                    current_range_comment_delimiters = row_comment_delimiters;
12028                    current_range_rewrap_prefix = row_rewrap_prefix;
12029                }
12030                prev_row = row;
12031            }
12032
12033            ranges.push((
12034                language_settings.clone(),
12035                Point::new(current_range_start, 0)
12036                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12037                current_range_indent,
12038                current_range_comment_delimiters,
12039                current_range_rewrap_prefix,
12040                from_empty_selection,
12041            ));
12042
12043            ranges
12044        });
12045
12046        let mut edits = Vec::new();
12047        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12048
12049        for (
12050            language_settings,
12051            wrap_range,
12052            mut indent_size,
12053            comment_prefix,
12054            rewrap_prefix,
12055            from_empty_selection,
12056        ) in wrap_ranges
12057        {
12058            let mut start_row = wrap_range.start.row;
12059            let mut end_row = wrap_range.end.row;
12060
12061            // Skip selections that overlap with a range that has already been rewrapped.
12062            let selection_range = start_row..end_row;
12063            if rewrapped_row_ranges
12064                .iter()
12065                .any(|range| range.overlaps(&selection_range))
12066            {
12067                continue;
12068            }
12069
12070            let tab_size = language_settings.tab_size;
12071
12072            let (line_prefix, inside_comment) = match &comment_prefix {
12073                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12074                    (Some(prefix.as_str()), true)
12075                }
12076                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12077                    (Some(prefix.as_ref()), true)
12078                }
12079                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12080                    start: _,
12081                    end: _,
12082                    prefix,
12083                    tab_size,
12084                })) => {
12085                    indent_size.len += tab_size;
12086                    (Some(prefix.as_ref()), true)
12087                }
12088                None => (None, false),
12089            };
12090            let indent_prefix = indent_size.chars().collect::<String>();
12091            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12092
12093            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12094                RewrapBehavior::InComments => inside_comment,
12095                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12096                RewrapBehavior::Anywhere => true,
12097            };
12098
12099            let should_rewrap = options.override_language_settings
12100                || allow_rewrap_based_on_language
12101                || self.hard_wrap.is_some();
12102            if !should_rewrap {
12103                continue;
12104            }
12105
12106            if from_empty_selection {
12107                'expand_upwards: while start_row > 0 {
12108                    let prev_row = start_row - 1;
12109                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12110                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12111                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12112                    {
12113                        start_row = prev_row;
12114                    } else {
12115                        break 'expand_upwards;
12116                    }
12117                }
12118
12119                'expand_downwards: while end_row < buffer.max_point().row {
12120                    let next_row = end_row + 1;
12121                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12122                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12123                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12124                    {
12125                        end_row = next_row;
12126                    } else {
12127                        break 'expand_downwards;
12128                    }
12129                }
12130            }
12131
12132            let start = Point::new(start_row, 0);
12133            let start_offset = start.to_offset(&buffer);
12134            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12135            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12136            let mut first_line_delimiter = None;
12137            let mut last_line_delimiter = None;
12138            let Some(lines_without_prefixes) = selection_text
12139                .lines()
12140                .enumerate()
12141                .map(|(ix, line)| {
12142                    let line_trimmed = line.trim_start();
12143                    if rewrap_prefix.is_some() && ix > 0 {
12144                        Ok(line_trimmed)
12145                    } else if let Some(
12146                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12147                            start,
12148                            prefix,
12149                            end,
12150                            tab_size,
12151                        })
12152                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12153                            start,
12154                            prefix,
12155                            end,
12156                            tab_size,
12157                        }),
12158                    ) = &comment_prefix
12159                    {
12160                        let line_trimmed = line_trimmed
12161                            .strip_prefix(start.as_ref())
12162                            .map(|s| {
12163                                let mut indent_size = indent_size;
12164                                indent_size.len -= tab_size;
12165                                let indent_prefix: String = indent_size.chars().collect();
12166                                first_line_delimiter = Some((indent_prefix, start));
12167                                s.trim_start()
12168                            })
12169                            .unwrap_or(line_trimmed);
12170                        let line_trimmed = line_trimmed
12171                            .strip_suffix(end.as_ref())
12172                            .map(|s| {
12173                                last_line_delimiter = Some(end);
12174                                s.trim_end()
12175                            })
12176                            .unwrap_or(line_trimmed);
12177                        let line_trimmed = line_trimmed
12178                            .strip_prefix(prefix.as_ref())
12179                            .unwrap_or(line_trimmed);
12180                        Ok(line_trimmed)
12181                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12182                        line_trimmed.strip_prefix(prefix).with_context(|| {
12183                            format!("line did not start with prefix {prefix:?}: {line:?}")
12184                        })
12185                    } else {
12186                        line_trimmed
12187                            .strip_prefix(&line_prefix.trim_start())
12188                            .with_context(|| {
12189                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12190                            })
12191                    }
12192                })
12193                .collect::<Result<Vec<_>, _>>()
12194                .log_err()
12195            else {
12196                continue;
12197            };
12198
12199            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12200                buffer
12201                    .language_settings_at(Point::new(start_row, 0), cx)
12202                    .preferred_line_length as usize
12203            });
12204
12205            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12206                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12207            } else {
12208                line_prefix.clone()
12209            };
12210
12211            let wrapped_text = {
12212                let mut wrapped_text = wrap_with_prefix(
12213                    line_prefix,
12214                    subsequent_lines_prefix,
12215                    lines_without_prefixes.join("\n"),
12216                    wrap_column,
12217                    tab_size,
12218                    options.preserve_existing_whitespace,
12219                );
12220
12221                if let Some((indent, delimiter)) = first_line_delimiter {
12222                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12223                }
12224                if let Some(last_line) = last_line_delimiter {
12225                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12226                }
12227
12228                wrapped_text
12229            };
12230
12231            // TODO: should always use char-based diff while still supporting cursor behavior that
12232            // matches vim.
12233            let mut diff_options = DiffOptions::default();
12234            if options.override_language_settings {
12235                diff_options.max_word_diff_len = 0;
12236                diff_options.max_word_diff_line_count = 0;
12237            } else {
12238                diff_options.max_word_diff_len = usize::MAX;
12239                diff_options.max_word_diff_line_count = usize::MAX;
12240            }
12241
12242            for (old_range, new_text) in
12243                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12244            {
12245                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12246                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12247                edits.push((edit_start..edit_end, new_text));
12248            }
12249
12250            rewrapped_row_ranges.push(start_row..=end_row);
12251        }
12252
12253        self.buffer
12254            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12255    }
12256
12257    pub fn cut_common(
12258        &mut self,
12259        cut_no_selection_line: bool,
12260        window: &mut Window,
12261        cx: &mut Context<Self>,
12262    ) -> ClipboardItem {
12263        let mut text = String::new();
12264        let buffer = self.buffer.read(cx).snapshot(cx);
12265        let mut selections = self.selections.all::<Point>(cx);
12266        let mut clipboard_selections = Vec::with_capacity(selections.len());
12267        {
12268            let max_point = buffer.max_point();
12269            let mut is_first = true;
12270            for selection in &mut selections {
12271                let is_entire_line =
12272                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12273                if is_entire_line {
12274                    selection.start = Point::new(selection.start.row, 0);
12275                    if !selection.is_empty() && selection.end.column == 0 {
12276                        selection.end = cmp::min(max_point, selection.end);
12277                    } else {
12278                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12279                    }
12280                    selection.goal = SelectionGoal::None;
12281                }
12282                if is_first {
12283                    is_first = false;
12284                } else {
12285                    text += "\n";
12286                }
12287                let mut len = 0;
12288                for chunk in buffer.text_for_range(selection.start..selection.end) {
12289                    text.push_str(chunk);
12290                    len += chunk.len();
12291                }
12292                clipboard_selections.push(ClipboardSelection {
12293                    len,
12294                    is_entire_line,
12295                    first_line_indent: buffer
12296                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12297                        .len,
12298                });
12299            }
12300        }
12301
12302        self.transact(window, cx, |this, window, cx| {
12303            this.change_selections(Default::default(), window, cx, |s| {
12304                s.select(selections);
12305            });
12306            this.insert("", window, cx);
12307        });
12308        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12309    }
12310
12311    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12312        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12313        let item = self.cut_common(true, window, cx);
12314        cx.write_to_clipboard(item);
12315    }
12316
12317    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12318        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12319        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12320            s.move_with(|snapshot, sel| {
12321                if sel.is_empty() {
12322                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12323                }
12324                if sel.is_empty() {
12325                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12326                }
12327            });
12328        });
12329        let item = self.cut_common(true, window, cx);
12330        cx.set_global(KillRing(item))
12331    }
12332
12333    pub fn kill_ring_yank(
12334        &mut self,
12335        _: &KillRingYank,
12336        window: &mut Window,
12337        cx: &mut Context<Self>,
12338    ) {
12339        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12340        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12341            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12342                (kill_ring.text().to_string(), kill_ring.metadata_json())
12343            } else {
12344                return;
12345            }
12346        } else {
12347            return;
12348        };
12349        self.do_paste(&text, metadata, false, window, cx);
12350    }
12351
12352    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12353        self.do_copy(true, cx);
12354    }
12355
12356    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12357        self.do_copy(false, cx);
12358    }
12359
12360    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12361        let selections = self.selections.all::<Point>(cx);
12362        let buffer = self.buffer.read(cx).read(cx);
12363        let mut text = String::new();
12364
12365        let mut clipboard_selections = Vec::with_capacity(selections.len());
12366        {
12367            let max_point = buffer.max_point();
12368            let mut is_first = true;
12369            for selection in &selections {
12370                let mut start = selection.start;
12371                let mut end = selection.end;
12372                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12373                if is_entire_line {
12374                    start = Point::new(start.row, 0);
12375                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12376                }
12377
12378                let mut trimmed_selections = Vec::new();
12379                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12380                    let row = MultiBufferRow(start.row);
12381                    let first_indent = buffer.indent_size_for_line(row);
12382                    if first_indent.len == 0 || start.column > first_indent.len {
12383                        trimmed_selections.push(start..end);
12384                    } else {
12385                        trimmed_selections.push(
12386                            Point::new(row.0, first_indent.len)
12387                                ..Point::new(row.0, buffer.line_len(row)),
12388                        );
12389                        for row in start.row + 1..=end.row {
12390                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12391                            if row == end.row {
12392                                line_len = end.column;
12393                            }
12394                            if line_len == 0 {
12395                                trimmed_selections
12396                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12397                                continue;
12398                            }
12399                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12400                            if row_indent_size.len >= first_indent.len {
12401                                trimmed_selections.push(
12402                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12403                                );
12404                            } else {
12405                                trimmed_selections.clear();
12406                                trimmed_selections.push(start..end);
12407                                break;
12408                            }
12409                        }
12410                    }
12411                } else {
12412                    trimmed_selections.push(start..end);
12413                }
12414
12415                for trimmed_range in trimmed_selections {
12416                    if is_first {
12417                        is_first = false;
12418                    } else {
12419                        text += "\n";
12420                    }
12421                    let mut len = 0;
12422                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12423                        text.push_str(chunk);
12424                        len += chunk.len();
12425                    }
12426                    clipboard_selections.push(ClipboardSelection {
12427                        len,
12428                        is_entire_line,
12429                        first_line_indent: buffer
12430                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12431                            .len,
12432                    });
12433                }
12434            }
12435        }
12436
12437        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12438            text,
12439            clipboard_selections,
12440        ));
12441    }
12442
12443    pub fn do_paste(
12444        &mut self,
12445        text: &String,
12446        clipboard_selections: Option<Vec<ClipboardSelection>>,
12447        handle_entire_lines: bool,
12448        window: &mut Window,
12449        cx: &mut Context<Self>,
12450    ) {
12451        if self.read_only(cx) {
12452            return;
12453        }
12454
12455        let clipboard_text = Cow::Borrowed(text.as_str());
12456
12457        self.transact(window, cx, |this, window, cx| {
12458            let had_active_edit_prediction = this.has_active_edit_prediction();
12459            let old_selections = this.selections.all::<usize>(cx);
12460            let cursor_offset = this.selections.last::<usize>(cx).head();
12461
12462            if let Some(mut clipboard_selections) = clipboard_selections {
12463                let all_selections_were_entire_line =
12464                    clipboard_selections.iter().all(|s| s.is_entire_line);
12465                let first_selection_indent_column =
12466                    clipboard_selections.first().map(|s| s.first_line_indent);
12467                if clipboard_selections.len() != old_selections.len() {
12468                    clipboard_selections.drain(..);
12469                }
12470                let mut auto_indent_on_paste = true;
12471
12472                this.buffer.update(cx, |buffer, cx| {
12473                    let snapshot = buffer.read(cx);
12474                    auto_indent_on_paste = snapshot
12475                        .language_settings_at(cursor_offset, cx)
12476                        .auto_indent_on_paste;
12477
12478                    let mut start_offset = 0;
12479                    let mut edits = Vec::new();
12480                    let mut original_indent_columns = Vec::new();
12481                    for (ix, selection) in old_selections.iter().enumerate() {
12482                        let to_insert;
12483                        let entire_line;
12484                        let original_indent_column;
12485                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12486                            let end_offset = start_offset + clipboard_selection.len;
12487                            to_insert = &clipboard_text[start_offset..end_offset];
12488                            entire_line = clipboard_selection.is_entire_line;
12489                            start_offset = end_offset + 1;
12490                            original_indent_column = Some(clipboard_selection.first_line_indent);
12491                        } else {
12492                            to_insert = &*clipboard_text;
12493                            entire_line = all_selections_were_entire_line;
12494                            original_indent_column = first_selection_indent_column
12495                        }
12496
12497                        let (range, to_insert) =
12498                            if selection.is_empty() && handle_entire_lines && entire_line {
12499                                // If the corresponding selection was empty when this slice of the
12500                                // clipboard text was written, then the entire line containing the
12501                                // selection was copied. If this selection is also currently empty,
12502                                // then paste the line before the current line of the buffer.
12503                                let column = selection.start.to_point(&snapshot).column as usize;
12504                                let line_start = selection.start - column;
12505                                (line_start..line_start, Cow::Borrowed(to_insert))
12506                            } else {
12507                                let language = snapshot.language_at(selection.head());
12508                                let range = selection.range();
12509                                if let Some(language) = language
12510                                    && language.name() == "Markdown".into()
12511                                {
12512                                    edit_for_markdown_paste(
12513                                        &snapshot,
12514                                        range,
12515                                        to_insert,
12516                                        url::Url::parse(to_insert).ok(),
12517                                    )
12518                                } else {
12519                                    (range, Cow::Borrowed(to_insert))
12520                                }
12521                            };
12522
12523                        edits.push((range, to_insert));
12524                        original_indent_columns.push(original_indent_column);
12525                    }
12526                    drop(snapshot);
12527
12528                    buffer.edit(
12529                        edits,
12530                        if auto_indent_on_paste {
12531                            Some(AutoindentMode::Block {
12532                                original_indent_columns,
12533                            })
12534                        } else {
12535                            None
12536                        },
12537                        cx,
12538                    );
12539                });
12540
12541                let selections = this.selections.all::<usize>(cx);
12542                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12543            } else {
12544                let url = url::Url::parse(&clipboard_text).ok();
12545
12546                let auto_indent_mode = if !clipboard_text.is_empty() {
12547                    Some(AutoindentMode::Block {
12548                        original_indent_columns: Vec::new(),
12549                    })
12550                } else {
12551                    None
12552                };
12553
12554                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12555                    let snapshot = buffer.snapshot(cx);
12556
12557                    let anchors = old_selections
12558                        .iter()
12559                        .map(|s| {
12560                            let anchor = snapshot.anchor_after(s.head());
12561                            s.map(|_| anchor)
12562                        })
12563                        .collect::<Vec<_>>();
12564
12565                    let mut edits = Vec::new();
12566
12567                    for selection in old_selections.iter() {
12568                        let language = snapshot.language_at(selection.head());
12569                        let range = selection.range();
12570
12571                        let (edit_range, edit_text) = if let Some(language) = language
12572                            && language.name() == "Markdown".into()
12573                        {
12574                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12575                        } else {
12576                            (range, clipboard_text.clone())
12577                        };
12578
12579                        edits.push((edit_range, edit_text));
12580                    }
12581
12582                    drop(snapshot);
12583                    buffer.edit(edits, auto_indent_mode, cx);
12584
12585                    anchors
12586                });
12587
12588                this.change_selections(Default::default(), window, cx, |s| {
12589                    s.select_anchors(selection_anchors);
12590                });
12591            }
12592
12593            let trigger_in_words =
12594                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12595
12596            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12597        });
12598    }
12599
12600    pub fn diff_clipboard_with_selection(
12601        &mut self,
12602        _: &DiffClipboardWithSelection,
12603        window: &mut Window,
12604        cx: &mut Context<Self>,
12605    ) {
12606        let selections = self.selections.all::<usize>(cx);
12607
12608        if selections.is_empty() {
12609            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12610            return;
12611        };
12612
12613        let clipboard_text = match cx.read_from_clipboard() {
12614            Some(item) => match item.entries().first() {
12615                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12616                _ => None,
12617            },
12618            None => None,
12619        };
12620
12621        let Some(clipboard_text) = clipboard_text else {
12622            log::warn!("Clipboard doesn't contain text.");
12623            return;
12624        };
12625
12626        window.dispatch_action(
12627            Box::new(DiffClipboardWithSelectionData {
12628                clipboard_text,
12629                editor: cx.entity(),
12630            }),
12631            cx,
12632        );
12633    }
12634
12635    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12636        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12637        if let Some(item) = cx.read_from_clipboard() {
12638            let entries = item.entries();
12639
12640            match entries.first() {
12641                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12642                // of all the pasted entries.
12643                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12644                    .do_paste(
12645                        clipboard_string.text(),
12646                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12647                        true,
12648                        window,
12649                        cx,
12650                    ),
12651                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12652            }
12653        }
12654    }
12655
12656    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12657        if self.read_only(cx) {
12658            return;
12659        }
12660
12661        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12662
12663        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12664            if let Some((selections, _)) =
12665                self.selection_history.transaction(transaction_id).cloned()
12666            {
12667                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12668                    s.select_anchors(selections.to_vec());
12669                });
12670            } else {
12671                log::error!(
12672                    "No entry in selection_history found for undo. \
12673                     This may correspond to a bug where undo does not update the selection. \
12674                     If this is occurring, please add details to \
12675                     https://github.com/zed-industries/zed/issues/22692"
12676                );
12677            }
12678            self.request_autoscroll(Autoscroll::fit(), cx);
12679            self.unmark_text(window, cx);
12680            self.refresh_edit_prediction(true, false, window, cx);
12681            cx.emit(EditorEvent::Edited { transaction_id });
12682            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12683        }
12684    }
12685
12686    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12687        if self.read_only(cx) {
12688            return;
12689        }
12690
12691        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12692
12693        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12694            if let Some((_, Some(selections))) =
12695                self.selection_history.transaction(transaction_id).cloned()
12696            {
12697                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12698                    s.select_anchors(selections.to_vec());
12699                });
12700            } else {
12701                log::error!(
12702                    "No entry in selection_history found for redo. \
12703                     This may correspond to a bug where undo does not update the selection. \
12704                     If this is occurring, please add details to \
12705                     https://github.com/zed-industries/zed/issues/22692"
12706                );
12707            }
12708            self.request_autoscroll(Autoscroll::fit(), cx);
12709            self.unmark_text(window, cx);
12710            self.refresh_edit_prediction(true, false, window, cx);
12711            cx.emit(EditorEvent::Edited { transaction_id });
12712        }
12713    }
12714
12715    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12716        self.buffer
12717            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12718    }
12719
12720    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12721        self.buffer
12722            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12723    }
12724
12725    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12727        self.change_selections(Default::default(), window, cx, |s| {
12728            s.move_with(|map, selection| {
12729                let cursor = if selection.is_empty() {
12730                    movement::left(map, selection.start)
12731                } else {
12732                    selection.start
12733                };
12734                selection.collapse_to(cursor, SelectionGoal::None);
12735            });
12736        })
12737    }
12738
12739    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12741        self.change_selections(Default::default(), window, cx, |s| {
12742            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12743        })
12744    }
12745
12746    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12748        self.change_selections(Default::default(), window, cx, |s| {
12749            s.move_with(|map, selection| {
12750                let cursor = if selection.is_empty() {
12751                    movement::right(map, selection.end)
12752                } else {
12753                    selection.end
12754                };
12755                selection.collapse_to(cursor, SelectionGoal::None)
12756            });
12757        })
12758    }
12759
12760    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12762        self.change_selections(Default::default(), window, cx, |s| {
12763            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12764        })
12765    }
12766
12767    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12768        if self.take_rename(true, window, cx).is_some() {
12769            return;
12770        }
12771
12772        if self.mode.is_single_line() {
12773            cx.propagate();
12774            return;
12775        }
12776
12777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12778
12779        let text_layout_details = &self.text_layout_details(window);
12780        let selection_count = self.selections.count();
12781        let first_selection = self.selections.first_anchor();
12782
12783        self.change_selections(Default::default(), window, cx, |s| {
12784            s.move_with(|map, selection| {
12785                if !selection.is_empty() {
12786                    selection.goal = SelectionGoal::None;
12787                }
12788                let (cursor, goal) = movement::up(
12789                    map,
12790                    selection.start,
12791                    selection.goal,
12792                    false,
12793                    text_layout_details,
12794                );
12795                selection.collapse_to(cursor, goal);
12796            });
12797        });
12798
12799        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12800        {
12801            cx.propagate();
12802        }
12803    }
12804
12805    pub fn move_up_by_lines(
12806        &mut self,
12807        action: &MoveUpByLines,
12808        window: &mut Window,
12809        cx: &mut Context<Self>,
12810    ) {
12811        if self.take_rename(true, window, cx).is_some() {
12812            return;
12813        }
12814
12815        if self.mode.is_single_line() {
12816            cx.propagate();
12817            return;
12818        }
12819
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12821
12822        let text_layout_details = &self.text_layout_details(window);
12823
12824        self.change_selections(Default::default(), window, cx, |s| {
12825            s.move_with(|map, selection| {
12826                if !selection.is_empty() {
12827                    selection.goal = SelectionGoal::None;
12828                }
12829                let (cursor, goal) = movement::up_by_rows(
12830                    map,
12831                    selection.start,
12832                    action.lines,
12833                    selection.goal,
12834                    false,
12835                    text_layout_details,
12836                );
12837                selection.collapse_to(cursor, goal);
12838            });
12839        })
12840    }
12841
12842    pub fn move_down_by_lines(
12843        &mut self,
12844        action: &MoveDownByLines,
12845        window: &mut Window,
12846        cx: &mut Context<Self>,
12847    ) {
12848        if self.take_rename(true, window, cx).is_some() {
12849            return;
12850        }
12851
12852        if self.mode.is_single_line() {
12853            cx.propagate();
12854            return;
12855        }
12856
12857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12858
12859        let text_layout_details = &self.text_layout_details(window);
12860
12861        self.change_selections(Default::default(), window, cx, |s| {
12862            s.move_with(|map, selection| {
12863                if !selection.is_empty() {
12864                    selection.goal = SelectionGoal::None;
12865                }
12866                let (cursor, goal) = movement::down_by_rows(
12867                    map,
12868                    selection.start,
12869                    action.lines,
12870                    selection.goal,
12871                    false,
12872                    text_layout_details,
12873                );
12874                selection.collapse_to(cursor, goal);
12875            });
12876        })
12877    }
12878
12879    pub fn select_down_by_lines(
12880        &mut self,
12881        action: &SelectDownByLines,
12882        window: &mut Window,
12883        cx: &mut Context<Self>,
12884    ) {
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12886        let text_layout_details = &self.text_layout_details(window);
12887        self.change_selections(Default::default(), window, cx, |s| {
12888            s.move_heads_with(|map, head, goal| {
12889                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12890            })
12891        })
12892    }
12893
12894    pub fn select_up_by_lines(
12895        &mut self,
12896        action: &SelectUpByLines,
12897        window: &mut Window,
12898        cx: &mut Context<Self>,
12899    ) {
12900        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12901        let text_layout_details = &self.text_layout_details(window);
12902        self.change_selections(Default::default(), window, cx, |s| {
12903            s.move_heads_with(|map, head, goal| {
12904                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12905            })
12906        })
12907    }
12908
12909    pub fn select_page_up(
12910        &mut self,
12911        _: &SelectPageUp,
12912        window: &mut Window,
12913        cx: &mut Context<Self>,
12914    ) {
12915        let Some(row_count) = self.visible_row_count() else {
12916            return;
12917        };
12918
12919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12920
12921        let text_layout_details = &self.text_layout_details(window);
12922
12923        self.change_selections(Default::default(), window, cx, |s| {
12924            s.move_heads_with(|map, head, goal| {
12925                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12926            })
12927        })
12928    }
12929
12930    pub fn move_page_up(
12931        &mut self,
12932        action: &MovePageUp,
12933        window: &mut Window,
12934        cx: &mut Context<Self>,
12935    ) {
12936        if self.take_rename(true, window, cx).is_some() {
12937            return;
12938        }
12939
12940        if self
12941            .context_menu
12942            .borrow_mut()
12943            .as_mut()
12944            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12945            .unwrap_or(false)
12946        {
12947            return;
12948        }
12949
12950        if matches!(self.mode, EditorMode::SingleLine) {
12951            cx.propagate();
12952            return;
12953        }
12954
12955        let Some(row_count) = self.visible_row_count() else {
12956            return;
12957        };
12958
12959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12960
12961        let effects = if action.center_cursor {
12962            SelectionEffects::scroll(Autoscroll::center())
12963        } else {
12964            SelectionEffects::default()
12965        };
12966
12967        let text_layout_details = &self.text_layout_details(window);
12968
12969        self.change_selections(effects, window, cx, |s| {
12970            s.move_with(|map, selection| {
12971                if !selection.is_empty() {
12972                    selection.goal = SelectionGoal::None;
12973                }
12974                let (cursor, goal) = movement::up_by_rows(
12975                    map,
12976                    selection.end,
12977                    row_count,
12978                    selection.goal,
12979                    false,
12980                    text_layout_details,
12981                );
12982                selection.collapse_to(cursor, goal);
12983            });
12984        });
12985    }
12986
12987    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12989        let text_layout_details = &self.text_layout_details(window);
12990        self.change_selections(Default::default(), window, cx, |s| {
12991            s.move_heads_with(|map, head, goal| {
12992                movement::up(map, head, goal, false, text_layout_details)
12993            })
12994        })
12995    }
12996
12997    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12998        self.take_rename(true, window, cx);
12999
13000        if self.mode.is_single_line() {
13001            cx.propagate();
13002            return;
13003        }
13004
13005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13006
13007        let text_layout_details = &self.text_layout_details(window);
13008        let selection_count = self.selections.count();
13009        let first_selection = self.selections.first_anchor();
13010
13011        self.change_selections(Default::default(), window, cx, |s| {
13012            s.move_with(|map, selection| {
13013                if !selection.is_empty() {
13014                    selection.goal = SelectionGoal::None;
13015                }
13016                let (cursor, goal) = movement::down(
13017                    map,
13018                    selection.end,
13019                    selection.goal,
13020                    false,
13021                    text_layout_details,
13022                );
13023                selection.collapse_to(cursor, goal);
13024            });
13025        });
13026
13027        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13028        {
13029            cx.propagate();
13030        }
13031    }
13032
13033    pub fn select_page_down(
13034        &mut self,
13035        _: &SelectPageDown,
13036        window: &mut Window,
13037        cx: &mut Context<Self>,
13038    ) {
13039        let Some(row_count) = self.visible_row_count() else {
13040            return;
13041        };
13042
13043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13044
13045        let text_layout_details = &self.text_layout_details(window);
13046
13047        self.change_selections(Default::default(), window, cx, |s| {
13048            s.move_heads_with(|map, head, goal| {
13049                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13050            })
13051        })
13052    }
13053
13054    pub fn move_page_down(
13055        &mut self,
13056        action: &MovePageDown,
13057        window: &mut Window,
13058        cx: &mut Context<Self>,
13059    ) {
13060        if self.take_rename(true, window, cx).is_some() {
13061            return;
13062        }
13063
13064        if self
13065            .context_menu
13066            .borrow_mut()
13067            .as_mut()
13068            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13069            .unwrap_or(false)
13070        {
13071            return;
13072        }
13073
13074        if matches!(self.mode, EditorMode::SingleLine) {
13075            cx.propagate();
13076            return;
13077        }
13078
13079        let Some(row_count) = self.visible_row_count() else {
13080            return;
13081        };
13082
13083        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13084
13085        let effects = if action.center_cursor {
13086            SelectionEffects::scroll(Autoscroll::center())
13087        } else {
13088            SelectionEffects::default()
13089        };
13090
13091        let text_layout_details = &self.text_layout_details(window);
13092        self.change_selections(effects, window, cx, |s| {
13093            s.move_with(|map, selection| {
13094                if !selection.is_empty() {
13095                    selection.goal = SelectionGoal::None;
13096                }
13097                let (cursor, goal) = movement::down_by_rows(
13098                    map,
13099                    selection.end,
13100                    row_count,
13101                    selection.goal,
13102                    false,
13103                    text_layout_details,
13104                );
13105                selection.collapse_to(cursor, goal);
13106            });
13107        });
13108    }
13109
13110    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13112        let text_layout_details = &self.text_layout_details(window);
13113        self.change_selections(Default::default(), window, cx, |s| {
13114            s.move_heads_with(|map, head, goal| {
13115                movement::down(map, head, goal, false, text_layout_details)
13116            })
13117        });
13118    }
13119
13120    pub fn context_menu_first(
13121        &mut self,
13122        _: &ContextMenuFirst,
13123        window: &mut Window,
13124        cx: &mut Context<Self>,
13125    ) {
13126        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13127            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13128        }
13129    }
13130
13131    pub fn context_menu_prev(
13132        &mut self,
13133        _: &ContextMenuPrevious,
13134        window: &mut Window,
13135        cx: &mut Context<Self>,
13136    ) {
13137        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13138            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13139        }
13140    }
13141
13142    pub fn context_menu_next(
13143        &mut self,
13144        _: &ContextMenuNext,
13145        window: &mut Window,
13146        cx: &mut Context<Self>,
13147    ) {
13148        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13149            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13150        }
13151    }
13152
13153    pub fn context_menu_last(
13154        &mut self,
13155        _: &ContextMenuLast,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13160            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13161        }
13162    }
13163
13164    pub fn signature_help_prev(
13165        &mut self,
13166        _: &SignatureHelpPrevious,
13167        _: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        if let Some(popover) = self.signature_help_state.popover_mut() {
13171            if popover.current_signature == 0 {
13172                popover.current_signature = popover.signatures.len() - 1;
13173            } else {
13174                popover.current_signature -= 1;
13175            }
13176            cx.notify();
13177        }
13178    }
13179
13180    pub fn signature_help_next(
13181        &mut self,
13182        _: &SignatureHelpNext,
13183        _: &mut Window,
13184        cx: &mut Context<Self>,
13185    ) {
13186        if let Some(popover) = self.signature_help_state.popover_mut() {
13187            if popover.current_signature + 1 == popover.signatures.len() {
13188                popover.current_signature = 0;
13189            } else {
13190                popover.current_signature += 1;
13191            }
13192            cx.notify();
13193        }
13194    }
13195
13196    pub fn move_to_previous_word_start(
13197        &mut self,
13198        _: &MoveToPreviousWordStart,
13199        window: &mut Window,
13200        cx: &mut Context<Self>,
13201    ) {
13202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13203        self.change_selections(Default::default(), window, cx, |s| {
13204            s.move_cursors_with(|map, head, _| {
13205                (
13206                    movement::previous_word_start(map, head),
13207                    SelectionGoal::None,
13208                )
13209            });
13210        })
13211    }
13212
13213    pub fn move_to_previous_subword_start(
13214        &mut self,
13215        _: &MoveToPreviousSubwordStart,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) {
13219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13220        self.change_selections(Default::default(), window, cx, |s| {
13221            s.move_cursors_with(|map, head, _| {
13222                (
13223                    movement::previous_subword_start(map, head),
13224                    SelectionGoal::None,
13225                )
13226            });
13227        })
13228    }
13229
13230    pub fn select_to_previous_word_start(
13231        &mut self,
13232        _: &SelectToPreviousWordStart,
13233        window: &mut Window,
13234        cx: &mut Context<Self>,
13235    ) {
13236        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13237        self.change_selections(Default::default(), window, cx, |s| {
13238            s.move_heads_with(|map, head, _| {
13239                (
13240                    movement::previous_word_start(map, head),
13241                    SelectionGoal::None,
13242                )
13243            });
13244        })
13245    }
13246
13247    pub fn select_to_previous_subword_start(
13248        &mut self,
13249        _: &SelectToPreviousSubwordStart,
13250        window: &mut Window,
13251        cx: &mut Context<Self>,
13252    ) {
13253        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13254        self.change_selections(Default::default(), window, cx, |s| {
13255            s.move_heads_with(|map, head, _| {
13256                (
13257                    movement::previous_subword_start(map, head),
13258                    SelectionGoal::None,
13259                )
13260            });
13261        })
13262    }
13263
13264    pub fn delete_to_previous_word_start(
13265        &mut self,
13266        action: &DeleteToPreviousWordStart,
13267        window: &mut Window,
13268        cx: &mut Context<Self>,
13269    ) {
13270        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13271        self.transact(window, cx, |this, window, cx| {
13272            this.select_autoclose_pair(window, cx);
13273            this.change_selections(Default::default(), window, cx, |s| {
13274                s.move_with(|map, selection| {
13275                    if selection.is_empty() {
13276                        let mut cursor = if action.ignore_newlines {
13277                            movement::previous_word_start(map, selection.head())
13278                        } else {
13279                            movement::previous_word_start_or_newline(map, selection.head())
13280                        };
13281                        cursor = movement::adjust_greedy_deletion(
13282                            map,
13283                            selection.head(),
13284                            cursor,
13285                            action.ignore_brackets,
13286                        );
13287                        selection.set_head(cursor, SelectionGoal::None);
13288                    }
13289                });
13290            });
13291            this.insert("", window, cx);
13292        });
13293    }
13294
13295    pub fn delete_to_previous_subword_start(
13296        &mut self,
13297        _: &DeleteToPreviousSubwordStart,
13298        window: &mut Window,
13299        cx: &mut Context<Self>,
13300    ) {
13301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13302        self.transact(window, cx, |this, window, cx| {
13303            this.select_autoclose_pair(window, cx);
13304            this.change_selections(Default::default(), window, cx, |s| {
13305                s.move_with(|map, selection| {
13306                    if selection.is_empty() {
13307                        let mut cursor = movement::previous_subword_start(map, selection.head());
13308                        cursor =
13309                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13310                        selection.set_head(cursor, SelectionGoal::None);
13311                    }
13312                });
13313            });
13314            this.insert("", window, cx);
13315        });
13316    }
13317
13318    pub fn move_to_next_word_end(
13319        &mut self,
13320        _: &MoveToNextWordEnd,
13321        window: &mut Window,
13322        cx: &mut Context<Self>,
13323    ) {
13324        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13325        self.change_selections(Default::default(), window, cx, |s| {
13326            s.move_cursors_with(|map, head, _| {
13327                (movement::next_word_end(map, head), SelectionGoal::None)
13328            });
13329        })
13330    }
13331
13332    pub fn move_to_next_subword_end(
13333        &mut self,
13334        _: &MoveToNextSubwordEnd,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13339        self.change_selections(Default::default(), window, cx, |s| {
13340            s.move_cursors_with(|map, head, _| {
13341                (movement::next_subword_end(map, head), SelectionGoal::None)
13342            });
13343        })
13344    }
13345
13346    pub fn select_to_next_word_end(
13347        &mut self,
13348        _: &SelectToNextWordEnd,
13349        window: &mut Window,
13350        cx: &mut Context<Self>,
13351    ) {
13352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13353        self.change_selections(Default::default(), window, cx, |s| {
13354            s.move_heads_with(|map, head, _| {
13355                (movement::next_word_end(map, head), SelectionGoal::None)
13356            });
13357        })
13358    }
13359
13360    pub fn select_to_next_subword_end(
13361        &mut self,
13362        _: &SelectToNextSubwordEnd,
13363        window: &mut Window,
13364        cx: &mut Context<Self>,
13365    ) {
13366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13367        self.change_selections(Default::default(), window, cx, |s| {
13368            s.move_heads_with(|map, head, _| {
13369                (movement::next_subword_end(map, head), SelectionGoal::None)
13370            });
13371        })
13372    }
13373
13374    pub fn delete_to_next_word_end(
13375        &mut self,
13376        action: &DeleteToNextWordEnd,
13377        window: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13381        self.transact(window, cx, |this, window, cx| {
13382            this.change_selections(Default::default(), window, cx, |s| {
13383                s.move_with(|map, selection| {
13384                    if selection.is_empty() {
13385                        let mut cursor = if action.ignore_newlines {
13386                            movement::next_word_end(map, selection.head())
13387                        } else {
13388                            movement::next_word_end_or_newline(map, selection.head())
13389                        };
13390                        cursor = movement::adjust_greedy_deletion(
13391                            map,
13392                            selection.head(),
13393                            cursor,
13394                            action.ignore_brackets,
13395                        );
13396                        selection.set_head(cursor, SelectionGoal::None);
13397                    }
13398                });
13399            });
13400            this.insert("", window, cx);
13401        });
13402    }
13403
13404    pub fn delete_to_next_subword_end(
13405        &mut self,
13406        _: &DeleteToNextSubwordEnd,
13407        window: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) {
13410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13411        self.transact(window, cx, |this, window, cx| {
13412            this.change_selections(Default::default(), window, cx, |s| {
13413                s.move_with(|map, selection| {
13414                    if selection.is_empty() {
13415                        let mut cursor = movement::next_subword_end(map, selection.head());
13416                        cursor =
13417                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13418                        selection.set_head(cursor, SelectionGoal::None);
13419                    }
13420                });
13421            });
13422            this.insert("", window, cx);
13423        });
13424    }
13425
13426    pub fn move_to_beginning_of_line(
13427        &mut self,
13428        action: &MoveToBeginningOfLine,
13429        window: &mut Window,
13430        cx: &mut Context<Self>,
13431    ) {
13432        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13433        self.change_selections(Default::default(), window, cx, |s| {
13434            s.move_cursors_with(|map, head, _| {
13435                (
13436                    movement::indented_line_beginning(
13437                        map,
13438                        head,
13439                        action.stop_at_soft_wraps,
13440                        action.stop_at_indent,
13441                    ),
13442                    SelectionGoal::None,
13443                )
13444            });
13445        })
13446    }
13447
13448    pub fn select_to_beginning_of_line(
13449        &mut self,
13450        action: &SelectToBeginningOfLine,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13455        self.change_selections(Default::default(), window, cx, |s| {
13456            s.move_heads_with(|map, head, _| {
13457                (
13458                    movement::indented_line_beginning(
13459                        map,
13460                        head,
13461                        action.stop_at_soft_wraps,
13462                        action.stop_at_indent,
13463                    ),
13464                    SelectionGoal::None,
13465                )
13466            });
13467        });
13468    }
13469
13470    pub fn delete_to_beginning_of_line(
13471        &mut self,
13472        action: &DeleteToBeginningOfLine,
13473        window: &mut Window,
13474        cx: &mut Context<Self>,
13475    ) {
13476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13477        self.transact(window, cx, |this, window, cx| {
13478            this.change_selections(Default::default(), window, cx, |s| {
13479                s.move_with(|_, selection| {
13480                    selection.reversed = true;
13481                });
13482            });
13483
13484            this.select_to_beginning_of_line(
13485                &SelectToBeginningOfLine {
13486                    stop_at_soft_wraps: false,
13487                    stop_at_indent: action.stop_at_indent,
13488                },
13489                window,
13490                cx,
13491            );
13492            this.backspace(&Backspace, window, cx);
13493        });
13494    }
13495
13496    pub fn move_to_end_of_line(
13497        &mut self,
13498        action: &MoveToEndOfLine,
13499        window: &mut Window,
13500        cx: &mut Context<Self>,
13501    ) {
13502        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13503        self.change_selections(Default::default(), window, cx, |s| {
13504            s.move_cursors_with(|map, head, _| {
13505                (
13506                    movement::line_end(map, head, action.stop_at_soft_wraps),
13507                    SelectionGoal::None,
13508                )
13509            });
13510        })
13511    }
13512
13513    pub fn select_to_end_of_line(
13514        &mut self,
13515        action: &SelectToEndOfLine,
13516        window: &mut Window,
13517        cx: &mut Context<Self>,
13518    ) {
13519        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13520        self.change_selections(Default::default(), window, cx, |s| {
13521            s.move_heads_with(|map, head, _| {
13522                (
13523                    movement::line_end(map, head, action.stop_at_soft_wraps),
13524                    SelectionGoal::None,
13525                )
13526            });
13527        })
13528    }
13529
13530    pub fn delete_to_end_of_line(
13531        &mut self,
13532        _: &DeleteToEndOfLine,
13533        window: &mut Window,
13534        cx: &mut Context<Self>,
13535    ) {
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13537        self.transact(window, cx, |this, window, cx| {
13538            this.select_to_end_of_line(
13539                &SelectToEndOfLine {
13540                    stop_at_soft_wraps: false,
13541                },
13542                window,
13543                cx,
13544            );
13545            this.delete(&Delete, window, cx);
13546        });
13547    }
13548
13549    pub fn cut_to_end_of_line(
13550        &mut self,
13551        action: &CutToEndOfLine,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13556        self.transact(window, cx, |this, window, cx| {
13557            this.select_to_end_of_line(
13558                &SelectToEndOfLine {
13559                    stop_at_soft_wraps: false,
13560                },
13561                window,
13562                cx,
13563            );
13564            if !action.stop_at_newlines {
13565                this.change_selections(Default::default(), window, cx, |s| {
13566                    s.move_with(|_, sel| {
13567                        if sel.is_empty() {
13568                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13569                        }
13570                    });
13571                });
13572            }
13573            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13574            let item = this.cut_common(false, window, cx);
13575            cx.write_to_clipboard(item);
13576        });
13577    }
13578
13579    pub fn move_to_start_of_paragraph(
13580        &mut self,
13581        _: &MoveToStartOfParagraph,
13582        window: &mut Window,
13583        cx: &mut Context<Self>,
13584    ) {
13585        if matches!(self.mode, EditorMode::SingleLine) {
13586            cx.propagate();
13587            return;
13588        }
13589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13590        self.change_selections(Default::default(), window, cx, |s| {
13591            s.move_with(|map, selection| {
13592                selection.collapse_to(
13593                    movement::start_of_paragraph(map, selection.head(), 1),
13594                    SelectionGoal::None,
13595                )
13596            });
13597        })
13598    }
13599
13600    pub fn move_to_end_of_paragraph(
13601        &mut self,
13602        _: &MoveToEndOfParagraph,
13603        window: &mut Window,
13604        cx: &mut Context<Self>,
13605    ) {
13606        if matches!(self.mode, EditorMode::SingleLine) {
13607            cx.propagate();
13608            return;
13609        }
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13611        self.change_selections(Default::default(), window, cx, |s| {
13612            s.move_with(|map, selection| {
13613                selection.collapse_to(
13614                    movement::end_of_paragraph(map, selection.head(), 1),
13615                    SelectionGoal::None,
13616                )
13617            });
13618        })
13619    }
13620
13621    pub fn select_to_start_of_paragraph(
13622        &mut self,
13623        _: &SelectToStartOfParagraph,
13624        window: &mut Window,
13625        cx: &mut Context<Self>,
13626    ) {
13627        if matches!(self.mode, EditorMode::SingleLine) {
13628            cx.propagate();
13629            return;
13630        }
13631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13632        self.change_selections(Default::default(), window, cx, |s| {
13633            s.move_heads_with(|map, head, _| {
13634                (
13635                    movement::start_of_paragraph(map, head, 1),
13636                    SelectionGoal::None,
13637                )
13638            });
13639        })
13640    }
13641
13642    pub fn select_to_end_of_paragraph(
13643        &mut self,
13644        _: &SelectToEndOfParagraph,
13645        window: &mut Window,
13646        cx: &mut Context<Self>,
13647    ) {
13648        if matches!(self.mode, EditorMode::SingleLine) {
13649            cx.propagate();
13650            return;
13651        }
13652        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13653        self.change_selections(Default::default(), window, cx, |s| {
13654            s.move_heads_with(|map, head, _| {
13655                (
13656                    movement::end_of_paragraph(map, head, 1),
13657                    SelectionGoal::None,
13658                )
13659            });
13660        })
13661    }
13662
13663    pub fn move_to_start_of_excerpt(
13664        &mut self,
13665        _: &MoveToStartOfExcerpt,
13666        window: &mut Window,
13667        cx: &mut Context<Self>,
13668    ) {
13669        if matches!(self.mode, EditorMode::SingleLine) {
13670            cx.propagate();
13671            return;
13672        }
13673        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13674        self.change_selections(Default::default(), window, cx, |s| {
13675            s.move_with(|map, selection| {
13676                selection.collapse_to(
13677                    movement::start_of_excerpt(
13678                        map,
13679                        selection.head(),
13680                        workspace::searchable::Direction::Prev,
13681                    ),
13682                    SelectionGoal::None,
13683                )
13684            });
13685        })
13686    }
13687
13688    pub fn move_to_start_of_next_excerpt(
13689        &mut self,
13690        _: &MoveToStartOfNextExcerpt,
13691        window: &mut Window,
13692        cx: &mut Context<Self>,
13693    ) {
13694        if matches!(self.mode, EditorMode::SingleLine) {
13695            cx.propagate();
13696            return;
13697        }
13698
13699        self.change_selections(Default::default(), window, cx, |s| {
13700            s.move_with(|map, selection| {
13701                selection.collapse_to(
13702                    movement::start_of_excerpt(
13703                        map,
13704                        selection.head(),
13705                        workspace::searchable::Direction::Next,
13706                    ),
13707                    SelectionGoal::None,
13708                )
13709            });
13710        })
13711    }
13712
13713    pub fn move_to_end_of_excerpt(
13714        &mut self,
13715        _: &MoveToEndOfExcerpt,
13716        window: &mut Window,
13717        cx: &mut Context<Self>,
13718    ) {
13719        if matches!(self.mode, EditorMode::SingleLine) {
13720            cx.propagate();
13721            return;
13722        }
13723        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13724        self.change_selections(Default::default(), window, cx, |s| {
13725            s.move_with(|map, selection| {
13726                selection.collapse_to(
13727                    movement::end_of_excerpt(
13728                        map,
13729                        selection.head(),
13730                        workspace::searchable::Direction::Next,
13731                    ),
13732                    SelectionGoal::None,
13733                )
13734            });
13735        })
13736    }
13737
13738    pub fn move_to_end_of_previous_excerpt(
13739        &mut self,
13740        _: &MoveToEndOfPreviousExcerpt,
13741        window: &mut Window,
13742        cx: &mut Context<Self>,
13743    ) {
13744        if matches!(self.mode, EditorMode::SingleLine) {
13745            cx.propagate();
13746            return;
13747        }
13748        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13749        self.change_selections(Default::default(), window, cx, |s| {
13750            s.move_with(|map, selection| {
13751                selection.collapse_to(
13752                    movement::end_of_excerpt(
13753                        map,
13754                        selection.head(),
13755                        workspace::searchable::Direction::Prev,
13756                    ),
13757                    SelectionGoal::None,
13758                )
13759            });
13760        })
13761    }
13762
13763    pub fn select_to_start_of_excerpt(
13764        &mut self,
13765        _: &SelectToStartOfExcerpt,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        if matches!(self.mode, EditorMode::SingleLine) {
13770            cx.propagate();
13771            return;
13772        }
13773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_heads_with(|map, head, _| {
13776                (
13777                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13778                    SelectionGoal::None,
13779                )
13780            });
13781        })
13782    }
13783
13784    pub fn select_to_start_of_next_excerpt(
13785        &mut self,
13786        _: &SelectToStartOfNextExcerpt,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) {
13790        if matches!(self.mode, EditorMode::SingleLine) {
13791            cx.propagate();
13792            return;
13793        }
13794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13795        self.change_selections(Default::default(), window, cx, |s| {
13796            s.move_heads_with(|map, head, _| {
13797                (
13798                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13799                    SelectionGoal::None,
13800                )
13801            });
13802        })
13803    }
13804
13805    pub fn select_to_end_of_excerpt(
13806        &mut self,
13807        _: &SelectToEndOfExcerpt,
13808        window: &mut Window,
13809        cx: &mut Context<Self>,
13810    ) {
13811        if matches!(self.mode, EditorMode::SingleLine) {
13812            cx.propagate();
13813            return;
13814        }
13815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13816        self.change_selections(Default::default(), window, cx, |s| {
13817            s.move_heads_with(|map, head, _| {
13818                (
13819                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13820                    SelectionGoal::None,
13821                )
13822            });
13823        })
13824    }
13825
13826    pub fn select_to_end_of_previous_excerpt(
13827        &mut self,
13828        _: &SelectToEndOfPreviousExcerpt,
13829        window: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        if matches!(self.mode, EditorMode::SingleLine) {
13833            cx.propagate();
13834            return;
13835        }
13836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13837        self.change_selections(Default::default(), window, cx, |s| {
13838            s.move_heads_with(|map, head, _| {
13839                (
13840                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13841                    SelectionGoal::None,
13842                )
13843            });
13844        })
13845    }
13846
13847    pub fn move_to_beginning(
13848        &mut self,
13849        _: &MoveToBeginning,
13850        window: &mut Window,
13851        cx: &mut Context<Self>,
13852    ) {
13853        if matches!(self.mode, EditorMode::SingleLine) {
13854            cx.propagate();
13855            return;
13856        }
13857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13858        self.change_selections(Default::default(), window, cx, |s| {
13859            s.select_ranges(vec![0..0]);
13860        });
13861    }
13862
13863    pub fn select_to_beginning(
13864        &mut self,
13865        _: &SelectToBeginning,
13866        window: &mut Window,
13867        cx: &mut Context<Self>,
13868    ) {
13869        let mut selection = self.selections.last::<Point>(cx);
13870        selection.set_head(Point::zero(), SelectionGoal::None);
13871        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13872        self.change_selections(Default::default(), window, cx, |s| {
13873            s.select(vec![selection]);
13874        });
13875    }
13876
13877    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13878        if matches!(self.mode, EditorMode::SingleLine) {
13879            cx.propagate();
13880            return;
13881        }
13882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13883        let cursor = self.buffer.read(cx).read(cx).len();
13884        self.change_selections(Default::default(), window, cx, |s| {
13885            s.select_ranges(vec![cursor..cursor])
13886        });
13887    }
13888
13889    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13890        self.nav_history = nav_history;
13891    }
13892
13893    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13894        self.nav_history.as_ref()
13895    }
13896
13897    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13898        self.push_to_nav_history(
13899            self.selections.newest_anchor().head(),
13900            None,
13901            false,
13902            true,
13903            cx,
13904        );
13905    }
13906
13907    fn push_to_nav_history(
13908        &mut self,
13909        cursor_anchor: Anchor,
13910        new_position: Option<Point>,
13911        is_deactivate: bool,
13912        always: bool,
13913        cx: &mut Context<Self>,
13914    ) {
13915        if let Some(nav_history) = self.nav_history.as_mut() {
13916            let buffer = self.buffer.read(cx).read(cx);
13917            let cursor_position = cursor_anchor.to_point(&buffer);
13918            let scroll_state = self.scroll_manager.anchor();
13919            let scroll_top_row = scroll_state.top_row(&buffer);
13920            drop(buffer);
13921
13922            if let Some(new_position) = new_position {
13923                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13924                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13925                    return;
13926                }
13927            }
13928
13929            nav_history.push(
13930                Some(NavigationData {
13931                    cursor_anchor,
13932                    cursor_position,
13933                    scroll_anchor: scroll_state,
13934                    scroll_top_row,
13935                }),
13936                cx,
13937            );
13938            cx.emit(EditorEvent::PushedToNavHistory {
13939                anchor: cursor_anchor,
13940                is_deactivate,
13941            })
13942        }
13943    }
13944
13945    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        let buffer = self.buffer.read(cx).snapshot(cx);
13948        let mut selection = self.selections.first::<usize>(cx);
13949        selection.set_head(buffer.len(), SelectionGoal::None);
13950        self.change_selections(Default::default(), window, cx, |s| {
13951            s.select(vec![selection]);
13952        });
13953    }
13954
13955    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13957        let end = self.buffer.read(cx).read(cx).len();
13958        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13959            s.select_ranges(vec![0..end]);
13960        });
13961    }
13962
13963    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13965        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13966        let mut selections = self.selections.all::<Point>(cx);
13967        let max_point = display_map.buffer_snapshot.max_point();
13968        for selection in &mut selections {
13969            let rows = selection.spanned_rows(true, &display_map);
13970            selection.start = Point::new(rows.start.0, 0);
13971            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13972            selection.reversed = false;
13973        }
13974        self.change_selections(Default::default(), window, cx, |s| {
13975            s.select(selections);
13976        });
13977    }
13978
13979    pub fn split_selection_into_lines(
13980        &mut self,
13981        action: &SplitSelectionIntoLines,
13982        window: &mut Window,
13983        cx: &mut Context<Self>,
13984    ) {
13985        let selections = self
13986            .selections
13987            .all::<Point>(cx)
13988            .into_iter()
13989            .map(|selection| selection.start..selection.end)
13990            .collect::<Vec<_>>();
13991        self.unfold_ranges(&selections, true, true, cx);
13992
13993        let mut new_selection_ranges = Vec::new();
13994        {
13995            let buffer = self.buffer.read(cx).read(cx);
13996            for selection in selections {
13997                for row in selection.start.row..selection.end.row {
13998                    let line_start = Point::new(row, 0);
13999                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14000
14001                    if action.keep_selections {
14002                        // Keep the selection range for each line
14003                        let selection_start = if row == selection.start.row {
14004                            selection.start
14005                        } else {
14006                            line_start
14007                        };
14008                        new_selection_ranges.push(selection_start..line_end);
14009                    } else {
14010                        // Collapse to cursor at end of line
14011                        new_selection_ranges.push(line_end..line_end);
14012                    }
14013                }
14014
14015                let is_multiline_selection = selection.start.row != selection.end.row;
14016                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14017                // so this action feels more ergonomic when paired with other selection operations
14018                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14019                if !should_skip_last {
14020                    if action.keep_selections {
14021                        if is_multiline_selection {
14022                            let line_start = Point::new(selection.end.row, 0);
14023                            new_selection_ranges.push(line_start..selection.end);
14024                        } else {
14025                            new_selection_ranges.push(selection.start..selection.end);
14026                        }
14027                    } else {
14028                        new_selection_ranges.push(selection.end..selection.end);
14029                    }
14030                }
14031            }
14032        }
14033        self.change_selections(Default::default(), window, cx, |s| {
14034            s.select_ranges(new_selection_ranges);
14035        });
14036    }
14037
14038    pub fn add_selection_above(
14039        &mut self,
14040        _: &AddSelectionAbove,
14041        window: &mut Window,
14042        cx: &mut Context<Self>,
14043    ) {
14044        self.add_selection(true, window, cx);
14045    }
14046
14047    pub fn add_selection_below(
14048        &mut self,
14049        _: &AddSelectionBelow,
14050        window: &mut Window,
14051        cx: &mut Context<Self>,
14052    ) {
14053        self.add_selection(false, window, cx);
14054    }
14055
14056    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14058
14059        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14060        let all_selections = self.selections.all::<Point>(cx);
14061        let text_layout_details = self.text_layout_details(window);
14062
14063        let (mut columnar_selections, new_selections_to_columnarize) = {
14064            if let Some(state) = self.add_selections_state.as_ref() {
14065                let columnar_selection_ids: HashSet<_> = state
14066                    .groups
14067                    .iter()
14068                    .flat_map(|group| group.stack.iter())
14069                    .copied()
14070                    .collect();
14071
14072                all_selections
14073                    .into_iter()
14074                    .partition(|s| columnar_selection_ids.contains(&s.id))
14075            } else {
14076                (Vec::new(), all_selections)
14077            }
14078        };
14079
14080        let mut state = self
14081            .add_selections_state
14082            .take()
14083            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14084
14085        for selection in new_selections_to_columnarize {
14086            let range = selection.display_range(&display_map).sorted();
14087            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14088            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14089            let positions = start_x.min(end_x)..start_x.max(end_x);
14090            let mut stack = Vec::new();
14091            for row in range.start.row().0..=range.end.row().0 {
14092                if let Some(selection) = self.selections.build_columnar_selection(
14093                    &display_map,
14094                    DisplayRow(row),
14095                    &positions,
14096                    selection.reversed,
14097                    &text_layout_details,
14098                ) {
14099                    stack.push(selection.id);
14100                    columnar_selections.push(selection);
14101                }
14102            }
14103            if !stack.is_empty() {
14104                if above {
14105                    stack.reverse();
14106                }
14107                state.groups.push(AddSelectionsGroup { above, stack });
14108            }
14109        }
14110
14111        let mut final_selections = Vec::new();
14112        let end_row = if above {
14113            DisplayRow(0)
14114        } else {
14115            display_map.max_point().row()
14116        };
14117
14118        let mut last_added_item_per_group = HashMap::default();
14119        for group in state.groups.iter_mut() {
14120            if let Some(last_id) = group.stack.last() {
14121                last_added_item_per_group.insert(*last_id, group);
14122            }
14123        }
14124
14125        for selection in columnar_selections {
14126            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14127                if above == group.above {
14128                    let range = selection.display_range(&display_map).sorted();
14129                    debug_assert_eq!(range.start.row(), range.end.row());
14130                    let mut row = range.start.row();
14131                    let positions =
14132                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14133                            px(start)..px(end)
14134                        } else {
14135                            let start_x =
14136                                display_map.x_for_display_point(range.start, &text_layout_details);
14137                            let end_x =
14138                                display_map.x_for_display_point(range.end, &text_layout_details);
14139                            start_x.min(end_x)..start_x.max(end_x)
14140                        };
14141
14142                    let mut maybe_new_selection = None;
14143                    while row != end_row {
14144                        if above {
14145                            row.0 -= 1;
14146                        } else {
14147                            row.0 += 1;
14148                        }
14149                        if let Some(new_selection) = self.selections.build_columnar_selection(
14150                            &display_map,
14151                            row,
14152                            &positions,
14153                            selection.reversed,
14154                            &text_layout_details,
14155                        ) {
14156                            maybe_new_selection = Some(new_selection);
14157                            break;
14158                        }
14159                    }
14160
14161                    if let Some(new_selection) = maybe_new_selection {
14162                        group.stack.push(new_selection.id);
14163                        if above {
14164                            final_selections.push(new_selection);
14165                            final_selections.push(selection);
14166                        } else {
14167                            final_selections.push(selection);
14168                            final_selections.push(new_selection);
14169                        }
14170                    } else {
14171                        final_selections.push(selection);
14172                    }
14173                } else {
14174                    group.stack.pop();
14175                }
14176            } else {
14177                final_selections.push(selection);
14178            }
14179        }
14180
14181        self.change_selections(Default::default(), window, cx, |s| {
14182            s.select(final_selections);
14183        });
14184
14185        let final_selection_ids: HashSet<_> = self
14186            .selections
14187            .all::<Point>(cx)
14188            .iter()
14189            .map(|s| s.id)
14190            .collect();
14191        state.groups.retain_mut(|group| {
14192            // selections might get merged above so we remove invalid items from stacks
14193            group.stack.retain(|id| final_selection_ids.contains(id));
14194
14195            // single selection in stack can be treated as initial state
14196            group.stack.len() > 1
14197        });
14198
14199        if !state.groups.is_empty() {
14200            self.add_selections_state = Some(state);
14201        }
14202    }
14203
14204    fn select_match_ranges(
14205        &mut self,
14206        range: Range<usize>,
14207        reversed: bool,
14208        replace_newest: bool,
14209        auto_scroll: Option<Autoscroll>,
14210        window: &mut Window,
14211        cx: &mut Context<Editor>,
14212    ) {
14213        self.unfold_ranges(
14214            std::slice::from_ref(&range),
14215            false,
14216            auto_scroll.is_some(),
14217            cx,
14218        );
14219        let effects = if let Some(scroll) = auto_scroll {
14220            SelectionEffects::scroll(scroll)
14221        } else {
14222            SelectionEffects::no_scroll()
14223        };
14224        self.change_selections(effects, window, cx, |s| {
14225            if replace_newest {
14226                s.delete(s.newest_anchor().id);
14227            }
14228            if reversed {
14229                s.insert_range(range.end..range.start);
14230            } else {
14231                s.insert_range(range);
14232            }
14233        });
14234    }
14235
14236    pub fn select_next_match_internal(
14237        &mut self,
14238        display_map: &DisplaySnapshot,
14239        replace_newest: bool,
14240        autoscroll: Option<Autoscroll>,
14241        window: &mut Window,
14242        cx: &mut Context<Self>,
14243    ) -> Result<()> {
14244        let buffer = &display_map.buffer_snapshot;
14245        let mut selections = self.selections.all::<usize>(cx);
14246        if let Some(mut select_next_state) = self.select_next_state.take() {
14247            let query = &select_next_state.query;
14248            if !select_next_state.done {
14249                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14250                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14251                let mut next_selected_range = None;
14252
14253                let bytes_after_last_selection =
14254                    buffer.bytes_in_range(last_selection.end..buffer.len());
14255                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14256                let query_matches = query
14257                    .stream_find_iter(bytes_after_last_selection)
14258                    .map(|result| (last_selection.end, result))
14259                    .chain(
14260                        query
14261                            .stream_find_iter(bytes_before_first_selection)
14262                            .map(|result| (0, result)),
14263                    );
14264
14265                for (start_offset, query_match) in query_matches {
14266                    let query_match = query_match.unwrap(); // can only fail due to I/O
14267                    let offset_range =
14268                        start_offset + query_match.start()..start_offset + query_match.end();
14269
14270                    if !select_next_state.wordwise
14271                        || (!buffer.is_inside_word(offset_range.start, None)
14272                            && !buffer.is_inside_word(offset_range.end, None))
14273                    {
14274                        // TODO: This is n^2, because we might check all the selections
14275                        if !selections
14276                            .iter()
14277                            .any(|selection| selection.range().overlaps(&offset_range))
14278                        {
14279                            next_selected_range = Some(offset_range);
14280                            break;
14281                        }
14282                    }
14283                }
14284
14285                if let Some(next_selected_range) = next_selected_range {
14286                    self.select_match_ranges(
14287                        next_selected_range,
14288                        last_selection.reversed,
14289                        replace_newest,
14290                        autoscroll,
14291                        window,
14292                        cx,
14293                    );
14294                } else {
14295                    select_next_state.done = true;
14296                }
14297            }
14298
14299            self.select_next_state = Some(select_next_state);
14300        } else {
14301            let mut only_carets = true;
14302            let mut same_text_selected = true;
14303            let mut selected_text = None;
14304
14305            let mut selections_iter = selections.iter().peekable();
14306            while let Some(selection) = selections_iter.next() {
14307                if selection.start != selection.end {
14308                    only_carets = false;
14309                }
14310
14311                if same_text_selected {
14312                    if selected_text.is_none() {
14313                        selected_text =
14314                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14315                    }
14316
14317                    if let Some(next_selection) = selections_iter.peek() {
14318                        if next_selection.range().len() == selection.range().len() {
14319                            let next_selected_text = buffer
14320                                .text_for_range(next_selection.range())
14321                                .collect::<String>();
14322                            if Some(next_selected_text) != selected_text {
14323                                same_text_selected = false;
14324                                selected_text = None;
14325                            }
14326                        } else {
14327                            same_text_selected = false;
14328                            selected_text = None;
14329                        }
14330                    }
14331                }
14332            }
14333
14334            if only_carets {
14335                for selection in &mut selections {
14336                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14337                    selection.start = word_range.start;
14338                    selection.end = word_range.end;
14339                    selection.goal = SelectionGoal::None;
14340                    selection.reversed = false;
14341                    self.select_match_ranges(
14342                        selection.start..selection.end,
14343                        selection.reversed,
14344                        replace_newest,
14345                        autoscroll,
14346                        window,
14347                        cx,
14348                    );
14349                }
14350
14351                if selections.len() == 1 {
14352                    let selection = selections
14353                        .last()
14354                        .expect("ensured that there's only one selection");
14355                    let query = buffer
14356                        .text_for_range(selection.start..selection.end)
14357                        .collect::<String>();
14358                    let is_empty = query.is_empty();
14359                    let select_state = SelectNextState {
14360                        query: AhoCorasick::new(&[query])?,
14361                        wordwise: true,
14362                        done: is_empty,
14363                    };
14364                    self.select_next_state = Some(select_state);
14365                } else {
14366                    self.select_next_state = None;
14367                }
14368            } else if let Some(selected_text) = selected_text {
14369                self.select_next_state = Some(SelectNextState {
14370                    query: AhoCorasick::new(&[selected_text])?,
14371                    wordwise: false,
14372                    done: false,
14373                });
14374                self.select_next_match_internal(
14375                    display_map,
14376                    replace_newest,
14377                    autoscroll,
14378                    window,
14379                    cx,
14380                )?;
14381            }
14382        }
14383        Ok(())
14384    }
14385
14386    pub fn select_all_matches(
14387        &mut self,
14388        _action: &SelectAllMatches,
14389        window: &mut Window,
14390        cx: &mut Context<Self>,
14391    ) -> Result<()> {
14392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14393
14394        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14395
14396        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14397        let Some(select_next_state) = self.select_next_state.as_mut() else {
14398            return Ok(());
14399        };
14400        if select_next_state.done {
14401            return Ok(());
14402        }
14403
14404        let mut new_selections = Vec::new();
14405
14406        let reversed = self.selections.oldest::<usize>(cx).reversed;
14407        let buffer = &display_map.buffer_snapshot;
14408        let query_matches = select_next_state
14409            .query
14410            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14411
14412        for query_match in query_matches.into_iter() {
14413            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14414            let offset_range = if reversed {
14415                query_match.end()..query_match.start()
14416            } else {
14417                query_match.start()..query_match.end()
14418            };
14419
14420            if !select_next_state.wordwise
14421                || (!buffer.is_inside_word(offset_range.start, None)
14422                    && !buffer.is_inside_word(offset_range.end, None))
14423            {
14424                new_selections.push(offset_range.start..offset_range.end);
14425            }
14426        }
14427
14428        select_next_state.done = true;
14429
14430        if new_selections.is_empty() {
14431            log::error!("bug: new_selections is empty in select_all_matches");
14432            return Ok(());
14433        }
14434
14435        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14436        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14437            selections.select_ranges(new_selections)
14438        });
14439
14440        Ok(())
14441    }
14442
14443    pub fn select_next(
14444        &mut self,
14445        action: &SelectNext,
14446        window: &mut Window,
14447        cx: &mut Context<Self>,
14448    ) -> Result<()> {
14449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14450        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14451        self.select_next_match_internal(
14452            &display_map,
14453            action.replace_newest,
14454            Some(Autoscroll::newest()),
14455            window,
14456            cx,
14457        )?;
14458        Ok(())
14459    }
14460
14461    pub fn select_previous(
14462        &mut self,
14463        action: &SelectPrevious,
14464        window: &mut Window,
14465        cx: &mut Context<Self>,
14466    ) -> Result<()> {
14467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14468        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14469        let buffer = &display_map.buffer_snapshot;
14470        let mut selections = self.selections.all::<usize>(cx);
14471        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14472            let query = &select_prev_state.query;
14473            if !select_prev_state.done {
14474                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14475                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14476                let mut next_selected_range = None;
14477                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14478                let bytes_before_last_selection =
14479                    buffer.reversed_bytes_in_range(0..last_selection.start);
14480                let bytes_after_first_selection =
14481                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14482                let query_matches = query
14483                    .stream_find_iter(bytes_before_last_selection)
14484                    .map(|result| (last_selection.start, result))
14485                    .chain(
14486                        query
14487                            .stream_find_iter(bytes_after_first_selection)
14488                            .map(|result| (buffer.len(), result)),
14489                    );
14490                for (end_offset, query_match) in query_matches {
14491                    let query_match = query_match.unwrap(); // can only fail due to I/O
14492                    let offset_range =
14493                        end_offset - query_match.end()..end_offset - query_match.start();
14494
14495                    if !select_prev_state.wordwise
14496                        || (!buffer.is_inside_word(offset_range.start, None)
14497                            && !buffer.is_inside_word(offset_range.end, None))
14498                    {
14499                        next_selected_range = Some(offset_range);
14500                        break;
14501                    }
14502                }
14503
14504                if let Some(next_selected_range) = next_selected_range {
14505                    self.select_match_ranges(
14506                        next_selected_range,
14507                        last_selection.reversed,
14508                        action.replace_newest,
14509                        Some(Autoscroll::newest()),
14510                        window,
14511                        cx,
14512                    );
14513                } else {
14514                    select_prev_state.done = true;
14515                }
14516            }
14517
14518            self.select_prev_state = Some(select_prev_state);
14519        } else {
14520            let mut only_carets = true;
14521            let mut same_text_selected = true;
14522            let mut selected_text = None;
14523
14524            let mut selections_iter = selections.iter().peekable();
14525            while let Some(selection) = selections_iter.next() {
14526                if selection.start != selection.end {
14527                    only_carets = false;
14528                }
14529
14530                if same_text_selected {
14531                    if selected_text.is_none() {
14532                        selected_text =
14533                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14534                    }
14535
14536                    if let Some(next_selection) = selections_iter.peek() {
14537                        if next_selection.range().len() == selection.range().len() {
14538                            let next_selected_text = buffer
14539                                .text_for_range(next_selection.range())
14540                                .collect::<String>();
14541                            if Some(next_selected_text) != selected_text {
14542                                same_text_selected = false;
14543                                selected_text = None;
14544                            }
14545                        } else {
14546                            same_text_selected = false;
14547                            selected_text = None;
14548                        }
14549                    }
14550                }
14551            }
14552
14553            if only_carets {
14554                for selection in &mut selections {
14555                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14556                    selection.start = word_range.start;
14557                    selection.end = word_range.end;
14558                    selection.goal = SelectionGoal::None;
14559                    selection.reversed = false;
14560                    self.select_match_ranges(
14561                        selection.start..selection.end,
14562                        selection.reversed,
14563                        action.replace_newest,
14564                        Some(Autoscroll::newest()),
14565                        window,
14566                        cx,
14567                    );
14568                }
14569                if selections.len() == 1 {
14570                    let selection = selections
14571                        .last()
14572                        .expect("ensured that there's only one selection");
14573                    let query = buffer
14574                        .text_for_range(selection.start..selection.end)
14575                        .collect::<String>();
14576                    let is_empty = query.is_empty();
14577                    let select_state = SelectNextState {
14578                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14579                        wordwise: true,
14580                        done: is_empty,
14581                    };
14582                    self.select_prev_state = Some(select_state);
14583                } else {
14584                    self.select_prev_state = None;
14585                }
14586            } else if let Some(selected_text) = selected_text {
14587                self.select_prev_state = Some(SelectNextState {
14588                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14589                    wordwise: false,
14590                    done: false,
14591                });
14592                self.select_previous(action, window, cx)?;
14593            }
14594        }
14595        Ok(())
14596    }
14597
14598    pub fn find_next_match(
14599        &mut self,
14600        _: &FindNextMatch,
14601        window: &mut Window,
14602        cx: &mut Context<Self>,
14603    ) -> Result<()> {
14604        let selections = self.selections.disjoint_anchors_arc();
14605        match selections.first() {
14606            Some(first) if selections.len() >= 2 => {
14607                self.change_selections(Default::default(), window, cx, |s| {
14608                    s.select_ranges([first.range()]);
14609                });
14610            }
14611            _ => self.select_next(
14612                &SelectNext {
14613                    replace_newest: true,
14614                },
14615                window,
14616                cx,
14617            )?,
14618        }
14619        Ok(())
14620    }
14621
14622    pub fn find_previous_match(
14623        &mut self,
14624        _: &FindPreviousMatch,
14625        window: &mut Window,
14626        cx: &mut Context<Self>,
14627    ) -> Result<()> {
14628        let selections = self.selections.disjoint_anchors_arc();
14629        match selections.last() {
14630            Some(last) if selections.len() >= 2 => {
14631                self.change_selections(Default::default(), window, cx, |s| {
14632                    s.select_ranges([last.range()]);
14633                });
14634            }
14635            _ => self.select_previous(
14636                &SelectPrevious {
14637                    replace_newest: true,
14638                },
14639                window,
14640                cx,
14641            )?,
14642        }
14643        Ok(())
14644    }
14645
14646    pub fn toggle_comments(
14647        &mut self,
14648        action: &ToggleComments,
14649        window: &mut Window,
14650        cx: &mut Context<Self>,
14651    ) {
14652        if self.read_only(cx) {
14653            return;
14654        }
14655        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14656        let text_layout_details = &self.text_layout_details(window);
14657        self.transact(window, cx, |this, window, cx| {
14658            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14659            let mut edits = Vec::new();
14660            let mut selection_edit_ranges = Vec::new();
14661            let mut last_toggled_row = None;
14662            let snapshot = this.buffer.read(cx).read(cx);
14663            let empty_str: Arc<str> = Arc::default();
14664            let mut suffixes_inserted = Vec::new();
14665            let ignore_indent = action.ignore_indent;
14666
14667            fn comment_prefix_range(
14668                snapshot: &MultiBufferSnapshot,
14669                row: MultiBufferRow,
14670                comment_prefix: &str,
14671                comment_prefix_whitespace: &str,
14672                ignore_indent: bool,
14673            ) -> Range<Point> {
14674                let indent_size = if ignore_indent {
14675                    0
14676                } else {
14677                    snapshot.indent_size_for_line(row).len
14678                };
14679
14680                let start = Point::new(row.0, indent_size);
14681
14682                let mut line_bytes = snapshot
14683                    .bytes_in_range(start..snapshot.max_point())
14684                    .flatten()
14685                    .copied();
14686
14687                // If this line currently begins with the line comment prefix, then record
14688                // the range containing the prefix.
14689                if line_bytes
14690                    .by_ref()
14691                    .take(comment_prefix.len())
14692                    .eq(comment_prefix.bytes())
14693                {
14694                    // Include any whitespace that matches the comment prefix.
14695                    let matching_whitespace_len = line_bytes
14696                        .zip(comment_prefix_whitespace.bytes())
14697                        .take_while(|(a, b)| a == b)
14698                        .count() as u32;
14699                    let end = Point::new(
14700                        start.row,
14701                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14702                    );
14703                    start..end
14704                } else {
14705                    start..start
14706                }
14707            }
14708
14709            fn comment_suffix_range(
14710                snapshot: &MultiBufferSnapshot,
14711                row: MultiBufferRow,
14712                comment_suffix: &str,
14713                comment_suffix_has_leading_space: bool,
14714            ) -> Range<Point> {
14715                let end = Point::new(row.0, snapshot.line_len(row));
14716                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14717
14718                let mut line_end_bytes = snapshot
14719                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14720                    .flatten()
14721                    .copied();
14722
14723                let leading_space_len = if suffix_start_column > 0
14724                    && line_end_bytes.next() == Some(b' ')
14725                    && comment_suffix_has_leading_space
14726                {
14727                    1
14728                } else {
14729                    0
14730                };
14731
14732                // If this line currently begins with the line comment prefix, then record
14733                // the range containing the prefix.
14734                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14735                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14736                    start..end
14737                } else {
14738                    end..end
14739                }
14740            }
14741
14742            // TODO: Handle selections that cross excerpts
14743            for selection in &mut selections {
14744                let start_column = snapshot
14745                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14746                    .len;
14747                let language = if let Some(language) =
14748                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14749                {
14750                    language
14751                } else {
14752                    continue;
14753                };
14754
14755                selection_edit_ranges.clear();
14756
14757                // If multiple selections contain a given row, avoid processing that
14758                // row more than once.
14759                let mut start_row = MultiBufferRow(selection.start.row);
14760                if last_toggled_row == Some(start_row) {
14761                    start_row = start_row.next_row();
14762                }
14763                let end_row =
14764                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14765                        MultiBufferRow(selection.end.row - 1)
14766                    } else {
14767                        MultiBufferRow(selection.end.row)
14768                    };
14769                last_toggled_row = Some(end_row);
14770
14771                if start_row > end_row {
14772                    continue;
14773                }
14774
14775                // If the language has line comments, toggle those.
14776                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14777
14778                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14779                if ignore_indent {
14780                    full_comment_prefixes = full_comment_prefixes
14781                        .into_iter()
14782                        .map(|s| Arc::from(s.trim_end()))
14783                        .collect();
14784                }
14785
14786                if !full_comment_prefixes.is_empty() {
14787                    let first_prefix = full_comment_prefixes
14788                        .first()
14789                        .expect("prefixes is non-empty");
14790                    let prefix_trimmed_lengths = full_comment_prefixes
14791                        .iter()
14792                        .map(|p| p.trim_end_matches(' ').len())
14793                        .collect::<SmallVec<[usize; 4]>>();
14794
14795                    let mut all_selection_lines_are_comments = true;
14796
14797                    for row in start_row.0..=end_row.0 {
14798                        let row = MultiBufferRow(row);
14799                        if start_row < end_row && snapshot.is_line_blank(row) {
14800                            continue;
14801                        }
14802
14803                        let prefix_range = full_comment_prefixes
14804                            .iter()
14805                            .zip(prefix_trimmed_lengths.iter().copied())
14806                            .map(|(prefix, trimmed_prefix_len)| {
14807                                comment_prefix_range(
14808                                    snapshot.deref(),
14809                                    row,
14810                                    &prefix[..trimmed_prefix_len],
14811                                    &prefix[trimmed_prefix_len..],
14812                                    ignore_indent,
14813                                )
14814                            })
14815                            .max_by_key(|range| range.end.column - range.start.column)
14816                            .expect("prefixes is non-empty");
14817
14818                        if prefix_range.is_empty() {
14819                            all_selection_lines_are_comments = false;
14820                        }
14821
14822                        selection_edit_ranges.push(prefix_range);
14823                    }
14824
14825                    if all_selection_lines_are_comments {
14826                        edits.extend(
14827                            selection_edit_ranges
14828                                .iter()
14829                                .cloned()
14830                                .map(|range| (range, empty_str.clone())),
14831                        );
14832                    } else {
14833                        let min_column = selection_edit_ranges
14834                            .iter()
14835                            .map(|range| range.start.column)
14836                            .min()
14837                            .unwrap_or(0);
14838                        edits.extend(selection_edit_ranges.iter().map(|range| {
14839                            let position = Point::new(range.start.row, min_column);
14840                            (position..position, first_prefix.clone())
14841                        }));
14842                    }
14843                } else if let Some(BlockCommentConfig {
14844                    start: full_comment_prefix,
14845                    end: comment_suffix,
14846                    ..
14847                }) = language.block_comment()
14848                {
14849                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14850                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14851                    let prefix_range = comment_prefix_range(
14852                        snapshot.deref(),
14853                        start_row,
14854                        comment_prefix,
14855                        comment_prefix_whitespace,
14856                        ignore_indent,
14857                    );
14858                    let suffix_range = comment_suffix_range(
14859                        snapshot.deref(),
14860                        end_row,
14861                        comment_suffix.trim_start_matches(' '),
14862                        comment_suffix.starts_with(' '),
14863                    );
14864
14865                    if prefix_range.is_empty() || suffix_range.is_empty() {
14866                        edits.push((
14867                            prefix_range.start..prefix_range.start,
14868                            full_comment_prefix.clone(),
14869                        ));
14870                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14871                        suffixes_inserted.push((end_row, comment_suffix.len()));
14872                    } else {
14873                        edits.push((prefix_range, empty_str.clone()));
14874                        edits.push((suffix_range, empty_str.clone()));
14875                    }
14876                } else {
14877                    continue;
14878                }
14879            }
14880
14881            drop(snapshot);
14882            this.buffer.update(cx, |buffer, cx| {
14883                buffer.edit(edits, None, cx);
14884            });
14885
14886            // Adjust selections so that they end before any comment suffixes that
14887            // were inserted.
14888            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14889            let mut selections = this.selections.all::<Point>(cx);
14890            let snapshot = this.buffer.read(cx).read(cx);
14891            for selection in &mut selections {
14892                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14893                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14894                        Ordering::Less => {
14895                            suffixes_inserted.next();
14896                            continue;
14897                        }
14898                        Ordering::Greater => break,
14899                        Ordering::Equal => {
14900                            if selection.end.column == snapshot.line_len(row) {
14901                                if selection.is_empty() {
14902                                    selection.start.column -= suffix_len as u32;
14903                                }
14904                                selection.end.column -= suffix_len as u32;
14905                            }
14906                            break;
14907                        }
14908                    }
14909                }
14910            }
14911
14912            drop(snapshot);
14913            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14914
14915            let selections = this.selections.all::<Point>(cx);
14916            let selections_on_single_row = selections.windows(2).all(|selections| {
14917                selections[0].start.row == selections[1].start.row
14918                    && selections[0].end.row == selections[1].end.row
14919                    && selections[0].start.row == selections[0].end.row
14920            });
14921            let selections_selecting = selections
14922                .iter()
14923                .any(|selection| selection.start != selection.end);
14924            let advance_downwards = action.advance_downwards
14925                && selections_on_single_row
14926                && !selections_selecting
14927                && !matches!(this.mode, EditorMode::SingleLine);
14928
14929            if advance_downwards {
14930                let snapshot = this.buffer.read(cx).snapshot(cx);
14931
14932                this.change_selections(Default::default(), window, cx, |s| {
14933                    s.move_cursors_with(|display_snapshot, display_point, _| {
14934                        let mut point = display_point.to_point(display_snapshot);
14935                        point.row += 1;
14936                        point = snapshot.clip_point(point, Bias::Left);
14937                        let display_point = point.to_display_point(display_snapshot);
14938                        let goal = SelectionGoal::HorizontalPosition(
14939                            display_snapshot
14940                                .x_for_display_point(display_point, text_layout_details)
14941                                .into(),
14942                        );
14943                        (display_point, goal)
14944                    })
14945                });
14946            }
14947        });
14948    }
14949
14950    pub fn select_enclosing_symbol(
14951        &mut self,
14952        _: &SelectEnclosingSymbol,
14953        window: &mut Window,
14954        cx: &mut Context<Self>,
14955    ) {
14956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14957
14958        let buffer = self.buffer.read(cx).snapshot(cx);
14959        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14960
14961        fn update_selection(
14962            selection: &Selection<usize>,
14963            buffer_snap: &MultiBufferSnapshot,
14964        ) -> Option<Selection<usize>> {
14965            let cursor = selection.head();
14966            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14967            for symbol in symbols.iter().rev() {
14968                let start = symbol.range.start.to_offset(buffer_snap);
14969                let end = symbol.range.end.to_offset(buffer_snap);
14970                let new_range = start..end;
14971                if start < selection.start || end > selection.end {
14972                    return Some(Selection {
14973                        id: selection.id,
14974                        start: new_range.start,
14975                        end: new_range.end,
14976                        goal: SelectionGoal::None,
14977                        reversed: selection.reversed,
14978                    });
14979                }
14980            }
14981            None
14982        }
14983
14984        let mut selected_larger_symbol = false;
14985        let new_selections = old_selections
14986            .iter()
14987            .map(|selection| match update_selection(selection, &buffer) {
14988                Some(new_selection) => {
14989                    if new_selection.range() != selection.range() {
14990                        selected_larger_symbol = true;
14991                    }
14992                    new_selection
14993                }
14994                None => selection.clone(),
14995            })
14996            .collect::<Vec<_>>();
14997
14998        if selected_larger_symbol {
14999            self.change_selections(Default::default(), window, cx, |s| {
15000                s.select(new_selections);
15001            });
15002        }
15003    }
15004
15005    pub fn select_larger_syntax_node(
15006        &mut self,
15007        _: &SelectLargerSyntaxNode,
15008        window: &mut Window,
15009        cx: &mut Context<Self>,
15010    ) {
15011        let Some(visible_row_count) = self.visible_row_count() else {
15012            return;
15013        };
15014        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15015        if old_selections.is_empty() {
15016            return;
15017        }
15018
15019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15020
15021        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15022        let buffer = self.buffer.read(cx).snapshot(cx);
15023
15024        let mut selected_larger_node = false;
15025        let mut new_selections = old_selections
15026            .iter()
15027            .map(|selection| {
15028                let old_range = selection.start..selection.end;
15029
15030                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15031                    // manually select word at selection
15032                    if ["string_content", "inline"].contains(&node.kind()) {
15033                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15034                        // ignore if word is already selected
15035                        if !word_range.is_empty() && old_range != word_range {
15036                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15037                            // only select word if start and end point belongs to same word
15038                            if word_range == last_word_range {
15039                                selected_larger_node = true;
15040                                return Selection {
15041                                    id: selection.id,
15042                                    start: word_range.start,
15043                                    end: word_range.end,
15044                                    goal: SelectionGoal::None,
15045                                    reversed: selection.reversed,
15046                                };
15047                            }
15048                        }
15049                    }
15050                }
15051
15052                let mut new_range = old_range.clone();
15053                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
15054                {
15055                    new_range = match containing_range {
15056                        MultiOrSingleBufferOffsetRange::Single(_) => break,
15057                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15058                    };
15059                    if !node.is_named() {
15060                        continue;
15061                    }
15062                    if !display_map.intersects_fold(new_range.start)
15063                        && !display_map.intersects_fold(new_range.end)
15064                    {
15065                        break;
15066                    }
15067                }
15068
15069                selected_larger_node |= new_range != old_range;
15070                Selection {
15071                    id: selection.id,
15072                    start: new_range.start,
15073                    end: new_range.end,
15074                    goal: SelectionGoal::None,
15075                    reversed: selection.reversed,
15076                }
15077            })
15078            .collect::<Vec<_>>();
15079
15080        if !selected_larger_node {
15081            return; // don't put this call in the history
15082        }
15083
15084        // scroll based on transformation done to the last selection created by the user
15085        let (last_old, last_new) = old_selections
15086            .last()
15087            .zip(new_selections.last().cloned())
15088            .expect("old_selections isn't empty");
15089
15090        // revert selection
15091        let is_selection_reversed = {
15092            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15093            new_selections.last_mut().expect("checked above").reversed =
15094                should_newest_selection_be_reversed;
15095            should_newest_selection_be_reversed
15096        };
15097
15098        if selected_larger_node {
15099            self.select_syntax_node_history.disable_clearing = true;
15100            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15101                s.select(new_selections.clone());
15102            });
15103            self.select_syntax_node_history.disable_clearing = false;
15104        }
15105
15106        let start_row = last_new.start.to_display_point(&display_map).row().0;
15107        let end_row = last_new.end.to_display_point(&display_map).row().0;
15108        let selection_height = end_row - start_row + 1;
15109        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15110
15111        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15112        let scroll_behavior = if fits_on_the_screen {
15113            self.request_autoscroll(Autoscroll::fit(), cx);
15114            SelectSyntaxNodeScrollBehavior::FitSelection
15115        } else if is_selection_reversed {
15116            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15117            SelectSyntaxNodeScrollBehavior::CursorTop
15118        } else {
15119            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15120            SelectSyntaxNodeScrollBehavior::CursorBottom
15121        };
15122
15123        self.select_syntax_node_history.push((
15124            old_selections,
15125            scroll_behavior,
15126            is_selection_reversed,
15127        ));
15128    }
15129
15130    pub fn select_smaller_syntax_node(
15131        &mut self,
15132        _: &SelectSmallerSyntaxNode,
15133        window: &mut Window,
15134        cx: &mut Context<Self>,
15135    ) {
15136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15137
15138        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15139            self.select_syntax_node_history.pop()
15140        {
15141            if let Some(selection) = selections.last_mut() {
15142                selection.reversed = is_selection_reversed;
15143            }
15144
15145            self.select_syntax_node_history.disable_clearing = true;
15146            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15147                s.select(selections.to_vec());
15148            });
15149            self.select_syntax_node_history.disable_clearing = false;
15150
15151            match scroll_behavior {
15152                SelectSyntaxNodeScrollBehavior::CursorTop => {
15153                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15154                }
15155                SelectSyntaxNodeScrollBehavior::FitSelection => {
15156                    self.request_autoscroll(Autoscroll::fit(), cx);
15157                }
15158                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15159                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15160                }
15161            }
15162        }
15163    }
15164
15165    pub fn unwrap_syntax_node(
15166        &mut self,
15167        _: &UnwrapSyntaxNode,
15168        window: &mut Window,
15169        cx: &mut Context<Self>,
15170    ) {
15171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15172
15173        let buffer = self.buffer.read(cx).snapshot(cx);
15174        let selections = self
15175            .selections
15176            .all::<usize>(cx)
15177            .into_iter()
15178            // subtracting the offset requires sorting
15179            .sorted_by_key(|i| i.start);
15180
15181        let full_edits = selections
15182            .into_iter()
15183            .filter_map(|selection| {
15184                let child = if selection.is_empty()
15185                    && let Some((_, ancestor_range)) =
15186                        buffer.syntax_ancestor(selection.start..selection.end)
15187                {
15188                    match ancestor_range {
15189                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15190                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15191                    }
15192                } else {
15193                    selection.range()
15194                };
15195
15196                let mut parent = child.clone();
15197                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15198                    parent = match ancestor_range {
15199                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15200                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15201                    };
15202                    if parent.start < child.start || parent.end > child.end {
15203                        break;
15204                    }
15205                }
15206
15207                if parent == child {
15208                    return None;
15209                }
15210                let text = buffer.text_for_range(child).collect::<String>();
15211                Some((selection.id, parent, text))
15212            })
15213            .collect::<Vec<_>>();
15214        if full_edits.is_empty() {
15215            return;
15216        }
15217
15218        self.transact(window, cx, |this, window, cx| {
15219            this.buffer.update(cx, |buffer, cx| {
15220                buffer.edit(
15221                    full_edits
15222                        .iter()
15223                        .map(|(_, p, t)| (p.clone(), t.clone()))
15224                        .collect::<Vec<_>>(),
15225                    None,
15226                    cx,
15227                );
15228            });
15229            this.change_selections(Default::default(), window, cx, |s| {
15230                let mut offset = 0;
15231                let mut selections = vec![];
15232                for (id, parent, text) in full_edits {
15233                    let start = parent.start - offset;
15234                    offset += parent.len() - text.len();
15235                    selections.push(Selection {
15236                        id,
15237                        start,
15238                        end: start + text.len(),
15239                        reversed: false,
15240                        goal: Default::default(),
15241                    });
15242                }
15243                s.select(selections);
15244            });
15245        });
15246    }
15247
15248    pub fn select_next_syntax_node(
15249        &mut self,
15250        _: &SelectNextSyntaxNode,
15251        window: &mut Window,
15252        cx: &mut Context<Self>,
15253    ) {
15254        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15255        if old_selections.is_empty() {
15256            return;
15257        }
15258
15259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15260
15261        let buffer = self.buffer.read(cx).snapshot(cx);
15262        let mut selected_sibling = false;
15263
15264        let new_selections = old_selections
15265            .iter()
15266            .map(|selection| {
15267                let old_range = selection.start..selection.end;
15268
15269                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15270                    let new_range = node.byte_range();
15271                    selected_sibling = true;
15272                    Selection {
15273                        id: selection.id,
15274                        start: new_range.start,
15275                        end: new_range.end,
15276                        goal: SelectionGoal::None,
15277                        reversed: selection.reversed,
15278                    }
15279                } else {
15280                    selection.clone()
15281                }
15282            })
15283            .collect::<Vec<_>>();
15284
15285        if selected_sibling {
15286            self.change_selections(
15287                SelectionEffects::scroll(Autoscroll::fit()),
15288                window,
15289                cx,
15290                |s| {
15291                    s.select(new_selections);
15292                },
15293            );
15294        }
15295    }
15296
15297    pub fn select_prev_syntax_node(
15298        &mut self,
15299        _: &SelectPreviousSyntaxNode,
15300        window: &mut Window,
15301        cx: &mut Context<Self>,
15302    ) {
15303        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15304        if old_selections.is_empty() {
15305            return;
15306        }
15307
15308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15309
15310        let buffer = self.buffer.read(cx).snapshot(cx);
15311        let mut selected_sibling = false;
15312
15313        let new_selections = old_selections
15314            .iter()
15315            .map(|selection| {
15316                let old_range = selection.start..selection.end;
15317
15318                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15319                    let new_range = node.byte_range();
15320                    selected_sibling = true;
15321                    Selection {
15322                        id: selection.id,
15323                        start: new_range.start,
15324                        end: new_range.end,
15325                        goal: SelectionGoal::None,
15326                        reversed: selection.reversed,
15327                    }
15328                } else {
15329                    selection.clone()
15330                }
15331            })
15332            .collect::<Vec<_>>();
15333
15334        if selected_sibling {
15335            self.change_selections(
15336                SelectionEffects::scroll(Autoscroll::fit()),
15337                window,
15338                cx,
15339                |s| {
15340                    s.select(new_selections);
15341                },
15342            );
15343        }
15344    }
15345
15346    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15347        if !EditorSettings::get_global(cx).gutter.runnables {
15348            self.clear_tasks();
15349            return Task::ready(());
15350        }
15351        let project = self.project().map(Entity::downgrade);
15352        let task_sources = self.lsp_task_sources(cx);
15353        let multi_buffer = self.buffer.downgrade();
15354        cx.spawn_in(window, async move |editor, cx| {
15355            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15356            let Some(project) = project.and_then(|p| p.upgrade()) else {
15357                return;
15358            };
15359            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15360                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15361            }) else {
15362                return;
15363            };
15364
15365            let hide_runnables = project
15366                .update(cx, |project, _| project.is_via_collab())
15367                .unwrap_or(true);
15368            if hide_runnables {
15369                return;
15370            }
15371            let new_rows =
15372                cx.background_spawn({
15373                    let snapshot = display_snapshot.clone();
15374                    async move {
15375                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15376                    }
15377                })
15378                    .await;
15379            let Ok(lsp_tasks) =
15380                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15381            else {
15382                return;
15383            };
15384            let lsp_tasks = lsp_tasks.await;
15385
15386            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15387                lsp_tasks
15388                    .into_iter()
15389                    .flat_map(|(kind, tasks)| {
15390                        tasks.into_iter().filter_map(move |(location, task)| {
15391                            Some((kind.clone(), location?, task))
15392                        })
15393                    })
15394                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15395                        let buffer = location.target.buffer;
15396                        let buffer_snapshot = buffer.read(cx).snapshot();
15397                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15398                            |(excerpt_id, snapshot, _)| {
15399                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15400                                    display_snapshot
15401                                        .buffer_snapshot
15402                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15403                                } else {
15404                                    None
15405                                }
15406                            },
15407                        );
15408                        if let Some(offset) = offset {
15409                            let task_buffer_range =
15410                                location.target.range.to_point(&buffer_snapshot);
15411                            let context_buffer_range =
15412                                task_buffer_range.to_offset(&buffer_snapshot);
15413                            let context_range = BufferOffset(context_buffer_range.start)
15414                                ..BufferOffset(context_buffer_range.end);
15415
15416                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15417                                .or_insert_with(|| RunnableTasks {
15418                                    templates: Vec::new(),
15419                                    offset,
15420                                    column: task_buffer_range.start.column,
15421                                    extra_variables: HashMap::default(),
15422                                    context_range,
15423                                })
15424                                .templates
15425                                .push((kind, task.original_task().clone()));
15426                        }
15427
15428                        acc
15429                    })
15430            }) else {
15431                return;
15432            };
15433
15434            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15435                buffer.language_settings(cx).tasks.prefer_lsp
15436            }) else {
15437                return;
15438            };
15439
15440            let rows = Self::runnable_rows(
15441                project,
15442                display_snapshot,
15443                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15444                new_rows,
15445                cx.clone(),
15446            )
15447            .await;
15448            editor
15449                .update(cx, |editor, _| {
15450                    editor.clear_tasks();
15451                    for (key, mut value) in rows {
15452                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15453                            value.templates.extend(lsp_tasks.templates);
15454                        }
15455
15456                        editor.insert_tasks(key, value);
15457                    }
15458                    for (key, value) in lsp_tasks_by_rows {
15459                        editor.insert_tasks(key, value);
15460                    }
15461                })
15462                .ok();
15463        })
15464    }
15465    fn fetch_runnable_ranges(
15466        snapshot: &DisplaySnapshot,
15467        range: Range<Anchor>,
15468    ) -> Vec<language::RunnableRange> {
15469        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15470    }
15471
15472    fn runnable_rows(
15473        project: Entity<Project>,
15474        snapshot: DisplaySnapshot,
15475        prefer_lsp: bool,
15476        runnable_ranges: Vec<RunnableRange>,
15477        cx: AsyncWindowContext,
15478    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15479        cx.spawn(async move |cx| {
15480            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15481            for mut runnable in runnable_ranges {
15482                let Some(tasks) = cx
15483                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15484                    .ok()
15485                else {
15486                    continue;
15487                };
15488                let mut tasks = tasks.await;
15489
15490                if prefer_lsp {
15491                    tasks.retain(|(task_kind, _)| {
15492                        !matches!(task_kind, TaskSourceKind::Language { .. })
15493                    });
15494                }
15495                if tasks.is_empty() {
15496                    continue;
15497                }
15498
15499                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15500                let Some(row) = snapshot
15501                    .buffer_snapshot
15502                    .buffer_line_for_row(MultiBufferRow(point.row))
15503                    .map(|(_, range)| range.start.row)
15504                else {
15505                    continue;
15506                };
15507
15508                let context_range =
15509                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15510                runnable_rows.push((
15511                    (runnable.buffer_id, row),
15512                    RunnableTasks {
15513                        templates: tasks,
15514                        offset: snapshot
15515                            .buffer_snapshot
15516                            .anchor_before(runnable.run_range.start),
15517                        context_range,
15518                        column: point.column,
15519                        extra_variables: runnable.extra_captures,
15520                    },
15521                ));
15522            }
15523            runnable_rows
15524        })
15525    }
15526
15527    fn templates_with_tags(
15528        project: &Entity<Project>,
15529        runnable: &mut Runnable,
15530        cx: &mut App,
15531    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15532        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15533            let (worktree_id, file) = project
15534                .buffer_for_id(runnable.buffer, cx)
15535                .and_then(|buffer| buffer.read(cx).file())
15536                .map(|file| (file.worktree_id(cx), file.clone()))
15537                .unzip();
15538
15539            (
15540                project.task_store().read(cx).task_inventory().cloned(),
15541                worktree_id,
15542                file,
15543            )
15544        });
15545
15546        let tags = mem::take(&mut runnable.tags);
15547        let language = runnable.language.clone();
15548        cx.spawn(async move |cx| {
15549            let mut templates_with_tags = Vec::new();
15550            if let Some(inventory) = inventory {
15551                for RunnableTag(tag) in tags {
15552                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15553                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15554                    }) else {
15555                        return templates_with_tags;
15556                    };
15557                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15558                        move |(_, template)| {
15559                            template.tags.iter().any(|source_tag| source_tag == &tag)
15560                        },
15561                    ));
15562                }
15563            }
15564            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15565
15566            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15567                // Strongest source wins; if we have worktree tag binding, prefer that to
15568                // global and language bindings;
15569                // if we have a global binding, prefer that to language binding.
15570                let first_mismatch = templates_with_tags
15571                    .iter()
15572                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15573                if let Some(index) = first_mismatch {
15574                    templates_with_tags.truncate(index);
15575                }
15576            }
15577
15578            templates_with_tags
15579        })
15580    }
15581
15582    pub fn move_to_enclosing_bracket(
15583        &mut self,
15584        _: &MoveToEnclosingBracket,
15585        window: &mut Window,
15586        cx: &mut Context<Self>,
15587    ) {
15588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15589        self.change_selections(Default::default(), window, cx, |s| {
15590            s.move_offsets_with(|snapshot, selection| {
15591                let Some(enclosing_bracket_ranges) =
15592                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15593                else {
15594                    return;
15595                };
15596
15597                let mut best_length = usize::MAX;
15598                let mut best_inside = false;
15599                let mut best_in_bracket_range = false;
15600                let mut best_destination = None;
15601                for (open, close) in enclosing_bracket_ranges {
15602                    let close = close.to_inclusive();
15603                    let length = close.end() - open.start;
15604                    let inside = selection.start >= open.end && selection.end <= *close.start();
15605                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15606                        || close.contains(&selection.head());
15607
15608                    // If best is next to a bracket and current isn't, skip
15609                    if !in_bracket_range && best_in_bracket_range {
15610                        continue;
15611                    }
15612
15613                    // Prefer smaller lengths unless best is inside and current isn't
15614                    if length > best_length && (best_inside || !inside) {
15615                        continue;
15616                    }
15617
15618                    best_length = length;
15619                    best_inside = inside;
15620                    best_in_bracket_range = in_bracket_range;
15621                    best_destination = Some(
15622                        if close.contains(&selection.start) && close.contains(&selection.end) {
15623                            if inside { open.end } else { open.start }
15624                        } else if inside {
15625                            *close.start()
15626                        } else {
15627                            *close.end()
15628                        },
15629                    );
15630                }
15631
15632                if let Some(destination) = best_destination {
15633                    selection.collapse_to(destination, SelectionGoal::None);
15634                }
15635            })
15636        });
15637    }
15638
15639    pub fn undo_selection(
15640        &mut self,
15641        _: &UndoSelection,
15642        window: &mut Window,
15643        cx: &mut Context<Self>,
15644    ) {
15645        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15646        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15647            self.selection_history.mode = SelectionHistoryMode::Undoing;
15648            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15649                this.end_selection(window, cx);
15650                this.change_selections(
15651                    SelectionEffects::scroll(Autoscroll::newest()),
15652                    window,
15653                    cx,
15654                    |s| s.select_anchors(entry.selections.to_vec()),
15655                );
15656            });
15657            self.selection_history.mode = SelectionHistoryMode::Normal;
15658
15659            self.select_next_state = entry.select_next_state;
15660            self.select_prev_state = entry.select_prev_state;
15661            self.add_selections_state = entry.add_selections_state;
15662        }
15663    }
15664
15665    pub fn redo_selection(
15666        &mut self,
15667        _: &RedoSelection,
15668        window: &mut Window,
15669        cx: &mut Context<Self>,
15670    ) {
15671        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15672        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15673            self.selection_history.mode = SelectionHistoryMode::Redoing;
15674            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15675                this.end_selection(window, cx);
15676                this.change_selections(
15677                    SelectionEffects::scroll(Autoscroll::newest()),
15678                    window,
15679                    cx,
15680                    |s| s.select_anchors(entry.selections.to_vec()),
15681                );
15682            });
15683            self.selection_history.mode = SelectionHistoryMode::Normal;
15684
15685            self.select_next_state = entry.select_next_state;
15686            self.select_prev_state = entry.select_prev_state;
15687            self.add_selections_state = entry.add_selections_state;
15688        }
15689    }
15690
15691    pub fn expand_excerpts(
15692        &mut self,
15693        action: &ExpandExcerpts,
15694        _: &mut Window,
15695        cx: &mut Context<Self>,
15696    ) {
15697        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15698    }
15699
15700    pub fn expand_excerpts_down(
15701        &mut self,
15702        action: &ExpandExcerptsDown,
15703        _: &mut Window,
15704        cx: &mut Context<Self>,
15705    ) {
15706        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15707    }
15708
15709    pub fn expand_excerpts_up(
15710        &mut self,
15711        action: &ExpandExcerptsUp,
15712        _: &mut Window,
15713        cx: &mut Context<Self>,
15714    ) {
15715        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15716    }
15717
15718    pub fn expand_excerpts_for_direction(
15719        &mut self,
15720        lines: u32,
15721        direction: ExpandExcerptDirection,
15722
15723        cx: &mut Context<Self>,
15724    ) {
15725        let selections = self.selections.disjoint_anchors_arc();
15726
15727        let lines = if lines == 0 {
15728            EditorSettings::get_global(cx).expand_excerpt_lines
15729        } else {
15730            lines
15731        };
15732
15733        self.buffer.update(cx, |buffer, cx| {
15734            let snapshot = buffer.snapshot(cx);
15735            let mut excerpt_ids = selections
15736                .iter()
15737                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15738                .collect::<Vec<_>>();
15739            excerpt_ids.sort();
15740            excerpt_ids.dedup();
15741            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15742        })
15743    }
15744
15745    pub fn expand_excerpt(
15746        &mut self,
15747        excerpt: ExcerptId,
15748        direction: ExpandExcerptDirection,
15749        window: &mut Window,
15750        cx: &mut Context<Self>,
15751    ) {
15752        let current_scroll_position = self.scroll_position(cx);
15753        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15754        let mut should_scroll_up = false;
15755
15756        if direction == ExpandExcerptDirection::Down {
15757            let multi_buffer = self.buffer.read(cx);
15758            let snapshot = multi_buffer.snapshot(cx);
15759            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15760                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15761                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15762            {
15763                let buffer_snapshot = buffer.read(cx).snapshot();
15764                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15765                let last_row = buffer_snapshot.max_point().row;
15766                let lines_below = last_row.saturating_sub(excerpt_end_row);
15767                should_scroll_up = lines_below >= lines_to_expand;
15768            }
15769        }
15770
15771        self.buffer.update(cx, |buffer, cx| {
15772            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15773        });
15774
15775        if should_scroll_up {
15776            let new_scroll_position =
15777                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15778            self.set_scroll_position(new_scroll_position, window, cx);
15779        }
15780    }
15781
15782    pub fn go_to_singleton_buffer_point(
15783        &mut self,
15784        point: Point,
15785        window: &mut Window,
15786        cx: &mut Context<Self>,
15787    ) {
15788        self.go_to_singleton_buffer_range(point..point, window, cx);
15789    }
15790
15791    pub fn go_to_singleton_buffer_range(
15792        &mut self,
15793        range: Range<Point>,
15794        window: &mut Window,
15795        cx: &mut Context<Self>,
15796    ) {
15797        let multibuffer = self.buffer().read(cx);
15798        let Some(buffer) = multibuffer.as_singleton() else {
15799            return;
15800        };
15801        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15802            return;
15803        };
15804        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15805            return;
15806        };
15807        self.change_selections(
15808            SelectionEffects::default().nav_history(true),
15809            window,
15810            cx,
15811            |s| s.select_anchor_ranges([start..end]),
15812        );
15813    }
15814
15815    pub fn go_to_diagnostic(
15816        &mut self,
15817        action: &GoToDiagnostic,
15818        window: &mut Window,
15819        cx: &mut Context<Self>,
15820    ) {
15821        if !self.diagnostics_enabled() {
15822            return;
15823        }
15824        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15825        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15826    }
15827
15828    pub fn go_to_prev_diagnostic(
15829        &mut self,
15830        action: &GoToPreviousDiagnostic,
15831        window: &mut Window,
15832        cx: &mut Context<Self>,
15833    ) {
15834        if !self.diagnostics_enabled() {
15835            return;
15836        }
15837        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15838        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15839    }
15840
15841    pub fn go_to_diagnostic_impl(
15842        &mut self,
15843        direction: Direction,
15844        severity: GoToDiagnosticSeverityFilter,
15845        window: &mut Window,
15846        cx: &mut Context<Self>,
15847    ) {
15848        let buffer = self.buffer.read(cx).snapshot(cx);
15849        let selection = self.selections.newest::<usize>(cx);
15850
15851        let mut active_group_id = None;
15852        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15853            && active_group.active_range.start.to_offset(&buffer) == selection.start
15854        {
15855            active_group_id = Some(active_group.group_id);
15856        }
15857
15858        fn filtered(
15859            snapshot: EditorSnapshot,
15860            severity: GoToDiagnosticSeverityFilter,
15861            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15862        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15863            diagnostics
15864                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15865                .filter(|entry| entry.range.start != entry.range.end)
15866                .filter(|entry| !entry.diagnostic.is_unnecessary)
15867                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15868        }
15869
15870        let snapshot = self.snapshot(window, cx);
15871        let before = filtered(
15872            snapshot.clone(),
15873            severity,
15874            buffer
15875                .diagnostics_in_range(0..selection.start)
15876                .filter(|entry| entry.range.start <= selection.start),
15877        );
15878        let after = filtered(
15879            snapshot,
15880            severity,
15881            buffer
15882                .diagnostics_in_range(selection.start..buffer.len())
15883                .filter(|entry| entry.range.start >= selection.start),
15884        );
15885
15886        let mut found: Option<DiagnosticEntry<usize>> = None;
15887        if direction == Direction::Prev {
15888            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15889            {
15890                for diagnostic in prev_diagnostics.into_iter().rev() {
15891                    if diagnostic.range.start != selection.start
15892                        || active_group_id
15893                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15894                    {
15895                        found = Some(diagnostic);
15896                        break 'outer;
15897                    }
15898                }
15899            }
15900        } else {
15901            for diagnostic in after.chain(before) {
15902                if diagnostic.range.start != selection.start
15903                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15904                {
15905                    found = Some(diagnostic);
15906                    break;
15907                }
15908            }
15909        }
15910        let Some(next_diagnostic) = found else {
15911            return;
15912        };
15913
15914        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15915        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15916            return;
15917        };
15918        self.change_selections(Default::default(), window, cx, |s| {
15919            s.select_ranges(vec![
15920                next_diagnostic.range.start..next_diagnostic.range.start,
15921            ])
15922        });
15923        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15924        self.refresh_edit_prediction(false, true, window, cx);
15925    }
15926
15927    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15929        let snapshot = self.snapshot(window, cx);
15930        let selection = self.selections.newest::<Point>(cx);
15931        self.go_to_hunk_before_or_after_position(
15932            &snapshot,
15933            selection.head(),
15934            Direction::Next,
15935            window,
15936            cx,
15937        );
15938    }
15939
15940    pub fn go_to_hunk_before_or_after_position(
15941        &mut self,
15942        snapshot: &EditorSnapshot,
15943        position: Point,
15944        direction: Direction,
15945        window: &mut Window,
15946        cx: &mut Context<Editor>,
15947    ) {
15948        let row = if direction == Direction::Next {
15949            self.hunk_after_position(snapshot, position)
15950                .map(|hunk| hunk.row_range.start)
15951        } else {
15952            self.hunk_before_position(snapshot, position)
15953        };
15954
15955        if let Some(row) = row {
15956            let destination = Point::new(row.0, 0);
15957            let autoscroll = Autoscroll::center();
15958
15959            self.unfold_ranges(&[destination..destination], false, false, cx);
15960            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15961                s.select_ranges([destination..destination]);
15962            });
15963        }
15964    }
15965
15966    fn hunk_after_position(
15967        &mut self,
15968        snapshot: &EditorSnapshot,
15969        position: Point,
15970    ) -> Option<MultiBufferDiffHunk> {
15971        snapshot
15972            .buffer_snapshot
15973            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15974            .find(|hunk| hunk.row_range.start.0 > position.row)
15975            .or_else(|| {
15976                snapshot
15977                    .buffer_snapshot
15978                    .diff_hunks_in_range(Point::zero()..position)
15979                    .find(|hunk| hunk.row_range.end.0 < position.row)
15980            })
15981    }
15982
15983    fn go_to_prev_hunk(
15984        &mut self,
15985        _: &GoToPreviousHunk,
15986        window: &mut Window,
15987        cx: &mut Context<Self>,
15988    ) {
15989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15990        let snapshot = self.snapshot(window, cx);
15991        let selection = self.selections.newest::<Point>(cx);
15992        self.go_to_hunk_before_or_after_position(
15993            &snapshot,
15994            selection.head(),
15995            Direction::Prev,
15996            window,
15997            cx,
15998        );
15999    }
16000
16001    fn hunk_before_position(
16002        &mut self,
16003        snapshot: &EditorSnapshot,
16004        position: Point,
16005    ) -> Option<MultiBufferRow> {
16006        snapshot
16007            .buffer_snapshot
16008            .diff_hunk_before(position)
16009            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16010    }
16011
16012    fn go_to_next_change(
16013        &mut self,
16014        _: &GoToNextChange,
16015        window: &mut Window,
16016        cx: &mut Context<Self>,
16017    ) {
16018        if let Some(selections) = self
16019            .change_list
16020            .next_change(1, Direction::Next)
16021            .map(|s| s.to_vec())
16022        {
16023            self.change_selections(Default::default(), window, cx, |s| {
16024                let map = s.display_map();
16025                s.select_display_ranges(selections.iter().map(|a| {
16026                    let point = a.to_display_point(&map);
16027                    point..point
16028                }))
16029            })
16030        }
16031    }
16032
16033    fn go_to_previous_change(
16034        &mut self,
16035        _: &GoToPreviousChange,
16036        window: &mut Window,
16037        cx: &mut Context<Self>,
16038    ) {
16039        if let Some(selections) = self
16040            .change_list
16041            .next_change(1, Direction::Prev)
16042            .map(|s| s.to_vec())
16043        {
16044            self.change_selections(Default::default(), window, cx, |s| {
16045                let map = s.display_map();
16046                s.select_display_ranges(selections.iter().map(|a| {
16047                    let point = a.to_display_point(&map);
16048                    point..point
16049                }))
16050            })
16051        }
16052    }
16053
16054    pub fn go_to_next_document_highlight(
16055        &mut self,
16056        _: &GoToNextDocumentHighlight,
16057        window: &mut Window,
16058        cx: &mut Context<Self>,
16059    ) {
16060        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16061    }
16062
16063    pub fn go_to_prev_document_highlight(
16064        &mut self,
16065        _: &GoToPreviousDocumentHighlight,
16066        window: &mut Window,
16067        cx: &mut Context<Self>,
16068    ) {
16069        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16070    }
16071
16072    pub fn go_to_document_highlight_before_or_after_position(
16073        &mut self,
16074        direction: Direction,
16075        window: &mut Window,
16076        cx: &mut Context<Editor>,
16077    ) {
16078        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16079        let snapshot = self.snapshot(window, cx);
16080        let buffer = &snapshot.buffer_snapshot;
16081        let position = self.selections.newest::<Point>(cx).head();
16082        let anchor_position = buffer.anchor_after(position);
16083
16084        // Get all document highlights (both read and write)
16085        let mut all_highlights = Vec::new();
16086
16087        if let Some((_, read_highlights)) = self
16088            .background_highlights
16089            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16090        {
16091            all_highlights.extend(read_highlights.iter());
16092        }
16093
16094        if let Some((_, write_highlights)) = self
16095            .background_highlights
16096            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16097        {
16098            all_highlights.extend(write_highlights.iter());
16099        }
16100
16101        if all_highlights.is_empty() {
16102            return;
16103        }
16104
16105        // Sort highlights by position
16106        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16107
16108        let target_highlight = match direction {
16109            Direction::Next => {
16110                // Find the first highlight after the current position
16111                all_highlights
16112                    .iter()
16113                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16114            }
16115            Direction::Prev => {
16116                // Find the last highlight before the current position
16117                all_highlights
16118                    .iter()
16119                    .rev()
16120                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16121            }
16122        };
16123
16124        if let Some(highlight) = target_highlight {
16125            let destination = highlight.start.to_point(buffer);
16126            let autoscroll = Autoscroll::center();
16127
16128            self.unfold_ranges(&[destination..destination], false, false, cx);
16129            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16130                s.select_ranges([destination..destination]);
16131            });
16132        }
16133    }
16134
16135    fn go_to_line<T: 'static>(
16136        &mut self,
16137        position: Anchor,
16138        highlight_color: Option<Hsla>,
16139        window: &mut Window,
16140        cx: &mut Context<Self>,
16141    ) {
16142        let snapshot = self.snapshot(window, cx).display_snapshot;
16143        let position = position.to_point(&snapshot.buffer_snapshot);
16144        let start = snapshot
16145            .buffer_snapshot
16146            .clip_point(Point::new(position.row, 0), Bias::Left);
16147        let end = start + Point::new(1, 0);
16148        let start = snapshot.buffer_snapshot.anchor_before(start);
16149        let end = snapshot.buffer_snapshot.anchor_before(end);
16150
16151        self.highlight_rows::<T>(
16152            start..end,
16153            highlight_color
16154                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16155            Default::default(),
16156            cx,
16157        );
16158
16159        if self.buffer.read(cx).is_singleton() {
16160            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16161        }
16162    }
16163
16164    pub fn go_to_definition(
16165        &mut self,
16166        _: &GoToDefinition,
16167        window: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) -> Task<Result<Navigated>> {
16170        let definition =
16171            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16172        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16173        cx.spawn_in(window, async move |editor, cx| {
16174            if definition.await? == Navigated::Yes {
16175                return Ok(Navigated::Yes);
16176            }
16177            match fallback_strategy {
16178                GoToDefinitionFallback::None => Ok(Navigated::No),
16179                GoToDefinitionFallback::FindAllReferences => {
16180                    match editor.update_in(cx, |editor, window, cx| {
16181                        editor.find_all_references(&FindAllReferences, window, cx)
16182                    })? {
16183                        Some(references) => references.await,
16184                        None => Ok(Navigated::No),
16185                    }
16186                }
16187            }
16188        })
16189    }
16190
16191    pub fn go_to_declaration(
16192        &mut self,
16193        _: &GoToDeclaration,
16194        window: &mut Window,
16195        cx: &mut Context<Self>,
16196    ) -> Task<Result<Navigated>> {
16197        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16198    }
16199
16200    pub fn go_to_declaration_split(
16201        &mut self,
16202        _: &GoToDeclaration,
16203        window: &mut Window,
16204        cx: &mut Context<Self>,
16205    ) -> Task<Result<Navigated>> {
16206        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16207    }
16208
16209    pub fn go_to_implementation(
16210        &mut self,
16211        _: &GoToImplementation,
16212        window: &mut Window,
16213        cx: &mut Context<Self>,
16214    ) -> Task<Result<Navigated>> {
16215        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16216    }
16217
16218    pub fn go_to_implementation_split(
16219        &mut self,
16220        _: &GoToImplementationSplit,
16221        window: &mut Window,
16222        cx: &mut Context<Self>,
16223    ) -> Task<Result<Navigated>> {
16224        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16225    }
16226
16227    pub fn go_to_type_definition(
16228        &mut self,
16229        _: &GoToTypeDefinition,
16230        window: &mut Window,
16231        cx: &mut Context<Self>,
16232    ) -> Task<Result<Navigated>> {
16233        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16234    }
16235
16236    pub fn go_to_definition_split(
16237        &mut self,
16238        _: &GoToDefinitionSplit,
16239        window: &mut Window,
16240        cx: &mut Context<Self>,
16241    ) -> Task<Result<Navigated>> {
16242        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16243    }
16244
16245    pub fn go_to_type_definition_split(
16246        &mut self,
16247        _: &GoToTypeDefinitionSplit,
16248        window: &mut Window,
16249        cx: &mut Context<Self>,
16250    ) -> Task<Result<Navigated>> {
16251        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16252    }
16253
16254    fn go_to_definition_of_kind(
16255        &mut self,
16256        kind: GotoDefinitionKind,
16257        split: bool,
16258        window: &mut Window,
16259        cx: &mut Context<Self>,
16260    ) -> Task<Result<Navigated>> {
16261        let Some(provider) = self.semantics_provider.clone() else {
16262            return Task::ready(Ok(Navigated::No));
16263        };
16264        let head = self.selections.newest::<usize>(cx).head();
16265        let buffer = self.buffer.read(cx);
16266        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16267            return Task::ready(Ok(Navigated::No));
16268        };
16269        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16270            return Task::ready(Ok(Navigated::No));
16271        };
16272
16273        cx.spawn_in(window, async move |editor, cx| {
16274            let Some(definitions) = definitions.await? else {
16275                return Ok(Navigated::No);
16276            };
16277            let navigated = editor
16278                .update_in(cx, |editor, window, cx| {
16279                    editor.navigate_to_hover_links(
16280                        Some(kind),
16281                        definitions
16282                            .into_iter()
16283                            .filter(|location| {
16284                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16285                            })
16286                            .map(HoverLink::Text)
16287                            .collect::<Vec<_>>(),
16288                        split,
16289                        window,
16290                        cx,
16291                    )
16292                })?
16293                .await?;
16294            anyhow::Ok(navigated)
16295        })
16296    }
16297
16298    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16299        let selection = self.selections.newest_anchor();
16300        let head = selection.head();
16301        let tail = selection.tail();
16302
16303        let Some((buffer, start_position)) =
16304            self.buffer.read(cx).text_anchor_for_position(head, cx)
16305        else {
16306            return;
16307        };
16308
16309        let end_position = if head != tail {
16310            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16311                return;
16312            };
16313            Some(pos)
16314        } else {
16315            None
16316        };
16317
16318        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16319            let url = if let Some(end_pos) = end_position {
16320                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16321            } else {
16322                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16323            };
16324
16325            if let Some(url) = url {
16326                editor.update(cx, |_, cx| {
16327                    cx.open_url(&url);
16328                })
16329            } else {
16330                Ok(())
16331            }
16332        });
16333
16334        url_finder.detach();
16335    }
16336
16337    pub fn open_selected_filename(
16338        &mut self,
16339        _: &OpenSelectedFilename,
16340        window: &mut Window,
16341        cx: &mut Context<Self>,
16342    ) {
16343        let Some(workspace) = self.workspace() else {
16344            return;
16345        };
16346
16347        let position = self.selections.newest_anchor().head();
16348
16349        let Some((buffer, buffer_position)) =
16350            self.buffer.read(cx).text_anchor_for_position(position, cx)
16351        else {
16352            return;
16353        };
16354
16355        let project = self.project.clone();
16356
16357        cx.spawn_in(window, async move |_, cx| {
16358            let result = find_file(&buffer, project, buffer_position, cx).await;
16359
16360            if let Some((_, path)) = result {
16361                workspace
16362                    .update_in(cx, |workspace, window, cx| {
16363                        workspace.open_resolved_path(path, window, cx)
16364                    })?
16365                    .await?;
16366            }
16367            anyhow::Ok(())
16368        })
16369        .detach();
16370    }
16371
16372    pub(crate) fn navigate_to_hover_links(
16373        &mut self,
16374        kind: Option<GotoDefinitionKind>,
16375        definitions: Vec<HoverLink>,
16376        split: bool,
16377        window: &mut Window,
16378        cx: &mut Context<Editor>,
16379    ) -> Task<Result<Navigated>> {
16380        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16381        let mut first_url_or_file = None;
16382        let definitions: Vec<_> = definitions
16383            .into_iter()
16384            .filter_map(|def| match def {
16385                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16386                HoverLink::InlayHint(lsp_location, server_id) => {
16387                    let computation =
16388                        self.compute_target_location(lsp_location, server_id, window, cx);
16389                    Some(cx.background_spawn(computation))
16390                }
16391                HoverLink::Url(url) => {
16392                    first_url_or_file = Some(Either::Left(url));
16393                    None
16394                }
16395                HoverLink::File(path) => {
16396                    first_url_or_file = Some(Either::Right(path));
16397                    None
16398                }
16399            })
16400            .collect();
16401
16402        let workspace = self.workspace();
16403
16404        cx.spawn_in(window, async move |editor, cx| {
16405            let locations: Vec<Location> = future::join_all(definitions)
16406                .await
16407                .into_iter()
16408                .filter_map(|location| location.transpose())
16409                .collect::<Result<_>>()
16410                .context("location tasks")?;
16411            let mut locations = cx.update(|_, cx| {
16412                locations
16413                    .into_iter()
16414                    .map(|location| {
16415                        let buffer = location.buffer.read(cx);
16416                        (location.buffer, location.range.to_point(buffer))
16417                    })
16418                    .into_group_map()
16419            })?;
16420            let mut num_locations = 0;
16421            for ranges in locations.values_mut() {
16422                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16423                ranges.dedup();
16424                num_locations += ranges.len();
16425            }
16426
16427            if num_locations > 1 {
16428                let Some(workspace) = workspace else {
16429                    return Ok(Navigated::No);
16430                };
16431
16432                let tab_kind = match kind {
16433                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16434                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16435                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16436                    Some(GotoDefinitionKind::Type) => "Types",
16437                };
16438                let title = editor
16439                    .update_in(cx, |_, _, cx| {
16440                        let target = locations
16441                            .iter()
16442                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16443                            .map(|(buffer, location)| {
16444                                buffer
16445                                    .read(cx)
16446                                    .text_for_range(location.clone())
16447                                    .collect::<String>()
16448                            })
16449                            .filter(|text| !text.contains('\n'))
16450                            .unique()
16451                            .take(3)
16452                            .join(", ");
16453                        if target.is_empty() {
16454                            tab_kind.to_owned()
16455                        } else {
16456                            format!("{tab_kind} for {target}")
16457                        }
16458                    })
16459                    .context("buffer title")?;
16460
16461                let opened = workspace
16462                    .update_in(cx, |workspace, window, cx| {
16463                        Self::open_locations_in_multibuffer(
16464                            workspace,
16465                            locations,
16466                            title,
16467                            split,
16468                            MultibufferSelectionMode::First,
16469                            window,
16470                            cx,
16471                        )
16472                    })
16473                    .is_ok();
16474
16475                anyhow::Ok(Navigated::from_bool(opened))
16476            } else if num_locations == 0 {
16477                // If there is one url or file, open it directly
16478                match first_url_or_file {
16479                    Some(Either::Left(url)) => {
16480                        cx.update(|_, cx| cx.open_url(&url))?;
16481                        Ok(Navigated::Yes)
16482                    }
16483                    Some(Either::Right(path)) => {
16484                        let Some(workspace) = workspace else {
16485                            return Ok(Navigated::No);
16486                        };
16487
16488                        workspace
16489                            .update_in(cx, |workspace, window, cx| {
16490                                workspace.open_resolved_path(path, window, cx)
16491                            })?
16492                            .await?;
16493                        Ok(Navigated::Yes)
16494                    }
16495                    None => Ok(Navigated::No),
16496                }
16497            } else {
16498                let Some(workspace) = workspace else {
16499                    return Ok(Navigated::No);
16500                };
16501
16502                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16503                let target_range = target_ranges.first().unwrap().clone();
16504
16505                editor.update_in(cx, |editor, window, cx| {
16506                    let range = target_range.to_point(target_buffer.read(cx));
16507                    let range = editor.range_for_match(&range);
16508                    let range = collapse_multiline_range(range);
16509
16510                    if !split
16511                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16512                    {
16513                        editor.go_to_singleton_buffer_range(range, window, cx);
16514                    } else {
16515                        let pane = workspace.read(cx).active_pane().clone();
16516                        window.defer(cx, move |window, cx| {
16517                            let target_editor: Entity<Self> =
16518                                workspace.update(cx, |workspace, cx| {
16519                                    let pane = if split {
16520                                        workspace.adjacent_pane(window, cx)
16521                                    } else {
16522                                        workspace.active_pane().clone()
16523                                    };
16524
16525                                    workspace.open_project_item(
16526                                        pane,
16527                                        target_buffer.clone(),
16528                                        true,
16529                                        true,
16530                                        window,
16531                                        cx,
16532                                    )
16533                                });
16534                            target_editor.update(cx, |target_editor, cx| {
16535                                // When selecting a definition in a different buffer, disable the nav history
16536                                // to avoid creating a history entry at the previous cursor location.
16537                                pane.update(cx, |pane, _| pane.disable_history());
16538                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16539                                pane.update(cx, |pane, _| pane.enable_history());
16540                            });
16541                        });
16542                    }
16543                    Navigated::Yes
16544                })
16545            }
16546        })
16547    }
16548
16549    fn compute_target_location(
16550        &self,
16551        lsp_location: lsp::Location,
16552        server_id: LanguageServerId,
16553        window: &mut Window,
16554        cx: &mut Context<Self>,
16555    ) -> Task<anyhow::Result<Option<Location>>> {
16556        let Some(project) = self.project.clone() else {
16557            return Task::ready(Ok(None));
16558        };
16559
16560        cx.spawn_in(window, async move |editor, cx| {
16561            let location_task = editor.update(cx, |_, cx| {
16562                project.update(cx, |project, cx| {
16563                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16564                })
16565            })?;
16566            let location = Some({
16567                let target_buffer_handle = location_task.await.context("open local buffer")?;
16568                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16569                    let target_start = target_buffer
16570                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16571                    let target_end = target_buffer
16572                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16573                    target_buffer.anchor_after(target_start)
16574                        ..target_buffer.anchor_before(target_end)
16575                })?;
16576                Location {
16577                    buffer: target_buffer_handle,
16578                    range,
16579                }
16580            });
16581            Ok(location)
16582        })
16583    }
16584
16585    pub fn find_all_references(
16586        &mut self,
16587        _: &FindAllReferences,
16588        window: &mut Window,
16589        cx: &mut Context<Self>,
16590    ) -> Option<Task<Result<Navigated>>> {
16591        let selection = self.selections.newest::<usize>(cx);
16592        let multi_buffer = self.buffer.read(cx);
16593        let head = selection.head();
16594
16595        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16596        let head_anchor = multi_buffer_snapshot.anchor_at(
16597            head,
16598            if head < selection.tail() {
16599                Bias::Right
16600            } else {
16601                Bias::Left
16602            },
16603        );
16604
16605        match self
16606            .find_all_references_task_sources
16607            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16608        {
16609            Ok(_) => {
16610                log::info!(
16611                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16612                );
16613                return None;
16614            }
16615            Err(i) => {
16616                self.find_all_references_task_sources.insert(i, head_anchor);
16617            }
16618        }
16619
16620        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16621        let workspace = self.workspace()?;
16622        let project = workspace.read(cx).project().clone();
16623        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16624        Some(cx.spawn_in(window, async move |editor, cx| {
16625            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16626                if let Ok(i) = editor
16627                    .find_all_references_task_sources
16628                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16629                {
16630                    editor.find_all_references_task_sources.remove(i);
16631                }
16632            });
16633
16634            let Some(locations) = references.await? else {
16635                return anyhow::Ok(Navigated::No);
16636            };
16637            let mut locations = cx.update(|_, cx| {
16638                locations
16639                    .into_iter()
16640                    .map(|location| {
16641                        let buffer = location.buffer.read(cx);
16642                        (location.buffer, location.range.to_point(buffer))
16643                    })
16644                    .into_group_map()
16645            })?;
16646            if locations.is_empty() {
16647                return anyhow::Ok(Navigated::No);
16648            }
16649            for ranges in locations.values_mut() {
16650                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16651                ranges.dedup();
16652            }
16653
16654            workspace.update_in(cx, |workspace, window, cx| {
16655                let target = locations
16656                    .iter()
16657                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16658                    .map(|(buffer, location)| {
16659                        buffer
16660                            .read(cx)
16661                            .text_for_range(location.clone())
16662                            .collect::<String>()
16663                    })
16664                    .filter(|text| !text.contains('\n'))
16665                    .unique()
16666                    .take(3)
16667                    .join(", ");
16668                let title = if target.is_empty() {
16669                    "References".to_owned()
16670                } else {
16671                    format!("References to {target}")
16672                };
16673                Self::open_locations_in_multibuffer(
16674                    workspace,
16675                    locations,
16676                    title,
16677                    false,
16678                    MultibufferSelectionMode::First,
16679                    window,
16680                    cx,
16681                );
16682                Navigated::Yes
16683            })
16684        }))
16685    }
16686
16687    /// Opens a multibuffer with the given project locations in it
16688    pub fn open_locations_in_multibuffer(
16689        workspace: &mut Workspace,
16690        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16691        title: String,
16692        split: bool,
16693        multibuffer_selection_mode: MultibufferSelectionMode,
16694        window: &mut Window,
16695        cx: &mut Context<Workspace>,
16696    ) {
16697        if locations.is_empty() {
16698            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16699            return;
16700        }
16701
16702        let capability = workspace.project().read(cx).capability();
16703        let mut ranges = <Vec<Range<Anchor>>>::new();
16704
16705        // a key to find existing multibuffer editors with the same set of locations
16706        // to prevent us from opening more and more multibuffer tabs for searches and the like
16707        let mut key = (title.clone(), vec![]);
16708        let excerpt_buffer = cx.new(|cx| {
16709            let key = &mut key.1;
16710            let mut multibuffer = MultiBuffer::new(capability);
16711            for (buffer, mut ranges_for_buffer) in locations {
16712                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16713                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16714                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16715                    PathKey::for_buffer(&buffer, cx),
16716                    buffer.clone(),
16717                    ranges_for_buffer,
16718                    multibuffer_context_lines(cx),
16719                    cx,
16720                );
16721                ranges.extend(new_ranges)
16722            }
16723
16724            multibuffer.with_title(title)
16725        });
16726        let existing = workspace.active_pane().update(cx, |pane, cx| {
16727            pane.items()
16728                .filter_map(|item| item.downcast::<Editor>())
16729                .find(|editor| {
16730                    editor
16731                        .read(cx)
16732                        .lookup_key
16733                        .as_ref()
16734                        .and_then(|it| {
16735                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16736                        })
16737                        .is_some_and(|it| *it == key)
16738                })
16739        });
16740        let editor = existing.unwrap_or_else(|| {
16741            cx.new(|cx| {
16742                let mut editor = Editor::for_multibuffer(
16743                    excerpt_buffer,
16744                    Some(workspace.project().clone()),
16745                    window,
16746                    cx,
16747                );
16748                editor.lookup_key = Some(Box::new(key));
16749                editor
16750            })
16751        });
16752        editor.update(cx, |editor, cx| {
16753            match multibuffer_selection_mode {
16754                MultibufferSelectionMode::First => {
16755                    if let Some(first_range) = ranges.first() {
16756                        editor.change_selections(
16757                            SelectionEffects::no_scroll(),
16758                            window,
16759                            cx,
16760                            |selections| {
16761                                selections.clear_disjoint();
16762                                selections
16763                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16764                            },
16765                        );
16766                    }
16767                    editor.highlight_background::<Self>(
16768                        &ranges,
16769                        |theme| theme.colors().editor_highlighted_line_background,
16770                        cx,
16771                    );
16772                }
16773                MultibufferSelectionMode::All => {
16774                    editor.change_selections(
16775                        SelectionEffects::no_scroll(),
16776                        window,
16777                        cx,
16778                        |selections| {
16779                            selections.clear_disjoint();
16780                            selections.select_anchor_ranges(ranges);
16781                        },
16782                    );
16783                }
16784            }
16785            editor.register_buffers_with_language_servers(cx);
16786        });
16787
16788        let item = Box::new(editor);
16789        let item_id = item.item_id();
16790
16791        if split {
16792            workspace.split_item(SplitDirection::Right, item, window, cx);
16793        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16794            let (preview_item_id, preview_item_idx) =
16795                workspace.active_pane().read_with(cx, |pane, _| {
16796                    (pane.preview_item_id(), pane.preview_item_idx())
16797                });
16798
16799            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16800
16801            if let Some(preview_item_id) = preview_item_id {
16802                workspace.active_pane().update(cx, |pane, cx| {
16803                    pane.remove_item(preview_item_id, false, false, window, cx);
16804                });
16805            }
16806        } else {
16807            workspace.add_item_to_active_pane(item, None, true, window, cx);
16808        }
16809        workspace.active_pane().update(cx, |pane, cx| {
16810            pane.set_preview_item_id(Some(item_id), cx);
16811        });
16812    }
16813
16814    pub fn rename(
16815        &mut self,
16816        _: &Rename,
16817        window: &mut Window,
16818        cx: &mut Context<Self>,
16819    ) -> Option<Task<Result<()>>> {
16820        use language::ToOffset as _;
16821
16822        let provider = self.semantics_provider.clone()?;
16823        let selection = self.selections.newest_anchor().clone();
16824        let (cursor_buffer, cursor_buffer_position) = self
16825            .buffer
16826            .read(cx)
16827            .text_anchor_for_position(selection.head(), cx)?;
16828        let (tail_buffer, cursor_buffer_position_end) = self
16829            .buffer
16830            .read(cx)
16831            .text_anchor_for_position(selection.tail(), cx)?;
16832        if tail_buffer != cursor_buffer {
16833            return None;
16834        }
16835
16836        let snapshot = cursor_buffer.read(cx).snapshot();
16837        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16838        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16839        let prepare_rename = provider
16840            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16841            .unwrap_or_else(|| Task::ready(Ok(None)));
16842        drop(snapshot);
16843
16844        Some(cx.spawn_in(window, async move |this, cx| {
16845            let rename_range = if let Some(range) = prepare_rename.await? {
16846                Some(range)
16847            } else {
16848                this.update(cx, |this, cx| {
16849                    let buffer = this.buffer.read(cx).snapshot(cx);
16850                    let mut buffer_highlights = this
16851                        .document_highlights_for_position(selection.head(), &buffer)
16852                        .filter(|highlight| {
16853                            highlight.start.excerpt_id == selection.head().excerpt_id
16854                                && highlight.end.excerpt_id == selection.head().excerpt_id
16855                        });
16856                    buffer_highlights
16857                        .next()
16858                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16859                })?
16860            };
16861            if let Some(rename_range) = rename_range {
16862                this.update_in(cx, |this, window, cx| {
16863                    let snapshot = cursor_buffer.read(cx).snapshot();
16864                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16865                    let cursor_offset_in_rename_range =
16866                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16867                    let cursor_offset_in_rename_range_end =
16868                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16869
16870                    this.take_rename(false, window, cx);
16871                    let buffer = this.buffer.read(cx).read(cx);
16872                    let cursor_offset = selection.head().to_offset(&buffer);
16873                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16874                    let rename_end = rename_start + rename_buffer_range.len();
16875                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16876                    let mut old_highlight_id = None;
16877                    let old_name: Arc<str> = buffer
16878                        .chunks(rename_start..rename_end, true)
16879                        .map(|chunk| {
16880                            if old_highlight_id.is_none() {
16881                                old_highlight_id = chunk.syntax_highlight_id;
16882                            }
16883                            chunk.text
16884                        })
16885                        .collect::<String>()
16886                        .into();
16887
16888                    drop(buffer);
16889
16890                    // Position the selection in the rename editor so that it matches the current selection.
16891                    this.show_local_selections = false;
16892                    let rename_editor = cx.new(|cx| {
16893                        let mut editor = Editor::single_line(window, cx);
16894                        editor.buffer.update(cx, |buffer, cx| {
16895                            buffer.edit([(0..0, old_name.clone())], None, cx)
16896                        });
16897                        let rename_selection_range = match cursor_offset_in_rename_range
16898                            .cmp(&cursor_offset_in_rename_range_end)
16899                        {
16900                            Ordering::Equal => {
16901                                editor.select_all(&SelectAll, window, cx);
16902                                return editor;
16903                            }
16904                            Ordering::Less => {
16905                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16906                            }
16907                            Ordering::Greater => {
16908                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16909                            }
16910                        };
16911                        if rename_selection_range.end > old_name.len() {
16912                            editor.select_all(&SelectAll, window, cx);
16913                        } else {
16914                            editor.change_selections(Default::default(), window, cx, |s| {
16915                                s.select_ranges([rename_selection_range]);
16916                            });
16917                        }
16918                        editor
16919                    });
16920                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16921                        if e == &EditorEvent::Focused {
16922                            cx.emit(EditorEvent::FocusedIn)
16923                        }
16924                    })
16925                    .detach();
16926
16927                    let write_highlights =
16928                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16929                    let read_highlights =
16930                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16931                    let ranges = write_highlights
16932                        .iter()
16933                        .flat_map(|(_, ranges)| ranges.iter())
16934                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16935                        .cloned()
16936                        .collect();
16937
16938                    this.highlight_text::<Rename>(
16939                        ranges,
16940                        HighlightStyle {
16941                            fade_out: Some(0.6),
16942                            ..Default::default()
16943                        },
16944                        cx,
16945                    );
16946                    let rename_focus_handle = rename_editor.focus_handle(cx);
16947                    window.focus(&rename_focus_handle);
16948                    let block_id = this.insert_blocks(
16949                        [BlockProperties {
16950                            style: BlockStyle::Flex,
16951                            placement: BlockPlacement::Below(range.start),
16952                            height: Some(1),
16953                            render: Arc::new({
16954                                let rename_editor = rename_editor.clone();
16955                                move |cx: &mut BlockContext| {
16956                                    let mut text_style = cx.editor_style.text.clone();
16957                                    if let Some(highlight_style) = old_highlight_id
16958                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16959                                    {
16960                                        text_style = text_style.highlight(highlight_style);
16961                                    }
16962                                    div()
16963                                        .block_mouse_except_scroll()
16964                                        .pl(cx.anchor_x)
16965                                        .child(EditorElement::new(
16966                                            &rename_editor,
16967                                            EditorStyle {
16968                                                background: cx.theme().system().transparent,
16969                                                local_player: cx.editor_style.local_player,
16970                                                text: text_style,
16971                                                scrollbar_width: cx.editor_style.scrollbar_width,
16972                                                syntax: cx.editor_style.syntax.clone(),
16973                                                status: cx.editor_style.status.clone(),
16974                                                inlay_hints_style: HighlightStyle {
16975                                                    font_weight: Some(FontWeight::BOLD),
16976                                                    ..make_inlay_hints_style(cx.app)
16977                                                },
16978                                                edit_prediction_styles: make_suggestion_styles(
16979                                                    cx.app,
16980                                                ),
16981                                                ..EditorStyle::default()
16982                                            },
16983                                        ))
16984                                        .into_any_element()
16985                                }
16986                            }),
16987                            priority: 0,
16988                        }],
16989                        Some(Autoscroll::fit()),
16990                        cx,
16991                    )[0];
16992                    this.pending_rename = Some(RenameState {
16993                        range,
16994                        old_name,
16995                        editor: rename_editor,
16996                        block_id,
16997                    });
16998                })?;
16999            }
17000
17001            Ok(())
17002        }))
17003    }
17004
17005    pub fn confirm_rename(
17006        &mut self,
17007        _: &ConfirmRename,
17008        window: &mut Window,
17009        cx: &mut Context<Self>,
17010    ) -> Option<Task<Result<()>>> {
17011        let rename = self.take_rename(false, window, cx)?;
17012        let workspace = self.workspace()?.downgrade();
17013        let (buffer, start) = self
17014            .buffer
17015            .read(cx)
17016            .text_anchor_for_position(rename.range.start, cx)?;
17017        let (end_buffer, _) = self
17018            .buffer
17019            .read(cx)
17020            .text_anchor_for_position(rename.range.end, cx)?;
17021        if buffer != end_buffer {
17022            return None;
17023        }
17024
17025        let old_name = rename.old_name;
17026        let new_name = rename.editor.read(cx).text(cx);
17027
17028        let rename = self.semantics_provider.as_ref()?.perform_rename(
17029            &buffer,
17030            start,
17031            new_name.clone(),
17032            cx,
17033        )?;
17034
17035        Some(cx.spawn_in(window, async move |editor, cx| {
17036            let project_transaction = rename.await?;
17037            Self::open_project_transaction(
17038                &editor,
17039                workspace,
17040                project_transaction,
17041                format!("Rename: {}{}", old_name, new_name),
17042                cx,
17043            )
17044            .await?;
17045
17046            editor.update(cx, |editor, cx| {
17047                editor.refresh_document_highlights(cx);
17048            })?;
17049            Ok(())
17050        }))
17051    }
17052
17053    fn take_rename(
17054        &mut self,
17055        moving_cursor: bool,
17056        window: &mut Window,
17057        cx: &mut Context<Self>,
17058    ) -> Option<RenameState> {
17059        let rename = self.pending_rename.take()?;
17060        if rename.editor.focus_handle(cx).is_focused(window) {
17061            window.focus(&self.focus_handle);
17062        }
17063
17064        self.remove_blocks(
17065            [rename.block_id].into_iter().collect(),
17066            Some(Autoscroll::fit()),
17067            cx,
17068        );
17069        self.clear_highlights::<Rename>(cx);
17070        self.show_local_selections = true;
17071
17072        if moving_cursor {
17073            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17074                editor.selections.newest::<usize>(cx).head()
17075            });
17076
17077            // Update the selection to match the position of the selection inside
17078            // the rename editor.
17079            let snapshot = self.buffer.read(cx).read(cx);
17080            let rename_range = rename.range.to_offset(&snapshot);
17081            let cursor_in_editor = snapshot
17082                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17083                .min(rename_range.end);
17084            drop(snapshot);
17085
17086            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17087                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17088            });
17089        } else {
17090            self.refresh_document_highlights(cx);
17091        }
17092
17093        Some(rename)
17094    }
17095
17096    pub fn pending_rename(&self) -> Option<&RenameState> {
17097        self.pending_rename.as_ref()
17098    }
17099
17100    fn format(
17101        &mut self,
17102        _: &Format,
17103        window: &mut Window,
17104        cx: &mut Context<Self>,
17105    ) -> Option<Task<Result<()>>> {
17106        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17107
17108        let project = match &self.project {
17109            Some(project) => project.clone(),
17110            None => return None,
17111        };
17112
17113        Some(self.perform_format(
17114            project,
17115            FormatTrigger::Manual,
17116            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17117            window,
17118            cx,
17119        ))
17120    }
17121
17122    fn format_selections(
17123        &mut self,
17124        _: &FormatSelections,
17125        window: &mut Window,
17126        cx: &mut Context<Self>,
17127    ) -> Option<Task<Result<()>>> {
17128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17129
17130        let project = match &self.project {
17131            Some(project) => project.clone(),
17132            None => return None,
17133        };
17134
17135        let ranges = self
17136            .selections
17137            .all_adjusted(cx)
17138            .into_iter()
17139            .map(|selection| selection.range())
17140            .collect_vec();
17141
17142        Some(self.perform_format(
17143            project,
17144            FormatTrigger::Manual,
17145            FormatTarget::Ranges(ranges),
17146            window,
17147            cx,
17148        ))
17149    }
17150
17151    fn perform_format(
17152        &mut self,
17153        project: Entity<Project>,
17154        trigger: FormatTrigger,
17155        target: FormatTarget,
17156        window: &mut Window,
17157        cx: &mut Context<Self>,
17158    ) -> Task<Result<()>> {
17159        let buffer = self.buffer.clone();
17160        let (buffers, target) = match target {
17161            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17162            FormatTarget::Ranges(selection_ranges) => {
17163                let multi_buffer = buffer.read(cx);
17164                let snapshot = multi_buffer.read(cx);
17165                let mut buffers = HashSet::default();
17166                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17167                    BTreeMap::new();
17168                for selection_range in selection_ranges {
17169                    for (buffer, buffer_range, _) in
17170                        snapshot.range_to_buffer_ranges(selection_range)
17171                    {
17172                        let buffer_id = buffer.remote_id();
17173                        let start = buffer.anchor_before(buffer_range.start);
17174                        let end = buffer.anchor_after(buffer_range.end);
17175                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17176                        buffer_id_to_ranges
17177                            .entry(buffer_id)
17178                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17179                            .or_insert_with(|| vec![start..end]);
17180                    }
17181                }
17182                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17183            }
17184        };
17185
17186        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17187        let selections_prev = transaction_id_prev
17188            .and_then(|transaction_id_prev| {
17189                // default to selections as they were after the last edit, if we have them,
17190                // instead of how they are now.
17191                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17192                // will take you back to where you made the last edit, instead of staying where you scrolled
17193                self.selection_history
17194                    .transaction(transaction_id_prev)
17195                    .map(|t| t.0.clone())
17196            })
17197            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17198
17199        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17200        let format = project.update(cx, |project, cx| {
17201            project.format(buffers, target, true, trigger, cx)
17202        });
17203
17204        cx.spawn_in(window, async move |editor, cx| {
17205            let transaction = futures::select_biased! {
17206                transaction = format.log_err().fuse() => transaction,
17207                () = timeout => {
17208                    log::warn!("timed out waiting for formatting");
17209                    None
17210                }
17211            };
17212
17213            buffer
17214                .update(cx, |buffer, cx| {
17215                    if let Some(transaction) = transaction
17216                        && !buffer.is_singleton()
17217                    {
17218                        buffer.push_transaction(&transaction.0, cx);
17219                    }
17220                    cx.notify();
17221                })
17222                .ok();
17223
17224            if let Some(transaction_id_now) =
17225                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17226            {
17227                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17228                if has_new_transaction {
17229                    _ = editor.update(cx, |editor, _| {
17230                        editor
17231                            .selection_history
17232                            .insert_transaction(transaction_id_now, selections_prev);
17233                    });
17234                }
17235            }
17236
17237            Ok(())
17238        })
17239    }
17240
17241    fn organize_imports(
17242        &mut self,
17243        _: &OrganizeImports,
17244        window: &mut Window,
17245        cx: &mut Context<Self>,
17246    ) -> Option<Task<Result<()>>> {
17247        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17248        let project = match &self.project {
17249            Some(project) => project.clone(),
17250            None => return None,
17251        };
17252        Some(self.perform_code_action_kind(
17253            project,
17254            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17255            window,
17256            cx,
17257        ))
17258    }
17259
17260    fn perform_code_action_kind(
17261        &mut self,
17262        project: Entity<Project>,
17263        kind: CodeActionKind,
17264        window: &mut Window,
17265        cx: &mut Context<Self>,
17266    ) -> Task<Result<()>> {
17267        let buffer = self.buffer.clone();
17268        let buffers = buffer.read(cx).all_buffers();
17269        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17270        let apply_action = project.update(cx, |project, cx| {
17271            project.apply_code_action_kind(buffers, kind, true, cx)
17272        });
17273        cx.spawn_in(window, async move |_, cx| {
17274            let transaction = futures::select_biased! {
17275                () = timeout => {
17276                    log::warn!("timed out waiting for executing code action");
17277                    None
17278                }
17279                transaction = apply_action.log_err().fuse() => transaction,
17280            };
17281            buffer
17282                .update(cx, |buffer, cx| {
17283                    // check if we need this
17284                    if let Some(transaction) = transaction
17285                        && !buffer.is_singleton()
17286                    {
17287                        buffer.push_transaction(&transaction.0, cx);
17288                    }
17289                    cx.notify();
17290                })
17291                .ok();
17292            Ok(())
17293        })
17294    }
17295
17296    pub fn restart_language_server(
17297        &mut self,
17298        _: &RestartLanguageServer,
17299        _: &mut Window,
17300        cx: &mut Context<Self>,
17301    ) {
17302        if let Some(project) = self.project.clone() {
17303            self.buffer.update(cx, |multi_buffer, cx| {
17304                project.update(cx, |project, cx| {
17305                    project.restart_language_servers_for_buffers(
17306                        multi_buffer.all_buffers().into_iter().collect(),
17307                        HashSet::default(),
17308                        cx,
17309                    );
17310                });
17311            })
17312        }
17313    }
17314
17315    pub fn stop_language_server(
17316        &mut self,
17317        _: &StopLanguageServer,
17318        _: &mut Window,
17319        cx: &mut Context<Self>,
17320    ) {
17321        if let Some(project) = self.project.clone() {
17322            self.buffer.update(cx, |multi_buffer, cx| {
17323                project.update(cx, |project, cx| {
17324                    project.stop_language_servers_for_buffers(
17325                        multi_buffer.all_buffers().into_iter().collect(),
17326                        HashSet::default(),
17327                        cx,
17328                    );
17329                    cx.emit(project::Event::RefreshInlayHints);
17330                });
17331            });
17332        }
17333    }
17334
17335    fn cancel_language_server_work(
17336        workspace: &mut Workspace,
17337        _: &actions::CancelLanguageServerWork,
17338        _: &mut Window,
17339        cx: &mut Context<Workspace>,
17340    ) {
17341        let project = workspace.project();
17342        let buffers = workspace
17343            .active_item(cx)
17344            .and_then(|item| item.act_as::<Editor>(cx))
17345            .map_or(HashSet::default(), |editor| {
17346                editor.read(cx).buffer.read(cx).all_buffers()
17347            });
17348        project.update(cx, |project, cx| {
17349            project.cancel_language_server_work_for_buffers(buffers, cx);
17350        });
17351    }
17352
17353    fn show_character_palette(
17354        &mut self,
17355        _: &ShowCharacterPalette,
17356        window: &mut Window,
17357        _: &mut Context<Self>,
17358    ) {
17359        window.show_character_palette();
17360    }
17361
17362    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17363        if !self.diagnostics_enabled() {
17364            return;
17365        }
17366
17367        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17368            let buffer = self.buffer.read(cx).snapshot(cx);
17369            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17370            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17371            let is_valid = buffer
17372                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17373                .any(|entry| {
17374                    entry.diagnostic.is_primary
17375                        && !entry.range.is_empty()
17376                        && entry.range.start == primary_range_start
17377                        && entry.diagnostic.message == active_diagnostics.active_message
17378                });
17379
17380            if !is_valid {
17381                self.dismiss_diagnostics(cx);
17382            }
17383        }
17384    }
17385
17386    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17387        match &self.active_diagnostics {
17388            ActiveDiagnostic::Group(group) => Some(group),
17389            _ => None,
17390        }
17391    }
17392
17393    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17394        if !self.diagnostics_enabled() {
17395            return;
17396        }
17397        self.dismiss_diagnostics(cx);
17398        self.active_diagnostics = ActiveDiagnostic::All;
17399    }
17400
17401    fn activate_diagnostics(
17402        &mut self,
17403        buffer_id: BufferId,
17404        diagnostic: DiagnosticEntry<usize>,
17405        window: &mut Window,
17406        cx: &mut Context<Self>,
17407    ) {
17408        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17409            return;
17410        }
17411        self.dismiss_diagnostics(cx);
17412        let snapshot = self.snapshot(window, cx);
17413        let buffer = self.buffer.read(cx).snapshot(cx);
17414        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17415            return;
17416        };
17417
17418        let diagnostic_group = buffer
17419            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17420            .collect::<Vec<_>>();
17421
17422        let blocks =
17423            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17424
17425        let blocks = self.display_map.update(cx, |display_map, cx| {
17426            display_map.insert_blocks(blocks, cx).into_iter().collect()
17427        });
17428        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17429            active_range: buffer.anchor_before(diagnostic.range.start)
17430                ..buffer.anchor_after(diagnostic.range.end),
17431            active_message: diagnostic.diagnostic.message.clone(),
17432            group_id: diagnostic.diagnostic.group_id,
17433            blocks,
17434        });
17435        cx.notify();
17436    }
17437
17438    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17439        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17440            return;
17441        };
17442
17443        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17444        if let ActiveDiagnostic::Group(group) = prev {
17445            self.display_map.update(cx, |display_map, cx| {
17446                display_map.remove_blocks(group.blocks, cx);
17447            });
17448            cx.notify();
17449        }
17450    }
17451
17452    /// Disable inline diagnostics rendering for this editor.
17453    pub fn disable_inline_diagnostics(&mut self) {
17454        self.inline_diagnostics_enabled = false;
17455        self.inline_diagnostics_update = Task::ready(());
17456        self.inline_diagnostics.clear();
17457    }
17458
17459    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17460        self.diagnostics_enabled = false;
17461        self.dismiss_diagnostics(cx);
17462        self.inline_diagnostics_update = Task::ready(());
17463        self.inline_diagnostics.clear();
17464    }
17465
17466    pub fn disable_word_completions(&mut self) {
17467        self.word_completions_enabled = false;
17468    }
17469
17470    pub fn diagnostics_enabled(&self) -> bool {
17471        self.diagnostics_enabled && self.mode.is_full()
17472    }
17473
17474    pub fn inline_diagnostics_enabled(&self) -> bool {
17475        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17476    }
17477
17478    pub fn show_inline_diagnostics(&self) -> bool {
17479        self.show_inline_diagnostics
17480    }
17481
17482    pub fn toggle_inline_diagnostics(
17483        &mut self,
17484        _: &ToggleInlineDiagnostics,
17485        window: &mut Window,
17486        cx: &mut Context<Editor>,
17487    ) {
17488        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17489        self.refresh_inline_diagnostics(false, window, cx);
17490    }
17491
17492    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17493        self.diagnostics_max_severity = severity;
17494        self.display_map.update(cx, |display_map, _| {
17495            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17496        });
17497    }
17498
17499    pub fn toggle_diagnostics(
17500        &mut self,
17501        _: &ToggleDiagnostics,
17502        window: &mut Window,
17503        cx: &mut Context<Editor>,
17504    ) {
17505        if !self.diagnostics_enabled() {
17506            return;
17507        }
17508
17509        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17510            EditorSettings::get_global(cx)
17511                .diagnostics_max_severity
17512                .filter(|severity| severity != &DiagnosticSeverity::Off)
17513                .unwrap_or(DiagnosticSeverity::Hint)
17514        } else {
17515            DiagnosticSeverity::Off
17516        };
17517        self.set_max_diagnostics_severity(new_severity, cx);
17518        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17519            self.active_diagnostics = ActiveDiagnostic::None;
17520            self.inline_diagnostics_update = Task::ready(());
17521            self.inline_diagnostics.clear();
17522        } else {
17523            self.refresh_inline_diagnostics(false, window, cx);
17524        }
17525
17526        cx.notify();
17527    }
17528
17529    pub fn toggle_minimap(
17530        &mut self,
17531        _: &ToggleMinimap,
17532        window: &mut Window,
17533        cx: &mut Context<Editor>,
17534    ) {
17535        if self.supports_minimap(cx) {
17536            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17537        }
17538    }
17539
17540    fn refresh_inline_diagnostics(
17541        &mut self,
17542        debounce: bool,
17543        window: &mut Window,
17544        cx: &mut Context<Self>,
17545    ) {
17546        let max_severity = ProjectSettings::get_global(cx)
17547            .diagnostics
17548            .inline
17549            .max_severity
17550            .unwrap_or(self.diagnostics_max_severity);
17551
17552        if !self.inline_diagnostics_enabled()
17553            || !self.show_inline_diagnostics
17554            || max_severity == DiagnosticSeverity::Off
17555        {
17556            self.inline_diagnostics_update = Task::ready(());
17557            self.inline_diagnostics.clear();
17558            return;
17559        }
17560
17561        let debounce_ms = ProjectSettings::get_global(cx)
17562            .diagnostics
17563            .inline
17564            .update_debounce_ms;
17565        let debounce = if debounce && debounce_ms > 0 {
17566            Some(Duration::from_millis(debounce_ms))
17567        } else {
17568            None
17569        };
17570        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17571            if let Some(debounce) = debounce {
17572                cx.background_executor().timer(debounce).await;
17573            }
17574            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17575                editor
17576                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17577                    .ok()
17578            }) else {
17579                return;
17580            };
17581
17582            let new_inline_diagnostics = cx
17583                .background_spawn(async move {
17584                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17585                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17586                        let message = diagnostic_entry
17587                            .diagnostic
17588                            .message
17589                            .split_once('\n')
17590                            .map(|(line, _)| line)
17591                            .map(SharedString::new)
17592                            .unwrap_or_else(|| {
17593                                SharedString::from(diagnostic_entry.diagnostic.message)
17594                            });
17595                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17596                        let (Ok(i) | Err(i)) = inline_diagnostics
17597                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17598                        inline_diagnostics.insert(
17599                            i,
17600                            (
17601                                start_anchor,
17602                                InlineDiagnostic {
17603                                    message,
17604                                    group_id: diagnostic_entry.diagnostic.group_id,
17605                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17606                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17607                                    severity: diagnostic_entry.diagnostic.severity,
17608                                },
17609                            ),
17610                        );
17611                    }
17612                    inline_diagnostics
17613                })
17614                .await;
17615
17616            editor
17617                .update(cx, |editor, cx| {
17618                    editor.inline_diagnostics = new_inline_diagnostics;
17619                    cx.notify();
17620                })
17621                .ok();
17622        });
17623    }
17624
17625    fn pull_diagnostics(
17626        &mut self,
17627        buffer_id: Option<BufferId>,
17628        window: &Window,
17629        cx: &mut Context<Self>,
17630    ) -> Option<()> {
17631        if !self.mode().is_full() {
17632            return None;
17633        }
17634        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17635            .diagnostics
17636            .lsp_pull_diagnostics;
17637        if !pull_diagnostics_settings.enabled {
17638            return None;
17639        }
17640        let project = self.project()?.downgrade();
17641        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17642        let mut buffers = self.buffer.read(cx).all_buffers();
17643        if let Some(buffer_id) = buffer_id {
17644            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17645        }
17646
17647        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17648            cx.background_executor().timer(debounce).await;
17649
17650            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17651                buffers
17652                    .into_iter()
17653                    .filter_map(|buffer| {
17654                        project
17655                            .update(cx, |project, cx| {
17656                                project.lsp_store().update(cx, |lsp_store, cx| {
17657                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17658                                })
17659                            })
17660                            .ok()
17661                    })
17662                    .collect::<FuturesUnordered<_>>()
17663            }) else {
17664                return;
17665            };
17666
17667            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17668                match pull_task {
17669                    Ok(()) => {
17670                        if editor
17671                            .update_in(cx, |editor, window, cx| {
17672                                editor.update_diagnostics_state(window, cx);
17673                            })
17674                            .is_err()
17675                        {
17676                            return;
17677                        }
17678                    }
17679                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17680                }
17681            }
17682        });
17683
17684        Some(())
17685    }
17686
17687    pub fn set_selections_from_remote(
17688        &mut self,
17689        selections: Vec<Selection<Anchor>>,
17690        pending_selection: Option<Selection<Anchor>>,
17691        window: &mut Window,
17692        cx: &mut Context<Self>,
17693    ) {
17694        let old_cursor_position = self.selections.newest_anchor().head();
17695        self.selections.change_with(cx, |s| {
17696            s.select_anchors(selections);
17697            if let Some(pending_selection) = pending_selection {
17698                s.set_pending(pending_selection, SelectMode::Character);
17699            } else {
17700                s.clear_pending();
17701            }
17702        });
17703        self.selections_did_change(
17704            false,
17705            &old_cursor_position,
17706            SelectionEffects::default(),
17707            window,
17708            cx,
17709        );
17710    }
17711
17712    pub fn transact(
17713        &mut self,
17714        window: &mut Window,
17715        cx: &mut Context<Self>,
17716        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17717    ) -> Option<TransactionId> {
17718        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17719            this.start_transaction_at(Instant::now(), window, cx);
17720            update(this, window, cx);
17721            this.end_transaction_at(Instant::now(), cx)
17722        })
17723    }
17724
17725    pub fn start_transaction_at(
17726        &mut self,
17727        now: Instant,
17728        window: &mut Window,
17729        cx: &mut Context<Self>,
17730    ) -> Option<TransactionId> {
17731        self.end_selection(window, cx);
17732        if let Some(tx_id) = self
17733            .buffer
17734            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17735        {
17736            self.selection_history
17737                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17738            cx.emit(EditorEvent::TransactionBegun {
17739                transaction_id: tx_id,
17740            });
17741            Some(tx_id)
17742        } else {
17743            None
17744        }
17745    }
17746
17747    pub fn end_transaction_at(
17748        &mut self,
17749        now: Instant,
17750        cx: &mut Context<Self>,
17751    ) -> Option<TransactionId> {
17752        if let Some(transaction_id) = self
17753            .buffer
17754            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17755        {
17756            if let Some((_, end_selections)) =
17757                self.selection_history.transaction_mut(transaction_id)
17758            {
17759                *end_selections = Some(self.selections.disjoint_anchors_arc());
17760            } else {
17761                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17762            }
17763
17764            cx.emit(EditorEvent::Edited { transaction_id });
17765            Some(transaction_id)
17766        } else {
17767            None
17768        }
17769    }
17770
17771    pub fn modify_transaction_selection_history(
17772        &mut self,
17773        transaction_id: TransactionId,
17774        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17775    ) -> bool {
17776        self.selection_history
17777            .transaction_mut(transaction_id)
17778            .map(modify)
17779            .is_some()
17780    }
17781
17782    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17783        if self.selection_mark_mode {
17784            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17785                s.move_with(|_, sel| {
17786                    sel.collapse_to(sel.head(), SelectionGoal::None);
17787                });
17788            })
17789        }
17790        self.selection_mark_mode = true;
17791        cx.notify();
17792    }
17793
17794    pub fn swap_selection_ends(
17795        &mut self,
17796        _: &actions::SwapSelectionEnds,
17797        window: &mut Window,
17798        cx: &mut Context<Self>,
17799    ) {
17800        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17801            s.move_with(|_, sel| {
17802                if sel.start != sel.end {
17803                    sel.reversed = !sel.reversed
17804                }
17805            });
17806        });
17807        self.request_autoscroll(Autoscroll::newest(), cx);
17808        cx.notify();
17809    }
17810
17811    pub fn toggle_focus(
17812        workspace: &mut Workspace,
17813        _: &actions::ToggleFocus,
17814        window: &mut Window,
17815        cx: &mut Context<Workspace>,
17816    ) {
17817        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17818            return;
17819        };
17820        workspace.activate_item(&item, true, true, window, cx);
17821    }
17822
17823    pub fn toggle_fold(
17824        &mut self,
17825        _: &actions::ToggleFold,
17826        window: &mut Window,
17827        cx: &mut Context<Self>,
17828    ) {
17829        if self.is_singleton(cx) {
17830            let selection = self.selections.newest::<Point>(cx);
17831
17832            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17833            let range = if selection.is_empty() {
17834                let point = selection.head().to_display_point(&display_map);
17835                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17836                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17837                    .to_point(&display_map);
17838                start..end
17839            } else {
17840                selection.range()
17841            };
17842            if display_map.folds_in_range(range).next().is_some() {
17843                self.unfold_lines(&Default::default(), window, cx)
17844            } else {
17845                self.fold(&Default::default(), window, cx)
17846            }
17847        } else {
17848            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17849            let buffer_ids: HashSet<_> = self
17850                .selections
17851                .disjoint_anchor_ranges()
17852                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17853                .collect();
17854
17855            let should_unfold = buffer_ids
17856                .iter()
17857                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17858
17859            for buffer_id in buffer_ids {
17860                if should_unfold {
17861                    self.unfold_buffer(buffer_id, cx);
17862                } else {
17863                    self.fold_buffer(buffer_id, cx);
17864                }
17865            }
17866        }
17867    }
17868
17869    pub fn toggle_fold_recursive(
17870        &mut self,
17871        _: &actions::ToggleFoldRecursive,
17872        window: &mut Window,
17873        cx: &mut Context<Self>,
17874    ) {
17875        let selection = self.selections.newest::<Point>(cx);
17876
17877        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17878        let range = if selection.is_empty() {
17879            let point = selection.head().to_display_point(&display_map);
17880            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17881            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17882                .to_point(&display_map);
17883            start..end
17884        } else {
17885            selection.range()
17886        };
17887        if display_map.folds_in_range(range).next().is_some() {
17888            self.unfold_recursive(&Default::default(), window, cx)
17889        } else {
17890            self.fold_recursive(&Default::default(), window, cx)
17891        }
17892    }
17893
17894    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17895        if self.is_singleton(cx) {
17896            let mut to_fold = Vec::new();
17897            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17898            let selections = self.selections.all_adjusted(cx);
17899
17900            for selection in selections {
17901                let range = selection.range().sorted();
17902                let buffer_start_row = range.start.row;
17903
17904                if range.start.row != range.end.row {
17905                    let mut found = false;
17906                    let mut row = range.start.row;
17907                    while row <= range.end.row {
17908                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17909                        {
17910                            found = true;
17911                            row = crease.range().end.row + 1;
17912                            to_fold.push(crease);
17913                        } else {
17914                            row += 1
17915                        }
17916                    }
17917                    if found {
17918                        continue;
17919                    }
17920                }
17921
17922                for row in (0..=range.start.row).rev() {
17923                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17924                        && crease.range().end.row >= buffer_start_row
17925                    {
17926                        to_fold.push(crease);
17927                        if row <= range.start.row {
17928                            break;
17929                        }
17930                    }
17931                }
17932            }
17933
17934            self.fold_creases(to_fold, true, window, cx);
17935        } else {
17936            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17937            let buffer_ids = self
17938                .selections
17939                .disjoint_anchor_ranges()
17940                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17941                .collect::<HashSet<_>>();
17942            for buffer_id in buffer_ids {
17943                self.fold_buffer(buffer_id, cx);
17944            }
17945        }
17946    }
17947
17948    pub fn toggle_fold_all(
17949        &mut self,
17950        _: &actions::ToggleFoldAll,
17951        window: &mut Window,
17952        cx: &mut Context<Self>,
17953    ) {
17954        if self.buffer.read(cx).is_singleton() {
17955            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17956            let has_folds = display_map
17957                .folds_in_range(0..display_map.buffer_snapshot.len())
17958                .next()
17959                .is_some();
17960
17961            if has_folds {
17962                self.unfold_all(&actions::UnfoldAll, window, cx);
17963            } else {
17964                self.fold_all(&actions::FoldAll, window, cx);
17965            }
17966        } else {
17967            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17968            let should_unfold = buffer_ids
17969                .iter()
17970                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17971
17972            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17973                editor
17974                    .update_in(cx, |editor, _, cx| {
17975                        for buffer_id in buffer_ids {
17976                            if should_unfold {
17977                                editor.unfold_buffer(buffer_id, cx);
17978                            } else {
17979                                editor.fold_buffer(buffer_id, cx);
17980                            }
17981                        }
17982                    })
17983                    .ok();
17984            });
17985        }
17986    }
17987
17988    fn fold_at_level(
17989        &mut self,
17990        fold_at: &FoldAtLevel,
17991        window: &mut Window,
17992        cx: &mut Context<Self>,
17993    ) {
17994        if !self.buffer.read(cx).is_singleton() {
17995            return;
17996        }
17997
17998        let fold_at_level = fold_at.0;
17999        let snapshot = self.buffer.read(cx).snapshot(cx);
18000        let mut to_fold = Vec::new();
18001        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18002
18003        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18004            while start_row < end_row {
18005                match self
18006                    .snapshot(window, cx)
18007                    .crease_for_buffer_row(MultiBufferRow(start_row))
18008                {
18009                    Some(crease) => {
18010                        let nested_start_row = crease.range().start.row + 1;
18011                        let nested_end_row = crease.range().end.row;
18012
18013                        if current_level < fold_at_level {
18014                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18015                        } else if current_level == fold_at_level {
18016                            to_fold.push(crease);
18017                        }
18018
18019                        start_row = nested_end_row + 1;
18020                    }
18021                    None => start_row += 1,
18022                }
18023            }
18024        }
18025
18026        self.fold_creases(to_fold, true, window, cx);
18027    }
18028
18029    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18030        if self.buffer.read(cx).is_singleton() {
18031            let mut fold_ranges = Vec::new();
18032            let snapshot = self.buffer.read(cx).snapshot(cx);
18033
18034            for row in 0..snapshot.max_row().0 {
18035                if let Some(foldable_range) = self
18036                    .snapshot(window, cx)
18037                    .crease_for_buffer_row(MultiBufferRow(row))
18038                {
18039                    fold_ranges.push(foldable_range);
18040                }
18041            }
18042
18043            self.fold_creases(fold_ranges, true, window, cx);
18044        } else {
18045            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18046                editor
18047                    .update_in(cx, |editor, _, cx| {
18048                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18049                            editor.fold_buffer(buffer_id, cx);
18050                        }
18051                    })
18052                    .ok();
18053            });
18054        }
18055    }
18056
18057    pub fn fold_function_bodies(
18058        &mut self,
18059        _: &actions::FoldFunctionBodies,
18060        window: &mut Window,
18061        cx: &mut Context<Self>,
18062    ) {
18063        let snapshot = self.buffer.read(cx).snapshot(cx);
18064
18065        let ranges = snapshot
18066            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18067            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18068            .collect::<Vec<_>>();
18069
18070        let creases = ranges
18071            .into_iter()
18072            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18073            .collect();
18074
18075        self.fold_creases(creases, true, window, cx);
18076    }
18077
18078    pub fn fold_recursive(
18079        &mut self,
18080        _: &actions::FoldRecursive,
18081        window: &mut Window,
18082        cx: &mut Context<Self>,
18083    ) {
18084        let mut to_fold = Vec::new();
18085        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18086        let selections = self.selections.all_adjusted(cx);
18087
18088        for selection in selections {
18089            let range = selection.range().sorted();
18090            let buffer_start_row = range.start.row;
18091
18092            if range.start.row != range.end.row {
18093                let mut found = false;
18094                for row in range.start.row..=range.end.row {
18095                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18096                        found = true;
18097                        to_fold.push(crease);
18098                    }
18099                }
18100                if found {
18101                    continue;
18102                }
18103            }
18104
18105            for row in (0..=range.start.row).rev() {
18106                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18107                    if crease.range().end.row >= buffer_start_row {
18108                        to_fold.push(crease);
18109                    } else {
18110                        break;
18111                    }
18112                }
18113            }
18114        }
18115
18116        self.fold_creases(to_fold, true, window, cx);
18117    }
18118
18119    pub fn fold_at(
18120        &mut self,
18121        buffer_row: MultiBufferRow,
18122        window: &mut Window,
18123        cx: &mut Context<Self>,
18124    ) {
18125        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18126
18127        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18128            let autoscroll = self
18129                .selections
18130                .all::<Point>(cx)
18131                .iter()
18132                .any(|selection| crease.range().overlaps(&selection.range()));
18133
18134            self.fold_creases(vec![crease], autoscroll, window, cx);
18135        }
18136    }
18137
18138    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18139        if self.is_singleton(cx) {
18140            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18141            let buffer = &display_map.buffer_snapshot;
18142            let selections = self.selections.all::<Point>(cx);
18143            let ranges = selections
18144                .iter()
18145                .map(|s| {
18146                    let range = s.display_range(&display_map).sorted();
18147                    let mut start = range.start.to_point(&display_map);
18148                    let mut end = range.end.to_point(&display_map);
18149                    start.column = 0;
18150                    end.column = buffer.line_len(MultiBufferRow(end.row));
18151                    start..end
18152                })
18153                .collect::<Vec<_>>();
18154
18155            self.unfold_ranges(&ranges, true, true, cx);
18156        } else {
18157            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18158            let buffer_ids = self
18159                .selections
18160                .disjoint_anchor_ranges()
18161                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18162                .collect::<HashSet<_>>();
18163            for buffer_id in buffer_ids {
18164                self.unfold_buffer(buffer_id, cx);
18165            }
18166        }
18167    }
18168
18169    pub fn unfold_recursive(
18170        &mut self,
18171        _: &UnfoldRecursive,
18172        _window: &mut Window,
18173        cx: &mut Context<Self>,
18174    ) {
18175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18176        let selections = self.selections.all::<Point>(cx);
18177        let ranges = selections
18178            .iter()
18179            .map(|s| {
18180                let mut range = s.display_range(&display_map).sorted();
18181                *range.start.column_mut() = 0;
18182                *range.end.column_mut() = display_map.line_len(range.end.row());
18183                let start = range.start.to_point(&display_map);
18184                let end = range.end.to_point(&display_map);
18185                start..end
18186            })
18187            .collect::<Vec<_>>();
18188
18189        self.unfold_ranges(&ranges, true, true, cx);
18190    }
18191
18192    pub fn unfold_at(
18193        &mut self,
18194        buffer_row: MultiBufferRow,
18195        _window: &mut Window,
18196        cx: &mut Context<Self>,
18197    ) {
18198        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18199
18200        let intersection_range = Point::new(buffer_row.0, 0)
18201            ..Point::new(
18202                buffer_row.0,
18203                display_map.buffer_snapshot.line_len(buffer_row),
18204            );
18205
18206        let autoscroll = self
18207            .selections
18208            .all::<Point>(cx)
18209            .iter()
18210            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18211
18212        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18213    }
18214
18215    pub fn unfold_all(
18216        &mut self,
18217        _: &actions::UnfoldAll,
18218        _window: &mut Window,
18219        cx: &mut Context<Self>,
18220    ) {
18221        if self.buffer.read(cx).is_singleton() {
18222            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18223            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18224        } else {
18225            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18226                editor
18227                    .update(cx, |editor, cx| {
18228                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18229                            editor.unfold_buffer(buffer_id, cx);
18230                        }
18231                    })
18232                    .ok();
18233            });
18234        }
18235    }
18236
18237    pub fn fold_selected_ranges(
18238        &mut self,
18239        _: &FoldSelectedRanges,
18240        window: &mut Window,
18241        cx: &mut Context<Self>,
18242    ) {
18243        let selections = self.selections.all_adjusted(cx);
18244        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18245        let ranges = selections
18246            .into_iter()
18247            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18248            .collect::<Vec<_>>();
18249        self.fold_creases(ranges, true, window, cx);
18250    }
18251
18252    pub fn fold_ranges<T: ToOffset + Clone>(
18253        &mut self,
18254        ranges: Vec<Range<T>>,
18255        auto_scroll: bool,
18256        window: &mut Window,
18257        cx: &mut Context<Self>,
18258    ) {
18259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18260        let ranges = ranges
18261            .into_iter()
18262            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18263            .collect::<Vec<_>>();
18264        self.fold_creases(ranges, auto_scroll, window, cx);
18265    }
18266
18267    pub fn fold_creases<T: ToOffset + Clone>(
18268        &mut self,
18269        creases: Vec<Crease<T>>,
18270        auto_scroll: bool,
18271        _window: &mut Window,
18272        cx: &mut Context<Self>,
18273    ) {
18274        if creases.is_empty() {
18275            return;
18276        }
18277
18278        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18279
18280        if auto_scroll {
18281            self.request_autoscroll(Autoscroll::fit(), cx);
18282        }
18283
18284        cx.notify();
18285
18286        self.scrollbar_marker_state.dirty = true;
18287        self.folds_did_change(cx);
18288    }
18289
18290    /// Removes any folds whose ranges intersect any of the given ranges.
18291    pub fn unfold_ranges<T: ToOffset + Clone>(
18292        &mut self,
18293        ranges: &[Range<T>],
18294        inclusive: bool,
18295        auto_scroll: bool,
18296        cx: &mut Context<Self>,
18297    ) {
18298        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18299            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18300        });
18301        self.folds_did_change(cx);
18302    }
18303
18304    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18305        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18306            return;
18307        }
18308        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18309        self.display_map.update(cx, |display_map, cx| {
18310            display_map.fold_buffers([buffer_id], cx)
18311        });
18312        cx.emit(EditorEvent::BufferFoldToggled {
18313            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18314            folded: true,
18315        });
18316        cx.notify();
18317    }
18318
18319    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18320        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18321            return;
18322        }
18323        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18324        self.display_map.update(cx, |display_map, cx| {
18325            display_map.unfold_buffers([buffer_id], cx);
18326        });
18327        cx.emit(EditorEvent::BufferFoldToggled {
18328            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18329            folded: false,
18330        });
18331        cx.notify();
18332    }
18333
18334    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18335        self.display_map.read(cx).is_buffer_folded(buffer)
18336    }
18337
18338    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18339        self.display_map.read(cx).folded_buffers()
18340    }
18341
18342    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18343        self.display_map.update(cx, |display_map, cx| {
18344            display_map.disable_header_for_buffer(buffer_id, cx);
18345        });
18346        cx.notify();
18347    }
18348
18349    /// Removes any folds with the given ranges.
18350    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18351        &mut self,
18352        ranges: &[Range<T>],
18353        type_id: TypeId,
18354        auto_scroll: bool,
18355        cx: &mut Context<Self>,
18356    ) {
18357        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18358            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18359        });
18360        self.folds_did_change(cx);
18361    }
18362
18363    fn remove_folds_with<T: ToOffset + Clone>(
18364        &mut self,
18365        ranges: &[Range<T>],
18366        auto_scroll: bool,
18367        cx: &mut Context<Self>,
18368        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18369    ) {
18370        if ranges.is_empty() {
18371            return;
18372        }
18373
18374        let mut buffers_affected = HashSet::default();
18375        let multi_buffer = self.buffer().read(cx);
18376        for range in ranges {
18377            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18378                buffers_affected.insert(buffer.read(cx).remote_id());
18379            };
18380        }
18381
18382        self.display_map.update(cx, update);
18383
18384        if auto_scroll {
18385            self.request_autoscroll(Autoscroll::fit(), cx);
18386        }
18387
18388        cx.notify();
18389        self.scrollbar_marker_state.dirty = true;
18390        self.active_indent_guides_state.dirty = true;
18391    }
18392
18393    pub fn update_renderer_widths(
18394        &mut self,
18395        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18396        cx: &mut Context<Self>,
18397    ) -> bool {
18398        self.display_map
18399            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18400    }
18401
18402    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18403        self.display_map.read(cx).fold_placeholder.clone()
18404    }
18405
18406    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18407        self.buffer.update(cx, |buffer, cx| {
18408            buffer.set_all_diff_hunks_expanded(cx);
18409        });
18410    }
18411
18412    pub fn expand_all_diff_hunks(
18413        &mut self,
18414        _: &ExpandAllDiffHunks,
18415        _window: &mut Window,
18416        cx: &mut Context<Self>,
18417    ) {
18418        self.buffer.update(cx, |buffer, cx| {
18419            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18420        });
18421    }
18422
18423    pub fn toggle_selected_diff_hunks(
18424        &mut self,
18425        _: &ToggleSelectedDiffHunks,
18426        _window: &mut Window,
18427        cx: &mut Context<Self>,
18428    ) {
18429        let ranges: Vec<_> = self
18430            .selections
18431            .disjoint_anchors()
18432            .iter()
18433            .map(|s| s.range())
18434            .collect();
18435        self.toggle_diff_hunks_in_ranges(ranges, cx);
18436    }
18437
18438    pub fn diff_hunks_in_ranges<'a>(
18439        &'a self,
18440        ranges: &'a [Range<Anchor>],
18441        buffer: &'a MultiBufferSnapshot,
18442    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18443        ranges.iter().flat_map(move |range| {
18444            let end_excerpt_id = range.end.excerpt_id;
18445            let range = range.to_point(buffer);
18446            let mut peek_end = range.end;
18447            if range.end.row < buffer.max_row().0 {
18448                peek_end = Point::new(range.end.row + 1, 0);
18449            }
18450            buffer
18451                .diff_hunks_in_range(range.start..peek_end)
18452                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18453        })
18454    }
18455
18456    pub fn has_stageable_diff_hunks_in_ranges(
18457        &self,
18458        ranges: &[Range<Anchor>],
18459        snapshot: &MultiBufferSnapshot,
18460    ) -> bool {
18461        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18462        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18463    }
18464
18465    pub fn toggle_staged_selected_diff_hunks(
18466        &mut self,
18467        _: &::git::ToggleStaged,
18468        _: &mut Window,
18469        cx: &mut Context<Self>,
18470    ) {
18471        let snapshot = self.buffer.read(cx).snapshot(cx);
18472        let ranges: Vec<_> = self
18473            .selections
18474            .disjoint_anchors()
18475            .iter()
18476            .map(|s| s.range())
18477            .collect();
18478        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18479        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18480    }
18481
18482    pub fn set_render_diff_hunk_controls(
18483        &mut self,
18484        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18485        cx: &mut Context<Self>,
18486    ) {
18487        self.render_diff_hunk_controls = render_diff_hunk_controls;
18488        cx.notify();
18489    }
18490
18491    pub fn stage_and_next(
18492        &mut self,
18493        _: &::git::StageAndNext,
18494        window: &mut Window,
18495        cx: &mut Context<Self>,
18496    ) {
18497        self.do_stage_or_unstage_and_next(true, window, cx);
18498    }
18499
18500    pub fn unstage_and_next(
18501        &mut self,
18502        _: &::git::UnstageAndNext,
18503        window: &mut Window,
18504        cx: &mut Context<Self>,
18505    ) {
18506        self.do_stage_or_unstage_and_next(false, window, cx);
18507    }
18508
18509    pub fn stage_or_unstage_diff_hunks(
18510        &mut self,
18511        stage: bool,
18512        ranges: Vec<Range<Anchor>>,
18513        cx: &mut Context<Self>,
18514    ) {
18515        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18516        cx.spawn(async move |this, cx| {
18517            task.await?;
18518            this.update(cx, |this, cx| {
18519                let snapshot = this.buffer.read(cx).snapshot(cx);
18520                let chunk_by = this
18521                    .diff_hunks_in_ranges(&ranges, &snapshot)
18522                    .chunk_by(|hunk| hunk.buffer_id);
18523                for (buffer_id, hunks) in &chunk_by {
18524                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18525                }
18526            })
18527        })
18528        .detach_and_log_err(cx);
18529    }
18530
18531    fn save_buffers_for_ranges_if_needed(
18532        &mut self,
18533        ranges: &[Range<Anchor>],
18534        cx: &mut Context<Editor>,
18535    ) -> Task<Result<()>> {
18536        let multibuffer = self.buffer.read(cx);
18537        let snapshot = multibuffer.read(cx);
18538        let buffer_ids: HashSet<_> = ranges
18539            .iter()
18540            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18541            .collect();
18542        drop(snapshot);
18543
18544        let mut buffers = HashSet::default();
18545        for buffer_id in buffer_ids {
18546            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18547                let buffer = buffer_entity.read(cx);
18548                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18549                {
18550                    buffers.insert(buffer_entity);
18551                }
18552            }
18553        }
18554
18555        if let Some(project) = &self.project {
18556            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18557        } else {
18558            Task::ready(Ok(()))
18559        }
18560    }
18561
18562    fn do_stage_or_unstage_and_next(
18563        &mut self,
18564        stage: bool,
18565        window: &mut Window,
18566        cx: &mut Context<Self>,
18567    ) {
18568        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18569
18570        if ranges.iter().any(|range| range.start != range.end) {
18571            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18572            return;
18573        }
18574
18575        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18576        let snapshot = self.snapshot(window, cx);
18577        let position = self.selections.newest::<Point>(cx).head();
18578        let mut row = snapshot
18579            .buffer_snapshot
18580            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18581            .find(|hunk| hunk.row_range.start.0 > position.row)
18582            .map(|hunk| hunk.row_range.start);
18583
18584        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18585        // Outside of the project diff editor, wrap around to the beginning.
18586        if !all_diff_hunks_expanded {
18587            row = row.or_else(|| {
18588                snapshot
18589                    .buffer_snapshot
18590                    .diff_hunks_in_range(Point::zero()..position)
18591                    .find(|hunk| hunk.row_range.end.0 < position.row)
18592                    .map(|hunk| hunk.row_range.start)
18593            });
18594        }
18595
18596        if let Some(row) = row {
18597            let destination = Point::new(row.0, 0);
18598            let autoscroll = Autoscroll::center();
18599
18600            self.unfold_ranges(&[destination..destination], false, false, cx);
18601            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18602                s.select_ranges([destination..destination]);
18603            });
18604        }
18605    }
18606
18607    fn do_stage_or_unstage(
18608        &self,
18609        stage: bool,
18610        buffer_id: BufferId,
18611        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18612        cx: &mut App,
18613    ) -> Option<()> {
18614        let project = self.project()?;
18615        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18616        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18617        let buffer_snapshot = buffer.read(cx).snapshot();
18618        let file_exists = buffer_snapshot
18619            .file()
18620            .is_some_and(|file| file.disk_state().exists());
18621        diff.update(cx, |diff, cx| {
18622            diff.stage_or_unstage_hunks(
18623                stage,
18624                &hunks
18625                    .map(|hunk| buffer_diff::DiffHunk {
18626                        buffer_range: hunk.buffer_range,
18627                        diff_base_byte_range: hunk.diff_base_byte_range,
18628                        secondary_status: hunk.secondary_status,
18629                        range: Point::zero()..Point::zero(), // unused
18630                    })
18631                    .collect::<Vec<_>>(),
18632                &buffer_snapshot,
18633                file_exists,
18634                cx,
18635            )
18636        });
18637        None
18638    }
18639
18640    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18641        let ranges: Vec<_> = self
18642            .selections
18643            .disjoint_anchors()
18644            .iter()
18645            .map(|s| s.range())
18646            .collect();
18647        self.buffer
18648            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18649    }
18650
18651    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18652        self.buffer.update(cx, |buffer, cx| {
18653            let ranges = vec![Anchor::min()..Anchor::max()];
18654            if !buffer.all_diff_hunks_expanded()
18655                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18656            {
18657                buffer.collapse_diff_hunks(ranges, cx);
18658                true
18659            } else {
18660                false
18661            }
18662        })
18663    }
18664
18665    fn toggle_diff_hunks_in_ranges(
18666        &mut self,
18667        ranges: Vec<Range<Anchor>>,
18668        cx: &mut Context<Editor>,
18669    ) {
18670        self.buffer.update(cx, |buffer, cx| {
18671            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18672            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18673        })
18674    }
18675
18676    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18677        self.buffer.update(cx, |buffer, cx| {
18678            let snapshot = buffer.snapshot(cx);
18679            let excerpt_id = range.end.excerpt_id;
18680            let point_range = range.to_point(&snapshot);
18681            let expand = !buffer.single_hunk_is_expanded(range, cx);
18682            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18683        })
18684    }
18685
18686    pub(crate) fn apply_all_diff_hunks(
18687        &mut self,
18688        _: &ApplyAllDiffHunks,
18689        window: &mut Window,
18690        cx: &mut Context<Self>,
18691    ) {
18692        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18693
18694        let buffers = self.buffer.read(cx).all_buffers();
18695        for branch_buffer in buffers {
18696            branch_buffer.update(cx, |branch_buffer, cx| {
18697                branch_buffer.merge_into_base(Vec::new(), cx);
18698            });
18699        }
18700
18701        if let Some(project) = self.project.clone() {
18702            self.save(
18703                SaveOptions {
18704                    format: true,
18705                    autosave: false,
18706                },
18707                project,
18708                window,
18709                cx,
18710            )
18711            .detach_and_log_err(cx);
18712        }
18713    }
18714
18715    pub(crate) fn apply_selected_diff_hunks(
18716        &mut self,
18717        _: &ApplyDiffHunk,
18718        window: &mut Window,
18719        cx: &mut Context<Self>,
18720    ) {
18721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18722        let snapshot = self.snapshot(window, cx);
18723        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18724        let mut ranges_by_buffer = HashMap::default();
18725        self.transact(window, cx, |editor, _window, cx| {
18726            for hunk in hunks {
18727                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18728                    ranges_by_buffer
18729                        .entry(buffer.clone())
18730                        .or_insert_with(Vec::new)
18731                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18732                }
18733            }
18734
18735            for (buffer, ranges) in ranges_by_buffer {
18736                buffer.update(cx, |buffer, cx| {
18737                    buffer.merge_into_base(ranges, cx);
18738                });
18739            }
18740        });
18741
18742        if let Some(project) = self.project.clone() {
18743            self.save(
18744                SaveOptions {
18745                    format: true,
18746                    autosave: false,
18747                },
18748                project,
18749                window,
18750                cx,
18751            )
18752            .detach_and_log_err(cx);
18753        }
18754    }
18755
18756    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18757        if hovered != self.gutter_hovered {
18758            self.gutter_hovered = hovered;
18759            cx.notify();
18760        }
18761    }
18762
18763    pub fn insert_blocks(
18764        &mut self,
18765        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18766        autoscroll: Option<Autoscroll>,
18767        cx: &mut Context<Self>,
18768    ) -> Vec<CustomBlockId> {
18769        let blocks = self
18770            .display_map
18771            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18772        if let Some(autoscroll) = autoscroll {
18773            self.request_autoscroll(autoscroll, cx);
18774        }
18775        cx.notify();
18776        blocks
18777    }
18778
18779    pub fn resize_blocks(
18780        &mut self,
18781        heights: HashMap<CustomBlockId, u32>,
18782        autoscroll: Option<Autoscroll>,
18783        cx: &mut Context<Self>,
18784    ) {
18785        self.display_map
18786            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18787        if let Some(autoscroll) = autoscroll {
18788            self.request_autoscroll(autoscroll, cx);
18789        }
18790        cx.notify();
18791    }
18792
18793    pub fn replace_blocks(
18794        &mut self,
18795        renderers: HashMap<CustomBlockId, RenderBlock>,
18796        autoscroll: Option<Autoscroll>,
18797        cx: &mut Context<Self>,
18798    ) {
18799        self.display_map
18800            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18801        if let Some(autoscroll) = autoscroll {
18802            self.request_autoscroll(autoscroll, cx);
18803        }
18804        cx.notify();
18805    }
18806
18807    pub fn remove_blocks(
18808        &mut self,
18809        block_ids: HashSet<CustomBlockId>,
18810        autoscroll: Option<Autoscroll>,
18811        cx: &mut Context<Self>,
18812    ) {
18813        self.display_map.update(cx, |display_map, cx| {
18814            display_map.remove_blocks(block_ids, cx)
18815        });
18816        if let Some(autoscroll) = autoscroll {
18817            self.request_autoscroll(autoscroll, cx);
18818        }
18819        cx.notify();
18820    }
18821
18822    pub fn row_for_block(
18823        &self,
18824        block_id: CustomBlockId,
18825        cx: &mut Context<Self>,
18826    ) -> Option<DisplayRow> {
18827        self.display_map
18828            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18829    }
18830
18831    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18832        self.focused_block = Some(focused_block);
18833    }
18834
18835    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18836        self.focused_block.take()
18837    }
18838
18839    pub fn insert_creases(
18840        &mut self,
18841        creases: impl IntoIterator<Item = Crease<Anchor>>,
18842        cx: &mut Context<Self>,
18843    ) -> Vec<CreaseId> {
18844        self.display_map
18845            .update(cx, |map, cx| map.insert_creases(creases, cx))
18846    }
18847
18848    pub fn remove_creases(
18849        &mut self,
18850        ids: impl IntoIterator<Item = CreaseId>,
18851        cx: &mut Context<Self>,
18852    ) -> Vec<(CreaseId, Range<Anchor>)> {
18853        self.display_map
18854            .update(cx, |map, cx| map.remove_creases(ids, cx))
18855    }
18856
18857    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18858        self.display_map
18859            .update(cx, |map, cx| map.snapshot(cx))
18860            .longest_row()
18861    }
18862
18863    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18864        self.display_map
18865            .update(cx, |map, cx| map.snapshot(cx))
18866            .max_point()
18867    }
18868
18869    pub fn text(&self, cx: &App) -> String {
18870        self.buffer.read(cx).read(cx).text()
18871    }
18872
18873    pub fn is_empty(&self, cx: &App) -> bool {
18874        self.buffer.read(cx).read(cx).is_empty()
18875    }
18876
18877    pub fn text_option(&self, cx: &App) -> Option<String> {
18878        let text = self.text(cx);
18879        let text = text.trim();
18880
18881        if text.is_empty() {
18882            return None;
18883        }
18884
18885        Some(text.to_string())
18886    }
18887
18888    pub fn set_text(
18889        &mut self,
18890        text: impl Into<Arc<str>>,
18891        window: &mut Window,
18892        cx: &mut Context<Self>,
18893    ) {
18894        self.transact(window, cx, |this, _, cx| {
18895            this.buffer
18896                .read(cx)
18897                .as_singleton()
18898                .expect("you can only call set_text on editors for singleton buffers")
18899                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18900        });
18901    }
18902
18903    pub fn display_text(&self, cx: &mut App) -> String {
18904        self.display_map
18905            .update(cx, |map, cx| map.snapshot(cx))
18906            .text()
18907    }
18908
18909    fn create_minimap(
18910        &self,
18911        minimap_settings: MinimapSettings,
18912        window: &mut Window,
18913        cx: &mut Context<Self>,
18914    ) -> Option<Entity<Self>> {
18915        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18916            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18917    }
18918
18919    fn initialize_new_minimap(
18920        &self,
18921        minimap_settings: MinimapSettings,
18922        window: &mut Window,
18923        cx: &mut Context<Self>,
18924    ) -> Entity<Self> {
18925        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18926
18927        let mut minimap = Editor::new_internal(
18928            EditorMode::Minimap {
18929                parent: cx.weak_entity(),
18930            },
18931            self.buffer.clone(),
18932            None,
18933            Some(self.display_map.clone()),
18934            window,
18935            cx,
18936        );
18937        minimap.scroll_manager.clone_state(&self.scroll_manager);
18938        minimap.set_text_style_refinement(TextStyleRefinement {
18939            font_size: Some(MINIMAP_FONT_SIZE),
18940            font_weight: Some(MINIMAP_FONT_WEIGHT),
18941            ..Default::default()
18942        });
18943        minimap.update_minimap_configuration(minimap_settings, cx);
18944        cx.new(|_| minimap)
18945    }
18946
18947    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18948        let current_line_highlight = minimap_settings
18949            .current_line_highlight
18950            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18951        self.set_current_line_highlight(Some(current_line_highlight));
18952    }
18953
18954    pub fn minimap(&self) -> Option<&Entity<Self>> {
18955        self.minimap
18956            .as_ref()
18957            .filter(|_| self.minimap_visibility.visible())
18958    }
18959
18960    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18961        let mut wrap_guides = smallvec![];
18962
18963        if self.show_wrap_guides == Some(false) {
18964            return wrap_guides;
18965        }
18966
18967        let settings = self.buffer.read(cx).language_settings(cx);
18968        if settings.show_wrap_guides {
18969            match self.soft_wrap_mode(cx) {
18970                SoftWrap::Column(soft_wrap) => {
18971                    wrap_guides.push((soft_wrap as usize, true));
18972                }
18973                SoftWrap::Bounded(soft_wrap) => {
18974                    wrap_guides.push((soft_wrap as usize, true));
18975                }
18976                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18977            }
18978            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18979        }
18980
18981        wrap_guides
18982    }
18983
18984    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18985        let settings = self.buffer.read(cx).language_settings(cx);
18986        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18987        match mode {
18988            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18989                SoftWrap::None
18990            }
18991            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18992            language_settings::SoftWrap::PreferredLineLength => {
18993                SoftWrap::Column(settings.preferred_line_length)
18994            }
18995            language_settings::SoftWrap::Bounded => {
18996                SoftWrap::Bounded(settings.preferred_line_length)
18997            }
18998        }
18999    }
19000
19001    pub fn set_soft_wrap_mode(
19002        &mut self,
19003        mode: language_settings::SoftWrap,
19004
19005        cx: &mut Context<Self>,
19006    ) {
19007        self.soft_wrap_mode_override = Some(mode);
19008        cx.notify();
19009    }
19010
19011    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19012        self.hard_wrap = hard_wrap;
19013        cx.notify();
19014    }
19015
19016    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19017        self.text_style_refinement = Some(style);
19018    }
19019
19020    /// called by the Element so we know what style we were most recently rendered with.
19021    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19022        // We intentionally do not inform the display map about the minimap style
19023        // so that wrapping is not recalculated and stays consistent for the editor
19024        // and its linked minimap.
19025        if !self.mode.is_minimap() {
19026            let font = style.text.font();
19027            let font_size = style.text.font_size.to_pixels(window.rem_size());
19028            let display_map = self
19029                .placeholder_display_map
19030                .as_ref()
19031                .filter(|_| self.is_empty(cx))
19032                .unwrap_or(&self.display_map);
19033
19034            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19035        }
19036        self.style = Some(style);
19037    }
19038
19039    pub fn style(&self) -> Option<&EditorStyle> {
19040        self.style.as_ref()
19041    }
19042
19043    // Called by the element. This method is not designed to be called outside of the editor
19044    // element's layout code because it does not notify when rewrapping is computed synchronously.
19045    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19046        if self.is_empty(cx) {
19047            self.placeholder_display_map
19048                .as_ref()
19049                .map_or(false, |display_map| {
19050                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19051                })
19052        } else {
19053            self.display_map
19054                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19055        }
19056    }
19057
19058    pub fn set_soft_wrap(&mut self) {
19059        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19060    }
19061
19062    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19063        if self.soft_wrap_mode_override.is_some() {
19064            self.soft_wrap_mode_override.take();
19065        } else {
19066            let soft_wrap = match self.soft_wrap_mode(cx) {
19067                SoftWrap::GitDiff => return,
19068                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19069                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19070                    language_settings::SoftWrap::None
19071                }
19072            };
19073            self.soft_wrap_mode_override = Some(soft_wrap);
19074        }
19075        cx.notify();
19076    }
19077
19078    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19079        let Some(workspace) = self.workspace() else {
19080            return;
19081        };
19082        let fs = workspace.read(cx).app_state().fs.clone();
19083        let current_show = TabBarSettings::get_global(cx).show;
19084        update_settings_file(fs, cx, move |setting, _| {
19085            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19086        });
19087    }
19088
19089    pub fn toggle_indent_guides(
19090        &mut self,
19091        _: &ToggleIndentGuides,
19092        _: &mut Window,
19093        cx: &mut Context<Self>,
19094    ) {
19095        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19096            self.buffer
19097                .read(cx)
19098                .language_settings(cx)
19099                .indent_guides
19100                .enabled
19101        });
19102        self.show_indent_guides = Some(!currently_enabled);
19103        cx.notify();
19104    }
19105
19106    fn should_show_indent_guides(&self) -> Option<bool> {
19107        self.show_indent_guides
19108    }
19109
19110    pub fn toggle_line_numbers(
19111        &mut self,
19112        _: &ToggleLineNumbers,
19113        _: &mut Window,
19114        cx: &mut Context<Self>,
19115    ) {
19116        let mut editor_settings = EditorSettings::get_global(cx).clone();
19117        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19118        EditorSettings::override_global(editor_settings, cx);
19119    }
19120
19121    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19122        if let Some(show_line_numbers) = self.show_line_numbers {
19123            return show_line_numbers;
19124        }
19125        EditorSettings::get_global(cx).gutter.line_numbers
19126    }
19127
19128    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19129        self.use_relative_line_numbers
19130            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19131    }
19132
19133    pub fn toggle_relative_line_numbers(
19134        &mut self,
19135        _: &ToggleRelativeLineNumbers,
19136        _: &mut Window,
19137        cx: &mut Context<Self>,
19138    ) {
19139        let is_relative = self.should_use_relative_line_numbers(cx);
19140        self.set_relative_line_number(Some(!is_relative), cx)
19141    }
19142
19143    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19144        self.use_relative_line_numbers = is_relative;
19145        cx.notify();
19146    }
19147
19148    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19149        self.show_gutter = show_gutter;
19150        cx.notify();
19151    }
19152
19153    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19154        self.show_scrollbars = ScrollbarAxes {
19155            horizontal: show,
19156            vertical: show,
19157        };
19158        cx.notify();
19159    }
19160
19161    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19162        self.show_scrollbars.vertical = show;
19163        cx.notify();
19164    }
19165
19166    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19167        self.show_scrollbars.horizontal = show;
19168        cx.notify();
19169    }
19170
19171    pub fn set_minimap_visibility(
19172        &mut self,
19173        minimap_visibility: MinimapVisibility,
19174        window: &mut Window,
19175        cx: &mut Context<Self>,
19176    ) {
19177        if self.minimap_visibility != minimap_visibility {
19178            if minimap_visibility.visible() && self.minimap.is_none() {
19179                let minimap_settings = EditorSettings::get_global(cx).minimap;
19180                self.minimap =
19181                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19182            }
19183            self.minimap_visibility = minimap_visibility;
19184            cx.notify();
19185        }
19186    }
19187
19188    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19189        self.set_show_scrollbars(false, cx);
19190        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19191    }
19192
19193    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19194        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19195    }
19196
19197    /// Normally the text in full mode and auto height editors is padded on the
19198    /// left side by roughly half a character width for improved hit testing.
19199    ///
19200    /// Use this method to disable this for cases where this is not wanted (e.g.
19201    /// if you want to align the editor text with some other text above or below)
19202    /// or if you want to add this padding to single-line editors.
19203    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19204        self.offset_content = offset_content;
19205        cx.notify();
19206    }
19207
19208    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19209        self.show_line_numbers = Some(show_line_numbers);
19210        cx.notify();
19211    }
19212
19213    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19214        self.disable_expand_excerpt_buttons = true;
19215        cx.notify();
19216    }
19217
19218    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19219        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19220        cx.notify();
19221    }
19222
19223    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19224        self.show_code_actions = Some(show_code_actions);
19225        cx.notify();
19226    }
19227
19228    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19229        self.show_runnables = Some(show_runnables);
19230        cx.notify();
19231    }
19232
19233    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19234        self.show_breakpoints = Some(show_breakpoints);
19235        cx.notify();
19236    }
19237
19238    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19239        if self.display_map.read(cx).masked != masked {
19240            self.display_map.update(cx, |map, _| map.masked = masked);
19241        }
19242        cx.notify()
19243    }
19244
19245    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19246        self.show_wrap_guides = Some(show_wrap_guides);
19247        cx.notify();
19248    }
19249
19250    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19251        self.show_indent_guides = Some(show_indent_guides);
19252        cx.notify();
19253    }
19254
19255    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19256        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19257            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19258                && let Some(dir) = file.abs_path(cx).parent()
19259            {
19260                return Some(dir.to_owned());
19261            }
19262        }
19263
19264        None
19265    }
19266
19267    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19268        self.active_excerpt(cx)?
19269            .1
19270            .read(cx)
19271            .file()
19272            .and_then(|f| f.as_local())
19273    }
19274
19275    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19276        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19277            let buffer = buffer.read(cx);
19278            if let Some(project_path) = buffer.project_path(cx) {
19279                let project = self.project()?.read(cx);
19280                project.absolute_path(&project_path, cx)
19281            } else {
19282                buffer
19283                    .file()
19284                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19285            }
19286        })
19287    }
19288
19289    pub fn reveal_in_finder(
19290        &mut self,
19291        _: &RevealInFileManager,
19292        _window: &mut Window,
19293        cx: &mut Context<Self>,
19294    ) {
19295        if let Some(target) = self.target_file(cx) {
19296            cx.reveal_path(&target.abs_path(cx));
19297        }
19298    }
19299
19300    pub fn copy_path(
19301        &mut self,
19302        _: &zed_actions::workspace::CopyPath,
19303        _window: &mut Window,
19304        cx: &mut Context<Self>,
19305    ) {
19306        if let Some(path) = self.target_file_abs_path(cx)
19307            && let Some(path) = path.to_str()
19308        {
19309            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19310        } else {
19311            cx.propagate();
19312        }
19313    }
19314
19315    pub fn copy_relative_path(
19316        &mut self,
19317        _: &zed_actions::workspace::CopyRelativePath,
19318        _window: &mut Window,
19319        cx: &mut Context<Self>,
19320    ) {
19321        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19322            let project = self.project()?.read(cx);
19323            let path = buffer.read(cx).file()?.path();
19324            let path = path.display(project.path_style(cx));
19325            Some(path)
19326        }) {
19327            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19328        } else {
19329            cx.propagate();
19330        }
19331    }
19332
19333    /// Returns the project path for the editor's buffer, if any buffer is
19334    /// opened in the editor.
19335    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19336        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19337            buffer.read(cx).project_path(cx)
19338        } else {
19339            None
19340        }
19341    }
19342
19343    // Returns true if the editor handled a go-to-line request
19344    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19345        maybe!({
19346            let breakpoint_store = self.breakpoint_store.as_ref()?;
19347
19348            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19349            else {
19350                self.clear_row_highlights::<ActiveDebugLine>();
19351                return None;
19352            };
19353
19354            let position = active_stack_frame.position;
19355            let buffer_id = position.buffer_id?;
19356            let snapshot = self
19357                .project
19358                .as_ref()?
19359                .read(cx)
19360                .buffer_for_id(buffer_id, cx)?
19361                .read(cx)
19362                .snapshot();
19363
19364            let mut handled = false;
19365            for (id, ExcerptRange { context, .. }) in
19366                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19367            {
19368                if context.start.cmp(&position, &snapshot).is_ge()
19369                    || context.end.cmp(&position, &snapshot).is_lt()
19370                {
19371                    continue;
19372                }
19373                let snapshot = self.buffer.read(cx).snapshot(cx);
19374                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19375
19376                handled = true;
19377                self.clear_row_highlights::<ActiveDebugLine>();
19378
19379                self.go_to_line::<ActiveDebugLine>(
19380                    multibuffer_anchor,
19381                    Some(cx.theme().colors().editor_debugger_active_line_background),
19382                    window,
19383                    cx,
19384                );
19385
19386                cx.notify();
19387            }
19388
19389            handled.then_some(())
19390        })
19391        .is_some()
19392    }
19393
19394    pub fn copy_file_name_without_extension(
19395        &mut self,
19396        _: &CopyFileNameWithoutExtension,
19397        _: &mut Window,
19398        cx: &mut Context<Self>,
19399    ) {
19400        if let Some(file) = self.target_file(cx)
19401            && let Some(file_stem) = file.path().file_stem()
19402        {
19403            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19404        }
19405    }
19406
19407    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19408        if let Some(file) = self.target_file(cx)
19409            && let Some(name) = file.path().file_name()
19410        {
19411            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19412        }
19413    }
19414
19415    pub fn toggle_git_blame(
19416        &mut self,
19417        _: &::git::Blame,
19418        window: &mut Window,
19419        cx: &mut Context<Self>,
19420    ) {
19421        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19422
19423        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19424            self.start_git_blame(true, window, cx);
19425        }
19426
19427        cx.notify();
19428    }
19429
19430    pub fn toggle_git_blame_inline(
19431        &mut self,
19432        _: &ToggleGitBlameInline,
19433        window: &mut Window,
19434        cx: &mut Context<Self>,
19435    ) {
19436        self.toggle_git_blame_inline_internal(true, window, cx);
19437        cx.notify();
19438    }
19439
19440    pub fn open_git_blame_commit(
19441        &mut self,
19442        _: &OpenGitBlameCommit,
19443        window: &mut Window,
19444        cx: &mut Context<Self>,
19445    ) {
19446        self.open_git_blame_commit_internal(window, cx);
19447    }
19448
19449    fn open_git_blame_commit_internal(
19450        &mut self,
19451        window: &mut Window,
19452        cx: &mut Context<Self>,
19453    ) -> Option<()> {
19454        let blame = self.blame.as_ref()?;
19455        let snapshot = self.snapshot(window, cx);
19456        let cursor = self.selections.newest::<Point>(cx).head();
19457        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19458        let (_, blame_entry) = blame
19459            .update(cx, |blame, cx| {
19460                blame
19461                    .blame_for_rows(
19462                        &[RowInfo {
19463                            buffer_id: Some(buffer.remote_id()),
19464                            buffer_row: Some(point.row),
19465                            ..Default::default()
19466                        }],
19467                        cx,
19468                    )
19469                    .next()
19470            })
19471            .flatten()?;
19472        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19473        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19474        let workspace = self.workspace()?.downgrade();
19475        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19476        None
19477    }
19478
19479    pub fn git_blame_inline_enabled(&self) -> bool {
19480        self.git_blame_inline_enabled
19481    }
19482
19483    pub fn toggle_selection_menu(
19484        &mut self,
19485        _: &ToggleSelectionMenu,
19486        _: &mut Window,
19487        cx: &mut Context<Self>,
19488    ) {
19489        self.show_selection_menu = self
19490            .show_selection_menu
19491            .map(|show_selections_menu| !show_selections_menu)
19492            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19493
19494        cx.notify();
19495    }
19496
19497    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19498        self.show_selection_menu
19499            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19500    }
19501
19502    fn start_git_blame(
19503        &mut self,
19504        user_triggered: bool,
19505        window: &mut Window,
19506        cx: &mut Context<Self>,
19507    ) {
19508        if let Some(project) = self.project() {
19509            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19510                && buffer.read(cx).file().is_none()
19511            {
19512                return;
19513            }
19514
19515            let focused = self.focus_handle(cx).contains_focused(window, cx);
19516
19517            let project = project.clone();
19518            let blame = cx
19519                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19520            self.blame_subscription =
19521                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19522            self.blame = Some(blame);
19523        }
19524    }
19525
19526    fn toggle_git_blame_inline_internal(
19527        &mut self,
19528        user_triggered: bool,
19529        window: &mut Window,
19530        cx: &mut Context<Self>,
19531    ) {
19532        if self.git_blame_inline_enabled {
19533            self.git_blame_inline_enabled = false;
19534            self.show_git_blame_inline = false;
19535            self.show_git_blame_inline_delay_task.take();
19536        } else {
19537            self.git_blame_inline_enabled = true;
19538            self.start_git_blame_inline(user_triggered, window, cx);
19539        }
19540
19541        cx.notify();
19542    }
19543
19544    fn start_git_blame_inline(
19545        &mut self,
19546        user_triggered: bool,
19547        window: &mut Window,
19548        cx: &mut Context<Self>,
19549    ) {
19550        self.start_git_blame(user_triggered, window, cx);
19551
19552        if ProjectSettings::get_global(cx)
19553            .git
19554            .inline_blame_delay()
19555            .is_some()
19556        {
19557            self.start_inline_blame_timer(window, cx);
19558        } else {
19559            self.show_git_blame_inline = true
19560        }
19561    }
19562
19563    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19564        self.blame.as_ref()
19565    }
19566
19567    pub fn show_git_blame_gutter(&self) -> bool {
19568        self.show_git_blame_gutter
19569    }
19570
19571    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19572        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19573    }
19574
19575    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19576        self.show_git_blame_inline
19577            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19578            && !self.newest_selection_head_on_empty_line(cx)
19579            && self.has_blame_entries(cx)
19580    }
19581
19582    fn has_blame_entries(&self, cx: &App) -> bool {
19583        self.blame()
19584            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19585    }
19586
19587    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19588        let cursor_anchor = self.selections.newest_anchor().head();
19589
19590        let snapshot = self.buffer.read(cx).snapshot(cx);
19591        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19592
19593        snapshot.line_len(buffer_row) == 0
19594    }
19595
19596    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19597        let buffer_and_selection = maybe!({
19598            let selection = self.selections.newest::<Point>(cx);
19599            let selection_range = selection.range();
19600
19601            let multi_buffer = self.buffer().read(cx);
19602            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19603            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19604
19605            let (buffer, range, _) = if selection.reversed {
19606                buffer_ranges.first()
19607            } else {
19608                buffer_ranges.last()
19609            }?;
19610
19611            let selection = text::ToPoint::to_point(&range.start, buffer).row
19612                ..text::ToPoint::to_point(&range.end, buffer).row;
19613            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19614        });
19615
19616        let Some((buffer, selection)) = buffer_and_selection else {
19617            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19618        };
19619
19620        let Some(project) = self.project() else {
19621            return Task::ready(Err(anyhow!("editor does not have project")));
19622        };
19623
19624        project.update(cx, |project, cx| {
19625            project.get_permalink_to_line(&buffer, selection, cx)
19626        })
19627    }
19628
19629    pub fn copy_permalink_to_line(
19630        &mut self,
19631        _: &CopyPermalinkToLine,
19632        window: &mut Window,
19633        cx: &mut Context<Self>,
19634    ) {
19635        let permalink_task = self.get_permalink_to_line(cx);
19636        let workspace = self.workspace();
19637
19638        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19639            Ok(permalink) => {
19640                cx.update(|_, cx| {
19641                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19642                })
19643                .ok();
19644            }
19645            Err(err) => {
19646                let message = format!("Failed to copy permalink: {err}");
19647
19648                anyhow::Result::<()>::Err(err).log_err();
19649
19650                if let Some(workspace) = workspace {
19651                    workspace
19652                        .update_in(cx, |workspace, _, cx| {
19653                            struct CopyPermalinkToLine;
19654
19655                            workspace.show_toast(
19656                                Toast::new(
19657                                    NotificationId::unique::<CopyPermalinkToLine>(),
19658                                    message,
19659                                ),
19660                                cx,
19661                            )
19662                        })
19663                        .ok();
19664                }
19665            }
19666        })
19667        .detach();
19668    }
19669
19670    pub fn copy_file_location(
19671        &mut self,
19672        _: &CopyFileLocation,
19673        _: &mut Window,
19674        cx: &mut Context<Self>,
19675    ) {
19676        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19677        if let Some(file) = self.target_file(cx) {
19678            let path = file.path().display(file.path_style(cx));
19679            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19680        }
19681    }
19682
19683    pub fn open_permalink_to_line(
19684        &mut self,
19685        _: &OpenPermalinkToLine,
19686        window: &mut Window,
19687        cx: &mut Context<Self>,
19688    ) {
19689        let permalink_task = self.get_permalink_to_line(cx);
19690        let workspace = self.workspace();
19691
19692        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19693            Ok(permalink) => {
19694                cx.update(|_, cx| {
19695                    cx.open_url(permalink.as_ref());
19696                })
19697                .ok();
19698            }
19699            Err(err) => {
19700                let message = format!("Failed to open permalink: {err}");
19701
19702                anyhow::Result::<()>::Err(err).log_err();
19703
19704                if let Some(workspace) = workspace {
19705                    workspace
19706                        .update(cx, |workspace, cx| {
19707                            struct OpenPermalinkToLine;
19708
19709                            workspace.show_toast(
19710                                Toast::new(
19711                                    NotificationId::unique::<OpenPermalinkToLine>(),
19712                                    message,
19713                                ),
19714                                cx,
19715                            )
19716                        })
19717                        .ok();
19718                }
19719            }
19720        })
19721        .detach();
19722    }
19723
19724    pub fn insert_uuid_v4(
19725        &mut self,
19726        _: &InsertUuidV4,
19727        window: &mut Window,
19728        cx: &mut Context<Self>,
19729    ) {
19730        self.insert_uuid(UuidVersion::V4, window, cx);
19731    }
19732
19733    pub fn insert_uuid_v7(
19734        &mut self,
19735        _: &InsertUuidV7,
19736        window: &mut Window,
19737        cx: &mut Context<Self>,
19738    ) {
19739        self.insert_uuid(UuidVersion::V7, window, cx);
19740    }
19741
19742    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19743        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19744        self.transact(window, cx, |this, window, cx| {
19745            let edits = this
19746                .selections
19747                .all::<Point>(cx)
19748                .into_iter()
19749                .map(|selection| {
19750                    let uuid = match version {
19751                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19752                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19753                    };
19754
19755                    (selection.range(), uuid.to_string())
19756                });
19757            this.edit(edits, cx);
19758            this.refresh_edit_prediction(true, false, window, cx);
19759        });
19760    }
19761
19762    pub fn open_selections_in_multibuffer(
19763        &mut self,
19764        _: &OpenSelectionsInMultibuffer,
19765        window: &mut Window,
19766        cx: &mut Context<Self>,
19767    ) {
19768        let multibuffer = self.buffer.read(cx);
19769
19770        let Some(buffer) = multibuffer.as_singleton() else {
19771            return;
19772        };
19773
19774        let Some(workspace) = self.workspace() else {
19775            return;
19776        };
19777
19778        let title = multibuffer.title(cx).to_string();
19779
19780        let locations = self
19781            .selections
19782            .all_anchors(cx)
19783            .iter()
19784            .map(|selection| {
19785                (
19786                    buffer.clone(),
19787                    (selection.start.text_anchor..selection.end.text_anchor)
19788                        .to_point(buffer.read(cx)),
19789                )
19790            })
19791            .into_group_map();
19792
19793        cx.spawn_in(window, async move |_, cx| {
19794            workspace.update_in(cx, |workspace, window, cx| {
19795                Self::open_locations_in_multibuffer(
19796                    workspace,
19797                    locations,
19798                    format!("Selections for '{title}'"),
19799                    false,
19800                    MultibufferSelectionMode::All,
19801                    window,
19802                    cx,
19803                );
19804            })
19805        })
19806        .detach();
19807    }
19808
19809    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19810    /// last highlight added will be used.
19811    ///
19812    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19813    pub fn highlight_rows<T: 'static>(
19814        &mut self,
19815        range: Range<Anchor>,
19816        color: Hsla,
19817        options: RowHighlightOptions,
19818        cx: &mut Context<Self>,
19819    ) {
19820        let snapshot = self.buffer().read(cx).snapshot(cx);
19821        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19822        let ix = row_highlights.binary_search_by(|highlight| {
19823            Ordering::Equal
19824                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19825                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19826        });
19827
19828        if let Err(mut ix) = ix {
19829            let index = post_inc(&mut self.highlight_order);
19830
19831            // If this range intersects with the preceding highlight, then merge it with
19832            // the preceding highlight. Otherwise insert a new highlight.
19833            let mut merged = false;
19834            if ix > 0 {
19835                let prev_highlight = &mut row_highlights[ix - 1];
19836                if prev_highlight
19837                    .range
19838                    .end
19839                    .cmp(&range.start, &snapshot)
19840                    .is_ge()
19841                {
19842                    ix -= 1;
19843                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19844                        prev_highlight.range.end = range.end;
19845                    }
19846                    merged = true;
19847                    prev_highlight.index = index;
19848                    prev_highlight.color = color;
19849                    prev_highlight.options = options;
19850                }
19851            }
19852
19853            if !merged {
19854                row_highlights.insert(
19855                    ix,
19856                    RowHighlight {
19857                        range,
19858                        index,
19859                        color,
19860                        options,
19861                        type_id: TypeId::of::<T>(),
19862                    },
19863                );
19864            }
19865
19866            // If any of the following highlights intersect with this one, merge them.
19867            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19868                let highlight = &row_highlights[ix];
19869                if next_highlight
19870                    .range
19871                    .start
19872                    .cmp(&highlight.range.end, &snapshot)
19873                    .is_le()
19874                {
19875                    if next_highlight
19876                        .range
19877                        .end
19878                        .cmp(&highlight.range.end, &snapshot)
19879                        .is_gt()
19880                    {
19881                        row_highlights[ix].range.end = next_highlight.range.end;
19882                    }
19883                    row_highlights.remove(ix + 1);
19884                } else {
19885                    break;
19886                }
19887            }
19888        }
19889    }
19890
19891    /// Remove any highlighted row ranges of the given type that intersect the
19892    /// given ranges.
19893    pub fn remove_highlighted_rows<T: 'static>(
19894        &mut self,
19895        ranges_to_remove: Vec<Range<Anchor>>,
19896        cx: &mut Context<Self>,
19897    ) {
19898        let snapshot = self.buffer().read(cx).snapshot(cx);
19899        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19900        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19901        row_highlights.retain(|highlight| {
19902            while let Some(range_to_remove) = ranges_to_remove.peek() {
19903                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19904                    Ordering::Less | Ordering::Equal => {
19905                        ranges_to_remove.next();
19906                    }
19907                    Ordering::Greater => {
19908                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19909                            Ordering::Less | Ordering::Equal => {
19910                                return false;
19911                            }
19912                            Ordering::Greater => break,
19913                        }
19914                    }
19915                }
19916            }
19917
19918            true
19919        })
19920    }
19921
19922    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19923    pub fn clear_row_highlights<T: 'static>(&mut self) {
19924        self.highlighted_rows.remove(&TypeId::of::<T>());
19925    }
19926
19927    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19928    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19929        self.highlighted_rows
19930            .get(&TypeId::of::<T>())
19931            .map_or(&[] as &[_], |vec| vec.as_slice())
19932            .iter()
19933            .map(|highlight| (highlight.range.clone(), highlight.color))
19934    }
19935
19936    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19937    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19938    /// Allows to ignore certain kinds of highlights.
19939    pub fn highlighted_display_rows(
19940        &self,
19941        window: &mut Window,
19942        cx: &mut App,
19943    ) -> BTreeMap<DisplayRow, LineHighlight> {
19944        let snapshot = self.snapshot(window, cx);
19945        let mut used_highlight_orders = HashMap::default();
19946        self.highlighted_rows
19947            .iter()
19948            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19949            .fold(
19950                BTreeMap::<DisplayRow, LineHighlight>::new(),
19951                |mut unique_rows, highlight| {
19952                    let start = highlight.range.start.to_display_point(&snapshot);
19953                    let end = highlight.range.end.to_display_point(&snapshot);
19954                    let start_row = start.row().0;
19955                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19956                        && end.column() == 0
19957                    {
19958                        end.row().0.saturating_sub(1)
19959                    } else {
19960                        end.row().0
19961                    };
19962                    for row in start_row..=end_row {
19963                        let used_index =
19964                            used_highlight_orders.entry(row).or_insert(highlight.index);
19965                        if highlight.index >= *used_index {
19966                            *used_index = highlight.index;
19967                            unique_rows.insert(
19968                                DisplayRow(row),
19969                                LineHighlight {
19970                                    include_gutter: highlight.options.include_gutter,
19971                                    border: None,
19972                                    background: highlight.color.into(),
19973                                    type_id: Some(highlight.type_id),
19974                                },
19975                            );
19976                        }
19977                    }
19978                    unique_rows
19979                },
19980            )
19981    }
19982
19983    pub fn highlighted_display_row_for_autoscroll(
19984        &self,
19985        snapshot: &DisplaySnapshot,
19986    ) -> Option<DisplayRow> {
19987        self.highlighted_rows
19988            .values()
19989            .flat_map(|highlighted_rows| highlighted_rows.iter())
19990            .filter_map(|highlight| {
19991                if highlight.options.autoscroll {
19992                    Some(highlight.range.start.to_display_point(snapshot).row())
19993                } else {
19994                    None
19995                }
19996            })
19997            .min()
19998    }
19999
20000    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20001        self.highlight_background::<SearchWithinRange>(
20002            ranges,
20003            |colors| colors.colors().editor_document_highlight_read_background,
20004            cx,
20005        )
20006    }
20007
20008    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20009        self.breadcrumb_header = Some(new_header);
20010    }
20011
20012    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20013        self.clear_background_highlights::<SearchWithinRange>(cx);
20014    }
20015
20016    pub fn highlight_background<T: 'static>(
20017        &mut self,
20018        ranges: &[Range<Anchor>],
20019        color_fetcher: fn(&Theme) -> Hsla,
20020        cx: &mut Context<Self>,
20021    ) {
20022        self.background_highlights.insert(
20023            HighlightKey::Type(TypeId::of::<T>()),
20024            (color_fetcher, Arc::from(ranges)),
20025        );
20026        self.scrollbar_marker_state.dirty = true;
20027        cx.notify();
20028    }
20029
20030    pub fn highlight_background_key<T: 'static>(
20031        &mut self,
20032        key: usize,
20033        ranges: &[Range<Anchor>],
20034        color_fetcher: fn(&Theme) -> Hsla,
20035        cx: &mut Context<Self>,
20036    ) {
20037        self.background_highlights.insert(
20038            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20039            (color_fetcher, Arc::from(ranges)),
20040        );
20041        self.scrollbar_marker_state.dirty = true;
20042        cx.notify();
20043    }
20044
20045    pub fn clear_background_highlights<T: 'static>(
20046        &mut self,
20047        cx: &mut Context<Self>,
20048    ) -> Option<BackgroundHighlight> {
20049        let text_highlights = self
20050            .background_highlights
20051            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20052        if !text_highlights.1.is_empty() {
20053            self.scrollbar_marker_state.dirty = true;
20054            cx.notify();
20055        }
20056        Some(text_highlights)
20057    }
20058
20059    pub fn highlight_gutter<T: 'static>(
20060        &mut self,
20061        ranges: impl Into<Vec<Range<Anchor>>>,
20062        color_fetcher: fn(&App) -> Hsla,
20063        cx: &mut Context<Self>,
20064    ) {
20065        self.gutter_highlights
20066            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20067        cx.notify();
20068    }
20069
20070    pub fn clear_gutter_highlights<T: 'static>(
20071        &mut self,
20072        cx: &mut Context<Self>,
20073    ) -> Option<GutterHighlight> {
20074        cx.notify();
20075        self.gutter_highlights.remove(&TypeId::of::<T>())
20076    }
20077
20078    pub fn insert_gutter_highlight<T: 'static>(
20079        &mut self,
20080        range: Range<Anchor>,
20081        color_fetcher: fn(&App) -> Hsla,
20082        cx: &mut Context<Self>,
20083    ) {
20084        let snapshot = self.buffer().read(cx).snapshot(cx);
20085        let mut highlights = self
20086            .gutter_highlights
20087            .remove(&TypeId::of::<T>())
20088            .map(|(_, highlights)| highlights)
20089            .unwrap_or_default();
20090        let ix = highlights.binary_search_by(|highlight| {
20091            Ordering::Equal
20092                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20093                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20094        });
20095        if let Err(ix) = ix {
20096            highlights.insert(ix, range);
20097        }
20098        self.gutter_highlights
20099            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20100    }
20101
20102    pub fn remove_gutter_highlights<T: 'static>(
20103        &mut self,
20104        ranges_to_remove: Vec<Range<Anchor>>,
20105        cx: &mut Context<Self>,
20106    ) {
20107        let snapshot = self.buffer().read(cx).snapshot(cx);
20108        let Some((color_fetcher, mut gutter_highlights)) =
20109            self.gutter_highlights.remove(&TypeId::of::<T>())
20110        else {
20111            return;
20112        };
20113        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20114        gutter_highlights.retain(|highlight| {
20115            while let Some(range_to_remove) = ranges_to_remove.peek() {
20116                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20117                    Ordering::Less | Ordering::Equal => {
20118                        ranges_to_remove.next();
20119                    }
20120                    Ordering::Greater => {
20121                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20122                            Ordering::Less | Ordering::Equal => {
20123                                return false;
20124                            }
20125                            Ordering::Greater => break,
20126                        }
20127                    }
20128                }
20129            }
20130
20131            true
20132        });
20133        self.gutter_highlights
20134            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20135    }
20136
20137    #[cfg(feature = "test-support")]
20138    pub fn all_text_highlights(
20139        &self,
20140        window: &mut Window,
20141        cx: &mut Context<Self>,
20142    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20143        let snapshot = self.snapshot(window, cx);
20144        self.display_map.update(cx, |display_map, _| {
20145            display_map
20146                .all_text_highlights()
20147                .map(|highlight| {
20148                    let (style, ranges) = highlight.as_ref();
20149                    (
20150                        *style,
20151                        ranges
20152                            .iter()
20153                            .map(|range| range.clone().to_display_points(&snapshot))
20154                            .collect(),
20155                    )
20156                })
20157                .collect()
20158        })
20159    }
20160
20161    #[cfg(feature = "test-support")]
20162    pub fn all_text_background_highlights(
20163        &self,
20164        window: &mut Window,
20165        cx: &mut Context<Self>,
20166    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20167        let snapshot = self.snapshot(window, cx);
20168        let buffer = &snapshot.buffer_snapshot;
20169        let start = buffer.anchor_before(0);
20170        let end = buffer.anchor_after(buffer.len());
20171        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20172    }
20173
20174    #[cfg(any(test, feature = "test-support"))]
20175    pub fn sorted_background_highlights_in_range(
20176        &self,
20177        search_range: Range<Anchor>,
20178        display_snapshot: &DisplaySnapshot,
20179        theme: &Theme,
20180    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20181        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20182        res.sort_by(|a, b| {
20183            a.0.start
20184                .cmp(&b.0.start)
20185                .then_with(|| a.0.end.cmp(&b.0.end))
20186                .then_with(|| a.1.cmp(&b.1))
20187        });
20188        res
20189    }
20190
20191    #[cfg(feature = "test-support")]
20192    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20193        let snapshot = self.buffer().read(cx).snapshot(cx);
20194
20195        let highlights = self
20196            .background_highlights
20197            .get(&HighlightKey::Type(TypeId::of::<
20198                items::BufferSearchHighlights,
20199            >()));
20200
20201        if let Some((_color, ranges)) = highlights {
20202            ranges
20203                .iter()
20204                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20205                .collect_vec()
20206        } else {
20207            vec![]
20208        }
20209    }
20210
20211    fn document_highlights_for_position<'a>(
20212        &'a self,
20213        position: Anchor,
20214        buffer: &'a MultiBufferSnapshot,
20215    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20216        let read_highlights = self
20217            .background_highlights
20218            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20219            .map(|h| &h.1);
20220        let write_highlights = self
20221            .background_highlights
20222            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20223            .map(|h| &h.1);
20224        let left_position = position.bias_left(buffer);
20225        let right_position = position.bias_right(buffer);
20226        read_highlights
20227            .into_iter()
20228            .chain(write_highlights)
20229            .flat_map(move |ranges| {
20230                let start_ix = match ranges.binary_search_by(|probe| {
20231                    let cmp = probe.end.cmp(&left_position, buffer);
20232                    if cmp.is_ge() {
20233                        Ordering::Greater
20234                    } else {
20235                        Ordering::Less
20236                    }
20237                }) {
20238                    Ok(i) | Err(i) => i,
20239                };
20240
20241                ranges[start_ix..]
20242                    .iter()
20243                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20244            })
20245    }
20246
20247    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20248        self.background_highlights
20249            .get(&HighlightKey::Type(TypeId::of::<T>()))
20250            .is_some_and(|(_, highlights)| !highlights.is_empty())
20251    }
20252
20253    /// Returns all background highlights for a given range.
20254    ///
20255    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20256    pub fn background_highlights_in_range(
20257        &self,
20258        search_range: Range<Anchor>,
20259        display_snapshot: &DisplaySnapshot,
20260        theme: &Theme,
20261    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20262        let mut results = Vec::new();
20263        for (color_fetcher, ranges) in self.background_highlights.values() {
20264            let color = color_fetcher(theme);
20265            let start_ix = match ranges.binary_search_by(|probe| {
20266                let cmp = probe
20267                    .end
20268                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20269                if cmp.is_gt() {
20270                    Ordering::Greater
20271                } else {
20272                    Ordering::Less
20273                }
20274            }) {
20275                Ok(i) | Err(i) => i,
20276            };
20277            for range in &ranges[start_ix..] {
20278                if range
20279                    .start
20280                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20281                    .is_ge()
20282                {
20283                    break;
20284                }
20285
20286                let start = range.start.to_display_point(display_snapshot);
20287                let end = range.end.to_display_point(display_snapshot);
20288                results.push((start..end, color))
20289            }
20290        }
20291        results
20292    }
20293
20294    pub fn gutter_highlights_in_range(
20295        &self,
20296        search_range: Range<Anchor>,
20297        display_snapshot: &DisplaySnapshot,
20298        cx: &App,
20299    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20300        let mut results = Vec::new();
20301        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20302            let color = color_fetcher(cx);
20303            let start_ix = match ranges.binary_search_by(|probe| {
20304                let cmp = probe
20305                    .end
20306                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20307                if cmp.is_gt() {
20308                    Ordering::Greater
20309                } else {
20310                    Ordering::Less
20311                }
20312            }) {
20313                Ok(i) | Err(i) => i,
20314            };
20315            for range in &ranges[start_ix..] {
20316                if range
20317                    .start
20318                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20319                    .is_ge()
20320                {
20321                    break;
20322                }
20323
20324                let start = range.start.to_display_point(display_snapshot);
20325                let end = range.end.to_display_point(display_snapshot);
20326                results.push((start..end, color))
20327            }
20328        }
20329        results
20330    }
20331
20332    /// Get the text ranges corresponding to the redaction query
20333    pub fn redacted_ranges(
20334        &self,
20335        search_range: Range<Anchor>,
20336        display_snapshot: &DisplaySnapshot,
20337        cx: &App,
20338    ) -> Vec<Range<DisplayPoint>> {
20339        display_snapshot
20340            .buffer_snapshot
20341            .redacted_ranges(search_range, |file| {
20342                if let Some(file) = file {
20343                    file.is_private()
20344                        && EditorSettings::get(
20345                            Some(SettingsLocation {
20346                                worktree_id: file.worktree_id(cx),
20347                                path: file.path().as_ref(),
20348                            }),
20349                            cx,
20350                        )
20351                        .redact_private_values
20352                } else {
20353                    false
20354                }
20355            })
20356            .map(|range| {
20357                range.start.to_display_point(display_snapshot)
20358                    ..range.end.to_display_point(display_snapshot)
20359            })
20360            .collect()
20361    }
20362
20363    pub fn highlight_text_key<T: 'static>(
20364        &mut self,
20365        key: usize,
20366        ranges: Vec<Range<Anchor>>,
20367        style: HighlightStyle,
20368        cx: &mut Context<Self>,
20369    ) {
20370        self.display_map.update(cx, |map, _| {
20371            map.highlight_text(
20372                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20373                ranges,
20374                style,
20375            );
20376        });
20377        cx.notify();
20378    }
20379
20380    pub fn highlight_text<T: 'static>(
20381        &mut self,
20382        ranges: Vec<Range<Anchor>>,
20383        style: HighlightStyle,
20384        cx: &mut Context<Self>,
20385    ) {
20386        self.display_map.update(cx, |map, _| {
20387            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20388        });
20389        cx.notify();
20390    }
20391
20392    pub(crate) fn highlight_inlays<T: 'static>(
20393        &mut self,
20394        highlights: Vec<InlayHighlight>,
20395        style: HighlightStyle,
20396        cx: &mut Context<Self>,
20397    ) {
20398        self.display_map.update(cx, |map, _| {
20399            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20400        });
20401        cx.notify();
20402    }
20403
20404    pub fn text_highlights<'a, T: 'static>(
20405        &'a self,
20406        cx: &'a App,
20407    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20408        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20409    }
20410
20411    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20412        let cleared = self
20413            .display_map
20414            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20415        if cleared {
20416            cx.notify();
20417        }
20418    }
20419
20420    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20421        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20422            && self.focus_handle.is_focused(window)
20423    }
20424
20425    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20426        self.show_cursor_when_unfocused = is_enabled;
20427        cx.notify();
20428    }
20429
20430    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20431        cx.notify();
20432    }
20433
20434    fn on_debug_session_event(
20435        &mut self,
20436        _session: Entity<Session>,
20437        event: &SessionEvent,
20438        cx: &mut Context<Self>,
20439    ) {
20440        if let SessionEvent::InvalidateInlineValue = event {
20441            self.refresh_inline_values(cx);
20442        }
20443    }
20444
20445    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20446        let Some(project) = self.project.clone() else {
20447            return;
20448        };
20449
20450        if !self.inline_value_cache.enabled {
20451            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20452            self.splice_inlays(&inlays, Vec::new(), cx);
20453            return;
20454        }
20455
20456        let current_execution_position = self
20457            .highlighted_rows
20458            .get(&TypeId::of::<ActiveDebugLine>())
20459            .and_then(|lines| lines.last().map(|line| line.range.end));
20460
20461        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20462            let inline_values = editor
20463                .update(cx, |editor, cx| {
20464                    let Some(current_execution_position) = current_execution_position else {
20465                        return Some(Task::ready(Ok(Vec::new())));
20466                    };
20467
20468                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20469                        let snapshot = buffer.snapshot(cx);
20470
20471                        let excerpt = snapshot.excerpt_containing(
20472                            current_execution_position..current_execution_position,
20473                        )?;
20474
20475                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20476                    })?;
20477
20478                    let range =
20479                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20480
20481                    project.inline_values(buffer, range, cx)
20482                })
20483                .ok()
20484                .flatten()?
20485                .await
20486                .context("refreshing debugger inlays")
20487                .log_err()?;
20488
20489            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20490
20491            for (buffer_id, inline_value) in inline_values
20492                .into_iter()
20493                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20494            {
20495                buffer_inline_values
20496                    .entry(buffer_id)
20497                    .or_default()
20498                    .push(inline_value);
20499            }
20500
20501            editor
20502                .update(cx, |editor, cx| {
20503                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20504                    let mut new_inlays = Vec::default();
20505
20506                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20507                        let buffer_id = buffer_snapshot.remote_id();
20508                        buffer_inline_values
20509                            .get(&buffer_id)
20510                            .into_iter()
20511                            .flatten()
20512                            .for_each(|hint| {
20513                                let inlay = Inlay::debugger(
20514                                    post_inc(&mut editor.next_inlay_id),
20515                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20516                                    hint.text(),
20517                                );
20518                                if !inlay.text.chars().contains(&'\n') {
20519                                    new_inlays.push(inlay);
20520                                }
20521                            });
20522                    }
20523
20524                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20525                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20526
20527                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20528                })
20529                .ok()?;
20530            Some(())
20531        });
20532    }
20533
20534    fn on_buffer_event(
20535        &mut self,
20536        multibuffer: &Entity<MultiBuffer>,
20537        event: &multi_buffer::Event,
20538        window: &mut Window,
20539        cx: &mut Context<Self>,
20540    ) {
20541        match event {
20542            multi_buffer::Event::Edited {
20543                singleton_buffer_edited,
20544                edited_buffer,
20545            } => {
20546                self.scrollbar_marker_state.dirty = true;
20547                self.active_indent_guides_state.dirty = true;
20548                self.refresh_active_diagnostics(cx);
20549                self.refresh_code_actions(window, cx);
20550                self.refresh_selected_text_highlights(true, window, cx);
20551                self.refresh_single_line_folds(window, cx);
20552                refresh_matching_bracket_highlights(self, window, cx);
20553                if self.has_active_edit_prediction() {
20554                    self.update_visible_edit_prediction(window, cx);
20555                }
20556                if let Some(project) = self.project.as_ref()
20557                    && let Some(edited_buffer) = edited_buffer
20558                {
20559                    project.update(cx, |project, cx| {
20560                        self.registered_buffers
20561                            .entry(edited_buffer.read(cx).remote_id())
20562                            .or_insert_with(|| {
20563                                project.register_buffer_with_language_servers(edited_buffer, cx)
20564                            });
20565                    });
20566                }
20567                cx.emit(EditorEvent::BufferEdited);
20568                cx.emit(SearchEvent::MatchesInvalidated);
20569
20570                if let Some(buffer) = edited_buffer {
20571                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20572                }
20573
20574                if *singleton_buffer_edited {
20575                    if let Some(buffer) = edited_buffer
20576                        && buffer.read(cx).file().is_none()
20577                    {
20578                        cx.emit(EditorEvent::TitleChanged);
20579                    }
20580                    if let Some(project) = &self.project {
20581                        #[allow(clippy::mutable_key_type)]
20582                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20583                            multibuffer
20584                                .all_buffers()
20585                                .into_iter()
20586                                .filter_map(|buffer| {
20587                                    buffer.update(cx, |buffer, cx| {
20588                                        let language = buffer.language()?;
20589                                        let should_discard = project.update(cx, |project, cx| {
20590                                            project.is_local()
20591                                                && !project.has_language_servers_for(buffer, cx)
20592                                        });
20593                                        should_discard.not().then_some(language.clone())
20594                                    })
20595                                })
20596                                .collect::<HashSet<_>>()
20597                        });
20598                        if !languages_affected.is_empty() {
20599                            self.refresh_inlay_hints(
20600                                InlayHintRefreshReason::BufferEdited(languages_affected),
20601                                cx,
20602                            );
20603                        }
20604                    }
20605                }
20606
20607                let Some(project) = &self.project else { return };
20608                let (telemetry, is_via_ssh) = {
20609                    let project = project.read(cx);
20610                    let telemetry = project.client().telemetry().clone();
20611                    let is_via_ssh = project.is_via_remote_server();
20612                    (telemetry, is_via_ssh)
20613                };
20614                refresh_linked_ranges(self, window, cx);
20615                telemetry.log_edit_event("editor", is_via_ssh);
20616            }
20617            multi_buffer::Event::ExcerptsAdded {
20618                buffer,
20619                predecessor,
20620                excerpts,
20621            } => {
20622                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20623                let buffer_id = buffer.read(cx).remote_id();
20624                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20625                    && let Some(project) = &self.project
20626                {
20627                    update_uncommitted_diff_for_buffer(
20628                        cx.entity(),
20629                        project,
20630                        [buffer.clone()],
20631                        self.buffer.clone(),
20632                        cx,
20633                    )
20634                    .detach();
20635                }
20636                if self.active_diagnostics != ActiveDiagnostic::All {
20637                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20638                }
20639                cx.emit(EditorEvent::ExcerptsAdded {
20640                    buffer: buffer.clone(),
20641                    predecessor: *predecessor,
20642                    excerpts: excerpts.clone(),
20643                });
20644                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20645            }
20646            multi_buffer::Event::ExcerptsRemoved {
20647                ids,
20648                removed_buffer_ids,
20649            } => {
20650                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20651                let buffer = self.buffer.read(cx);
20652                self.registered_buffers
20653                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20654                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20655                cx.emit(EditorEvent::ExcerptsRemoved {
20656                    ids: ids.clone(),
20657                    removed_buffer_ids: removed_buffer_ids.clone(),
20658                });
20659            }
20660            multi_buffer::Event::ExcerptsEdited {
20661                excerpt_ids,
20662                buffer_ids,
20663            } => {
20664                self.display_map.update(cx, |map, cx| {
20665                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20666                });
20667                cx.emit(EditorEvent::ExcerptsEdited {
20668                    ids: excerpt_ids.clone(),
20669                });
20670            }
20671            multi_buffer::Event::ExcerptsExpanded { ids } => {
20672                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20673                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20674            }
20675            multi_buffer::Event::Reparsed(buffer_id) => {
20676                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20677                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20678
20679                cx.emit(EditorEvent::Reparsed(*buffer_id));
20680            }
20681            multi_buffer::Event::DiffHunksToggled => {
20682                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20683            }
20684            multi_buffer::Event::LanguageChanged(buffer_id) => {
20685                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20686                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20687                cx.emit(EditorEvent::Reparsed(*buffer_id));
20688                cx.notify();
20689            }
20690            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20691            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20692            multi_buffer::Event::FileHandleChanged
20693            | multi_buffer::Event::Reloaded
20694            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20695            multi_buffer::Event::DiagnosticsUpdated => {
20696                self.update_diagnostics_state(window, cx);
20697            }
20698            _ => {}
20699        };
20700    }
20701
20702    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20703        if !self.diagnostics_enabled() {
20704            return;
20705        }
20706        self.refresh_active_diagnostics(cx);
20707        self.refresh_inline_diagnostics(true, window, cx);
20708        self.scrollbar_marker_state.dirty = true;
20709        cx.notify();
20710    }
20711
20712    pub fn start_temporary_diff_override(&mut self) {
20713        self.load_diff_task.take();
20714        self.temporary_diff_override = true;
20715    }
20716
20717    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20718        self.temporary_diff_override = false;
20719        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20720        self.buffer.update(cx, |buffer, cx| {
20721            buffer.set_all_diff_hunks_collapsed(cx);
20722        });
20723
20724        if let Some(project) = self.project.clone() {
20725            self.load_diff_task = Some(
20726                update_uncommitted_diff_for_buffer(
20727                    cx.entity(),
20728                    &project,
20729                    self.buffer.read(cx).all_buffers(),
20730                    self.buffer.clone(),
20731                    cx,
20732                )
20733                .shared(),
20734            );
20735        }
20736    }
20737
20738    fn on_display_map_changed(
20739        &mut self,
20740        _: Entity<DisplayMap>,
20741        _: &mut Window,
20742        cx: &mut Context<Self>,
20743    ) {
20744        cx.notify();
20745    }
20746
20747    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20748        if self.diagnostics_enabled() {
20749            let new_severity = EditorSettings::get_global(cx)
20750                .diagnostics_max_severity
20751                .unwrap_or(DiagnosticSeverity::Hint);
20752            self.set_max_diagnostics_severity(new_severity, cx);
20753        }
20754        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20755        self.update_edit_prediction_settings(cx);
20756        self.refresh_edit_prediction(true, false, window, cx);
20757        self.refresh_inline_values(cx);
20758        self.refresh_inlay_hints(
20759            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20760                self.selections.newest_anchor().head(),
20761                &self.buffer.read(cx).snapshot(cx),
20762                cx,
20763            )),
20764            cx,
20765        );
20766
20767        let old_cursor_shape = self.cursor_shape;
20768        let old_show_breadcrumbs = self.show_breadcrumbs;
20769
20770        {
20771            let editor_settings = EditorSettings::get_global(cx);
20772            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20773            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20774            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20775            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20776        }
20777
20778        if old_cursor_shape != self.cursor_shape {
20779            cx.emit(EditorEvent::CursorShapeChanged);
20780        }
20781
20782        if old_show_breadcrumbs != self.show_breadcrumbs {
20783            cx.emit(EditorEvent::BreadcrumbsChanged);
20784        }
20785
20786        let project_settings = ProjectSettings::get_global(cx);
20787        self.serialize_dirty_buffers =
20788            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20789
20790        if self.mode.is_full() {
20791            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20792            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20793            if self.show_inline_diagnostics != show_inline_diagnostics {
20794                self.show_inline_diagnostics = show_inline_diagnostics;
20795                self.refresh_inline_diagnostics(false, window, cx);
20796            }
20797
20798            if self.git_blame_inline_enabled != inline_blame_enabled {
20799                self.toggle_git_blame_inline_internal(false, window, cx);
20800            }
20801
20802            let minimap_settings = EditorSettings::get_global(cx).minimap;
20803            if self.minimap_visibility != MinimapVisibility::Disabled {
20804                if self.minimap_visibility.settings_visibility()
20805                    != minimap_settings.minimap_enabled()
20806                {
20807                    self.set_minimap_visibility(
20808                        MinimapVisibility::for_mode(self.mode(), cx),
20809                        window,
20810                        cx,
20811                    );
20812                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20813                    minimap_entity.update(cx, |minimap_editor, cx| {
20814                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20815                    })
20816                }
20817            }
20818        }
20819
20820        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20821            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20822        }) {
20823            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20824                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20825            }
20826            self.refresh_colors(false, None, window, cx);
20827        }
20828
20829        cx.notify();
20830    }
20831
20832    pub fn set_searchable(&mut self, searchable: bool) {
20833        self.searchable = searchable;
20834    }
20835
20836    pub fn searchable(&self) -> bool {
20837        self.searchable
20838    }
20839
20840    fn open_proposed_changes_editor(
20841        &mut self,
20842        _: &OpenProposedChangesEditor,
20843        window: &mut Window,
20844        cx: &mut Context<Self>,
20845    ) {
20846        let Some(workspace) = self.workspace() else {
20847            cx.propagate();
20848            return;
20849        };
20850
20851        let selections = self.selections.all::<usize>(cx);
20852        let multi_buffer = self.buffer.read(cx);
20853        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20854        let mut new_selections_by_buffer = HashMap::default();
20855        for selection in selections {
20856            for (buffer, range, _) in
20857                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20858            {
20859                let mut range = range.to_point(buffer);
20860                range.start.column = 0;
20861                range.end.column = buffer.line_len(range.end.row);
20862                new_selections_by_buffer
20863                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20864                    .or_insert(Vec::new())
20865                    .push(range)
20866            }
20867        }
20868
20869        let proposed_changes_buffers = new_selections_by_buffer
20870            .into_iter()
20871            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20872            .collect::<Vec<_>>();
20873        let proposed_changes_editor = cx.new(|cx| {
20874            ProposedChangesEditor::new(
20875                "Proposed changes",
20876                proposed_changes_buffers,
20877                self.project.clone(),
20878                window,
20879                cx,
20880            )
20881        });
20882
20883        window.defer(cx, move |window, cx| {
20884            workspace.update(cx, |workspace, cx| {
20885                workspace.active_pane().update(cx, |pane, cx| {
20886                    pane.add_item(
20887                        Box::new(proposed_changes_editor),
20888                        true,
20889                        true,
20890                        None,
20891                        window,
20892                        cx,
20893                    );
20894                });
20895            });
20896        });
20897    }
20898
20899    pub fn open_excerpts_in_split(
20900        &mut self,
20901        _: &OpenExcerptsSplit,
20902        window: &mut Window,
20903        cx: &mut Context<Self>,
20904    ) {
20905        self.open_excerpts_common(None, true, window, cx)
20906    }
20907
20908    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20909        self.open_excerpts_common(None, false, window, cx)
20910    }
20911
20912    fn open_excerpts_common(
20913        &mut self,
20914        jump_data: Option<JumpData>,
20915        split: bool,
20916        window: &mut Window,
20917        cx: &mut Context<Self>,
20918    ) {
20919        let Some(workspace) = self.workspace() else {
20920            cx.propagate();
20921            return;
20922        };
20923
20924        if self.buffer.read(cx).is_singleton() {
20925            cx.propagate();
20926            return;
20927        }
20928
20929        let mut new_selections_by_buffer = HashMap::default();
20930        match &jump_data {
20931            Some(JumpData::MultiBufferPoint {
20932                excerpt_id,
20933                position,
20934                anchor,
20935                line_offset_from_top,
20936            }) => {
20937                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20938                if let Some(buffer) = multi_buffer_snapshot
20939                    .buffer_id_for_excerpt(*excerpt_id)
20940                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20941                {
20942                    let buffer_snapshot = buffer.read(cx).snapshot();
20943                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20944                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20945                    } else {
20946                        buffer_snapshot.clip_point(*position, Bias::Left)
20947                    };
20948                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20949                    new_selections_by_buffer.insert(
20950                        buffer,
20951                        (
20952                            vec![jump_to_offset..jump_to_offset],
20953                            Some(*line_offset_from_top),
20954                        ),
20955                    );
20956                }
20957            }
20958            Some(JumpData::MultiBufferRow {
20959                row,
20960                line_offset_from_top,
20961            }) => {
20962                let point = MultiBufferPoint::new(row.0, 0);
20963                if let Some((buffer, buffer_point, _)) =
20964                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20965                {
20966                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20967                    new_selections_by_buffer
20968                        .entry(buffer)
20969                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20970                        .0
20971                        .push(buffer_offset..buffer_offset)
20972                }
20973            }
20974            None => {
20975                let selections = self.selections.all::<usize>(cx);
20976                let multi_buffer = self.buffer.read(cx);
20977                for selection in selections {
20978                    for (snapshot, range, _, anchor) in multi_buffer
20979                        .snapshot(cx)
20980                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20981                    {
20982                        if let Some(anchor) = anchor {
20983                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20984                            else {
20985                                continue;
20986                            };
20987                            let offset = text::ToOffset::to_offset(
20988                                &anchor.text_anchor,
20989                                &buffer_handle.read(cx).snapshot(),
20990                            );
20991                            let range = offset..offset;
20992                            new_selections_by_buffer
20993                                .entry(buffer_handle)
20994                                .or_insert((Vec::new(), None))
20995                                .0
20996                                .push(range)
20997                        } else {
20998                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20999                            else {
21000                                continue;
21001                            };
21002                            new_selections_by_buffer
21003                                .entry(buffer_handle)
21004                                .or_insert((Vec::new(), None))
21005                                .0
21006                                .push(range)
21007                        }
21008                    }
21009                }
21010            }
21011        }
21012
21013        new_selections_by_buffer
21014            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21015
21016        if new_selections_by_buffer.is_empty() {
21017            return;
21018        }
21019
21020        // We defer the pane interaction because we ourselves are a workspace item
21021        // and activating a new item causes the pane to call a method on us reentrantly,
21022        // which panics if we're on the stack.
21023        window.defer(cx, move |window, cx| {
21024            workspace.update(cx, |workspace, cx| {
21025                let pane = if split {
21026                    workspace.adjacent_pane(window, cx)
21027                } else {
21028                    workspace.active_pane().clone()
21029                };
21030
21031                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21032                    let editor = buffer
21033                        .read(cx)
21034                        .file()
21035                        .is_none()
21036                        .then(|| {
21037                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21038                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21039                            // Instead, we try to activate the existing editor in the pane first.
21040                            let (editor, pane_item_index) =
21041                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21042                                    let editor = item.downcast::<Editor>()?;
21043                                    let singleton_buffer =
21044                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21045                                    if singleton_buffer == buffer {
21046                                        Some((editor, i))
21047                                    } else {
21048                                        None
21049                                    }
21050                                })?;
21051                            pane.update(cx, |pane, cx| {
21052                                pane.activate_item(pane_item_index, true, true, window, cx)
21053                            });
21054                            Some(editor)
21055                        })
21056                        .flatten()
21057                        .unwrap_or_else(|| {
21058                            workspace.open_project_item::<Self>(
21059                                pane.clone(),
21060                                buffer,
21061                                true,
21062                                true,
21063                                window,
21064                                cx,
21065                            )
21066                        });
21067
21068                    editor.update(cx, |editor, cx| {
21069                        let autoscroll = match scroll_offset {
21070                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21071                            None => Autoscroll::newest(),
21072                        };
21073                        let nav_history = editor.nav_history.take();
21074                        editor.change_selections(
21075                            SelectionEffects::scroll(autoscroll),
21076                            window,
21077                            cx,
21078                            |s| {
21079                                s.select_ranges(ranges);
21080                            },
21081                        );
21082                        editor.nav_history = nav_history;
21083                    });
21084                }
21085            })
21086        });
21087    }
21088
21089    // For now, don't allow opening excerpts in buffers that aren't backed by
21090    // regular project files.
21091    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21092        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21093    }
21094
21095    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21096        let snapshot = self.buffer.read(cx).read(cx);
21097        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21098        Some(
21099            ranges
21100                .iter()
21101                .map(move |range| {
21102                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21103                })
21104                .collect(),
21105        )
21106    }
21107
21108    fn selection_replacement_ranges(
21109        &self,
21110        range: Range<OffsetUtf16>,
21111        cx: &mut App,
21112    ) -> Vec<Range<OffsetUtf16>> {
21113        let selections = self.selections.all::<OffsetUtf16>(cx);
21114        let newest_selection = selections
21115            .iter()
21116            .max_by_key(|selection| selection.id)
21117            .unwrap();
21118        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21119        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21120        let snapshot = self.buffer.read(cx).read(cx);
21121        selections
21122            .into_iter()
21123            .map(|mut selection| {
21124                selection.start.0 =
21125                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21126                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21127                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21128                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21129            })
21130            .collect()
21131    }
21132
21133    fn report_editor_event(
21134        &self,
21135        reported_event: ReportEditorEvent,
21136        file_extension: Option<String>,
21137        cx: &App,
21138    ) {
21139        if cfg!(any(test, feature = "test-support")) {
21140            return;
21141        }
21142
21143        let Some(project) = &self.project else { return };
21144
21145        // If None, we are in a file without an extension
21146        let file = self
21147            .buffer
21148            .read(cx)
21149            .as_singleton()
21150            .and_then(|b| b.read(cx).file());
21151        let file_extension = file_extension.or(file
21152            .as_ref()
21153            .and_then(|file| Path::new(file.file_name(cx)).extension())
21154            .and_then(|e| e.to_str())
21155            .map(|a| a.to_string()));
21156
21157        let vim_mode = vim_enabled(cx);
21158
21159        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21160        let copilot_enabled = edit_predictions_provider
21161            == language::language_settings::EditPredictionProvider::Copilot;
21162        let copilot_enabled_for_language = self
21163            .buffer
21164            .read(cx)
21165            .language_settings(cx)
21166            .show_edit_predictions;
21167
21168        let project = project.read(cx);
21169        let event_type = reported_event.event_type();
21170
21171        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21172            telemetry::event!(
21173                event_type,
21174                type = if auto_saved {"autosave"} else {"manual"},
21175                file_extension,
21176                vim_mode,
21177                copilot_enabled,
21178                copilot_enabled_for_language,
21179                edit_predictions_provider,
21180                is_via_ssh = project.is_via_remote_server(),
21181            );
21182        } else {
21183            telemetry::event!(
21184                event_type,
21185                file_extension,
21186                vim_mode,
21187                copilot_enabled,
21188                copilot_enabled_for_language,
21189                edit_predictions_provider,
21190                is_via_ssh = project.is_via_remote_server(),
21191            );
21192        };
21193    }
21194
21195    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21196    /// with each line being an array of {text, highlight} objects.
21197    fn copy_highlight_json(
21198        &mut self,
21199        _: &CopyHighlightJson,
21200        window: &mut Window,
21201        cx: &mut Context<Self>,
21202    ) {
21203        #[derive(Serialize)]
21204        struct Chunk<'a> {
21205            text: String,
21206            highlight: Option<&'a str>,
21207        }
21208
21209        let snapshot = self.buffer.read(cx).snapshot(cx);
21210        let range = self
21211            .selected_text_range(false, window, cx)
21212            .and_then(|selection| {
21213                if selection.range.is_empty() {
21214                    None
21215                } else {
21216                    Some(selection.range)
21217                }
21218            })
21219            .unwrap_or_else(|| 0..snapshot.len());
21220
21221        let chunks = snapshot.chunks(range, true);
21222        let mut lines = Vec::new();
21223        let mut line: VecDeque<Chunk> = VecDeque::new();
21224
21225        let Some(style) = self.style.as_ref() else {
21226            return;
21227        };
21228
21229        for chunk in chunks {
21230            let highlight = chunk
21231                .syntax_highlight_id
21232                .and_then(|id| id.name(&style.syntax));
21233            let mut chunk_lines = chunk.text.split('\n').peekable();
21234            while let Some(text) = chunk_lines.next() {
21235                let mut merged_with_last_token = false;
21236                if let Some(last_token) = line.back_mut()
21237                    && last_token.highlight == highlight
21238                {
21239                    last_token.text.push_str(text);
21240                    merged_with_last_token = true;
21241                }
21242
21243                if !merged_with_last_token {
21244                    line.push_back(Chunk {
21245                        text: text.into(),
21246                        highlight,
21247                    });
21248                }
21249
21250                if chunk_lines.peek().is_some() {
21251                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21252                        line.pop_front();
21253                    }
21254                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21255                        line.pop_back();
21256                    }
21257
21258                    lines.push(mem::take(&mut line));
21259                }
21260            }
21261        }
21262
21263        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21264            return;
21265        };
21266        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21267    }
21268
21269    pub fn open_context_menu(
21270        &mut self,
21271        _: &OpenContextMenu,
21272        window: &mut Window,
21273        cx: &mut Context<Self>,
21274    ) {
21275        self.request_autoscroll(Autoscroll::newest(), cx);
21276        let position = self.selections.newest_display(cx).start;
21277        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21278    }
21279
21280    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21281        &self.inlay_hint_cache
21282    }
21283
21284    pub fn replay_insert_event(
21285        &mut self,
21286        text: &str,
21287        relative_utf16_range: Option<Range<isize>>,
21288        window: &mut Window,
21289        cx: &mut Context<Self>,
21290    ) {
21291        if !self.input_enabled {
21292            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21293            return;
21294        }
21295        if let Some(relative_utf16_range) = relative_utf16_range {
21296            let selections = self.selections.all::<OffsetUtf16>(cx);
21297            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21298                let new_ranges = selections.into_iter().map(|range| {
21299                    let start = OffsetUtf16(
21300                        range
21301                            .head()
21302                            .0
21303                            .saturating_add_signed(relative_utf16_range.start),
21304                    );
21305                    let end = OffsetUtf16(
21306                        range
21307                            .head()
21308                            .0
21309                            .saturating_add_signed(relative_utf16_range.end),
21310                    );
21311                    start..end
21312                });
21313                s.select_ranges(new_ranges);
21314            });
21315        }
21316
21317        self.handle_input(text, window, cx);
21318    }
21319
21320    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21321        let Some(provider) = self.semantics_provider.as_ref() else {
21322            return false;
21323        };
21324
21325        let mut supports = false;
21326        self.buffer().update(cx, |this, cx| {
21327            this.for_each_buffer(|buffer| {
21328                supports |= provider.supports_inlay_hints(buffer, cx);
21329            });
21330        });
21331
21332        supports
21333    }
21334
21335    pub fn is_focused(&self, window: &Window) -> bool {
21336        self.focus_handle.is_focused(window)
21337    }
21338
21339    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21340        cx.emit(EditorEvent::Focused);
21341
21342        if let Some(descendant) = self
21343            .last_focused_descendant
21344            .take()
21345            .and_then(|descendant| descendant.upgrade())
21346        {
21347            window.focus(&descendant);
21348        } else {
21349            if let Some(blame) = self.blame.as_ref() {
21350                blame.update(cx, GitBlame::focus)
21351            }
21352
21353            self.blink_manager.update(cx, BlinkManager::enable);
21354            self.show_cursor_names(window, cx);
21355            self.buffer.update(cx, |buffer, cx| {
21356                buffer.finalize_last_transaction(cx);
21357                if self.leader_id.is_none() {
21358                    buffer.set_active_selections(
21359                        &self.selections.disjoint_anchors_arc(),
21360                        self.selections.line_mode(),
21361                        self.cursor_shape,
21362                        cx,
21363                    );
21364                }
21365            });
21366        }
21367    }
21368
21369    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21370        cx.emit(EditorEvent::FocusedIn)
21371    }
21372
21373    fn handle_focus_out(
21374        &mut self,
21375        event: FocusOutEvent,
21376        _window: &mut Window,
21377        cx: &mut Context<Self>,
21378    ) {
21379        if event.blurred != self.focus_handle {
21380            self.last_focused_descendant = Some(event.blurred);
21381        }
21382        self.selection_drag_state = SelectionDragState::None;
21383        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21384    }
21385
21386    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21387        self.blink_manager.update(cx, BlinkManager::disable);
21388        self.buffer
21389            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21390
21391        if let Some(blame) = self.blame.as_ref() {
21392            blame.update(cx, GitBlame::blur)
21393        }
21394        if !self.hover_state.focused(window, cx) {
21395            hide_hover(self, cx);
21396        }
21397        if !self
21398            .context_menu
21399            .borrow()
21400            .as_ref()
21401            .is_some_and(|context_menu| context_menu.focused(window, cx))
21402        {
21403            self.hide_context_menu(window, cx);
21404        }
21405        self.discard_edit_prediction(false, cx);
21406        cx.emit(EditorEvent::Blurred);
21407        cx.notify();
21408    }
21409
21410    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21411        let mut pending: String = window
21412            .pending_input_keystrokes()
21413            .into_iter()
21414            .flatten()
21415            .filter_map(|keystroke| {
21416                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21417                    keystroke.key_char.clone()
21418                } else {
21419                    None
21420                }
21421            })
21422            .collect();
21423
21424        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21425            pending = "".to_string();
21426        }
21427
21428        let existing_pending = self
21429            .text_highlights::<PendingInput>(cx)
21430            .map(|(_, ranges)| ranges.to_vec());
21431        if existing_pending.is_none() && pending.is_empty() {
21432            return;
21433        }
21434        let transaction =
21435            self.transact(window, cx, |this, window, cx| {
21436                let selections = this.selections.all::<usize>(cx);
21437                let edits = selections
21438                    .iter()
21439                    .map(|selection| (selection.end..selection.end, pending.clone()));
21440                this.edit(edits, cx);
21441                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21442                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21443                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21444                    }));
21445                });
21446                if let Some(existing_ranges) = existing_pending {
21447                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21448                    this.edit(edits, cx);
21449                }
21450            });
21451
21452        let snapshot = self.snapshot(window, cx);
21453        let ranges = self
21454            .selections
21455            .all::<usize>(cx)
21456            .into_iter()
21457            .map(|selection| {
21458                snapshot.buffer_snapshot.anchor_after(selection.end)
21459                    ..snapshot
21460                        .buffer_snapshot
21461                        .anchor_before(selection.end + pending.len())
21462            })
21463            .collect();
21464
21465        if pending.is_empty() {
21466            self.clear_highlights::<PendingInput>(cx);
21467        } else {
21468            self.highlight_text::<PendingInput>(
21469                ranges,
21470                HighlightStyle {
21471                    underline: Some(UnderlineStyle {
21472                        thickness: px(1.),
21473                        color: None,
21474                        wavy: false,
21475                    }),
21476                    ..Default::default()
21477                },
21478                cx,
21479            );
21480        }
21481
21482        self.ime_transaction = self.ime_transaction.or(transaction);
21483        if let Some(transaction) = self.ime_transaction {
21484            self.buffer.update(cx, |buffer, cx| {
21485                buffer.group_until_transaction(transaction, cx);
21486            });
21487        }
21488
21489        if self.text_highlights::<PendingInput>(cx).is_none() {
21490            self.ime_transaction.take();
21491        }
21492    }
21493
21494    pub fn register_action_renderer(
21495        &mut self,
21496        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21497    ) -> Subscription {
21498        let id = self.next_editor_action_id.post_inc();
21499        self.editor_actions
21500            .borrow_mut()
21501            .insert(id, Box::new(listener));
21502
21503        let editor_actions = self.editor_actions.clone();
21504        Subscription::new(move || {
21505            editor_actions.borrow_mut().remove(&id);
21506        })
21507    }
21508
21509    pub fn register_action<A: Action>(
21510        &mut self,
21511        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21512    ) -> Subscription {
21513        let id = self.next_editor_action_id.post_inc();
21514        let listener = Arc::new(listener);
21515        self.editor_actions.borrow_mut().insert(
21516            id,
21517            Box::new(move |_, window, _| {
21518                let listener = listener.clone();
21519                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21520                    let action = action.downcast_ref().unwrap();
21521                    if phase == DispatchPhase::Bubble {
21522                        listener(action, window, cx)
21523                    }
21524                })
21525            }),
21526        );
21527
21528        let editor_actions = self.editor_actions.clone();
21529        Subscription::new(move || {
21530            editor_actions.borrow_mut().remove(&id);
21531        })
21532    }
21533
21534    pub fn file_header_size(&self) -> u32 {
21535        FILE_HEADER_HEIGHT
21536    }
21537
21538    pub fn restore(
21539        &mut self,
21540        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21541        window: &mut Window,
21542        cx: &mut Context<Self>,
21543    ) {
21544        let workspace = self.workspace();
21545        let project = self.project();
21546        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21547            let mut tasks = Vec::new();
21548            for (buffer_id, changes) in revert_changes {
21549                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21550                    buffer.update(cx, |buffer, cx| {
21551                        buffer.edit(
21552                            changes
21553                                .into_iter()
21554                                .map(|(range, text)| (range, text.to_string())),
21555                            None,
21556                            cx,
21557                        );
21558                    });
21559
21560                    if let Some(project) =
21561                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21562                    {
21563                        project.update(cx, |project, cx| {
21564                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21565                        })
21566                    }
21567                }
21568            }
21569            tasks
21570        });
21571        cx.spawn_in(window, async move |_, cx| {
21572            for (buffer, task) in save_tasks {
21573                let result = task.await;
21574                if result.is_err() {
21575                    let Some(path) = buffer
21576                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21577                        .ok()
21578                    else {
21579                        continue;
21580                    };
21581                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21582                        let Some(task) = cx
21583                            .update_window_entity(workspace, |workspace, window, cx| {
21584                                workspace
21585                                    .open_path_preview(path, None, false, false, false, window, cx)
21586                            })
21587                            .ok()
21588                        else {
21589                            continue;
21590                        };
21591                        task.await.log_err();
21592                    }
21593                }
21594            }
21595        })
21596        .detach();
21597        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21598            selections.refresh()
21599        });
21600    }
21601
21602    pub fn to_pixel_point(
21603        &self,
21604        source: multi_buffer::Anchor,
21605        editor_snapshot: &EditorSnapshot,
21606        window: &mut Window,
21607    ) -> Option<gpui::Point<Pixels>> {
21608        let source_point = source.to_display_point(editor_snapshot);
21609        self.display_to_pixel_point(source_point, editor_snapshot, window)
21610    }
21611
21612    pub fn display_to_pixel_point(
21613        &self,
21614        source: DisplayPoint,
21615        editor_snapshot: &EditorSnapshot,
21616        window: &mut Window,
21617    ) -> Option<gpui::Point<Pixels>> {
21618        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21619        let text_layout_details = self.text_layout_details(window);
21620        let scroll_top = text_layout_details
21621            .scroll_anchor
21622            .scroll_position(editor_snapshot)
21623            .y;
21624
21625        if source.row().as_f32() < scroll_top.floor() {
21626            return None;
21627        }
21628        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21629        let source_y = line_height * (source.row().as_f32() - scroll_top);
21630        Some(gpui::Point::new(source_x, source_y))
21631    }
21632
21633    pub fn has_visible_completions_menu(&self) -> bool {
21634        !self.edit_prediction_preview_is_active()
21635            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21636                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21637            })
21638    }
21639
21640    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21641        if self.mode.is_minimap() {
21642            return;
21643        }
21644        self.addons
21645            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21646    }
21647
21648    pub fn unregister_addon<T: Addon>(&mut self) {
21649        self.addons.remove(&std::any::TypeId::of::<T>());
21650    }
21651
21652    pub fn addon<T: Addon>(&self) -> Option<&T> {
21653        let type_id = std::any::TypeId::of::<T>();
21654        self.addons
21655            .get(&type_id)
21656            .and_then(|item| item.to_any().downcast_ref::<T>())
21657    }
21658
21659    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21660        let type_id = std::any::TypeId::of::<T>();
21661        self.addons
21662            .get_mut(&type_id)
21663            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21664    }
21665
21666    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21667        let text_layout_details = self.text_layout_details(window);
21668        let style = &text_layout_details.editor_style;
21669        let font_id = window.text_system().resolve_font(&style.text.font());
21670        let font_size = style.text.font_size.to_pixels(window.rem_size());
21671        let line_height = style.text.line_height_in_pixels(window.rem_size());
21672        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21673        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21674
21675        CharacterDimensions {
21676            em_width,
21677            em_advance,
21678            line_height,
21679        }
21680    }
21681
21682    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21683        self.load_diff_task.clone()
21684    }
21685
21686    fn read_metadata_from_db(
21687        &mut self,
21688        item_id: u64,
21689        workspace_id: WorkspaceId,
21690        window: &mut Window,
21691        cx: &mut Context<Editor>,
21692    ) {
21693        if self.is_singleton(cx)
21694            && !self.mode.is_minimap()
21695            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21696        {
21697            let buffer_snapshot = OnceCell::new();
21698
21699            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21700                && !folds.is_empty()
21701            {
21702                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21703                self.fold_ranges(
21704                    folds
21705                        .into_iter()
21706                        .map(|(start, end)| {
21707                            snapshot.clip_offset(start, Bias::Left)
21708                                ..snapshot.clip_offset(end, Bias::Right)
21709                        })
21710                        .collect(),
21711                    false,
21712                    window,
21713                    cx,
21714                );
21715            }
21716
21717            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21718                && !selections.is_empty()
21719            {
21720                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21721                // skip adding the initial selection to selection history
21722                self.selection_history.mode = SelectionHistoryMode::Skipping;
21723                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21724                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21725                        snapshot.clip_offset(start, Bias::Left)
21726                            ..snapshot.clip_offset(end, Bias::Right)
21727                    }));
21728                });
21729                self.selection_history.mode = SelectionHistoryMode::Normal;
21730            };
21731        }
21732
21733        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21734    }
21735
21736    fn update_lsp_data(
21737        &mut self,
21738        ignore_cache: bool,
21739        for_buffer: Option<BufferId>,
21740        window: &mut Window,
21741        cx: &mut Context<'_, Self>,
21742    ) {
21743        self.pull_diagnostics(for_buffer, window, cx);
21744        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21745    }
21746}
21747
21748fn edit_for_markdown_paste<'a>(
21749    buffer: &MultiBufferSnapshot,
21750    range: Range<usize>,
21751    to_insert: &'a str,
21752    url: Option<url::Url>,
21753) -> (Range<usize>, Cow<'a, str>) {
21754    if url.is_none() {
21755        return (range, Cow::Borrowed(to_insert));
21756    };
21757
21758    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21759
21760    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21761        Cow::Borrowed(to_insert)
21762    } else {
21763        Cow::Owned(format!("[{old_text}]({to_insert})"))
21764    };
21765    (range, new_text)
21766}
21767
21768fn vim_enabled(cx: &App) -> bool {
21769    vim_mode_setting::VimModeSetting::try_get(cx)
21770        .map(|vim_mode| vim_mode.0)
21771        .unwrap_or(false)
21772}
21773
21774fn process_completion_for_edit(
21775    completion: &Completion,
21776    intent: CompletionIntent,
21777    buffer: &Entity<Buffer>,
21778    cursor_position: &text::Anchor,
21779    cx: &mut Context<Editor>,
21780) -> CompletionEdit {
21781    let buffer = buffer.read(cx);
21782    let buffer_snapshot = buffer.snapshot();
21783    let (snippet, new_text) = if completion.is_snippet() {
21784        // Workaround for typescript language server issues so that methods don't expand within
21785        // strings and functions with type expressions. The previous point is used because the query
21786        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21787        let mut snippet_source = completion.new_text.clone();
21788        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21789        previous_point.column = previous_point.column.saturating_sub(1);
21790        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21791            && scope.prefers_label_for_snippet_in_completion()
21792            && let Some(label) = completion.label()
21793            && matches!(
21794                completion.kind(),
21795                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21796            )
21797        {
21798            snippet_source = label;
21799        }
21800        match Snippet::parse(&snippet_source).log_err() {
21801            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21802            None => (None, completion.new_text.clone()),
21803        }
21804    } else {
21805        (None, completion.new_text.clone())
21806    };
21807
21808    let mut range_to_replace = {
21809        let replace_range = &completion.replace_range;
21810        if let CompletionSource::Lsp {
21811            insert_range: Some(insert_range),
21812            ..
21813        } = &completion.source
21814        {
21815            debug_assert_eq!(
21816                insert_range.start, replace_range.start,
21817                "insert_range and replace_range should start at the same position"
21818            );
21819            debug_assert!(
21820                insert_range
21821                    .start
21822                    .cmp(cursor_position, &buffer_snapshot)
21823                    .is_le(),
21824                "insert_range should start before or at cursor position"
21825            );
21826            debug_assert!(
21827                replace_range
21828                    .start
21829                    .cmp(cursor_position, &buffer_snapshot)
21830                    .is_le(),
21831                "replace_range should start before or at cursor position"
21832            );
21833
21834            let should_replace = match intent {
21835                CompletionIntent::CompleteWithInsert => false,
21836                CompletionIntent::CompleteWithReplace => true,
21837                CompletionIntent::Complete | CompletionIntent::Compose => {
21838                    let insert_mode =
21839                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21840                            .completions
21841                            .lsp_insert_mode;
21842                    match insert_mode {
21843                        LspInsertMode::Insert => false,
21844                        LspInsertMode::Replace => true,
21845                        LspInsertMode::ReplaceSubsequence => {
21846                            let mut text_to_replace = buffer.chars_for_range(
21847                                buffer.anchor_before(replace_range.start)
21848                                    ..buffer.anchor_after(replace_range.end),
21849                            );
21850                            let mut current_needle = text_to_replace.next();
21851                            for haystack_ch in completion.label.text.chars() {
21852                                if let Some(needle_ch) = current_needle
21853                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21854                                {
21855                                    current_needle = text_to_replace.next();
21856                                }
21857                            }
21858                            current_needle.is_none()
21859                        }
21860                        LspInsertMode::ReplaceSuffix => {
21861                            if replace_range
21862                                .end
21863                                .cmp(cursor_position, &buffer_snapshot)
21864                                .is_gt()
21865                            {
21866                                let range_after_cursor = *cursor_position..replace_range.end;
21867                                let text_after_cursor = buffer
21868                                    .text_for_range(
21869                                        buffer.anchor_before(range_after_cursor.start)
21870                                            ..buffer.anchor_after(range_after_cursor.end),
21871                                    )
21872                                    .collect::<String>()
21873                                    .to_ascii_lowercase();
21874                                completion
21875                                    .label
21876                                    .text
21877                                    .to_ascii_lowercase()
21878                                    .ends_with(&text_after_cursor)
21879                            } else {
21880                                true
21881                            }
21882                        }
21883                    }
21884                }
21885            };
21886
21887            if should_replace {
21888                replace_range.clone()
21889            } else {
21890                insert_range.clone()
21891            }
21892        } else {
21893            replace_range.clone()
21894        }
21895    };
21896
21897    if range_to_replace
21898        .end
21899        .cmp(cursor_position, &buffer_snapshot)
21900        .is_lt()
21901    {
21902        range_to_replace.end = *cursor_position;
21903    }
21904
21905    CompletionEdit {
21906        new_text,
21907        replace_range: range_to_replace.to_offset(buffer),
21908        snippet,
21909    }
21910}
21911
21912struct CompletionEdit {
21913    new_text: String,
21914    replace_range: Range<usize>,
21915    snippet: Option<Snippet>,
21916}
21917
21918fn insert_extra_newline_brackets(
21919    buffer: &MultiBufferSnapshot,
21920    range: Range<usize>,
21921    language: &language::LanguageScope,
21922) -> bool {
21923    let leading_whitespace_len = buffer
21924        .reversed_chars_at(range.start)
21925        .take_while(|c| c.is_whitespace() && *c != '\n')
21926        .map(|c| c.len_utf8())
21927        .sum::<usize>();
21928    let trailing_whitespace_len = buffer
21929        .chars_at(range.end)
21930        .take_while(|c| c.is_whitespace() && *c != '\n')
21931        .map(|c| c.len_utf8())
21932        .sum::<usize>();
21933    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21934
21935    language.brackets().any(|(pair, enabled)| {
21936        let pair_start = pair.start.trim_end();
21937        let pair_end = pair.end.trim_start();
21938
21939        enabled
21940            && pair.newline
21941            && buffer.contains_str_at(range.end, pair_end)
21942            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21943    })
21944}
21945
21946fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21947    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21948        [(buffer, range, _)] => (*buffer, range.clone()),
21949        _ => return false,
21950    };
21951    let pair = {
21952        let mut result: Option<BracketMatch> = None;
21953
21954        for pair in buffer
21955            .all_bracket_ranges(range.clone())
21956            .filter(move |pair| {
21957                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21958            })
21959        {
21960            let len = pair.close_range.end - pair.open_range.start;
21961
21962            if let Some(existing) = &result {
21963                let existing_len = existing.close_range.end - existing.open_range.start;
21964                if len > existing_len {
21965                    continue;
21966                }
21967            }
21968
21969            result = Some(pair);
21970        }
21971
21972        result
21973    };
21974    let Some(pair) = pair else {
21975        return false;
21976    };
21977    pair.newline_only
21978        && buffer
21979            .chars_for_range(pair.open_range.end..range.start)
21980            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21981            .all(|c| c.is_whitespace() && c != '\n')
21982}
21983
21984fn update_uncommitted_diff_for_buffer(
21985    editor: Entity<Editor>,
21986    project: &Entity<Project>,
21987    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21988    buffer: Entity<MultiBuffer>,
21989    cx: &mut App,
21990) -> Task<()> {
21991    let mut tasks = Vec::new();
21992    project.update(cx, |project, cx| {
21993        for buffer in buffers {
21994            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21995                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21996            }
21997        }
21998    });
21999    cx.spawn(async move |cx| {
22000        let diffs = future::join_all(tasks).await;
22001        if editor
22002            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22003            .unwrap_or(false)
22004        {
22005            return;
22006        }
22007
22008        buffer
22009            .update(cx, |buffer, cx| {
22010                for diff in diffs.into_iter().flatten() {
22011                    buffer.add_diff(diff, cx);
22012                }
22013            })
22014            .ok();
22015    })
22016}
22017
22018fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22019    let tab_size = tab_size.get() as usize;
22020    let mut width = offset;
22021
22022    for ch in text.chars() {
22023        width += if ch == '\t' {
22024            tab_size - (width % tab_size)
22025        } else {
22026            1
22027        };
22028    }
22029
22030    width - offset
22031}
22032
22033#[cfg(test)]
22034mod tests {
22035    use super::*;
22036
22037    #[test]
22038    fn test_string_size_with_expanded_tabs() {
22039        let nz = |val| NonZeroU32::new(val).unwrap();
22040        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22041        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22042        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22043        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22044        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22045        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22046        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22047        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22048    }
22049}
22050
22051/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22052struct WordBreakingTokenizer<'a> {
22053    input: &'a str,
22054}
22055
22056impl<'a> WordBreakingTokenizer<'a> {
22057    fn new(input: &'a str) -> Self {
22058        Self { input }
22059    }
22060}
22061
22062fn is_char_ideographic(ch: char) -> bool {
22063    use unicode_script::Script::*;
22064    use unicode_script::UnicodeScript;
22065    matches!(ch.script(), Han | Tangut | Yi)
22066}
22067
22068fn is_grapheme_ideographic(text: &str) -> bool {
22069    text.chars().any(is_char_ideographic)
22070}
22071
22072fn is_grapheme_whitespace(text: &str) -> bool {
22073    text.chars().any(|x| x.is_whitespace())
22074}
22075
22076fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22077    text.chars()
22078        .next()
22079        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22080}
22081
22082#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22083enum WordBreakToken<'a> {
22084    Word { token: &'a str, grapheme_len: usize },
22085    InlineWhitespace { token: &'a str, grapheme_len: usize },
22086    Newline,
22087}
22088
22089impl<'a> Iterator for WordBreakingTokenizer<'a> {
22090    /// Yields a span, the count of graphemes in the token, and whether it was
22091    /// whitespace. Note that it also breaks at word boundaries.
22092    type Item = WordBreakToken<'a>;
22093
22094    fn next(&mut self) -> Option<Self::Item> {
22095        use unicode_segmentation::UnicodeSegmentation;
22096        if self.input.is_empty() {
22097            return None;
22098        }
22099
22100        let mut iter = self.input.graphemes(true).peekable();
22101        let mut offset = 0;
22102        let mut grapheme_len = 0;
22103        if let Some(first_grapheme) = iter.next() {
22104            let is_newline = first_grapheme == "\n";
22105            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22106            offset += first_grapheme.len();
22107            grapheme_len += 1;
22108            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22109                if let Some(grapheme) = iter.peek().copied()
22110                    && should_stay_with_preceding_ideograph(grapheme)
22111                {
22112                    offset += grapheme.len();
22113                    grapheme_len += 1;
22114                }
22115            } else {
22116                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22117                let mut next_word_bound = words.peek().copied();
22118                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22119                    next_word_bound = words.next();
22120                }
22121                while let Some(grapheme) = iter.peek().copied() {
22122                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22123                        break;
22124                    };
22125                    if is_grapheme_whitespace(grapheme) != is_whitespace
22126                        || (grapheme == "\n") != is_newline
22127                    {
22128                        break;
22129                    };
22130                    offset += grapheme.len();
22131                    grapheme_len += 1;
22132                    iter.next();
22133                }
22134            }
22135            let token = &self.input[..offset];
22136            self.input = &self.input[offset..];
22137            if token == "\n" {
22138                Some(WordBreakToken::Newline)
22139            } else if is_whitespace {
22140                Some(WordBreakToken::InlineWhitespace {
22141                    token,
22142                    grapheme_len,
22143                })
22144            } else {
22145                Some(WordBreakToken::Word {
22146                    token,
22147                    grapheme_len,
22148                })
22149            }
22150        } else {
22151            None
22152        }
22153    }
22154}
22155
22156#[test]
22157fn test_word_breaking_tokenizer() {
22158    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22159        ("", &[]),
22160        ("  ", &[whitespace("  ", 2)]),
22161        ("Ʒ", &[word("Ʒ", 1)]),
22162        ("Ǽ", &[word("Ǽ", 1)]),
22163        ("", &[word("", 1)]),
22164        ("⋑⋑", &[word("⋑⋑", 2)]),
22165        (
22166            "原理,进而",
22167            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22168        ),
22169        (
22170            "hello world",
22171            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22172        ),
22173        (
22174            "hello, world",
22175            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22176        ),
22177        (
22178            "  hello world",
22179            &[
22180                whitespace("  ", 2),
22181                word("hello", 5),
22182                whitespace(" ", 1),
22183                word("world", 5),
22184            ],
22185        ),
22186        (
22187            "这是什么 \n 钢笔",
22188            &[
22189                word("", 1),
22190                word("", 1),
22191                word("", 1),
22192                word("", 1),
22193                whitespace(" ", 1),
22194                newline(),
22195                whitespace(" ", 1),
22196                word("", 1),
22197                word("", 1),
22198            ],
22199        ),
22200        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22201    ];
22202
22203    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22204        WordBreakToken::Word {
22205            token,
22206            grapheme_len,
22207        }
22208    }
22209
22210    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22211        WordBreakToken::InlineWhitespace {
22212            token,
22213            grapheme_len,
22214        }
22215    }
22216
22217    fn newline() -> WordBreakToken<'static> {
22218        WordBreakToken::Newline
22219    }
22220
22221    for (input, result) in tests {
22222        assert_eq!(
22223            WordBreakingTokenizer::new(input)
22224                .collect::<Vec<_>>()
22225                .as_slice(),
22226            *result,
22227        );
22228    }
22229}
22230
22231fn wrap_with_prefix(
22232    first_line_prefix: String,
22233    subsequent_lines_prefix: String,
22234    unwrapped_text: String,
22235    wrap_column: usize,
22236    tab_size: NonZeroU32,
22237    preserve_existing_whitespace: bool,
22238) -> String {
22239    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22240    let subsequent_lines_prefix_len =
22241        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22242    let mut wrapped_text = String::new();
22243    let mut current_line = first_line_prefix;
22244    let mut is_first_line = true;
22245
22246    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22247    let mut current_line_len = first_line_prefix_len;
22248    let mut in_whitespace = false;
22249    for token in tokenizer {
22250        let have_preceding_whitespace = in_whitespace;
22251        match token {
22252            WordBreakToken::Word {
22253                token,
22254                grapheme_len,
22255            } => {
22256                in_whitespace = false;
22257                let current_prefix_len = if is_first_line {
22258                    first_line_prefix_len
22259                } else {
22260                    subsequent_lines_prefix_len
22261                };
22262                if current_line_len + grapheme_len > wrap_column
22263                    && current_line_len != current_prefix_len
22264                {
22265                    wrapped_text.push_str(current_line.trim_end());
22266                    wrapped_text.push('\n');
22267                    is_first_line = false;
22268                    current_line = subsequent_lines_prefix.clone();
22269                    current_line_len = subsequent_lines_prefix_len;
22270                }
22271                current_line.push_str(token);
22272                current_line_len += grapheme_len;
22273            }
22274            WordBreakToken::InlineWhitespace {
22275                mut token,
22276                mut grapheme_len,
22277            } => {
22278                in_whitespace = true;
22279                if have_preceding_whitespace && !preserve_existing_whitespace {
22280                    continue;
22281                }
22282                if !preserve_existing_whitespace {
22283                    token = " ";
22284                    grapheme_len = 1;
22285                }
22286                let current_prefix_len = if is_first_line {
22287                    first_line_prefix_len
22288                } else {
22289                    subsequent_lines_prefix_len
22290                };
22291                if current_line_len + grapheme_len > wrap_column {
22292                    wrapped_text.push_str(current_line.trim_end());
22293                    wrapped_text.push('\n');
22294                    is_first_line = false;
22295                    current_line = subsequent_lines_prefix.clone();
22296                    current_line_len = subsequent_lines_prefix_len;
22297                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22298                    current_line.push_str(token);
22299                    current_line_len += grapheme_len;
22300                }
22301            }
22302            WordBreakToken::Newline => {
22303                in_whitespace = true;
22304                let current_prefix_len = if is_first_line {
22305                    first_line_prefix_len
22306                } else {
22307                    subsequent_lines_prefix_len
22308                };
22309                if preserve_existing_whitespace {
22310                    wrapped_text.push_str(current_line.trim_end());
22311                    wrapped_text.push('\n');
22312                    is_first_line = false;
22313                    current_line = subsequent_lines_prefix.clone();
22314                    current_line_len = subsequent_lines_prefix_len;
22315                } else if have_preceding_whitespace {
22316                    continue;
22317                } else if current_line_len + 1 > wrap_column
22318                    && current_line_len != current_prefix_len
22319                {
22320                    wrapped_text.push_str(current_line.trim_end());
22321                    wrapped_text.push('\n');
22322                    is_first_line = false;
22323                    current_line = subsequent_lines_prefix.clone();
22324                    current_line_len = subsequent_lines_prefix_len;
22325                } else if current_line_len != current_prefix_len {
22326                    current_line.push(' ');
22327                    current_line_len += 1;
22328                }
22329            }
22330        }
22331    }
22332
22333    if !current_line.is_empty() {
22334        wrapped_text.push_str(&current_line);
22335    }
22336    wrapped_text
22337}
22338
22339#[test]
22340fn test_wrap_with_prefix() {
22341    assert_eq!(
22342        wrap_with_prefix(
22343            "# ".to_string(),
22344            "# ".to_string(),
22345            "abcdefg".to_string(),
22346            4,
22347            NonZeroU32::new(4).unwrap(),
22348            false,
22349        ),
22350        "# abcdefg"
22351    );
22352    assert_eq!(
22353        wrap_with_prefix(
22354            "".to_string(),
22355            "".to_string(),
22356            "\thello world".to_string(),
22357            8,
22358            NonZeroU32::new(4).unwrap(),
22359            false,
22360        ),
22361        "hello\nworld"
22362    );
22363    assert_eq!(
22364        wrap_with_prefix(
22365            "// ".to_string(),
22366            "// ".to_string(),
22367            "xx \nyy zz aa bb cc".to_string(),
22368            12,
22369            NonZeroU32::new(4).unwrap(),
22370            false,
22371        ),
22372        "// xx yy zz\n// aa bb cc"
22373    );
22374    assert_eq!(
22375        wrap_with_prefix(
22376            String::new(),
22377            String::new(),
22378            "这是什么 \n 钢笔".to_string(),
22379            3,
22380            NonZeroU32::new(4).unwrap(),
22381            false,
22382        ),
22383        "这是什\n么 钢\n"
22384    );
22385}
22386
22387pub trait CollaborationHub {
22388    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22389    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22390    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22391}
22392
22393impl CollaborationHub for Entity<Project> {
22394    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22395        self.read(cx).collaborators()
22396    }
22397
22398    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22399        self.read(cx).user_store().read(cx).participant_indices()
22400    }
22401
22402    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22403        let this = self.read(cx);
22404        let user_ids = this.collaborators().values().map(|c| c.user_id);
22405        this.user_store().read(cx).participant_names(user_ids, cx)
22406    }
22407}
22408
22409pub trait SemanticsProvider {
22410    fn hover(
22411        &self,
22412        buffer: &Entity<Buffer>,
22413        position: text::Anchor,
22414        cx: &mut App,
22415    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22416
22417    fn inline_values(
22418        &self,
22419        buffer_handle: Entity<Buffer>,
22420        range: Range<text::Anchor>,
22421        cx: &mut App,
22422    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22423
22424    fn inlay_hints(
22425        &self,
22426        buffer_handle: Entity<Buffer>,
22427        range: Range<text::Anchor>,
22428        cx: &mut App,
22429    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22430
22431    fn resolve_inlay_hint(
22432        &self,
22433        hint: InlayHint,
22434        buffer_handle: Entity<Buffer>,
22435        server_id: LanguageServerId,
22436        cx: &mut App,
22437    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22438
22439    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22440
22441    fn document_highlights(
22442        &self,
22443        buffer: &Entity<Buffer>,
22444        position: text::Anchor,
22445        cx: &mut App,
22446    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22447
22448    fn definitions(
22449        &self,
22450        buffer: &Entity<Buffer>,
22451        position: text::Anchor,
22452        kind: GotoDefinitionKind,
22453        cx: &mut App,
22454    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22455
22456    fn range_for_rename(
22457        &self,
22458        buffer: &Entity<Buffer>,
22459        position: text::Anchor,
22460        cx: &mut App,
22461    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22462
22463    fn perform_rename(
22464        &self,
22465        buffer: &Entity<Buffer>,
22466        position: text::Anchor,
22467        new_name: String,
22468        cx: &mut App,
22469    ) -> Option<Task<Result<ProjectTransaction>>>;
22470}
22471
22472pub trait CompletionProvider {
22473    fn completions(
22474        &self,
22475        excerpt_id: ExcerptId,
22476        buffer: &Entity<Buffer>,
22477        buffer_position: text::Anchor,
22478        trigger: CompletionContext,
22479        window: &mut Window,
22480        cx: &mut Context<Editor>,
22481    ) -> Task<Result<Vec<CompletionResponse>>>;
22482
22483    fn resolve_completions(
22484        &self,
22485        _buffer: Entity<Buffer>,
22486        _completion_indices: Vec<usize>,
22487        _completions: Rc<RefCell<Box<[Completion]>>>,
22488        _cx: &mut Context<Editor>,
22489    ) -> Task<Result<bool>> {
22490        Task::ready(Ok(false))
22491    }
22492
22493    fn apply_additional_edits_for_completion(
22494        &self,
22495        _buffer: Entity<Buffer>,
22496        _completions: Rc<RefCell<Box<[Completion]>>>,
22497        _completion_index: usize,
22498        _push_to_history: bool,
22499        _cx: &mut Context<Editor>,
22500    ) -> Task<Result<Option<language::Transaction>>> {
22501        Task::ready(Ok(None))
22502    }
22503
22504    fn is_completion_trigger(
22505        &self,
22506        buffer: &Entity<Buffer>,
22507        position: language::Anchor,
22508        text: &str,
22509        trigger_in_words: bool,
22510        menu_is_open: bool,
22511        cx: &mut Context<Editor>,
22512    ) -> bool;
22513
22514    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22515
22516    fn sort_completions(&self) -> bool {
22517        true
22518    }
22519
22520    fn filter_completions(&self) -> bool {
22521        true
22522    }
22523}
22524
22525pub trait CodeActionProvider {
22526    fn id(&self) -> Arc<str>;
22527
22528    fn code_actions(
22529        &self,
22530        buffer: &Entity<Buffer>,
22531        range: Range<text::Anchor>,
22532        window: &mut Window,
22533        cx: &mut App,
22534    ) -> Task<Result<Vec<CodeAction>>>;
22535
22536    fn apply_code_action(
22537        &self,
22538        buffer_handle: Entity<Buffer>,
22539        action: CodeAction,
22540        excerpt_id: ExcerptId,
22541        push_to_history: bool,
22542        window: &mut Window,
22543        cx: &mut App,
22544    ) -> Task<Result<ProjectTransaction>>;
22545}
22546
22547impl CodeActionProvider for Entity<Project> {
22548    fn id(&self) -> Arc<str> {
22549        "project".into()
22550    }
22551
22552    fn code_actions(
22553        &self,
22554        buffer: &Entity<Buffer>,
22555        range: Range<text::Anchor>,
22556        _window: &mut Window,
22557        cx: &mut App,
22558    ) -> Task<Result<Vec<CodeAction>>> {
22559        self.update(cx, |project, cx| {
22560            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22561            let code_actions = project.code_actions(buffer, range, None, cx);
22562            cx.background_spawn(async move {
22563                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22564                Ok(code_lens_actions
22565                    .context("code lens fetch")?
22566                    .into_iter()
22567                    .flatten()
22568                    .chain(
22569                        code_actions
22570                            .context("code action fetch")?
22571                            .into_iter()
22572                            .flatten(),
22573                    )
22574                    .collect())
22575            })
22576        })
22577    }
22578
22579    fn apply_code_action(
22580        &self,
22581        buffer_handle: Entity<Buffer>,
22582        action: CodeAction,
22583        _excerpt_id: ExcerptId,
22584        push_to_history: bool,
22585        _window: &mut Window,
22586        cx: &mut App,
22587    ) -> Task<Result<ProjectTransaction>> {
22588        self.update(cx, |project, cx| {
22589            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22590        })
22591    }
22592}
22593
22594fn snippet_completions(
22595    project: &Project,
22596    buffer: &Entity<Buffer>,
22597    buffer_position: text::Anchor,
22598    cx: &mut App,
22599) -> Task<Result<CompletionResponse>> {
22600    let languages = buffer.read(cx).languages_at(buffer_position);
22601    let snippet_store = project.snippets().read(cx);
22602
22603    let scopes: Vec<_> = languages
22604        .iter()
22605        .filter_map(|language| {
22606            let language_name = language.lsp_id();
22607            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22608
22609            if snippets.is_empty() {
22610                None
22611            } else {
22612                Some((language.default_scope(), snippets))
22613            }
22614        })
22615        .collect();
22616
22617    if scopes.is_empty() {
22618        return Task::ready(Ok(CompletionResponse {
22619            completions: vec![],
22620            display_options: CompletionDisplayOptions::default(),
22621            is_incomplete: false,
22622        }));
22623    }
22624
22625    let snapshot = buffer.read(cx).text_snapshot();
22626    let chars: String = snapshot
22627        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22628        .collect();
22629    let executor = cx.background_executor().clone();
22630
22631    cx.background_spawn(async move {
22632        let mut is_incomplete = false;
22633        let mut completions: Vec<Completion> = Vec::new();
22634        for (scope, snippets) in scopes.into_iter() {
22635            let classifier =
22636                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22637            let mut last_word = chars
22638                .chars()
22639                .take_while(|c| classifier.is_word(*c))
22640                .collect::<String>();
22641            last_word = last_word.chars().rev().collect();
22642
22643            if last_word.is_empty() {
22644                return Ok(CompletionResponse {
22645                    completions: vec![],
22646                    display_options: CompletionDisplayOptions::default(),
22647                    is_incomplete: true,
22648                });
22649            }
22650
22651            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22652            let to_lsp = |point: &text::Anchor| {
22653                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22654                point_to_lsp(end)
22655            };
22656            let lsp_end = to_lsp(&buffer_position);
22657
22658            let candidates = snippets
22659                .iter()
22660                .enumerate()
22661                .flat_map(|(ix, snippet)| {
22662                    snippet
22663                        .prefix
22664                        .iter()
22665                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22666                })
22667                .collect::<Vec<StringMatchCandidate>>();
22668
22669            const MAX_RESULTS: usize = 100;
22670            let mut matches = fuzzy::match_strings(
22671                &candidates,
22672                &last_word,
22673                last_word.chars().any(|c| c.is_uppercase()),
22674                true,
22675                MAX_RESULTS,
22676                &Default::default(),
22677                executor.clone(),
22678            )
22679            .await;
22680
22681            if matches.len() >= MAX_RESULTS {
22682                is_incomplete = true;
22683            }
22684
22685            // Remove all candidates where the query's start does not match the start of any word in the candidate
22686            if let Some(query_start) = last_word.chars().next() {
22687                matches.retain(|string_match| {
22688                    split_words(&string_match.string).any(|word| {
22689                        // Check that the first codepoint of the word as lowercase matches the first
22690                        // codepoint of the query as lowercase
22691                        word.chars()
22692                            .flat_map(|codepoint| codepoint.to_lowercase())
22693                            .zip(query_start.to_lowercase())
22694                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22695                    })
22696                });
22697            }
22698
22699            let matched_strings = matches
22700                .into_iter()
22701                .map(|m| m.string)
22702                .collect::<HashSet<_>>();
22703
22704            completions.extend(snippets.iter().filter_map(|snippet| {
22705                let matching_prefix = snippet
22706                    .prefix
22707                    .iter()
22708                    .find(|prefix| matched_strings.contains(*prefix))?;
22709                let start = as_offset - last_word.len();
22710                let start = snapshot.anchor_before(start);
22711                let range = start..buffer_position;
22712                let lsp_start = to_lsp(&start);
22713                let lsp_range = lsp::Range {
22714                    start: lsp_start,
22715                    end: lsp_end,
22716                };
22717                Some(Completion {
22718                    replace_range: range,
22719                    new_text: snippet.body.clone(),
22720                    source: CompletionSource::Lsp {
22721                        insert_range: None,
22722                        server_id: LanguageServerId(usize::MAX),
22723                        resolved: true,
22724                        lsp_completion: Box::new(lsp::CompletionItem {
22725                            label: snippet.prefix.first().unwrap().clone(),
22726                            kind: Some(CompletionItemKind::SNIPPET),
22727                            label_details: snippet.description.as_ref().map(|description| {
22728                                lsp::CompletionItemLabelDetails {
22729                                    detail: Some(description.clone()),
22730                                    description: None,
22731                                }
22732                            }),
22733                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22734                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22735                                lsp::InsertReplaceEdit {
22736                                    new_text: snippet.body.clone(),
22737                                    insert: lsp_range,
22738                                    replace: lsp_range,
22739                                },
22740                            )),
22741                            filter_text: Some(snippet.body.clone()),
22742                            sort_text: Some(char::MAX.to_string()),
22743                            ..lsp::CompletionItem::default()
22744                        }),
22745                        lsp_defaults: None,
22746                    },
22747                    label: CodeLabel {
22748                        text: matching_prefix.clone(),
22749                        runs: Vec::new(),
22750                        filter_range: 0..matching_prefix.len(),
22751                    },
22752                    icon_path: None,
22753                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22754                        single_line: snippet.name.clone().into(),
22755                        plain_text: snippet
22756                            .description
22757                            .clone()
22758                            .map(|description| description.into()),
22759                    }),
22760                    insert_text_mode: None,
22761                    confirm: None,
22762                })
22763            }))
22764        }
22765
22766        Ok(CompletionResponse {
22767            completions,
22768            display_options: CompletionDisplayOptions::default(),
22769            is_incomplete,
22770        })
22771    })
22772}
22773
22774impl CompletionProvider for Entity<Project> {
22775    fn completions(
22776        &self,
22777        _excerpt_id: ExcerptId,
22778        buffer: &Entity<Buffer>,
22779        buffer_position: text::Anchor,
22780        options: CompletionContext,
22781        _window: &mut Window,
22782        cx: &mut Context<Editor>,
22783    ) -> Task<Result<Vec<CompletionResponse>>> {
22784        self.update(cx, |project, cx| {
22785            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22786            let project_completions = project.completions(buffer, buffer_position, options, cx);
22787            cx.background_spawn(async move {
22788                let mut responses = project_completions.await?;
22789                let snippets = snippets.await?;
22790                if !snippets.completions.is_empty() {
22791                    responses.push(snippets);
22792                }
22793                Ok(responses)
22794            })
22795        })
22796    }
22797
22798    fn resolve_completions(
22799        &self,
22800        buffer: Entity<Buffer>,
22801        completion_indices: Vec<usize>,
22802        completions: Rc<RefCell<Box<[Completion]>>>,
22803        cx: &mut Context<Editor>,
22804    ) -> Task<Result<bool>> {
22805        self.update(cx, |project, cx| {
22806            project.lsp_store().update(cx, |lsp_store, cx| {
22807                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22808            })
22809        })
22810    }
22811
22812    fn apply_additional_edits_for_completion(
22813        &self,
22814        buffer: Entity<Buffer>,
22815        completions: Rc<RefCell<Box<[Completion]>>>,
22816        completion_index: usize,
22817        push_to_history: bool,
22818        cx: &mut Context<Editor>,
22819    ) -> Task<Result<Option<language::Transaction>>> {
22820        self.update(cx, |project, cx| {
22821            project.lsp_store().update(cx, |lsp_store, cx| {
22822                lsp_store.apply_additional_edits_for_completion(
22823                    buffer,
22824                    completions,
22825                    completion_index,
22826                    push_to_history,
22827                    cx,
22828                )
22829            })
22830        })
22831    }
22832
22833    fn is_completion_trigger(
22834        &self,
22835        buffer: &Entity<Buffer>,
22836        position: language::Anchor,
22837        text: &str,
22838        trigger_in_words: bool,
22839        menu_is_open: bool,
22840        cx: &mut Context<Editor>,
22841    ) -> bool {
22842        let mut chars = text.chars();
22843        let char = if let Some(char) = chars.next() {
22844            char
22845        } else {
22846            return false;
22847        };
22848        if chars.next().is_some() {
22849            return false;
22850        }
22851
22852        let buffer = buffer.read(cx);
22853        let snapshot = buffer.snapshot();
22854        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22855            return false;
22856        }
22857        let classifier = snapshot
22858            .char_classifier_at(position)
22859            .scope_context(Some(CharScopeContext::Completion));
22860        if trigger_in_words && classifier.is_word(char) {
22861            return true;
22862        }
22863
22864        buffer.completion_triggers().contains(text)
22865    }
22866}
22867
22868impl SemanticsProvider for Entity<Project> {
22869    fn hover(
22870        &self,
22871        buffer: &Entity<Buffer>,
22872        position: text::Anchor,
22873        cx: &mut App,
22874    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22875        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22876    }
22877
22878    fn document_highlights(
22879        &self,
22880        buffer: &Entity<Buffer>,
22881        position: text::Anchor,
22882        cx: &mut App,
22883    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22884        Some(self.update(cx, |project, cx| {
22885            project.document_highlights(buffer, position, cx)
22886        }))
22887    }
22888
22889    fn definitions(
22890        &self,
22891        buffer: &Entity<Buffer>,
22892        position: text::Anchor,
22893        kind: GotoDefinitionKind,
22894        cx: &mut App,
22895    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22896        Some(self.update(cx, |project, cx| match kind {
22897            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22898            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22899            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22900            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22901        }))
22902    }
22903
22904    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22905        self.update(cx, |project, cx| {
22906            if project
22907                .active_debug_session(cx)
22908                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22909            {
22910                return true;
22911            }
22912
22913            buffer.update(cx, |buffer, cx| {
22914                project.any_language_server_supports_inlay_hints(buffer, cx)
22915            })
22916        })
22917    }
22918
22919    fn inline_values(
22920        &self,
22921        buffer_handle: Entity<Buffer>,
22922        range: Range<text::Anchor>,
22923        cx: &mut App,
22924    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22925        self.update(cx, |project, cx| {
22926            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22927
22928            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22929        })
22930    }
22931
22932    fn inlay_hints(
22933        &self,
22934        buffer_handle: Entity<Buffer>,
22935        range: Range<text::Anchor>,
22936        cx: &mut App,
22937    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22938        Some(self.update(cx, |project, cx| {
22939            project.inlay_hints(buffer_handle, range, cx)
22940        }))
22941    }
22942
22943    fn resolve_inlay_hint(
22944        &self,
22945        hint: InlayHint,
22946        buffer_handle: Entity<Buffer>,
22947        server_id: LanguageServerId,
22948        cx: &mut App,
22949    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22950        Some(self.update(cx, |project, cx| {
22951            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22952        }))
22953    }
22954
22955    fn range_for_rename(
22956        &self,
22957        buffer: &Entity<Buffer>,
22958        position: text::Anchor,
22959        cx: &mut App,
22960    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22961        Some(self.update(cx, |project, cx| {
22962            let buffer = buffer.clone();
22963            let task = project.prepare_rename(buffer.clone(), position, cx);
22964            cx.spawn(async move |_, cx| {
22965                Ok(match task.await? {
22966                    PrepareRenameResponse::Success(range) => Some(range),
22967                    PrepareRenameResponse::InvalidPosition => None,
22968                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22969                        // Fallback on using TreeSitter info to determine identifier range
22970                        buffer.read_with(cx, |buffer, _| {
22971                            let snapshot = buffer.snapshot();
22972                            let (range, kind) = snapshot.surrounding_word(position, None);
22973                            if kind != Some(CharKind::Word) {
22974                                return None;
22975                            }
22976                            Some(
22977                                snapshot.anchor_before(range.start)
22978                                    ..snapshot.anchor_after(range.end),
22979                            )
22980                        })?
22981                    }
22982                })
22983            })
22984        }))
22985    }
22986
22987    fn perform_rename(
22988        &self,
22989        buffer: &Entity<Buffer>,
22990        position: text::Anchor,
22991        new_name: String,
22992        cx: &mut App,
22993    ) -> Option<Task<Result<ProjectTransaction>>> {
22994        Some(self.update(cx, |project, cx| {
22995            project.perform_rename(buffer.clone(), position, new_name, cx)
22996        }))
22997    }
22998}
22999
23000fn inlay_hint_settings(
23001    location: Anchor,
23002    snapshot: &MultiBufferSnapshot,
23003    cx: &mut Context<Editor>,
23004) -> InlayHintSettings {
23005    let file = snapshot.file_at(location);
23006    let language = snapshot.language_at(location).map(|l| l.name());
23007    language_settings(language, file, cx).inlay_hints
23008}
23009
23010fn consume_contiguous_rows(
23011    contiguous_row_selections: &mut Vec<Selection<Point>>,
23012    selection: &Selection<Point>,
23013    display_map: &DisplaySnapshot,
23014    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23015) -> (MultiBufferRow, MultiBufferRow) {
23016    contiguous_row_selections.push(selection.clone());
23017    let start_row = starting_row(selection, display_map);
23018    let mut end_row = ending_row(selection, display_map);
23019
23020    while let Some(next_selection) = selections.peek() {
23021        if next_selection.start.row <= end_row.0 {
23022            end_row = ending_row(next_selection, display_map);
23023            contiguous_row_selections.push(selections.next().unwrap().clone());
23024        } else {
23025            break;
23026        }
23027    }
23028    (start_row, end_row)
23029}
23030
23031fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23032    if selection.start.column > 0 {
23033        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23034    } else {
23035        MultiBufferRow(selection.start.row)
23036    }
23037}
23038
23039fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23040    if next_selection.end.column > 0 || next_selection.is_empty() {
23041        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23042    } else {
23043        MultiBufferRow(next_selection.end.row)
23044    }
23045}
23046
23047impl EditorSnapshot {
23048    pub fn remote_selections_in_range<'a>(
23049        &'a self,
23050        range: &'a Range<Anchor>,
23051        collaboration_hub: &dyn CollaborationHub,
23052        cx: &'a App,
23053    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23054        let participant_names = collaboration_hub.user_names(cx);
23055        let participant_indices = collaboration_hub.user_participant_indices(cx);
23056        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23057        let collaborators_by_replica_id = collaborators_by_peer_id
23058            .values()
23059            .map(|collaborator| (collaborator.replica_id, collaborator))
23060            .collect::<HashMap<_, _>>();
23061        self.buffer_snapshot
23062            .selections_in_range(range, false)
23063            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23064                if replica_id == AGENT_REPLICA_ID {
23065                    Some(RemoteSelection {
23066                        replica_id,
23067                        selection,
23068                        cursor_shape,
23069                        line_mode,
23070                        collaborator_id: CollaboratorId::Agent,
23071                        user_name: Some("Agent".into()),
23072                        color: cx.theme().players().agent(),
23073                    })
23074                } else {
23075                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23076                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23077                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23078                    Some(RemoteSelection {
23079                        replica_id,
23080                        selection,
23081                        cursor_shape,
23082                        line_mode,
23083                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23084                        user_name,
23085                        color: if let Some(index) = participant_index {
23086                            cx.theme().players().color_for_participant(index.0)
23087                        } else {
23088                            cx.theme().players().absent()
23089                        },
23090                    })
23091                }
23092            })
23093    }
23094
23095    pub fn hunks_for_ranges(
23096        &self,
23097        ranges: impl IntoIterator<Item = Range<Point>>,
23098    ) -> Vec<MultiBufferDiffHunk> {
23099        let mut hunks = Vec::new();
23100        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23101            HashMap::default();
23102        for query_range in ranges {
23103            let query_rows =
23104                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23105            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23106                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23107            ) {
23108                // Include deleted hunks that are adjacent to the query range, because
23109                // otherwise they would be missed.
23110                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23111                if hunk.status().is_deleted() {
23112                    intersects_range |= hunk.row_range.start == query_rows.end;
23113                    intersects_range |= hunk.row_range.end == query_rows.start;
23114                }
23115                if intersects_range {
23116                    if !processed_buffer_rows
23117                        .entry(hunk.buffer_id)
23118                        .or_default()
23119                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23120                    {
23121                        continue;
23122                    }
23123                    hunks.push(hunk);
23124                }
23125            }
23126        }
23127
23128        hunks
23129    }
23130
23131    fn display_diff_hunks_for_rows<'a>(
23132        &'a self,
23133        display_rows: Range<DisplayRow>,
23134        folded_buffers: &'a HashSet<BufferId>,
23135    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23136        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23137        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23138
23139        self.buffer_snapshot
23140            .diff_hunks_in_range(buffer_start..buffer_end)
23141            .filter_map(|hunk| {
23142                if folded_buffers.contains(&hunk.buffer_id) {
23143                    return None;
23144                }
23145
23146                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23147                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23148
23149                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23150                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23151
23152                let display_hunk = if hunk_display_start.column() != 0 {
23153                    DisplayDiffHunk::Folded {
23154                        display_row: hunk_display_start.row(),
23155                    }
23156                } else {
23157                    let mut end_row = hunk_display_end.row();
23158                    if hunk_display_end.column() > 0 {
23159                        end_row.0 += 1;
23160                    }
23161                    let is_created_file = hunk.is_created_file();
23162                    DisplayDiffHunk::Unfolded {
23163                        status: hunk.status(),
23164                        diff_base_byte_range: hunk.diff_base_byte_range,
23165                        display_row_range: hunk_display_start.row()..end_row,
23166                        multi_buffer_range: Anchor::range_in_buffer(
23167                            hunk.excerpt_id,
23168                            hunk.buffer_id,
23169                            hunk.buffer_range,
23170                        ),
23171                        is_created_file,
23172                    }
23173                };
23174
23175                Some(display_hunk)
23176            })
23177    }
23178
23179    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23180        self.display_snapshot.buffer_snapshot.language_at(position)
23181    }
23182
23183    pub fn is_focused(&self) -> bool {
23184        self.is_focused
23185    }
23186
23187    pub fn placeholder_text(&self) -> Option<String> {
23188        self.placeholder_display_snapshot
23189            .as_ref()
23190            .map(|display_map| display_map.text())
23191    }
23192
23193    pub fn scroll_position(&self) -> gpui::Point<f32> {
23194        self.scroll_anchor.scroll_position(&self.display_snapshot)
23195    }
23196
23197    fn gutter_dimensions(
23198        &self,
23199        font_id: FontId,
23200        font_size: Pixels,
23201        max_line_number_width: Pixels,
23202        cx: &App,
23203    ) -> Option<GutterDimensions> {
23204        if !self.show_gutter {
23205            return None;
23206        }
23207
23208        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23209        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23210
23211        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23212            matches!(
23213                ProjectSettings::get_global(cx).git.git_gutter,
23214                GitGutterSetting::TrackedFiles
23215            )
23216        });
23217        let gutter_settings = EditorSettings::get_global(cx).gutter;
23218        let show_line_numbers = self
23219            .show_line_numbers
23220            .unwrap_or(gutter_settings.line_numbers);
23221        let line_gutter_width = if show_line_numbers {
23222            // Avoid flicker-like gutter resizes when the line number gains another digit by
23223            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23224            let min_width_for_number_on_gutter =
23225                ch_advance * gutter_settings.min_line_number_digits as f32;
23226            max_line_number_width.max(min_width_for_number_on_gutter)
23227        } else {
23228            0.0.into()
23229        };
23230
23231        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23232        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23233
23234        let git_blame_entries_width =
23235            self.git_blame_gutter_max_author_length
23236                .map(|max_author_length| {
23237                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23238                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23239
23240                    /// The number of characters to dedicate to gaps and margins.
23241                    const SPACING_WIDTH: usize = 4;
23242
23243                    let max_char_count = max_author_length.min(renderer.max_author_length())
23244                        + ::git::SHORT_SHA_LENGTH
23245                        + MAX_RELATIVE_TIMESTAMP.len()
23246                        + SPACING_WIDTH;
23247
23248                    ch_advance * max_char_count
23249                });
23250
23251        let is_singleton = self.buffer_snapshot.is_singleton();
23252
23253        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23254        left_padding += if !is_singleton {
23255            ch_width * 4.0
23256        } else if show_runnables || show_breakpoints {
23257            ch_width * 3.0
23258        } else if show_git_gutter && show_line_numbers {
23259            ch_width * 2.0
23260        } else if show_git_gutter || show_line_numbers {
23261            ch_width
23262        } else {
23263            px(0.)
23264        };
23265
23266        let shows_folds = is_singleton && gutter_settings.folds;
23267
23268        let right_padding = if shows_folds && show_line_numbers {
23269            ch_width * 4.0
23270        } else if shows_folds || (!is_singleton && show_line_numbers) {
23271            ch_width * 3.0
23272        } else if show_line_numbers {
23273            ch_width
23274        } else {
23275            px(0.)
23276        };
23277
23278        Some(GutterDimensions {
23279            left_padding,
23280            right_padding,
23281            width: line_gutter_width + left_padding + right_padding,
23282            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23283            git_blame_entries_width,
23284        })
23285    }
23286
23287    pub fn render_crease_toggle(
23288        &self,
23289        buffer_row: MultiBufferRow,
23290        row_contains_cursor: bool,
23291        editor: Entity<Editor>,
23292        window: &mut Window,
23293        cx: &mut App,
23294    ) -> Option<AnyElement> {
23295        let folded = self.is_line_folded(buffer_row);
23296        let mut is_foldable = false;
23297
23298        if let Some(crease) = self
23299            .crease_snapshot
23300            .query_row(buffer_row, &self.buffer_snapshot)
23301        {
23302            is_foldable = true;
23303            match crease {
23304                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23305                    if let Some(render_toggle) = render_toggle {
23306                        let toggle_callback =
23307                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23308                                if folded {
23309                                    editor.update(cx, |editor, cx| {
23310                                        editor.fold_at(buffer_row, window, cx)
23311                                    });
23312                                } else {
23313                                    editor.update(cx, |editor, cx| {
23314                                        editor.unfold_at(buffer_row, window, cx)
23315                                    });
23316                                }
23317                            });
23318                        return Some((render_toggle)(
23319                            buffer_row,
23320                            folded,
23321                            toggle_callback,
23322                            window,
23323                            cx,
23324                        ));
23325                    }
23326                }
23327            }
23328        }
23329
23330        is_foldable |= self.starts_indent(buffer_row);
23331
23332        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23333            Some(
23334                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23335                    .toggle_state(folded)
23336                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23337                        if folded {
23338                            this.unfold_at(buffer_row, window, cx);
23339                        } else {
23340                            this.fold_at(buffer_row, window, cx);
23341                        }
23342                    }))
23343                    .into_any_element(),
23344            )
23345        } else {
23346            None
23347        }
23348    }
23349
23350    pub fn render_crease_trailer(
23351        &self,
23352        buffer_row: MultiBufferRow,
23353        window: &mut Window,
23354        cx: &mut App,
23355    ) -> Option<AnyElement> {
23356        let folded = self.is_line_folded(buffer_row);
23357        if let Crease::Inline { render_trailer, .. } = self
23358            .crease_snapshot
23359            .query_row(buffer_row, &self.buffer_snapshot)?
23360        {
23361            let render_trailer = render_trailer.as_ref()?;
23362            Some(render_trailer(buffer_row, folded, window, cx))
23363        } else {
23364            None
23365        }
23366    }
23367}
23368
23369impl Deref for EditorSnapshot {
23370    type Target = DisplaySnapshot;
23371
23372    fn deref(&self) -> &Self::Target {
23373        &self.display_snapshot
23374    }
23375}
23376
23377#[derive(Clone, Debug, PartialEq, Eq)]
23378pub enum EditorEvent {
23379    InputIgnored {
23380        text: Arc<str>,
23381    },
23382    InputHandled {
23383        utf16_range_to_replace: Option<Range<isize>>,
23384        text: Arc<str>,
23385    },
23386    ExcerptsAdded {
23387        buffer: Entity<Buffer>,
23388        predecessor: ExcerptId,
23389        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23390    },
23391    ExcerptsRemoved {
23392        ids: Vec<ExcerptId>,
23393        removed_buffer_ids: Vec<BufferId>,
23394    },
23395    BufferFoldToggled {
23396        ids: Vec<ExcerptId>,
23397        folded: bool,
23398    },
23399    ExcerptsEdited {
23400        ids: Vec<ExcerptId>,
23401    },
23402    ExcerptsExpanded {
23403        ids: Vec<ExcerptId>,
23404    },
23405    BufferEdited,
23406    Edited {
23407        transaction_id: clock::Lamport,
23408    },
23409    Reparsed(BufferId),
23410    Focused,
23411    FocusedIn,
23412    Blurred,
23413    DirtyChanged,
23414    Saved,
23415    TitleChanged,
23416    SelectionsChanged {
23417        local: bool,
23418    },
23419    ScrollPositionChanged {
23420        local: bool,
23421        autoscroll: bool,
23422    },
23423    TransactionUndone {
23424        transaction_id: clock::Lamport,
23425    },
23426    TransactionBegun {
23427        transaction_id: clock::Lamport,
23428    },
23429    CursorShapeChanged,
23430    BreadcrumbsChanged,
23431    PushedToNavHistory {
23432        anchor: Anchor,
23433        is_deactivate: bool,
23434    },
23435}
23436
23437impl EventEmitter<EditorEvent> for Editor {}
23438
23439impl Focusable for Editor {
23440    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23441        self.focus_handle.clone()
23442    }
23443}
23444
23445impl Render for Editor {
23446    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23447        let settings = ThemeSettings::get_global(cx);
23448
23449        let mut text_style = match self.mode {
23450            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23451                color: cx.theme().colors().editor_foreground,
23452                font_family: settings.ui_font.family.clone(),
23453                font_features: settings.ui_font.features.clone(),
23454                font_fallbacks: settings.ui_font.fallbacks.clone(),
23455                font_size: rems(0.875).into(),
23456                font_weight: settings.ui_font.weight,
23457                line_height: relative(settings.buffer_line_height.value()),
23458                ..Default::default()
23459            },
23460            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23461                color: cx.theme().colors().editor_foreground,
23462                font_family: settings.buffer_font.family.clone(),
23463                font_features: settings.buffer_font.features.clone(),
23464                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23465                font_size: settings.buffer_font_size(cx).into(),
23466                font_weight: settings.buffer_font.weight,
23467                line_height: relative(settings.buffer_line_height.value()),
23468                ..Default::default()
23469            },
23470        };
23471        if let Some(text_style_refinement) = &self.text_style_refinement {
23472            text_style.refine(text_style_refinement)
23473        }
23474
23475        let background = match self.mode {
23476            EditorMode::SingleLine => cx.theme().system().transparent,
23477            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23478            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23479            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23480        };
23481
23482        EditorElement::new(
23483            &cx.entity(),
23484            EditorStyle {
23485                background,
23486                border: cx.theme().colors().border,
23487                local_player: cx.theme().players().local(),
23488                text: text_style,
23489                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23490                syntax: cx.theme().syntax().clone(),
23491                status: cx.theme().status().clone(),
23492                inlay_hints_style: make_inlay_hints_style(cx),
23493                edit_prediction_styles: make_suggestion_styles(cx),
23494                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23495                show_underlines: self.diagnostics_enabled(),
23496            },
23497        )
23498    }
23499}
23500
23501impl EntityInputHandler for Editor {
23502    fn text_for_range(
23503        &mut self,
23504        range_utf16: Range<usize>,
23505        adjusted_range: &mut Option<Range<usize>>,
23506        _: &mut Window,
23507        cx: &mut Context<Self>,
23508    ) -> Option<String> {
23509        let snapshot = self.buffer.read(cx).read(cx);
23510        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23511        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23512        if (start.0..end.0) != range_utf16 {
23513            adjusted_range.replace(start.0..end.0);
23514        }
23515        Some(snapshot.text_for_range(start..end).collect())
23516    }
23517
23518    fn selected_text_range(
23519        &mut self,
23520        ignore_disabled_input: bool,
23521        _: &mut Window,
23522        cx: &mut Context<Self>,
23523    ) -> Option<UTF16Selection> {
23524        // Prevent the IME menu from appearing when holding down an alphabetic key
23525        // while input is disabled.
23526        if !ignore_disabled_input && !self.input_enabled {
23527            return None;
23528        }
23529
23530        let selection = self.selections.newest::<OffsetUtf16>(cx);
23531        let range = selection.range();
23532
23533        Some(UTF16Selection {
23534            range: range.start.0..range.end.0,
23535            reversed: selection.reversed,
23536        })
23537    }
23538
23539    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23540        let snapshot = self.buffer.read(cx).read(cx);
23541        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23542        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23543    }
23544
23545    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23546        self.clear_highlights::<InputComposition>(cx);
23547        self.ime_transaction.take();
23548    }
23549
23550    fn replace_text_in_range(
23551        &mut self,
23552        range_utf16: Option<Range<usize>>,
23553        text: &str,
23554        window: &mut Window,
23555        cx: &mut Context<Self>,
23556    ) {
23557        if !self.input_enabled {
23558            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23559            return;
23560        }
23561
23562        self.transact(window, cx, |this, window, cx| {
23563            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23564                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23565                Some(this.selection_replacement_ranges(range_utf16, cx))
23566            } else {
23567                this.marked_text_ranges(cx)
23568            };
23569
23570            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23571                let newest_selection_id = this.selections.newest_anchor().id;
23572                this.selections
23573                    .all::<OffsetUtf16>(cx)
23574                    .iter()
23575                    .zip(ranges_to_replace.iter())
23576                    .find_map(|(selection, range)| {
23577                        if selection.id == newest_selection_id {
23578                            Some(
23579                                (range.start.0 as isize - selection.head().0 as isize)
23580                                    ..(range.end.0 as isize - selection.head().0 as isize),
23581                            )
23582                        } else {
23583                            None
23584                        }
23585                    })
23586            });
23587
23588            cx.emit(EditorEvent::InputHandled {
23589                utf16_range_to_replace: range_to_replace,
23590                text: text.into(),
23591            });
23592
23593            if let Some(new_selected_ranges) = new_selected_ranges {
23594                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23595                    selections.select_ranges(new_selected_ranges)
23596                });
23597                this.backspace(&Default::default(), window, cx);
23598            }
23599
23600            this.handle_input(text, window, cx);
23601        });
23602
23603        if let Some(transaction) = self.ime_transaction {
23604            self.buffer.update(cx, |buffer, cx| {
23605                buffer.group_until_transaction(transaction, cx);
23606            });
23607        }
23608
23609        self.unmark_text(window, cx);
23610    }
23611
23612    fn replace_and_mark_text_in_range(
23613        &mut self,
23614        range_utf16: Option<Range<usize>>,
23615        text: &str,
23616        new_selected_range_utf16: Option<Range<usize>>,
23617        window: &mut Window,
23618        cx: &mut Context<Self>,
23619    ) {
23620        if !self.input_enabled {
23621            return;
23622        }
23623
23624        let transaction = self.transact(window, cx, |this, window, cx| {
23625            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23626                let snapshot = this.buffer.read(cx).read(cx);
23627                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23628                    for marked_range in &mut marked_ranges {
23629                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23630                        marked_range.start.0 += relative_range_utf16.start;
23631                        marked_range.start =
23632                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23633                        marked_range.end =
23634                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23635                    }
23636                }
23637                Some(marked_ranges)
23638            } else if let Some(range_utf16) = range_utf16 {
23639                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23640                Some(this.selection_replacement_ranges(range_utf16, cx))
23641            } else {
23642                None
23643            };
23644
23645            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23646                let newest_selection_id = this.selections.newest_anchor().id;
23647                this.selections
23648                    .all::<OffsetUtf16>(cx)
23649                    .iter()
23650                    .zip(ranges_to_replace.iter())
23651                    .find_map(|(selection, range)| {
23652                        if selection.id == newest_selection_id {
23653                            Some(
23654                                (range.start.0 as isize - selection.head().0 as isize)
23655                                    ..(range.end.0 as isize - selection.head().0 as isize),
23656                            )
23657                        } else {
23658                            None
23659                        }
23660                    })
23661            });
23662
23663            cx.emit(EditorEvent::InputHandled {
23664                utf16_range_to_replace: range_to_replace,
23665                text: text.into(),
23666            });
23667
23668            if let Some(ranges) = ranges_to_replace {
23669                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23670                    s.select_ranges(ranges)
23671                });
23672            }
23673
23674            let marked_ranges = {
23675                let snapshot = this.buffer.read(cx).read(cx);
23676                this.selections
23677                    .disjoint_anchors_arc()
23678                    .iter()
23679                    .map(|selection| {
23680                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23681                    })
23682                    .collect::<Vec<_>>()
23683            };
23684
23685            if text.is_empty() {
23686                this.unmark_text(window, cx);
23687            } else {
23688                this.highlight_text::<InputComposition>(
23689                    marked_ranges.clone(),
23690                    HighlightStyle {
23691                        underline: Some(UnderlineStyle {
23692                            thickness: px(1.),
23693                            color: None,
23694                            wavy: false,
23695                        }),
23696                        ..Default::default()
23697                    },
23698                    cx,
23699                );
23700            }
23701
23702            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23703            let use_autoclose = this.use_autoclose;
23704            let use_auto_surround = this.use_auto_surround;
23705            this.set_use_autoclose(false);
23706            this.set_use_auto_surround(false);
23707            this.handle_input(text, window, cx);
23708            this.set_use_autoclose(use_autoclose);
23709            this.set_use_auto_surround(use_auto_surround);
23710
23711            if let Some(new_selected_range) = new_selected_range_utf16 {
23712                let snapshot = this.buffer.read(cx).read(cx);
23713                let new_selected_ranges = marked_ranges
23714                    .into_iter()
23715                    .map(|marked_range| {
23716                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23717                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23718                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23719                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23720                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23721                    })
23722                    .collect::<Vec<_>>();
23723
23724                drop(snapshot);
23725                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23726                    selections.select_ranges(new_selected_ranges)
23727                });
23728            }
23729        });
23730
23731        self.ime_transaction = self.ime_transaction.or(transaction);
23732        if let Some(transaction) = self.ime_transaction {
23733            self.buffer.update(cx, |buffer, cx| {
23734                buffer.group_until_transaction(transaction, cx);
23735            });
23736        }
23737
23738        if self.text_highlights::<InputComposition>(cx).is_none() {
23739            self.ime_transaction.take();
23740        }
23741    }
23742
23743    fn bounds_for_range(
23744        &mut self,
23745        range_utf16: Range<usize>,
23746        element_bounds: gpui::Bounds<Pixels>,
23747        window: &mut Window,
23748        cx: &mut Context<Self>,
23749    ) -> Option<gpui::Bounds<Pixels>> {
23750        let text_layout_details = self.text_layout_details(window);
23751        let CharacterDimensions {
23752            em_width,
23753            em_advance,
23754            line_height,
23755        } = self.character_dimensions(window);
23756
23757        let snapshot = self.snapshot(window, cx);
23758        let scroll_position = snapshot.scroll_position();
23759        let scroll_left = scroll_position.x * em_advance;
23760
23761        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23762        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23763            + self.gutter_dimensions.full_width();
23764        let y = line_height * (start.row().as_f32() - scroll_position.y);
23765
23766        Some(Bounds {
23767            origin: element_bounds.origin + point(x, y),
23768            size: size(em_width, line_height),
23769        })
23770    }
23771
23772    fn character_index_for_point(
23773        &mut self,
23774        point: gpui::Point<Pixels>,
23775        _window: &mut Window,
23776        _cx: &mut Context<Self>,
23777    ) -> Option<usize> {
23778        let position_map = self.last_position_map.as_ref()?;
23779        if !position_map.text_hitbox.contains(&point) {
23780            return None;
23781        }
23782        let display_point = position_map.point_for_position(point).previous_valid;
23783        let anchor = position_map
23784            .snapshot
23785            .display_point_to_anchor(display_point, Bias::Left);
23786        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23787        Some(utf16_offset.0)
23788    }
23789}
23790
23791trait SelectionExt {
23792    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23793    fn spanned_rows(
23794        &self,
23795        include_end_if_at_line_start: bool,
23796        map: &DisplaySnapshot,
23797    ) -> Range<MultiBufferRow>;
23798}
23799
23800impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23801    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23802        let start = self
23803            .start
23804            .to_point(&map.buffer_snapshot)
23805            .to_display_point(map);
23806        let end = self
23807            .end
23808            .to_point(&map.buffer_snapshot)
23809            .to_display_point(map);
23810        if self.reversed {
23811            end..start
23812        } else {
23813            start..end
23814        }
23815    }
23816
23817    fn spanned_rows(
23818        &self,
23819        include_end_if_at_line_start: bool,
23820        map: &DisplaySnapshot,
23821    ) -> Range<MultiBufferRow> {
23822        let start = self.start.to_point(&map.buffer_snapshot);
23823        let mut end = self.end.to_point(&map.buffer_snapshot);
23824        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23825            end.row -= 1;
23826        }
23827
23828        let buffer_start = map.prev_line_boundary(start).0;
23829        let buffer_end = map.next_line_boundary(end).0;
23830        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23831    }
23832}
23833
23834impl<T: InvalidationRegion> InvalidationStack<T> {
23835    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23836    where
23837        S: Clone + ToOffset,
23838    {
23839        while let Some(region) = self.last() {
23840            let all_selections_inside_invalidation_ranges =
23841                if selections.len() == region.ranges().len() {
23842                    selections
23843                        .iter()
23844                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23845                        .all(|(selection, invalidation_range)| {
23846                            let head = selection.head().to_offset(buffer);
23847                            invalidation_range.start <= head && invalidation_range.end >= head
23848                        })
23849                } else {
23850                    false
23851                };
23852
23853            if all_selections_inside_invalidation_ranges {
23854                break;
23855            } else {
23856                self.pop();
23857            }
23858        }
23859    }
23860}
23861
23862impl<T> Default for InvalidationStack<T> {
23863    fn default() -> Self {
23864        Self(Default::default())
23865    }
23866}
23867
23868impl<T> Deref for InvalidationStack<T> {
23869    type Target = Vec<T>;
23870
23871    fn deref(&self) -> &Self::Target {
23872        &self.0
23873    }
23874}
23875
23876impl<T> DerefMut for InvalidationStack<T> {
23877    fn deref_mut(&mut self) -> &mut Self::Target {
23878        &mut self.0
23879    }
23880}
23881
23882impl InvalidationRegion for SnippetState {
23883    fn ranges(&self) -> &[Range<Anchor>] {
23884        &self.ranges[self.active_index]
23885    }
23886}
23887
23888fn edit_prediction_edit_text(
23889    current_snapshot: &BufferSnapshot,
23890    edits: &[(Range<Anchor>, String)],
23891    edit_preview: &EditPreview,
23892    include_deletions: bool,
23893    cx: &App,
23894) -> HighlightedText {
23895    let edits = edits
23896        .iter()
23897        .map(|(anchor, text)| {
23898            (
23899                anchor.start.text_anchor..anchor.end.text_anchor,
23900                text.clone(),
23901            )
23902        })
23903        .collect::<Vec<_>>();
23904
23905    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23906}
23907
23908fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23909    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23910    // Just show the raw edit text with basic styling
23911    let mut text = String::new();
23912    let mut highlights = Vec::new();
23913
23914    let insertion_highlight_style = HighlightStyle {
23915        color: Some(cx.theme().colors().text),
23916        ..Default::default()
23917    };
23918
23919    for (_, edit_text) in edits {
23920        let start_offset = text.len();
23921        text.push_str(edit_text);
23922        let end_offset = text.len();
23923
23924        if start_offset < end_offset {
23925            highlights.push((start_offset..end_offset, insertion_highlight_style));
23926        }
23927    }
23928
23929    HighlightedText {
23930        text: text.into(),
23931        highlights,
23932    }
23933}
23934
23935pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23936    match severity {
23937        lsp::DiagnosticSeverity::ERROR => colors.error,
23938        lsp::DiagnosticSeverity::WARNING => colors.warning,
23939        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23940        lsp::DiagnosticSeverity::HINT => colors.info,
23941        _ => colors.ignored,
23942    }
23943}
23944
23945pub fn styled_runs_for_code_label<'a>(
23946    label: &'a CodeLabel,
23947    syntax_theme: &'a theme::SyntaxTheme,
23948) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23949    let fade_out = HighlightStyle {
23950        fade_out: Some(0.35),
23951        ..Default::default()
23952    };
23953
23954    let mut prev_end = label.filter_range.end;
23955    label
23956        .runs
23957        .iter()
23958        .enumerate()
23959        .flat_map(move |(ix, (range, highlight_id))| {
23960            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23961                style
23962            } else {
23963                return Default::default();
23964            };
23965            let muted_style = style.highlight(fade_out);
23966
23967            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23968            if range.start >= label.filter_range.end {
23969                if range.start > prev_end {
23970                    runs.push((prev_end..range.start, fade_out));
23971                }
23972                runs.push((range.clone(), muted_style));
23973            } else if range.end <= label.filter_range.end {
23974                runs.push((range.clone(), style));
23975            } else {
23976                runs.push((range.start..label.filter_range.end, style));
23977                runs.push((label.filter_range.end..range.end, muted_style));
23978            }
23979            prev_end = cmp::max(prev_end, range.end);
23980
23981            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23982                runs.push((prev_end..label.text.len(), fade_out));
23983            }
23984
23985            runs
23986        })
23987}
23988
23989pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23990    let mut prev_index = 0;
23991    let mut prev_codepoint: Option<char> = None;
23992    text.char_indices()
23993        .chain([(text.len(), '\0')])
23994        .filter_map(move |(index, codepoint)| {
23995            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23996            let is_boundary = index == text.len()
23997                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23998                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23999            if is_boundary {
24000                let chunk = &text[prev_index..index];
24001                prev_index = index;
24002                Some(chunk)
24003            } else {
24004                None
24005            }
24006        })
24007}
24008
24009pub trait RangeToAnchorExt: Sized {
24010    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24011
24012    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24013        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24014        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24015    }
24016}
24017
24018impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24019    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24020        let start_offset = self.start.to_offset(snapshot);
24021        let end_offset = self.end.to_offset(snapshot);
24022        if start_offset == end_offset {
24023            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24024        } else {
24025            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24026        }
24027    }
24028}
24029
24030pub trait RowExt {
24031    fn as_f32(&self) -> f32;
24032
24033    fn next_row(&self) -> Self;
24034
24035    fn previous_row(&self) -> Self;
24036
24037    fn minus(&self, other: Self) -> u32;
24038}
24039
24040impl RowExt for DisplayRow {
24041    fn as_f32(&self) -> f32 {
24042        self.0 as f32
24043    }
24044
24045    fn next_row(&self) -> Self {
24046        Self(self.0 + 1)
24047    }
24048
24049    fn previous_row(&self) -> Self {
24050        Self(self.0.saturating_sub(1))
24051    }
24052
24053    fn minus(&self, other: Self) -> u32 {
24054        self.0 - other.0
24055    }
24056}
24057
24058impl RowExt for MultiBufferRow {
24059    fn as_f32(&self) -> f32 {
24060        self.0 as f32
24061    }
24062
24063    fn next_row(&self) -> Self {
24064        Self(self.0 + 1)
24065    }
24066
24067    fn previous_row(&self) -> Self {
24068        Self(self.0.saturating_sub(1))
24069    }
24070
24071    fn minus(&self, other: Self) -> u32 {
24072        self.0 - other.0
24073    }
24074}
24075
24076trait RowRangeExt {
24077    type Row;
24078
24079    fn len(&self) -> usize;
24080
24081    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24082}
24083
24084impl RowRangeExt for Range<MultiBufferRow> {
24085    type Row = MultiBufferRow;
24086
24087    fn len(&self) -> usize {
24088        (self.end.0 - self.start.0) as usize
24089    }
24090
24091    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24092        (self.start.0..self.end.0).map(MultiBufferRow)
24093    }
24094}
24095
24096impl RowRangeExt for Range<DisplayRow> {
24097    type Row = DisplayRow;
24098
24099    fn len(&self) -> usize {
24100        (self.end.0 - self.start.0) as usize
24101    }
24102
24103    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24104        (self.start.0..self.end.0).map(DisplayRow)
24105    }
24106}
24107
24108/// If select range has more than one line, we
24109/// just point the cursor to range.start.
24110fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24111    if range.start.row == range.end.row {
24112        range
24113    } else {
24114        range.start..range.start
24115    }
24116}
24117pub struct KillRing(ClipboardItem);
24118impl Global for KillRing {}
24119
24120const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24121
24122enum BreakpointPromptEditAction {
24123    Log,
24124    Condition,
24125    HitCondition,
24126}
24127
24128struct BreakpointPromptEditor {
24129    pub(crate) prompt: Entity<Editor>,
24130    editor: WeakEntity<Editor>,
24131    breakpoint_anchor: Anchor,
24132    breakpoint: Breakpoint,
24133    edit_action: BreakpointPromptEditAction,
24134    block_ids: HashSet<CustomBlockId>,
24135    editor_margins: Arc<Mutex<EditorMargins>>,
24136    _subscriptions: Vec<Subscription>,
24137}
24138
24139impl BreakpointPromptEditor {
24140    const MAX_LINES: u8 = 4;
24141
24142    fn new(
24143        editor: WeakEntity<Editor>,
24144        breakpoint_anchor: Anchor,
24145        breakpoint: Breakpoint,
24146        edit_action: BreakpointPromptEditAction,
24147        window: &mut Window,
24148        cx: &mut Context<Self>,
24149    ) -> Self {
24150        let base_text = match edit_action {
24151            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24152            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24153            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24154        }
24155        .map(|msg| msg.to_string())
24156        .unwrap_or_default();
24157
24158        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24159        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24160
24161        let prompt = cx.new(|cx| {
24162            let mut prompt = Editor::new(
24163                EditorMode::AutoHeight {
24164                    min_lines: 1,
24165                    max_lines: Some(Self::MAX_LINES as usize),
24166                },
24167                buffer,
24168                None,
24169                window,
24170                cx,
24171            );
24172            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24173            prompt.set_show_cursor_when_unfocused(false, cx);
24174            prompt.set_placeholder_text(
24175                match edit_action {
24176                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24177                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24178                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24179                },
24180                window,
24181                cx,
24182            );
24183
24184            prompt
24185        });
24186
24187        Self {
24188            prompt,
24189            editor,
24190            breakpoint_anchor,
24191            breakpoint,
24192            edit_action,
24193            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24194            block_ids: Default::default(),
24195            _subscriptions: vec![],
24196        }
24197    }
24198
24199    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24200        self.block_ids.extend(block_ids)
24201    }
24202
24203    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24204        if let Some(editor) = self.editor.upgrade() {
24205            let message = self
24206                .prompt
24207                .read(cx)
24208                .buffer
24209                .read(cx)
24210                .as_singleton()
24211                .expect("A multi buffer in breakpoint prompt isn't possible")
24212                .read(cx)
24213                .as_rope()
24214                .to_string();
24215
24216            editor.update(cx, |editor, cx| {
24217                editor.edit_breakpoint_at_anchor(
24218                    self.breakpoint_anchor,
24219                    self.breakpoint.clone(),
24220                    match self.edit_action {
24221                        BreakpointPromptEditAction::Log => {
24222                            BreakpointEditAction::EditLogMessage(message.into())
24223                        }
24224                        BreakpointPromptEditAction::Condition => {
24225                            BreakpointEditAction::EditCondition(message.into())
24226                        }
24227                        BreakpointPromptEditAction::HitCondition => {
24228                            BreakpointEditAction::EditHitCondition(message.into())
24229                        }
24230                    },
24231                    cx,
24232                );
24233
24234                editor.remove_blocks(self.block_ids.clone(), None, cx);
24235                cx.focus_self(window);
24236            });
24237        }
24238    }
24239
24240    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24241        self.editor
24242            .update(cx, |editor, cx| {
24243                editor.remove_blocks(self.block_ids.clone(), None, cx);
24244                window.focus(&editor.focus_handle);
24245            })
24246            .log_err();
24247    }
24248
24249    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24250        let settings = ThemeSettings::get_global(cx);
24251        let text_style = TextStyle {
24252            color: if self.prompt.read(cx).read_only(cx) {
24253                cx.theme().colors().text_disabled
24254            } else {
24255                cx.theme().colors().text
24256            },
24257            font_family: settings.buffer_font.family.clone(),
24258            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24259            font_size: settings.buffer_font_size(cx).into(),
24260            font_weight: settings.buffer_font.weight,
24261            line_height: relative(settings.buffer_line_height.value()),
24262            ..Default::default()
24263        };
24264        EditorElement::new(
24265            &self.prompt,
24266            EditorStyle {
24267                background: cx.theme().colors().editor_background,
24268                local_player: cx.theme().players().local(),
24269                text: text_style,
24270                ..Default::default()
24271            },
24272        )
24273    }
24274}
24275
24276impl Render for BreakpointPromptEditor {
24277    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24278        let editor_margins = *self.editor_margins.lock();
24279        let gutter_dimensions = editor_margins.gutter;
24280        h_flex()
24281            .key_context("Editor")
24282            .bg(cx.theme().colors().editor_background)
24283            .border_y_1()
24284            .border_color(cx.theme().status().info_border)
24285            .size_full()
24286            .py(window.line_height() / 2.5)
24287            .on_action(cx.listener(Self::confirm))
24288            .on_action(cx.listener(Self::cancel))
24289            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24290            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24291    }
24292}
24293
24294impl Focusable for BreakpointPromptEditor {
24295    fn focus_handle(&self, cx: &App) -> FocusHandle {
24296        self.prompt.focus_handle(cx)
24297    }
24298}
24299
24300fn all_edits_insertions_or_deletions(
24301    edits: &Vec<(Range<Anchor>, String)>,
24302    snapshot: &MultiBufferSnapshot,
24303) -> bool {
24304    let mut all_insertions = true;
24305    let mut all_deletions = true;
24306
24307    for (range, new_text) in edits.iter() {
24308        let range_is_empty = range.to_offset(snapshot).is_empty();
24309        let text_is_empty = new_text.is_empty();
24310
24311        if range_is_empty != text_is_empty {
24312            if range_is_empty {
24313                all_deletions = false;
24314            } else {
24315                all_insertions = false;
24316            }
24317        } else {
24318            return false;
24319        }
24320
24321        if !all_insertions && !all_deletions {
24322            return false;
24323        }
24324    }
24325    all_insertions || all_deletions
24326}
24327
24328struct MissingEditPredictionKeybindingTooltip;
24329
24330impl Render for MissingEditPredictionKeybindingTooltip {
24331    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24332        ui::tooltip_container(window, cx, |container, _, cx| {
24333            container
24334                .flex_shrink_0()
24335                .max_w_80()
24336                .min_h(rems_from_px(124.))
24337                .justify_between()
24338                .child(
24339                    v_flex()
24340                        .flex_1()
24341                        .text_ui_sm(cx)
24342                        .child(Label::new("Conflict with Accept Keybinding"))
24343                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24344                )
24345                .child(
24346                    h_flex()
24347                        .pb_1()
24348                        .gap_1()
24349                        .items_end()
24350                        .w_full()
24351                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24352                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24353                        }))
24354                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24355                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24356                        })),
24357                )
24358        })
24359    }
24360}
24361
24362#[derive(Debug, Clone, Copy, PartialEq)]
24363pub struct LineHighlight {
24364    pub background: Background,
24365    pub border: Option<gpui::Hsla>,
24366    pub include_gutter: bool,
24367    pub type_id: Option<TypeId>,
24368}
24369
24370struct LineManipulationResult {
24371    pub new_text: String,
24372    pub line_count_before: usize,
24373    pub line_count_after: usize,
24374}
24375
24376fn render_diff_hunk_controls(
24377    row: u32,
24378    status: &DiffHunkStatus,
24379    hunk_range: Range<Anchor>,
24380    is_created_file: bool,
24381    line_height: Pixels,
24382    editor: &Entity<Editor>,
24383    _window: &mut Window,
24384    cx: &mut App,
24385) -> AnyElement {
24386    h_flex()
24387        .h(line_height)
24388        .mr_1()
24389        .gap_1()
24390        .px_0p5()
24391        .pb_1()
24392        .border_x_1()
24393        .border_b_1()
24394        .border_color(cx.theme().colors().border_variant)
24395        .rounded_b_lg()
24396        .bg(cx.theme().colors().editor_background)
24397        .gap_1()
24398        .block_mouse_except_scroll()
24399        .shadow_md()
24400        .child(if status.has_secondary_hunk() {
24401            Button::new(("stage", row as u64), "Stage")
24402                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24403                .tooltip({
24404                    let focus_handle = editor.focus_handle(cx);
24405                    move |window, cx| {
24406                        Tooltip::for_action_in(
24407                            "Stage Hunk",
24408                            &::git::ToggleStaged,
24409                            &focus_handle,
24410                            window,
24411                            cx,
24412                        )
24413                    }
24414                })
24415                .on_click({
24416                    let editor = editor.clone();
24417                    move |_event, _window, cx| {
24418                        editor.update(cx, |editor, cx| {
24419                            editor.stage_or_unstage_diff_hunks(
24420                                true,
24421                                vec![hunk_range.start..hunk_range.start],
24422                                cx,
24423                            );
24424                        });
24425                    }
24426                })
24427        } else {
24428            Button::new(("unstage", row as u64), "Unstage")
24429                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24430                .tooltip({
24431                    let focus_handle = editor.focus_handle(cx);
24432                    move |window, cx| {
24433                        Tooltip::for_action_in(
24434                            "Unstage Hunk",
24435                            &::git::ToggleStaged,
24436                            &focus_handle,
24437                            window,
24438                            cx,
24439                        )
24440                    }
24441                })
24442                .on_click({
24443                    let editor = editor.clone();
24444                    move |_event, _window, cx| {
24445                        editor.update(cx, |editor, cx| {
24446                            editor.stage_or_unstage_diff_hunks(
24447                                false,
24448                                vec![hunk_range.start..hunk_range.start],
24449                                cx,
24450                            );
24451                        });
24452                    }
24453                })
24454        })
24455        .child(
24456            Button::new(("restore", row as u64), "Restore")
24457                .tooltip({
24458                    let focus_handle = editor.focus_handle(cx);
24459                    move |window, cx| {
24460                        Tooltip::for_action_in(
24461                            "Restore Hunk",
24462                            &::git::Restore,
24463                            &focus_handle,
24464                            window,
24465                            cx,
24466                        )
24467                    }
24468                })
24469                .on_click({
24470                    let editor = editor.clone();
24471                    move |_event, window, cx| {
24472                        editor.update(cx, |editor, cx| {
24473                            let snapshot = editor.snapshot(window, cx);
24474                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24475                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24476                        });
24477                    }
24478                })
24479                .disabled(is_created_file),
24480        )
24481        .when(
24482            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24483            |el| {
24484                el.child(
24485                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24486                        .shape(IconButtonShape::Square)
24487                        .icon_size(IconSize::Small)
24488                        // .disabled(!has_multiple_hunks)
24489                        .tooltip({
24490                            let focus_handle = editor.focus_handle(cx);
24491                            move |window, cx| {
24492                                Tooltip::for_action_in(
24493                                    "Next Hunk",
24494                                    &GoToHunk,
24495                                    &focus_handle,
24496                                    window,
24497                                    cx,
24498                                )
24499                            }
24500                        })
24501                        .on_click({
24502                            let editor = editor.clone();
24503                            move |_event, window, cx| {
24504                                editor.update(cx, |editor, cx| {
24505                                    let snapshot = editor.snapshot(window, cx);
24506                                    let position =
24507                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24508                                    editor.go_to_hunk_before_or_after_position(
24509                                        &snapshot,
24510                                        position,
24511                                        Direction::Next,
24512                                        window,
24513                                        cx,
24514                                    );
24515                                    editor.expand_selected_diff_hunks(cx);
24516                                });
24517                            }
24518                        }),
24519                )
24520                .child(
24521                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24522                        .shape(IconButtonShape::Square)
24523                        .icon_size(IconSize::Small)
24524                        // .disabled(!has_multiple_hunks)
24525                        .tooltip({
24526                            let focus_handle = editor.focus_handle(cx);
24527                            move |window, cx| {
24528                                Tooltip::for_action_in(
24529                                    "Previous Hunk",
24530                                    &GoToPreviousHunk,
24531                                    &focus_handle,
24532                                    window,
24533                                    cx,
24534                                )
24535                            }
24536                        })
24537                        .on_click({
24538                            let editor = editor.clone();
24539                            move |_event, window, cx| {
24540                                editor.update(cx, |editor, cx| {
24541                                    let snapshot = editor.snapshot(window, cx);
24542                                    let point =
24543                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24544                                    editor.go_to_hunk_before_or_after_position(
24545                                        &snapshot,
24546                                        point,
24547                                        Direction::Prev,
24548                                        window,
24549                                        cx,
24550                                    );
24551                                    editor.expand_selected_diff_hunks(cx);
24552                                });
24553                            }
24554                        }),
24555                )
24556            },
24557        )
24558        .into_any_element()
24559}
24560
24561pub fn multibuffer_context_lines(cx: &App) -> u32 {
24562    EditorSettings::try_get(cx)
24563        .map(|settings| settings.excerpt_context_lines)
24564        .unwrap_or(2)
24565        .min(32)
24566}